1 // Copyright (c) 2012 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 
5 #include "chrome/browser/spellchecker/spellcheck_custom_dictionary.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/bind.h"
14 #include "base/files/file_util.h"
15 #include "base/macros.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/metrics/histogram_samples.h"
18 #include "base/metrics/statistics_recorder.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "build/build_config.h"
21 #include "chrome/browser/spellchecker/spellcheck_factory.h"
22 #include "chrome/browser/spellchecker/spellcheck_service.h"
23 #include "chrome/common/chrome_constants.h"
24 #include "chrome/test/base/testing_profile.h"
25 #include "components/spellcheck/browser/spellcheck_host_metrics.h"
26 #include "components/spellcheck/common/spellcheck_common.h"
27 #include "components/sync/model/sync_change.h"
28 #include "components/sync/model/sync_change_processor_wrapper_for_test.h"
29 #include "components/sync/model/sync_data.h"
30 #include "components/sync/model/sync_error_factory.h"
31 #include "components/sync/model/sync_error_factory_mock.h"
32 #include "components/sync/protocol/sync.pb.h"
33 #include "content/public/test/browser_task_environment.h"
34 #include "content/public/test/test_utils.h"
35 #include "net/test/embedded_test_server/default_handlers.h"
36 #include "net/test/embedded_test_server/embedded_test_server.h"
37 #include "net/test/embedded_test_server/http_request.h"
38 #include "net/test/embedded_test_server/http_response.h"
39 #include "testing/gmock/include/gmock/gmock.h"
40 #include "testing/gtest/include/gtest/gtest.h"
41 
42 using base::HistogramBase;
43 using base::HistogramSamples;
44 using base::StatisticsRecorder;
45 
46 namespace {
47 
48 // Get all sync data for the custom dictionary without limiting to maximum
49 // number of syncable words.
GetAllSyncDataNoLimit(const SpellcheckCustomDictionary * dictionary)50 syncer::SyncDataList GetAllSyncDataNoLimit(
51     const SpellcheckCustomDictionary* dictionary) {
52   syncer::SyncDataList data;
53   for (const std::string& word : dictionary->GetWords()) {
54     sync_pb::EntitySpecifics specifics;
55     specifics.mutable_dictionary()->set_word(word);
56     data.push_back(syncer::SyncData::CreateLocalData(word, word, specifics));
57   }
58   return data;
59 }
60 
61 }  // namespace
62 
BuildSpellcheckService(content::BrowserContext * profile)63 static std::unique_ptr<KeyedService> BuildSpellcheckService(
64     content::BrowserContext* profile) {
65   return std::make_unique<SpellcheckService>(static_cast<Profile*>(profile));
66 }
67 
68 class SpellcheckCustomDictionaryTest : public testing::Test {
69  public:
SpellcheckCustomDictionaryTest()70   SpellcheckCustomDictionaryTest()
71       : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {}
72 
73  protected:
SetUp()74   void SetUp() override {
75     // Use SetTestingFactoryAndUse to force creation and initialization.
76     SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
77         &profile_, base::BindRepeating(&BuildSpellcheckService));
78   }
79 
80   // A wrapper around SpellcheckCustomDictionary::LoadDictionaryFile private
81   // function to avoid a large number of FRIEND_TEST declarations in
82   // SpellcheckCustomDictionary.
83   std::unique_ptr<SpellcheckCustomDictionary::LoadFileResult>
LoadDictionaryFile(const base::FilePath & path)84   LoadDictionaryFile(const base::FilePath& path) {
85     return SpellcheckCustomDictionary::LoadDictionaryFile(path);
86   }
87 
88   // A wrapper around SpellcheckCustomDictionary::UpdateDictionaryFile private
89   // function to avoid a large number of FRIEND_TEST declarations in
90   // SpellcheckCustomDictionary.
UpdateDictionaryFile(std::unique_ptr<SpellcheckCustomDictionary::Change> dictionary_change,const base::FilePath & path)91   void UpdateDictionaryFile(
92       std::unique_ptr<SpellcheckCustomDictionary::Change> dictionary_change,
93       const base::FilePath& path) {
94     SpellcheckCustomDictionary::UpdateDictionaryFile(
95         std::move(dictionary_change), path);
96   }
97 
98   // A wrapper around SpellcheckCustomDictionary::OnLoaded private method to
99   // avoid a large number of FRIEND_TEST declarations in
100   // SpellcheckCustomDictionary.
OnLoaded(SpellcheckCustomDictionary & dictionary,std::unique_ptr<std::set<std::string>> words)101   void OnLoaded(SpellcheckCustomDictionary& dictionary,
102                 std::unique_ptr<std::set<std::string>> words) {
103     std::unique_ptr<SpellcheckCustomDictionary::LoadFileResult> result(
104         new SpellcheckCustomDictionary::LoadFileResult);
105     result->is_valid_file = true;
106     result->words = *words;
107     dictionary.OnLoaded(std::move(result));
108   }
109 
110   // A wrapper around SpellcheckCustomDictionary::Apply private method to avoid
111   // a large number of FRIEND_TEST declarations in SpellcheckCustomDictionary.
Apply(SpellcheckCustomDictionary & dictionary,const SpellcheckCustomDictionary::Change & change)112   void Apply(
113       SpellcheckCustomDictionary& dictionary,
114       const SpellcheckCustomDictionary::Change& change) {
115     return dictionary.Apply(change);
116   }
117 
118   content::BrowserTaskEnvironment task_environment_;
119 
120   TestingProfile profile_;
121 };
122 
123 // An implementation of SyncErrorFactory that does not upload the error message
124 // and updates an outside error counter. This lets us know the number of error
125 // messages in an instance of this class after that instance is deleted.
126 class SyncErrorFactoryStub : public syncer::SyncErrorFactory {
127  public:
SyncErrorFactoryStub(int * error_counter)128   explicit SyncErrorFactoryStub(int* error_counter)
129       : error_counter_(error_counter) {}
~SyncErrorFactoryStub()130   ~SyncErrorFactoryStub() override {}
131 
132   // Overridden from syncer::SyncErrorFactory:
CreateAndUploadError(const base::Location & location,const std::string & message)133   syncer::SyncError CreateAndUploadError(const base::Location& location,
134                                          const std::string& message) override {
135     (*error_counter_)++;
136     return syncer::SyncError(location,
137                              syncer::SyncError::DATATYPE_ERROR,
138                              message,
139                              syncer::DICTIONARY);
140   }
141 
142  private:
143   int* error_counter_;
144   DISALLOW_COPY_AND_ASSIGN(SyncErrorFactoryStub);
145 };
146 
147 // Counts the number of notifications for dictionary load and change.
148 class DictionaryObserverCounter : public SpellcheckCustomDictionary::Observer {
149  public:
DictionaryObserverCounter()150   DictionaryObserverCounter() : loads_(0), changes_(0) {}
~DictionaryObserverCounter()151   virtual ~DictionaryObserverCounter() {}
152 
loads() const153   int loads() const { return loads_; }
changes() const154   int changes() const { return changes_; }
155 
156   // Overridden from SpellcheckCustomDictionary::Observer:
OnCustomDictionaryLoaded()157   void OnCustomDictionaryLoaded() override { loads_++; }
OnCustomDictionaryChanged(const SpellcheckCustomDictionary::Change & change)158   void OnCustomDictionaryChanged(
159       const SpellcheckCustomDictionary::Change& change) override {
160     changes_++;
161   }
162 
163  private:
164   int loads_;
165   int changes_;
166   DISALLOW_COPY_AND_ASSIGN(DictionaryObserverCounter);
167 };
168 
TEST_F(SpellcheckCustomDictionaryTest,SaveAndLoad)169 TEST_F(SpellcheckCustomDictionaryTest, SaveAndLoad) {
170   base::FilePath path =
171       profile_.GetPath().Append(chrome::kCustomDictionaryFileName);
172 
173   // The custom word list should be empty now.
174   EXPECT_TRUE(LoadDictionaryFile(path)->words.empty());
175 
176   std::unique_ptr<SpellcheckCustomDictionary::Change> change(
177       new SpellcheckCustomDictionary::Change);
178   change->AddWord("bar");
179   change->AddWord("foo");
180 
181   UpdateDictionaryFile(std::move(change), path);
182   std::set<std::string> expected;
183   expected.insert("bar");
184   expected.insert("foo");
185 
186   // The custom word list should include written words.
187   EXPECT_EQ(expected, LoadDictionaryFile(path)->words);
188 
189   std::unique_ptr<SpellcheckCustomDictionary::Change> change2(
190       new SpellcheckCustomDictionary::Change);
191   change2->RemoveWord("bar");
192   change2->RemoveWord("foo");
193   UpdateDictionaryFile(std::move(change2), path);
194   EXPECT_TRUE(LoadDictionaryFile(path)->words.empty());
195 }
196 
TEST_F(SpellcheckCustomDictionaryTest,MultiProfile)197 TEST_F(SpellcheckCustomDictionaryTest, MultiProfile) {
198   SpellcheckService* spellcheck_service =
199       SpellcheckServiceFactory::GetForContext(&profile_);
200   SpellcheckCustomDictionary* custom_dictionary =
201       spellcheck_service->GetCustomDictionary();
202   TestingProfile profile2;
203   SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
204       SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
205           &profile2, base::BindRepeating(&BuildSpellcheckService)));
206   SpellcheckCustomDictionary* custom_dictionary2 =
207       spellcheck_service2->GetCustomDictionary();
208 
209   std::set<std::string> expected1;
210   std::set<std::string> expected2;
211 
212   custom_dictionary->AddWord("foo");
213   custom_dictionary->AddWord("bar");
214   expected1.insert("foo");
215   expected1.insert("bar");
216 
217   custom_dictionary2->AddWord("hoge");
218   custom_dictionary2->AddWord("fuga");
219   expected2.insert("hoge");
220   expected2.insert("fuga");
221 
222   std::set<std::string> actual1 = custom_dictionary->GetWords();
223   EXPECT_EQ(actual1, expected1);
224 
225   std::set<std::string> actual2 = custom_dictionary2->GetWords();
226   EXPECT_EQ(actual2, expected2);
227 }
228 
229 // Legacy empty dictionary should be converted to new format empty dictionary.
TEST_F(SpellcheckCustomDictionaryTest,LegacyEmptyDictionaryShouldBeConverted)230 TEST_F(SpellcheckCustomDictionaryTest, LegacyEmptyDictionaryShouldBeConverted) {
231   base::FilePath path =
232       profile_.GetPath().Append(chrome::kCustomDictionaryFileName);
233 
234   std::string content;
235   base::WriteFile(path, content.c_str(), content.length());
236   EXPECT_TRUE(LoadDictionaryFile(path)->words.empty());
237 }
238 
239 // Legacy dictionary with two words should be converted to new format dictionary
240 // with two words.
TEST_F(SpellcheckCustomDictionaryTest,LegacyDictionaryWithTwoWordsShouldBeConverted)241 TEST_F(SpellcheckCustomDictionaryTest,
242        LegacyDictionaryWithTwoWordsShouldBeConverted) {
243   base::FilePath path =
244       profile_.GetPath().Append(chrome::kCustomDictionaryFileName);
245 
246   std::string content = "foo\nbar\nfoo\n";
247   base::WriteFile(path, content.c_str(), content.length());
248   std::set<std::string> expected;
249   expected.insert("bar");
250   expected.insert("foo");
251   EXPECT_EQ(expected, LoadDictionaryFile(path)->words);
252 }
253 
254 // Illegal words should be removed. Leading and trailing whitespace should be
255 // trimmed.
TEST_F(SpellcheckCustomDictionaryTest,IllegalWordsShouldBeRemovedFromDictionary)256 TEST_F(SpellcheckCustomDictionaryTest,
257        IllegalWordsShouldBeRemovedFromDictionary) {
258   base::FilePath path =
259       profile_.GetPath().Append(chrome::kCustomDictionaryFileName);
260 
261   std::string content = "foo\n foo bar \n\n \nbar\n"
262       "01234567890123456789012345678901234567890123456789"
263       "01234567890123456789012345678901234567890123456789";
264   base::WriteFile(path, content.c_str(), content.length());
265   std::set<std::string> expected;
266   expected.insert("bar");
267   expected.insert("foo");
268   expected.insert("foo bar");
269   EXPECT_EQ(expected, LoadDictionaryFile(path)->words);
270 }
271 
272 // Write to dictionary should backup previous version and write the word to the
273 // end of the dictionary. If the dictionary file is corrupted on disk, the
274 // previous version should be reloaded.
TEST_F(SpellcheckCustomDictionaryTest,CorruptedWriteShouldBeRecovered)275 TEST_F(SpellcheckCustomDictionaryTest, CorruptedWriteShouldBeRecovered) {
276   base::FilePath path =
277       profile_.GetPath().Append(chrome::kCustomDictionaryFileName);
278 
279   std::string content = "foo\nbar";
280   base::WriteFile(path, content.c_str(), content.length());
281   std::set<std::string> expected;
282   expected.insert("bar");
283   expected.insert("foo");
284   EXPECT_EQ(expected, LoadDictionaryFile(path)->words);
285 
286   std::unique_ptr<SpellcheckCustomDictionary::Change> change(
287       new SpellcheckCustomDictionary::Change);
288   change->AddWord("baz");
289   UpdateDictionaryFile(std::move(change), path);
290   content.clear();
291   base::ReadFileToString(path, &content);
292   content.append("corruption");
293   base::WriteFile(path, content.c_str(), content.length());
294   EXPECT_EQ(expected, LoadDictionaryFile(path)->words);
295 }
296 
TEST_F(SpellcheckCustomDictionaryTest,GetAllSyncDataAccuratelyReflectsDictionaryState)297 TEST_F(SpellcheckCustomDictionaryTest,
298        GetAllSyncDataAccuratelyReflectsDictionaryState) {
299   SpellcheckCustomDictionary* dictionary =
300       SpellcheckServiceFactory::GetForContext(
301           &profile_)->GetCustomDictionary();
302 
303   syncer::SyncDataList data =
304       dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY);
305   EXPECT_TRUE(data.empty());
306 
307   EXPECT_TRUE(dictionary->AddWord("bar"));
308   EXPECT_TRUE(dictionary->AddWord("foo"));
309 
310   data = dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY);
311   EXPECT_EQ(2UL, data.size());
312   std::vector<std::string> words;
313   words.push_back("bar");
314   words.push_back("foo");
315   for (size_t i = 0; i < data.size(); i++) {
316     EXPECT_TRUE(data[i].GetSpecifics().has_dictionary());
317     EXPECT_EQ(syncer::DICTIONARY, data[i].GetDataType());
318     EXPECT_EQ(words[i], syncer::SyncDataLocal(data[i]).GetTag());
319     EXPECT_EQ(words[i], data[i].GetSpecifics().dictionary().word());
320   }
321 
322   EXPECT_TRUE(dictionary->RemoveWord("bar"));
323   EXPECT_TRUE(dictionary->RemoveWord("foo"));
324 
325   data = dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY);
326   EXPECT_TRUE(data.empty());
327 }
328 
TEST_F(SpellcheckCustomDictionaryTest,GetAllSyncDataHasLimit)329 TEST_F(SpellcheckCustomDictionaryTest, GetAllSyncDataHasLimit) {
330   SpellcheckCustomDictionary* dictionary =
331       SpellcheckServiceFactory::GetForContext(
332           &profile_)->GetCustomDictionary();
333 
334   SpellcheckCustomDictionary::Change change;
335   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords - 1; i++) {
336     change.AddWord("foo" + base::NumberToString(i));
337   }
338   Apply(*dictionary, change);
339   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords - 1,
340             dictionary->GetWords().size());
341   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords - 1,
342             dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
343 
344   dictionary->AddWord("baz");
345   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
346             dictionary->GetWords().size());
347   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
348             dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
349 
350   dictionary->AddWord("bar");
351   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords + 1,
352             dictionary->GetWords().size());
353   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
354             dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
355 
356   dictionary->AddWord("snafoo");
357   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords + 2,
358             dictionary->GetWords().size());
359   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
360             dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
361 }
362 
TEST_F(SpellcheckCustomDictionaryTest,ProcessSyncChanges)363 TEST_F(SpellcheckCustomDictionaryTest, ProcessSyncChanges) {
364   SpellcheckService* spellcheck_service =
365       SpellcheckServiceFactory::GetForContext(&profile_);
366   SpellcheckCustomDictionary* dictionary =
367       spellcheck_service->GetCustomDictionary();
368 
369   dictionary->AddWord("foo");
370   dictionary->AddWord("bar");
371 
372   syncer::SyncChangeList changes;
373   {
374     // Add existing word.
375     std::string word = "foo";
376     sync_pb::EntitySpecifics specifics;
377     specifics.mutable_dictionary()->set_word(word);
378     changes.push_back(syncer::SyncChange(
379         FROM_HERE,
380         syncer::SyncChange::ACTION_ADD,
381         syncer::SyncData::CreateLocalData(word, word, specifics)));
382   }
383   {
384     // Add invalid word. This word is too long.
385     std::string word = "01234567890123456789012345678901234567890123456789"
386         "01234567890123456789012345678901234567890123456789";
387     sync_pb::EntitySpecifics specifics;
388     specifics.mutable_dictionary()->set_word(word);
389     changes.push_back(syncer::SyncChange(
390         FROM_HERE,
391         syncer::SyncChange::ACTION_ADD,
392         syncer::SyncData::CreateLocalData(word, word, specifics)));
393   }
394   {
395     // Add valid word.
396     std::string word = "baz";
397     sync_pb::EntitySpecifics specifics;
398     specifics.mutable_dictionary()->set_word(word);
399     changes.push_back(syncer::SyncChange(
400         FROM_HERE,
401         syncer::SyncChange::ACTION_ADD,
402         syncer::SyncData::CreateLocalData(word, word, specifics)));
403   }
404   {
405     // Remove missing word.
406     std::string word = "snafoo";
407     sync_pb::EntitySpecifics specifics;
408     specifics.mutable_dictionary()->set_word(word);
409     changes.push_back(syncer::SyncChange(
410         FROM_HERE,
411         syncer::SyncChange::ACTION_DELETE,
412         syncer::SyncData::CreateLocalData(word, word, specifics)));
413   }
414   {
415     // Remove existing word.
416     std::string word = "bar";
417     sync_pb::EntitySpecifics specifics;
418     specifics.mutable_dictionary()->set_word(word);
419     changes.push_back(syncer::SyncChange(
420         FROM_HERE,
421         syncer::SyncChange::ACTION_DELETE,
422         syncer::SyncData::CreateLocalData(word, word, specifics)));
423   }
424 
425   EXPECT_FALSE(dictionary->ProcessSyncChanges(FROM_HERE, changes).IsSet());
426 
427   const std::set<std::string>& words = dictionary->GetWords();
428   EXPECT_EQ(2UL, words.size());
429   EXPECT_EQ(0UL, words.count("bar"));
430   EXPECT_EQ(1UL, words.count("foo"));
431   EXPECT_EQ(1UL, words.count("baz"));
432 }
433 
TEST_F(SpellcheckCustomDictionaryTest,MergeDataAndStartSyncing)434 TEST_F(SpellcheckCustomDictionaryTest, MergeDataAndStartSyncing) {
435   SpellcheckService* spellcheck_service =
436       SpellcheckServiceFactory::GetForContext(&profile_);
437   SpellcheckCustomDictionary* custom_dictionary =
438       spellcheck_service->GetCustomDictionary();
439   TestingProfile profile2;
440   SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
441       SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
442           &profile2, base::BindRepeating(&BuildSpellcheckService)));
443   SpellcheckCustomDictionary* custom_dictionary2 =
444       spellcheck_service2->GetCustomDictionary();
445 
446   SpellcheckCustomDictionary::Change change;
447   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords / 2; ++i) {
448     change.AddWord("foo" + base::NumberToString(i));
449   }
450   Apply(*custom_dictionary, change);
451 
452   SpellcheckCustomDictionary::Change change2;
453   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords / 2; ++i) {
454     change2.AddWord("bar" + base::NumberToString(i));
455   }
456   Apply(*custom_dictionary2, change2);
457 
458   int error_counter = 0;
459   EXPECT_FALSE(
460       custom_dictionary
461           ->MergeDataAndStartSyncing(
462               syncer::DICTIONARY,
463               custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY),
464               std::unique_ptr<syncer::SyncChangeProcessor>(
465                   new syncer::SyncChangeProcessorWrapperForTest(
466                       custom_dictionary2)),
467               std::unique_ptr<syncer::SyncErrorFactory>(
468                   new SyncErrorFactoryStub(&error_counter)))
469           .error()
470           .IsSet());
471   EXPECT_EQ(0, error_counter);
472   EXPECT_TRUE(custom_dictionary->IsSyncing());
473 
474   std::set<std::string> words = custom_dictionary->GetWords();
475   std::set<std::string> words2 = custom_dictionary2->GetWords();
476   EXPECT_EQ(words.size(), words2.size());
477   EXPECT_EQ(words, words2);
478 }
479 
TEST_F(SpellcheckCustomDictionaryTest,SyncBeforeLoadDoesNotDuplicateWords)480 TEST_F(SpellcheckCustomDictionaryTest, SyncBeforeLoadDoesNotDuplicateWords) {
481   // Test triggers network requests since it indirectly instantiates
482   // SpellcheckHunspellDictionary's.
483   // Install a mock server to avoid sending random network request to
484   // localhost.
485   net::EmbeddedTestServer embedded_test_server;
486   embedded_test_server.RegisterRequestHandler(
487       base::BindRepeating([](const net::test_server::HttpRequest& request) {
488         // Mock implementation to hang the request.
489         std::unique_ptr<net::test_server::HttpResponse> response;
490         return response;
491       }));
492   net::test_server::RegisterDefaultHandlers(&embedded_test_server);
493   ASSERT_TRUE(embedded_test_server.Start());
494 
495   // Forcibly set a hanging URL.
496   GURL url = embedded_test_server.GetURL("/hang");
497   SpellcheckHunspellDictionary::SetDownloadURLForTesting(url);
498 
499   SpellcheckCustomDictionary* custom_dictionary =
500       SpellcheckServiceFactory::GetForContext(&profile_)->GetCustomDictionary();
501 
502   TestingProfile profile2;
503   SpellcheckCustomDictionary* custom_dictionary2 =
504       static_cast<SpellcheckService*>(
505           SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
506               &profile2, base::BindRepeating(&BuildSpellcheckService)))
507           ->GetCustomDictionary();
508 
509   std::unique_ptr<SpellcheckCustomDictionary::Change> change(
510       new SpellcheckCustomDictionary::Change);
511   change->AddWord("foo");
512   Apply(*custom_dictionary2, *change);
513 
514   base::FilePath path =
515       profile_.GetPath().Append(chrome::kCustomDictionaryFileName);
516   UpdateDictionaryFile(std::move(change), path);
517   EXPECT_TRUE(custom_dictionary->GetWords().empty());
518 
519   int error_counter = 0;
520   EXPECT_FALSE(
521       custom_dictionary
522           ->MergeDataAndStartSyncing(
523               syncer::DICTIONARY,
524               custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY),
525               std::unique_ptr<syncer::SyncChangeProcessor>(
526                   new syncer::SyncChangeProcessorWrapperForTest(
527                       custom_dictionary2)),
528               std::unique_ptr<syncer::SyncErrorFactory>(
529                   new SyncErrorFactoryStub(&error_counter)))
530           .error()
531           .IsSet());
532   EXPECT_EQ(0, error_counter);
533   EXPECT_TRUE(custom_dictionary->IsSyncing());
534 
535   std::set<std::string> expected_words_in_memory;
536   expected_words_in_memory.insert("foo");
537   EXPECT_EQ(expected_words_in_memory, custom_dictionary->GetWords());
538 
539   // Finish all writes to disk.
540   content::RunAllTasksUntilIdle();
541 
542   std::string actual_contents_on_disk;
543   base::ReadFileToString(path, &actual_contents_on_disk);
544   static const char kExpectedContentsPrefix[] = "foo\nchecksum_v1 = ";
545   EXPECT_EQ(
546       kExpectedContentsPrefix,
547       actual_contents_on_disk.substr(0, sizeof kExpectedContentsPrefix - 1));
548 }
549 
TEST_F(SpellcheckCustomDictionaryTest,DictionaryTooBigBeforeSyncing)550 TEST_F(SpellcheckCustomDictionaryTest, DictionaryTooBigBeforeSyncing) {
551   SpellcheckService* spellcheck_service =
552       SpellcheckServiceFactory::GetForContext(&profile_);
553   SpellcheckCustomDictionary* custom_dictionary =
554       spellcheck_service->GetCustomDictionary();
555   TestingProfile profile2;
556   SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
557       SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
558           &profile2, base::BindRepeating(&BuildSpellcheckService)));
559   SpellcheckCustomDictionary* custom_dictionary2 =
560       spellcheck_service2->GetCustomDictionary();
561 
562   SpellcheckCustomDictionary::Change change;
563   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords + 1; ++i) {
564     change.AddWord("foo" + base::NumberToString(i));
565   }
566   Apply(*custom_dictionary, change);
567 
568   int error_counter = 0;
569   EXPECT_FALSE(
570       custom_dictionary
571           ->MergeDataAndStartSyncing(
572               syncer::DICTIONARY,
573               custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY),
574               std::unique_ptr<syncer::SyncChangeProcessor>(
575                   new syncer::SyncChangeProcessorWrapperForTest(
576                       custom_dictionary2)),
577               std::unique_ptr<syncer::SyncErrorFactory>(
578                   new SyncErrorFactoryStub(&error_counter)))
579           .error()
580           .IsSet());
581   EXPECT_EQ(0, error_counter);
582   EXPECT_FALSE(custom_dictionary->IsSyncing());
583 
584   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords + 1,
585             custom_dictionary->GetWords().size());
586   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
587             custom_dictionary2->GetWords().size());
588 
589   EXPECT_EQ(
590       spellcheck::kMaxSyncableDictionaryWords,
591       custom_dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
592   EXPECT_EQ(
593       spellcheck::kMaxSyncableDictionaryWords,
594       custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
595 }
596 
TEST_F(SpellcheckCustomDictionaryTest,DictionaryTooBigAndServerFull)597 TEST_F(SpellcheckCustomDictionaryTest, DictionaryTooBigAndServerFull) {
598   SpellcheckService* spellcheck_service =
599       SpellcheckServiceFactory::GetForContext(&profile_);
600   SpellcheckCustomDictionary* custom_dictionary =
601       spellcheck_service->GetCustomDictionary();
602   TestingProfile profile2;
603   SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
604       SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
605           &profile2, base::BindRepeating(&BuildSpellcheckService)));
606   SpellcheckCustomDictionary* custom_dictionary2 =
607       spellcheck_service2->GetCustomDictionary();
608 
609   SpellcheckCustomDictionary::Change change;
610   SpellcheckCustomDictionary::Change change2;
611   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords; ++i) {
612     change.AddWord("foo" + base::NumberToString(i));
613     change2.AddWord("bar" + base::NumberToString(i));
614   }
615   change.AddWord("foo");
616   Apply(*custom_dictionary, change);
617   Apply(*custom_dictionary2, change2);
618 
619   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords + 1,
620             custom_dictionary->GetWords().size());
621   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
622             custom_dictionary2->GetWords().size());
623 
624   int error_counter = 0;
625   EXPECT_FALSE(
626       custom_dictionary
627           ->MergeDataAndStartSyncing(
628               syncer::DICTIONARY,
629               custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY),
630               std::unique_ptr<syncer::SyncChangeProcessor>(
631                   new syncer::SyncChangeProcessorWrapperForTest(
632                       custom_dictionary2)),
633               std::unique_ptr<syncer::SyncErrorFactory>(
634                   new SyncErrorFactoryStub(&error_counter)))
635           .error()
636           .IsSet());
637   EXPECT_EQ(0, error_counter);
638   EXPECT_FALSE(custom_dictionary->IsSyncing());
639 
640   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords * 2 + 1,
641             custom_dictionary->GetWords().size());
642   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
643             custom_dictionary2->GetWords().size());
644 
645   EXPECT_EQ(
646       spellcheck::kMaxSyncableDictionaryWords,
647       custom_dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
648   EXPECT_EQ(
649       spellcheck::kMaxSyncableDictionaryWords,
650       custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
651 }
652 
TEST_F(SpellcheckCustomDictionaryTest,ServerTooBig)653 TEST_F(SpellcheckCustomDictionaryTest, ServerTooBig) {
654   SpellcheckService* spellcheck_service =
655       SpellcheckServiceFactory::GetForContext(&profile_);
656   SpellcheckCustomDictionary* custom_dictionary =
657       spellcheck_service->GetCustomDictionary();
658   TestingProfile profile2;
659   SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
660       SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
661           &profile2, base::BindRepeating(&BuildSpellcheckService)));
662   SpellcheckCustomDictionary* custom_dictionary2 =
663       spellcheck_service2->GetCustomDictionary();
664 
665   SpellcheckCustomDictionary::Change change;
666   SpellcheckCustomDictionary::Change change2;
667   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords + 1; ++i) {
668     change.AddWord("foo" + base::NumberToString(i));
669     change2.AddWord("bar" + base::NumberToString(i));
670   }
671   Apply(*custom_dictionary, change);
672   Apply(*custom_dictionary2, change2);
673 
674   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords + 1,
675             custom_dictionary->GetWords().size());
676   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords + 1,
677             custom_dictionary2->GetWords().size());
678 
679   int error_counter = 0;
680   EXPECT_FALSE(custom_dictionary
681                    ->MergeDataAndStartSyncing(
682                        syncer::DICTIONARY,
683                        GetAllSyncDataNoLimit(custom_dictionary2),
684                        std::unique_ptr<syncer::SyncChangeProcessor>(
685                            new syncer::SyncChangeProcessorWrapperForTest(
686                                custom_dictionary2)),
687                        std::unique_ptr<syncer::SyncErrorFactory>(
688                            new SyncErrorFactoryStub(&error_counter)))
689                    .error()
690                    .IsSet());
691   EXPECT_EQ(0, error_counter);
692   EXPECT_FALSE(custom_dictionary->IsSyncing());
693 
694   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords * 2 + 2,
695             custom_dictionary->GetWords().size());
696   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords + 1,
697             custom_dictionary2->GetWords().size());
698 
699   EXPECT_EQ(
700       spellcheck::kMaxSyncableDictionaryWords,
701       custom_dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
702   EXPECT_EQ(
703       spellcheck::kMaxSyncableDictionaryWords,
704       custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
705 }
706 
TEST_F(SpellcheckCustomDictionaryTest,DictionaryTooBigToStartSyncing)707 TEST_F(SpellcheckCustomDictionaryTest, DictionaryTooBigToStartSyncing) {
708   SpellcheckService* spellcheck_service =
709       SpellcheckServiceFactory::GetForContext(&profile_);
710   SpellcheckCustomDictionary* custom_dictionary =
711       spellcheck_service->GetCustomDictionary();
712   TestingProfile profile2;
713   SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
714       SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
715           &profile2, base::BindRepeating(&BuildSpellcheckService)));
716   SpellcheckCustomDictionary* custom_dictionary2 =
717       spellcheck_service2->GetCustomDictionary();
718 
719   SpellcheckCustomDictionary::Change change;
720   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords - 1; ++i) {
721     change.AddWord("foo" + base::NumberToString(i));
722   }
723   Apply(*custom_dictionary, change);
724 
725   custom_dictionary2->AddWord("bar");
726   custom_dictionary2->AddWord("baz");
727 
728   int error_counter = 0;
729   EXPECT_FALSE(
730       custom_dictionary
731           ->MergeDataAndStartSyncing(
732               syncer::DICTIONARY,
733               custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY),
734               std::unique_ptr<syncer::SyncChangeProcessor>(
735                   new syncer::SyncChangeProcessorWrapperForTest(
736                       custom_dictionary2)),
737               std::unique_ptr<syncer::SyncErrorFactory>(
738                   new SyncErrorFactoryStub(&error_counter)))
739           .error()
740           .IsSet());
741   EXPECT_EQ(0, error_counter);
742   EXPECT_FALSE(custom_dictionary->IsSyncing());
743 
744   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords + 1,
745             custom_dictionary->GetWords().size());
746   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
747             custom_dictionary2->GetWords().size());
748 
749   EXPECT_EQ(
750       spellcheck::kMaxSyncableDictionaryWords,
751       custom_dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
752   EXPECT_EQ(
753       spellcheck::kMaxSyncableDictionaryWords,
754       custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
755 }
756 
TEST_F(SpellcheckCustomDictionaryTest,DictionaryTooBigToContiueSyncing)757 TEST_F(SpellcheckCustomDictionaryTest, DictionaryTooBigToContiueSyncing) {
758   SpellcheckService* spellcheck_service =
759       SpellcheckServiceFactory::GetForContext(&profile_);
760   SpellcheckCustomDictionary* custom_dictionary =
761       spellcheck_service->GetCustomDictionary();
762   TestingProfile profile2;
763   SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
764       SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
765           &profile2, base::BindRepeating(&BuildSpellcheckService)));
766   SpellcheckCustomDictionary* custom_dictionary2 =
767       spellcheck_service2->GetCustomDictionary();
768 
769   SpellcheckCustomDictionary::Change change;
770   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords - 1; ++i) {
771     change.AddWord("foo" + base::NumberToString(i));
772   }
773   Apply(*custom_dictionary, change);
774 
775   int error_counter = 0;
776   EXPECT_FALSE(
777       custom_dictionary
778           ->MergeDataAndStartSyncing(
779               syncer::DICTIONARY,
780               custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY),
781               std::unique_ptr<syncer::SyncChangeProcessor>(
782                   new syncer::SyncChangeProcessorWrapperForTest(
783                       custom_dictionary2)),
784               std::unique_ptr<syncer::SyncErrorFactory>(
785                   new SyncErrorFactoryStub(&error_counter)))
786           .error()
787           .IsSet());
788   EXPECT_EQ(0, error_counter);
789   EXPECT_TRUE(custom_dictionary->IsSyncing());
790 
791   custom_dictionary->AddWord("bar");
792   EXPECT_EQ(0, error_counter);
793   EXPECT_TRUE(custom_dictionary->IsSyncing());
794 
795   custom_dictionary->AddWord("baz");
796   EXPECT_EQ(0, error_counter);
797   EXPECT_FALSE(custom_dictionary->IsSyncing());
798 
799   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords + 1,
800             custom_dictionary->GetWords().size());
801   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
802             custom_dictionary2->GetWords().size());
803 
804   EXPECT_EQ(
805       spellcheck::kMaxSyncableDictionaryWords,
806       custom_dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
807   EXPECT_EQ(
808       spellcheck::kMaxSyncableDictionaryWords,
809       custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
810 }
811 
TEST_F(SpellcheckCustomDictionaryTest,LoadAfterSyncStart)812 TEST_F(SpellcheckCustomDictionaryTest, LoadAfterSyncStart) {
813   SpellcheckService* spellcheck_service =
814       SpellcheckServiceFactory::GetForContext(&profile_);
815   SpellcheckCustomDictionary* custom_dictionary =
816       spellcheck_service->GetCustomDictionary();
817   TestingProfile profile2;
818   SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
819       SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
820           &profile2, base::BindRepeating(&BuildSpellcheckService)));
821   SpellcheckCustomDictionary* custom_dictionary2 =
822       spellcheck_service2->GetCustomDictionary();
823 
824   custom_dictionary->AddWord("foo");
825 
826   int error_counter = 0;
827   EXPECT_FALSE(
828       custom_dictionary
829           ->MergeDataAndStartSyncing(
830               syncer::DICTIONARY,
831               custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY),
832               std::unique_ptr<syncer::SyncChangeProcessor>(
833                   new syncer::SyncChangeProcessorWrapperForTest(
834                       custom_dictionary2)),
835               std::unique_ptr<syncer::SyncErrorFactory>(
836                   new SyncErrorFactoryStub(&error_counter)))
837           .error()
838           .IsSet());
839   EXPECT_EQ(0, error_counter);
840   EXPECT_TRUE(custom_dictionary->IsSyncing());
841 
842   std::unique_ptr<std::set<std::string>> custom_words(
843       new std::set<std::string>);
844   custom_words->insert("bar");
845   OnLoaded(*custom_dictionary, std::move(custom_words));
846   EXPECT_TRUE(custom_dictionary->IsSyncing());
847 
848   EXPECT_EQ(2UL, custom_dictionary->GetWords().size());
849   EXPECT_EQ(2UL, custom_dictionary2->GetWords().size());
850 
851   EXPECT_EQ(
852       2UL,
853       custom_dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
854   EXPECT_EQ(
855       2UL,
856       custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
857 }
858 
TEST_F(SpellcheckCustomDictionaryTest,LoadAfterSyncStartTooBigToSync)859 TEST_F(SpellcheckCustomDictionaryTest, LoadAfterSyncStartTooBigToSync) {
860   SpellcheckService* spellcheck_service =
861       SpellcheckServiceFactory::GetForContext(&profile_);
862   SpellcheckCustomDictionary* custom_dictionary =
863       spellcheck_service->GetCustomDictionary();
864   TestingProfile profile2;
865   SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
866       SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
867           &profile2, base::BindRepeating(&BuildSpellcheckService)));
868   SpellcheckCustomDictionary* custom_dictionary2 =
869       spellcheck_service2->GetCustomDictionary();
870 
871   custom_dictionary->AddWord("foo");
872 
873   int error_counter = 0;
874   EXPECT_FALSE(
875       custom_dictionary
876           ->MergeDataAndStartSyncing(
877               syncer::DICTIONARY,
878               custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY),
879               std::unique_ptr<syncer::SyncChangeProcessor>(
880                   new syncer::SyncChangeProcessorWrapperForTest(
881                       custom_dictionary2)),
882               std::unique_ptr<syncer::SyncErrorFactory>(
883                   new SyncErrorFactoryStub(&error_counter)))
884           .error()
885           .IsSet());
886   EXPECT_EQ(0, error_counter);
887   EXPECT_TRUE(custom_dictionary->IsSyncing());
888 
889   std::unique_ptr<std::set<std::string>> custom_words(
890       new std::set<std::string>);
891   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords; ++i) {
892     custom_words->insert(custom_words->end(), "foo" + base::NumberToString(i));
893   }
894   OnLoaded(*custom_dictionary, std::move(custom_words));
895   EXPECT_EQ(0, error_counter);
896   EXPECT_FALSE(custom_dictionary->IsSyncing());
897 
898   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords + 1,
899             custom_dictionary->GetWords().size());
900   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
901             custom_dictionary2->GetWords().size());
902 
903   EXPECT_EQ(
904       spellcheck::kMaxSyncableDictionaryWords,
905       custom_dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
906   EXPECT_EQ(
907       spellcheck::kMaxSyncableDictionaryWords,
908       custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
909 }
910 
TEST_F(SpellcheckCustomDictionaryTest,LoadDuplicatesAfterSync)911 TEST_F(SpellcheckCustomDictionaryTest, LoadDuplicatesAfterSync) {
912   SpellcheckService* spellcheck_service =
913       SpellcheckServiceFactory::GetForContext(&profile_);
914   SpellcheckCustomDictionary* custom_dictionary =
915       spellcheck_service->GetCustomDictionary();
916   TestingProfile profile2;
917   SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
918       SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
919           &profile2, base::BindRepeating(&BuildSpellcheckService)));
920   SpellcheckCustomDictionary* custom_dictionary2 =
921       spellcheck_service2->GetCustomDictionary();
922 
923   SpellcheckCustomDictionary::Change change;
924   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords / 2; ++i) {
925     change.AddWord("foo" + base::NumberToString(i));
926   }
927   Apply(*custom_dictionary, change);
928 
929   int error_counter = 0;
930   EXPECT_FALSE(
931       custom_dictionary
932           ->MergeDataAndStartSyncing(
933               syncer::DICTIONARY,
934               custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY),
935               std::unique_ptr<syncer::SyncChangeProcessor>(
936                   new syncer::SyncChangeProcessorWrapperForTest(
937                       custom_dictionary2)),
938               std::unique_ptr<syncer::SyncErrorFactory>(
939                   new SyncErrorFactoryStub(&error_counter)))
940           .error()
941           .IsSet());
942   EXPECT_EQ(0, error_counter);
943   EXPECT_TRUE(custom_dictionary->IsSyncing());
944 
945   OnLoaded(*custom_dictionary,
946            std::make_unique<std::set<std::string>>(change.to_add()));
947   EXPECT_EQ(0, error_counter);
948   EXPECT_TRUE(custom_dictionary->IsSyncing());
949 
950   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords / 2,
951             custom_dictionary->GetWords().size());
952   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords / 2,
953             custom_dictionary2->GetWords().size());
954 
955   EXPECT_EQ(
956       spellcheck::kMaxSyncableDictionaryWords / 2,
957       custom_dictionary->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
958   EXPECT_EQ(
959       spellcheck::kMaxSyncableDictionaryWords / 2,
960       custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY).size());
961 }
962 
TEST_F(SpellcheckCustomDictionaryTest,DictionaryLoadNotification)963 TEST_F(SpellcheckCustomDictionaryTest, DictionaryLoadNotification) {
964   SpellcheckService* spellcheck_service =
965       SpellcheckServiceFactory::GetForContext(&profile_);
966   SpellcheckCustomDictionary* custom_dictionary =
967       spellcheck_service->GetCustomDictionary();
968 
969   DictionaryObserverCounter observer;
970   custom_dictionary->AddObserver(&observer);
971 
972   std::unique_ptr<std::set<std::string>> custom_words(
973       new std::set<std::string>);
974   custom_words->insert("foo");
975   custom_words->insert("bar");
976   OnLoaded(*custom_dictionary, std::move(custom_words));
977 
978   EXPECT_GE(observer.loads(), 1);
979   EXPECT_LE(observer.loads(), 2);
980   EXPECT_EQ(0, observer.changes());
981 
982   custom_dictionary->RemoveObserver(&observer);
983 }
984 
TEST_F(SpellcheckCustomDictionaryTest,DictionaryAddWordNotification)985 TEST_F(SpellcheckCustomDictionaryTest, DictionaryAddWordNotification) {
986   SpellcheckService* spellcheck_service =
987       SpellcheckServiceFactory::GetForContext(&profile_);
988   SpellcheckCustomDictionary* custom_dictionary =
989       spellcheck_service->GetCustomDictionary();
990 
991   OnLoaded(*custom_dictionary, base::WrapUnique(new std::set<std::string>));
992 
993   DictionaryObserverCounter observer;
994   custom_dictionary->AddObserver(&observer);
995 
996   EXPECT_TRUE(custom_dictionary->AddWord("foo"));
997   EXPECT_TRUE(custom_dictionary->AddWord("bar"));
998   EXPECT_FALSE(custom_dictionary->AddWord("bar"));
999 
1000   EXPECT_EQ(2, observer.changes());
1001 
1002   custom_dictionary->RemoveObserver(&observer);
1003 }
1004 
TEST_F(SpellcheckCustomDictionaryTest,DictionaryRemoveWordNotification)1005 TEST_F(SpellcheckCustomDictionaryTest, DictionaryRemoveWordNotification) {
1006   SpellcheckService* spellcheck_service =
1007       SpellcheckServiceFactory::GetForContext(&profile_);
1008   SpellcheckCustomDictionary* custom_dictionary =
1009       spellcheck_service->GetCustomDictionary();
1010 
1011   OnLoaded(*custom_dictionary, base::WrapUnique(new std::set<std::string>));
1012 
1013   EXPECT_TRUE(custom_dictionary->AddWord("foo"));
1014   EXPECT_TRUE(custom_dictionary->AddWord("bar"));
1015 
1016   DictionaryObserverCounter observer;
1017   custom_dictionary->AddObserver(&observer);
1018 
1019   EXPECT_TRUE(custom_dictionary->RemoveWord("foo"));
1020   EXPECT_TRUE(custom_dictionary->RemoveWord("bar"));
1021   EXPECT_FALSE(custom_dictionary->RemoveWord("baz"));
1022 
1023   EXPECT_EQ(2, observer.changes());
1024 
1025   custom_dictionary->RemoveObserver(&observer);
1026 }
1027 
TEST_F(SpellcheckCustomDictionaryTest,DictionarySyncNotification)1028 TEST_F(SpellcheckCustomDictionaryTest, DictionarySyncNotification) {
1029   SpellcheckService* spellcheck_service =
1030       SpellcheckServiceFactory::GetForContext(&profile_);
1031   SpellcheckCustomDictionary* custom_dictionary =
1032       spellcheck_service->GetCustomDictionary();
1033   TestingProfile profile2;
1034   SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
1035       SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
1036           &profile2, base::BindRepeating(&BuildSpellcheckService)));
1037   SpellcheckCustomDictionary* custom_dictionary2 =
1038       spellcheck_service2->GetCustomDictionary();
1039 
1040   OnLoaded(*custom_dictionary, base::WrapUnique(new std::set<std::string>));
1041   OnLoaded(*custom_dictionary2, base::WrapUnique(new std::set<std::string>));
1042 
1043   custom_dictionary->AddWord("foo");
1044   custom_dictionary->AddWord("bar");
1045   custom_dictionary2->AddWord("foo");
1046   custom_dictionary2->AddWord("baz");
1047 
1048   DictionaryObserverCounter observer;
1049   custom_dictionary->AddObserver(&observer);
1050 
1051   DictionaryObserverCounter observer2;
1052   custom_dictionary2->AddObserver(&observer2);
1053 
1054   int error_counter = 0;
1055   EXPECT_FALSE(
1056       custom_dictionary
1057           ->MergeDataAndStartSyncing(
1058               syncer::DICTIONARY,
1059               custom_dictionary2->GetAllSyncDataForTesting(syncer::DICTIONARY),
1060               std::unique_ptr<syncer::SyncChangeProcessor>(
1061                   new syncer::SyncChangeProcessorWrapperForTest(
1062                       custom_dictionary2)),
1063               std::unique_ptr<syncer::SyncErrorFactory>(
1064                   new SyncErrorFactoryStub(&error_counter)))
1065           .error()
1066           .IsSet());
1067   EXPECT_EQ(0, error_counter);
1068   EXPECT_TRUE(custom_dictionary->IsSyncing());
1069 
1070   EXPECT_EQ(1, observer.changes());
1071   EXPECT_EQ(1, observer2.changes());
1072 
1073   custom_dictionary->RemoveObserver(&observer);
1074   custom_dictionary2->RemoveObserver(&observer2);
1075 }
1076 
1077 // The server has maximum number of words and the client has maximum number of
1078 // different words before association time. No new words should be pushed to the
1079 // sync server upon association. The client should accept words from the sync
1080 // server, however.
TEST_F(SpellcheckCustomDictionaryTest,DictionarySyncLimit)1081 TEST_F(SpellcheckCustomDictionaryTest, DictionarySyncLimit) {
1082   TestingProfile server_profile;
1083   SpellcheckService* server_spellcheck_service =
1084       static_cast<SpellcheckService*>(
1085           SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
1086               &server_profile, base::BindRepeating(&BuildSpellcheckService)));
1087 
1088   // Here, |server_custom_dictionary| plays the role of the sync server.
1089   SpellcheckCustomDictionary* server_custom_dictionary =
1090       server_spellcheck_service->GetCustomDictionary();
1091 
1092   // Upload the maximum number of words to the sync server.
1093   {
1094     SpellcheckService* spellcheck_service =
1095         SpellcheckServiceFactory::GetForContext(&profile_);
1096     SpellcheckCustomDictionary* custom_dictionary =
1097         spellcheck_service->GetCustomDictionary();
1098 
1099     SpellcheckCustomDictionary::Change change;
1100     for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords; ++i) {
1101       change.AddWord("foo" + base::NumberToString(i));
1102     }
1103     Apply(*custom_dictionary, change);
1104 
1105     int error_counter = 0;
1106     EXPECT_FALSE(custom_dictionary
1107                      ->MergeDataAndStartSyncing(
1108                          syncer::DICTIONARY,
1109                          server_custom_dictionary->GetAllSyncDataForTesting(
1110                              syncer::DICTIONARY),
1111                          std::unique_ptr<syncer::SyncChangeProcessor>(
1112                              new syncer::SyncChangeProcessorWrapperForTest(
1113                                  server_custom_dictionary)),
1114                          std::unique_ptr<syncer::SyncErrorFactory>(
1115                              new SyncErrorFactoryStub(&error_counter)))
1116                      .error()
1117                      .IsSet());
1118     EXPECT_EQ(0, error_counter);
1119     EXPECT_TRUE(custom_dictionary->IsSyncing());
1120     EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
1121               custom_dictionary->GetWords().size());
1122   }
1123 
1124   // The sync server now has the maximum number of words.
1125   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
1126             server_custom_dictionary->GetWords().size());
1127 
1128   // Associate the sync server with a client that also has the maximum number of
1129   // words, but all of these words are different from the ones on the sync
1130   // server.
1131   {
1132     TestingProfile client_profile;
1133     SpellcheckService* client_spellcheck_service =
1134         static_cast<SpellcheckService*>(
1135             SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
1136                 &client_profile, base::BindRepeating(&BuildSpellcheckService)));
1137 
1138     // Here, |client_custom_dictionary| plays the role of the client.
1139     SpellcheckCustomDictionary* client_custom_dictionary =
1140         client_spellcheck_service->GetCustomDictionary();
1141 
1142     // Add the maximum number of words to the client. These words are all
1143     // different from those on the server.
1144     SpellcheckCustomDictionary::Change change;
1145     for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords; ++i) {
1146       change.AddWord("bar" + base::NumberToString(i));
1147     }
1148     Apply(*client_custom_dictionary, change);
1149 
1150     // Associate the server and the client.
1151     int error_counter = 0;
1152     EXPECT_FALSE(client_custom_dictionary
1153                      ->MergeDataAndStartSyncing(
1154                          syncer::DICTIONARY,
1155                          server_custom_dictionary->GetAllSyncDataForTesting(
1156                              syncer::DICTIONARY),
1157                          std::unique_ptr<syncer::SyncChangeProcessor>(
1158                              new syncer::SyncChangeProcessorWrapperForTest(
1159                                  server_custom_dictionary)),
1160                          std::unique_ptr<syncer::SyncErrorFactory>(
1161                              new SyncErrorFactoryStub(&error_counter)))
1162                      .error()
1163                      .IsSet());
1164     EXPECT_EQ(0, error_counter);
1165     EXPECT_FALSE(client_custom_dictionary->IsSyncing());
1166     EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords * 2,
1167               client_custom_dictionary->GetWords().size());
1168   }
1169 
1170   // The sync server should not receive more words, because it has the maximum
1171   // number of words already.
1172   EXPECT_EQ(spellcheck::kMaxSyncableDictionaryWords,
1173             server_custom_dictionary->GetWords().size());
1174 }
1175 
1176 #if defined(OS_WIN)
1177 // Failing consistently on Win7+. See crbug.com/230534.
1178 #define MAYBE_RecordSizeStatsCorrectly DISABLED_RecordSizeStatsCorrectly
1179 #else
1180 #define MAYBE_RecordSizeStatsCorrectly RecordSizeStatsCorrectly
1181 #endif
1182 
TEST_F(SpellcheckCustomDictionaryTest,MAYBE_RecordSizeStatsCorrectly)1183 TEST_F(SpellcheckCustomDictionaryTest, MAYBE_RecordSizeStatsCorrectly) {
1184   // Record a baseline.
1185   SpellCheckHostMetrics::RecordCustomWordCountStats(123);
1186 
1187   HistogramBase* histogram =
1188       StatisticsRecorder::FindHistogram("SpellCheck.CustomWords");
1189   ASSERT_TRUE(histogram != NULL);
1190   std::unique_ptr<HistogramSamples> baseline = histogram->SnapshotSamples();
1191 
1192   // Load the dictionary which should be empty.
1193   base::FilePath path =
1194       profile_.GetPath().Append(chrome::kCustomDictionaryFileName);
1195   EXPECT_TRUE(LoadDictionaryFile(path)->words.empty());
1196 
1197   // We expect there to be an entry with 0.
1198   histogram =
1199       StatisticsRecorder::FindHistogram("SpellCheck.CustomWords");
1200   ASSERT_TRUE(histogram != NULL);
1201   std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
1202 
1203   samples->Subtract(*baseline);
1204   EXPECT_EQ(0,samples->sum());
1205 
1206   std::unique_ptr<SpellcheckCustomDictionary::Change> change(
1207       new SpellcheckCustomDictionary::Change);
1208   change->AddWord("bar");
1209   change->AddWord("foo");
1210   UpdateDictionaryFile(std::move(change), path);
1211 
1212   // Load the dictionary again and it should have 2 entries.
1213   EXPECT_EQ(2u, LoadDictionaryFile(path)->words.size());
1214 
1215   histogram =
1216       StatisticsRecorder::FindHistogram("SpellCheck.CustomWords");
1217   ASSERT_TRUE(histogram != NULL);
1218   std::unique_ptr<HistogramSamples> samples2 = histogram->SnapshotSamples();
1219 
1220   samples2->Subtract(*baseline);
1221   EXPECT_EQ(2,samples2->sum());
1222 }
1223 
TEST_F(SpellcheckCustomDictionaryTest,HasWord)1224 TEST_F(SpellcheckCustomDictionaryTest, HasWord) {
1225   SpellcheckService* spellcheck_service =
1226       SpellcheckServiceFactory::GetForContext(&profile_);
1227   SpellcheckCustomDictionary* custom_dictionary =
1228       spellcheck_service->GetCustomDictionary();
1229   OnLoaded(*custom_dictionary, base::WrapUnique(new std::set<std::string>));
1230   EXPECT_FALSE(custom_dictionary->HasWord("foo"));
1231   EXPECT_FALSE(custom_dictionary->HasWord("bar"));
1232   custom_dictionary->AddWord("foo");
1233   EXPECT_TRUE(custom_dictionary->HasWord("foo"));
1234   EXPECT_FALSE(custom_dictionary->HasWord("bar"));
1235 }
1236