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