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