Home | History | Annotate | Download | only in spellchecker
      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 }
   1144