spellcheck_provider_unittest.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/spellcheck/renderer/spellcheck_provider_test.h"
  5. #include "base/strings/utf_string_conversions.h"
  6. #include "base/test/scoped_feature_list.h"
  7. #include "build/build_config.h"
  8. #include "components/spellcheck/common/spellcheck_features.h"
  9. #include "components/spellcheck/renderer/spellcheck.h"
  10. #include "components/spellcheck/spellcheck_buildflags.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. #include "third_party/blink/public/platform/web_string.h"
  13. #include "third_party/blink/public/platform/web_vector.h"
  14. #include "third_party/blink/public/web/web_text_checking_result.h"
  15. #include "third_party/blink/public/web/web_text_decoration_type.h"
  16. namespace {
  17. #if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
  18. struct HybridSpellCheckTestCase {
  19. size_t language_count;
  20. size_t enabled_language_count;
  21. size_t expected_spelling_service_calls_count;
  22. size_t expected_text_check_requests_count;
  23. };
  24. struct CombineSpellCheckResultsTestCase {
  25. std::string browser_locale;
  26. std::string renderer_locale;
  27. const wchar_t* text;
  28. std::vector<SpellCheckResult> browser_results;
  29. bool use_spelling_service;
  30. blink::WebVector<blink::WebTextCheckingResult> expected_results;
  31. };
  32. std::ostream& operator<<(std::ostream& out,
  33. const CombineSpellCheckResultsTestCase& test_case) {
  34. out << "browser_locale=" << test_case.browser_locale
  35. << ", renderer_locale=" << test_case.renderer_locale << ", text=\""
  36. << test_case.text
  37. << "\", use_spelling_service=" << test_case.use_spelling_service;
  38. return out;
  39. }
  40. #endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
  41. class SpellCheckProviderCacheTest : public SpellCheckProviderTest {
  42. protected:
  43. void UpdateCustomDictionary() {
  44. SpellCheck* spellcheck = provider_.spellcheck();
  45. EXPECT_NE(spellcheck, nullptr);
  46. // Skip adding friend class - use public CustomDictionaryChanged from
  47. // |spellcheck::mojom::SpellChecker|
  48. static_cast<spellcheck::mojom::SpellChecker*>(spellcheck)
  49. ->CustomDictionaryChanged({}, {});
  50. }
  51. };
  52. #if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
  53. // Test fixture for testing hybrid check cases.
  54. class HybridSpellCheckTest
  55. : public testing::TestWithParam<HybridSpellCheckTestCase> {
  56. public:
  57. HybridSpellCheckTest() : provider_(&embedder_provider_) {}
  58. ~HybridSpellCheckTest() override {}
  59. void SetUp() override {
  60. // Don't delay initialization of the SpellcheckService on browser launch.
  61. feature_list_.InitWithFeatures(
  62. /*enabled_features=*/{spellcheck::kWinUseBrowserSpellChecker},
  63. /*disabled_features=*/{spellcheck::kWinDelaySpellcheckServiceInit});
  64. }
  65. void RunShouldUseBrowserSpellCheckOnlyWhenNeededTest();
  66. protected:
  67. base::test::ScopedFeatureList feature_list_;
  68. base::test::SingleThreadTaskEnvironment task_environment_;
  69. spellcheck::EmptyLocalInterfaceProvider embedder_provider_;
  70. TestingSpellCheckProvider provider_;
  71. };
  72. // Test fixture for testing hybrid check cases with delayed initialization of
  73. // the spellcheck service.
  74. class HybridSpellCheckTestDelayInit : public HybridSpellCheckTest {
  75. public:
  76. HybridSpellCheckTestDelayInit() = default;
  77. void SetUp() override {
  78. // Don't initialize the SpellcheckService on browser launch.
  79. feature_list_.InitWithFeatures(
  80. /*enabled_features=*/{spellcheck::kWinUseBrowserSpellChecker,
  81. spellcheck::kWinDelaySpellcheckServiceInit},
  82. /*disabled_features=*/{});
  83. }
  84. };
  85. // Test fixture for testing combining results from both the native spell checker
  86. // and Hunspell.
  87. class CombineSpellCheckResultsTest
  88. : public testing::TestWithParam<CombineSpellCheckResultsTestCase> {
  89. public:
  90. CombineSpellCheckResultsTest() : provider_(&embedder_provider_) {}
  91. ~CombineSpellCheckResultsTest() override {}
  92. protected:
  93. base::test::SingleThreadTaskEnvironment task_environment_;
  94. spellcheck::EmptyLocalInterfaceProvider embedder_provider_;
  95. TestingSpellCheckProvider provider_;
  96. };
  97. #endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
  98. TEST_F(SpellCheckProviderCacheTest, SubstringWithoutMisspellings) {
  99. FakeTextCheckingResult result;
  100. FakeTextCheckingCompletion completion(&result);
  101. blink::WebVector<blink::WebTextCheckingResult> last_results;
  102. provider_.SetLastResults(u"This is a test", last_results);
  103. EXPECT_TRUE(provider_.SatisfyRequestFromCache(u"This is a", &completion));
  104. EXPECT_EQ(result.completion_count_, 1U);
  105. }
  106. TEST_F(SpellCheckProviderCacheTest, SubstringWithMisspellings) {
  107. FakeTextCheckingResult result;
  108. FakeTextCheckingCompletion completion(&result);
  109. blink::WebVector<blink::WebTextCheckingResult> last_results;
  110. std::vector<blink::WebTextCheckingResult> results;
  111. results.push_back(
  112. blink::WebTextCheckingResult(blink::kWebTextDecorationTypeSpelling, 5, 3,
  113. std::vector<blink::WebString>({"isq"})));
  114. last_results.Assign(results);
  115. provider_.SetLastResults(u"This isq a test", last_results);
  116. EXPECT_TRUE(provider_.SatisfyRequestFromCache(u"This isq a", &completion));
  117. EXPECT_EQ(result.completion_count_, 1U);
  118. }
  119. TEST_F(SpellCheckProviderCacheTest, ShorterTextNotSubstring) {
  120. FakeTextCheckingResult result;
  121. FakeTextCheckingCompletion completion(&result);
  122. blink::WebVector<blink::WebTextCheckingResult> last_results;
  123. provider_.SetLastResults(u"This is a test", last_results);
  124. EXPECT_FALSE(provider_.SatisfyRequestFromCache(u"That is a", &completion));
  125. EXPECT_EQ(result.completion_count_, 0U);
  126. }
  127. TEST_F(SpellCheckProviderCacheTest, ResetCacheOnCustomDictionaryUpdate) {
  128. FakeTextCheckingResult result;
  129. FakeTextCheckingCompletion completion(&result);
  130. blink::WebVector<blink::WebTextCheckingResult> last_results;
  131. provider_.SetLastResults(u"This is a test", last_results);
  132. UpdateCustomDictionary();
  133. EXPECT_FALSE(provider_.SatisfyRequestFromCache(u"This is a", &completion));
  134. EXPECT_EQ(result.completion_count_, 0U);
  135. }
  136. #if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
  137. // Tests that the SpellCheckProvider does not call into the native spell checker
  138. // on Windows when the native spell checker flags are disabled.
  139. TEST_F(SpellCheckProviderTest, ShouldNotUseBrowserSpellCheck) {
  140. base::test::ScopedFeatureList local_feature;
  141. local_feature.InitAndDisableFeature(spellcheck::kWinUseBrowserSpellChecker);
  142. FakeTextCheckingResult completion;
  143. std::u16string text = u"This is a test";
  144. provider_.RequestTextChecking(
  145. text, std::make_unique<FakeTextCheckingCompletion>(&completion));
  146. EXPECT_EQ(provider_.spelling_service_call_count_, 1U);
  147. EXPECT_EQ(provider_.text_check_requests_.size(), 0U);
  148. EXPECT_EQ(completion.completion_count_, 1U);
  149. EXPECT_EQ(completion.cancellation_count_, 0U);
  150. }
  151. static const HybridSpellCheckTestCase kSpellCheckProviderHybridTestsParams[] = {
  152. // No languages - should go straight to completion
  153. HybridSpellCheckTestCase{0U, 0U, 0U, 0U},
  154. // 1 disabled language - should go to browser
  155. HybridSpellCheckTestCase{1U, 0U, 0U, 1U},
  156. // 1 enabled language - should skip browser
  157. HybridSpellCheckTestCase{1U, 1U, 1U, 0U},
  158. // 1 disabled language, 1 enabled - should should go to browser
  159. HybridSpellCheckTestCase{2U, 1U, 0U, 1U},
  160. // 3 enabled languages - should skip browser
  161. HybridSpellCheckTestCase{3U, 3U, 1U, 0U},
  162. // 3 disabled languages - should go to browser
  163. HybridSpellCheckTestCase{3U, 0U, 0U, 1U},
  164. // 3 disabled languages, 3 enabled - should go to browser
  165. HybridSpellCheckTestCase{6U, 3U, 0U, 1U}};
  166. // Tests that the SpellCheckProvider calls into the native spell checker only
  167. // when needed.
  168. INSTANTIATE_TEST_SUITE_P(
  169. SpellCheckProviderHybridTests,
  170. HybridSpellCheckTest,
  171. testing::ValuesIn(kSpellCheckProviderHybridTestsParams));
  172. TEST_P(HybridSpellCheckTest, ShouldUseBrowserSpellCheckOnlyWhenNeeded) {
  173. RunShouldUseBrowserSpellCheckOnlyWhenNeededTest();
  174. }
  175. void HybridSpellCheckTest::RunShouldUseBrowserSpellCheckOnlyWhenNeededTest() {
  176. if (!spellcheck::WindowsVersionSupportsSpellchecker()) {
  177. return;
  178. }
  179. const auto& test_case = GetParam();
  180. FakeTextCheckingResult completion;
  181. provider_.spellcheck()->SetFakeLanguageCounts(
  182. test_case.language_count, test_case.enabled_language_count);
  183. provider_.RequestTextChecking(
  184. u"This is a test",
  185. std::make_unique<FakeTextCheckingCompletion>(&completion));
  186. EXPECT_EQ(provider_.spelling_service_call_count_,
  187. test_case.expected_spelling_service_calls_count);
  188. EXPECT_EQ(provider_.text_check_requests_.size(),
  189. test_case.expected_text_check_requests_count);
  190. EXPECT_EQ(completion.completion_count_,
  191. test_case.expected_text_check_requests_count > 0u ? 0u : 1u);
  192. EXPECT_EQ(completion.cancellation_count_, 0U);
  193. }
  194. // Tests that the SpellCheckProvider calls into the native spell checker only
  195. // when needed when the code path through
  196. // SpellCheckProvider::RequestTextChecking is that used when the spellcheck
  197. // service is initialized on demand.
  198. INSTANTIATE_TEST_SUITE_P(
  199. SpellCheckProviderHybridTests,
  200. HybridSpellCheckTestDelayInit,
  201. testing::ValuesIn(kSpellCheckProviderHybridTestsParams));
  202. TEST_P(HybridSpellCheckTestDelayInit,
  203. ShouldUseBrowserSpellCheckOnlyWhenNeeded) {
  204. RunShouldUseBrowserSpellCheckOnlyWhenNeededTest();
  205. }
  206. // Tests that the SpellCheckProvider can correctly combine results from the
  207. // native spell checker and Hunspell.
  208. INSTANTIATE_TEST_SUITE_P(
  209. SpellCheckProviderCombineResultsTests,
  210. CombineSpellCheckResultsTest,
  211. testing::Values(
  212. // Browser-only check, no browser results
  213. CombineSpellCheckResultsTestCase{"en-US",
  214. "",
  215. L"This has no misspellings",
  216. {},
  217. false,
  218. {}},
  219. // Browser-only check, no spelling service, browser results
  220. CombineSpellCheckResultsTestCase{
  221. "en-US",
  222. "",
  223. L"Tihs has soem misspellings",
  224. {SpellCheckResult(SpellCheckResult::SPELLING,
  225. 0,
  226. 4,
  227. {std::u16string(u"foo")}),
  228. SpellCheckResult(SpellCheckResult::SPELLING,
  229. 9,
  230. 4,
  231. {std::u16string(u"foo")})},
  232. false,
  233. blink::WebVector<blink::WebTextCheckingResult>(
  234. {blink::WebTextCheckingResult(
  235. blink::WebTextDecorationType::
  236. kWebTextDecorationTypeSpelling,
  237. 0,
  238. 4),
  239. blink::WebTextCheckingResult(
  240. blink::WebTextDecorationType::
  241. kWebTextDecorationTypeSpelling,
  242. 9,
  243. 4)})},
  244. // Browser-only check, no spelling service, browser results, some words
  245. // in character sets with no dictionaries enabled.
  246. CombineSpellCheckResultsTestCase{
  247. "en-US",
  248. "",
  249. L"Tihs has soem \x3053\x3093\x306B\x3061\x306F \x4F60\x597D "
  250. L"\xC548\xB155\xD558\xC138\xC694 "
  251. L"\x0930\x093E\x091C\x0927\x093E\x0928 words in different "
  252. L"character sets "
  253. L"(Japanese, Chinese, Korean, Hindi)",
  254. {SpellCheckResult(SpellCheckResult::SPELLING,
  255. 0,
  256. 4,
  257. {std::u16string(u"foo")}),
  258. SpellCheckResult(SpellCheckResult::SPELLING,
  259. 9,
  260. 4,
  261. {std::u16string(u"foo")}),
  262. SpellCheckResult(SpellCheckResult::SPELLING,
  263. 14,
  264. 5,
  265. {std::u16string(u"foo")}),
  266. SpellCheckResult(SpellCheckResult::SPELLING,
  267. 20,
  268. 2,
  269. {std::u16string(u"foo")}),
  270. SpellCheckResult(SpellCheckResult::SPELLING,
  271. 23,
  272. 5,
  273. {std::u16string(u"foo")}),
  274. SpellCheckResult(SpellCheckResult::SPELLING,
  275. 29,
  276. 6,
  277. {std::u16string(u"foo")})},
  278. false,
  279. blink::WebVector<blink::WebTextCheckingResult>(
  280. {blink::WebTextCheckingResult(
  281. blink::WebTextDecorationType::
  282. kWebTextDecorationTypeSpelling,
  283. 0,
  284. 4),
  285. blink::WebTextCheckingResult(
  286. blink::WebTextDecorationType::
  287. kWebTextDecorationTypeSpelling,
  288. 9,
  289. 4)})},
  290. // Browser-only check, spelling service, spelling-only browser results
  291. CombineSpellCheckResultsTestCase{
  292. "en-US",
  293. "",
  294. L"Tihs has soem misspellings",
  295. {SpellCheckResult(SpellCheckResult::SPELLING,
  296. 0,
  297. 4,
  298. {std::u16string(u"foo")}),
  299. SpellCheckResult(SpellCheckResult::SPELLING,
  300. 9,
  301. 4,
  302. {std::u16string(u"foo")})},
  303. true,
  304. blink::WebVector<blink::WebTextCheckingResult>(
  305. {blink::WebTextCheckingResult(
  306. blink::WebTextDecorationType::
  307. kWebTextDecorationTypeSpelling,
  308. 0,
  309. 4),
  310. blink::WebTextCheckingResult(
  311. blink::WebTextDecorationType::
  312. kWebTextDecorationTypeSpelling,
  313. 9,
  314. 4)})},
  315. // Browser-only check, spelling service, spelling and grammar browser
  316. // results
  317. CombineSpellCheckResultsTestCase{
  318. "en-US",
  319. "",
  320. L"Tihs has soem misspellings",
  321. {SpellCheckResult(SpellCheckResult::SPELLING,
  322. 0,
  323. 4,
  324. {std::u16string(u"foo")}),
  325. SpellCheckResult(SpellCheckResult::GRAMMAR,
  326. 9,
  327. 4,
  328. {std::u16string(u"foo")})},
  329. true,
  330. blink::WebVector<blink::WebTextCheckingResult>(
  331. {blink::WebTextCheckingResult(
  332. blink::WebTextDecorationType::
  333. kWebTextDecorationTypeSpelling,
  334. 0,
  335. 4),
  336. blink::WebTextCheckingResult(blink::WebTextDecorationType::
  337. kWebTextDecorationTypeGrammar,
  338. 9,
  339. 4)})},
  340. // Hybrid check, no browser results
  341. CombineSpellCheckResultsTestCase{"en-US",
  342. "en-US",
  343. L"This has no misspellings",
  344. {},
  345. false,
  346. {}},
  347. // Hybrid check, no spelling service, browser results that all coincide
  348. // with Hunspell results
  349. CombineSpellCheckResultsTestCase{
  350. "en-US",
  351. "en-US",
  352. L"Tihs has soem misspellings",
  353. {SpellCheckResult(SpellCheckResult::SPELLING,
  354. 0,
  355. 4,
  356. {std::u16string(u"foo")}),
  357. SpellCheckResult(SpellCheckResult::SPELLING,
  358. 9,
  359. 4,
  360. {std::u16string(u"foo")})},
  361. false,
  362. blink::WebVector<blink::WebTextCheckingResult>(
  363. {blink::WebTextCheckingResult(
  364. blink::WebTextDecorationType::
  365. kWebTextDecorationTypeSpelling,
  366. 0,
  367. 4),
  368. blink::WebTextCheckingResult(
  369. blink::WebTextDecorationType::
  370. kWebTextDecorationTypeSpelling,
  371. 9,
  372. 4)})},
  373. // Hybrid check, no spelling service, browser results that partially
  374. // coincide with Hunspell results
  375. CombineSpellCheckResultsTestCase{
  376. "en-US",
  377. "en-US",
  378. L"Tihs has soem misspellings",
  379. {
  380. SpellCheckResult(SpellCheckResult::SPELLING,
  381. 0,
  382. 4,
  383. {std::u16string(u"foo")}),
  384. SpellCheckResult(SpellCheckResult::SPELLING,
  385. 5,
  386. 3,
  387. {std::u16string(u"foo")}),
  388. SpellCheckResult(SpellCheckResult::SPELLING,
  389. 9,
  390. 4,
  391. {std::u16string(u"foo")}),
  392. SpellCheckResult(SpellCheckResult::SPELLING,
  393. 14,
  394. 12,
  395. {std::u16string(u"foo")}),
  396. },
  397. false,
  398. blink::WebVector<blink::WebTextCheckingResult>(
  399. {blink::WebTextCheckingResult(
  400. blink::WebTextDecorationType::
  401. kWebTextDecorationTypeSpelling,
  402. 0,
  403. 4),
  404. blink::WebTextCheckingResult(
  405. blink::WebTextDecorationType::
  406. kWebTextDecorationTypeSpelling,
  407. 9,
  408. 4)})},
  409. // Hybrid check, no spelling service, browser results that don't
  410. // coincide with Hunspell results
  411. CombineSpellCheckResultsTestCase{
  412. "en-US",
  413. "en-US",
  414. L"Tihs has soem misspellings",
  415. {SpellCheckResult(SpellCheckResult::SPELLING,
  416. 5,
  417. 3,
  418. {std::u16string(u"foo")}),
  419. SpellCheckResult(SpellCheckResult::SPELLING,
  420. 14,
  421. 12,
  422. {std::u16string(u"foo")})},
  423. false,
  424. blink::WebVector<blink::WebTextCheckingResult>()},
  425. // Hybrid check, no spelling service, browser results with some that
  426. // that are in character set that does not have dictionary support (so
  427. // (are considered spelled correctly)
  428. CombineSpellCheckResultsTestCase{
  429. "en-US",
  430. "fr",
  431. L"Tihs mot is misspelled in Russian: "
  432. L"\x043C\x0438\x0440\x0432\x043E\x0439",
  433. {SpellCheckResult(SpellCheckResult::SPELLING,
  434. 0,
  435. 4,
  436. {std::u16string(u"foo")}),
  437. SpellCheckResult(SpellCheckResult::SPELLING,
  438. 5,
  439. 3,
  440. {std::u16string(u"foo")}),
  441. SpellCheckResult(SpellCheckResult::SPELLING,
  442. 35,
  443. 6,
  444. {std::u16string(u"foo")})},
  445. false,
  446. blink::WebVector<blink::WebTextCheckingResult>(
  447. std::vector<blink::WebTextCheckingResult>(
  448. {blink::WebTextCheckingResult(
  449. blink::WebTextDecorationType::
  450. kWebTextDecorationTypeSpelling,
  451. 0,
  452. 4)}))},
  453. // Hybrid check, no spelling service, text with some words in a
  454. // character set that only has a Hunspell dictionary enabled.
  455. CombineSpellCheckResultsTestCase{
  456. "en-US",
  457. "ru",
  458. L"Tihs \x0432\x0441\x0435\x0445 is misspelled in Russian: "
  459. L"\x043C\x0438\x0440\x0432\x043E\x0439",
  460. {SpellCheckResult(SpellCheckResult::SPELLING,
  461. 0,
  462. 4,
  463. {std::u16string(u"foo")}),
  464. SpellCheckResult(SpellCheckResult::SPELLING,
  465. 5,
  466. 4,
  467. {std::u16string(u"foo")}),
  468. SpellCheckResult(SpellCheckResult::SPELLING,
  469. 36,
  470. 6,
  471. {std::u16string(u"foo")})},
  472. false,
  473. blink::WebVector<blink::WebTextCheckingResult>(
  474. {blink::WebTextCheckingResult(
  475. blink::WebTextDecorationType::
  476. kWebTextDecorationTypeSpelling,
  477. 0,
  478. 4),
  479. blink::WebTextCheckingResult(
  480. blink::WebTextDecorationType::
  481. kWebTextDecorationTypeSpelling,
  482. 36,
  483. 6)})},
  484. // Hybrid check, spelling service, spelling and grammar browser results
  485. // that all coincide with Hunspell results
  486. CombineSpellCheckResultsTestCase{
  487. "en-US",
  488. "en-US",
  489. L"Tihs has soem misspellings",
  490. {SpellCheckResult(SpellCheckResult::SPELLING,
  491. 0,
  492. 4,
  493. {std::u16string(u"foo")}),
  494. SpellCheckResult(SpellCheckResult::GRAMMAR,
  495. 9,
  496. 4,
  497. {std::u16string(u"foo")})},
  498. true,
  499. blink::WebVector<blink::WebTextCheckingResult>(
  500. {blink::WebTextCheckingResult(
  501. blink::WebTextDecorationType::
  502. kWebTextDecorationTypeSpelling,
  503. 0,
  504. 4),
  505. blink::WebTextCheckingResult(blink::WebTextDecorationType::
  506. kWebTextDecorationTypeGrammar,
  507. 9,
  508. 4)})},
  509. // Hybrid check, spelling service, spelling and grammar browser results
  510. // but some of the spelling results are correctly spelled in Hunspell
  511. // locales
  512. CombineSpellCheckResultsTestCase{
  513. "en-US",
  514. "en-US",
  515. L"This has soem misspellings",
  516. {SpellCheckResult(SpellCheckResult::SPELLING,
  517. 0,
  518. 4,
  519. {std::u16string(u"foo")}),
  520. SpellCheckResult(SpellCheckResult::SPELLING,
  521. 9,
  522. 4,
  523. {std::u16string(u"foo")})},
  524. true,
  525. blink::WebVector<blink::WebTextCheckingResult>(
  526. {blink::WebTextCheckingResult(blink::WebTextDecorationType::
  527. kWebTextDecorationTypeGrammar,
  528. 0,
  529. 4),
  530. blink::WebTextCheckingResult(
  531. blink::WebTextDecorationType::
  532. kWebTextDecorationTypeSpelling,
  533. 9,
  534. 4)})}));
  535. TEST_P(CombineSpellCheckResultsTest, ShouldCorrectlyCombineHybridResults) {
  536. if (!spellcheck::WindowsVersionSupportsSpellchecker()) {
  537. return;
  538. }
  539. const auto& test_case = GetParam();
  540. base::test::ScopedFeatureList local_features;
  541. local_features.InitAndEnableFeature(spellcheck::kWinUseBrowserSpellChecker);
  542. const bool has_browser_check = !test_case.browser_locale.empty();
  543. const bool has_renderer_check = !test_case.renderer_locale.empty();
  544. if (has_browser_check) {
  545. provider_.spellcheck()->InitializeSpellCheckForLocale(
  546. test_case.browser_locale, /*use_hunspell*/ false);
  547. }
  548. if (has_renderer_check) {
  549. provider_.spellcheck()->InitializeSpellCheckForLocale(
  550. test_case.renderer_locale, /*use_hunspell*/ true);
  551. }
  552. if (test_case.use_spelling_service) {
  553. for (auto& result : test_case.browser_results) {
  554. const_cast<SpellCheckResult&>(result).spelling_service_used = true;
  555. }
  556. }
  557. FakeTextCheckingResult completion;
  558. SpellCheckProvider::HybridSpellCheckRequestInfo request_info = {
  559. /*used_hunspell=*/has_renderer_check,
  560. /*used_native=*/has_browser_check, base::TimeTicks::Now()};
  561. int check_id = provider_.AddCompletionForTest(
  562. std::make_unique<FakeTextCheckingCompletion>(&completion), request_info);
  563. provider_.OnRespondTextCheck(check_id, base::WideToUTF16(test_case.text),
  564. test_case.browser_results);
  565. // Should have called the completion callback without cancellation, and should
  566. // not have initiated more requests.
  567. ASSERT_EQ(completion.completion_count_, 1u);
  568. ASSERT_EQ(completion.cancellation_count_, 0U);
  569. ASSERT_EQ(provider_.spelling_service_call_count_, 0u);
  570. ASSERT_EQ(provider_.text_check_requests_.size(), 0u);
  571. // Should have the expected spell check results.
  572. ASSERT_EQ(test_case.expected_results.size(), completion.results_.size());
  573. for (size_t i = 0; i < test_case.expected_results.size(); ++i) {
  574. const auto& expected = test_case.expected_results[i];
  575. const auto& actual = completion.results_[i];
  576. ASSERT_EQ(expected.decoration, actual.decoration);
  577. ASSERT_EQ(expected.location, actual.location);
  578. ASSERT_EQ(expected.length, actual.length);
  579. if (has_renderer_check) {
  580. // Replacements should have been purged so Blink doesn't cache incomplete
  581. // suggestions.
  582. ASSERT_EQ(actual.replacements.size(), 0u);
  583. } else {
  584. // Replacements should have been kept since they are complete.
  585. ASSERT_GT(actual.replacements.size(), 0u);
  586. }
  587. }
  588. }
  589. #endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
  590. } // namespace