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