// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/sync/test/integration/dictionary_helper.h" #include #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/spellchecker/spellcheck_factory.h" #include "chrome/browser/spellchecker/spellcheck_service.h" #include "chrome/browser/sync/test/integration/dictionary_load_observer.h" #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h" #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h" #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" #include "chrome/browser/sync/test/integration/sync_datatype_helper.h" #include "chrome/browser/sync/test/integration/sync_test.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/spellcheck_common.h" #include "content/public/test/test_utils.h" class DictionarySyncIntegrationTestHelper { public: // Same as SpellcheckCustomDictionary::AddWord/RemoveWord, except does not // write to disk. static bool ApplyChange( SpellcheckCustomDictionary* dictionary, SpellcheckCustomDictionary::Change& change) { int result = change.Sanitize(dictionary->GetWords()); dictionary->Apply(change); dictionary->Notify(change); dictionary->Sync(change); return !result; } DISALLOW_COPY_AND_ASSIGN(DictionarySyncIntegrationTestHelper); }; namespace dictionary_helper { namespace { SpellcheckCustomDictionary* GetDictionary(int index) { return SpellcheckServiceFactory::GetForContext( sync_datatype_helper::test()->GetProfile(index))->GetCustomDictionary(); } SpellcheckCustomDictionary* GetVerifierDictionary() { return SpellcheckServiceFactory::GetForContext( sync_datatype_helper::test()->verifier())->GetCustomDictionary(); } void LoadDictionary(SpellcheckCustomDictionary* dictionary) { if (dictionary->IsLoaded()) return; base::RunLoop run_loop; DictionaryLoadObserver observer(content::GetQuitTaskForRunLoop(&run_loop)); dictionary->AddObserver(&observer); dictionary->Load(); content::RunThisRunLoop(&run_loop); dictionary->RemoveObserver(&observer); ASSERT_TRUE(dictionary->IsLoaded()); } } // namespace void LoadDictionaries() { for (int i = 0; i < sync_datatype_helper::test()->num_clients(); ++i) LoadDictionary(GetDictionary(i)); if (sync_datatype_helper::test()->use_verifier()) LoadDictionary(GetVerifierDictionary()); } size_t GetDictionarySize(int index) { return GetDictionary(index)->GetWords().size(); } size_t GetVerifierDictionarySize() { return GetVerifierDictionary()->GetWords().size(); } bool DictionariesMatch() { const chrome::spellcheck_common::WordSet& reference = sync_datatype_helper::test()->use_verifier() ? GetVerifierDictionary()->GetWords() : GetDictionary(0)->GetWords(); for (int i = 0; i < sync_datatype_helper::test()->num_clients(); ++i) { const chrome::spellcheck_common::WordSet& dictionary = GetDictionary(i)->GetWords(); if (reference.size() != dictionary.size() || !std::equal(reference.begin(), reference.end(), dictionary.begin())) { return false; } } return true; } namespace { // Helper class used in the implementation of AwaitDictionariesMatch. class DictionaryMatchStatusChecker : public MultiClientStatusChangeChecker { public: DictionaryMatchStatusChecker(); ~DictionaryMatchStatusChecker() override; bool IsExitConditionSatisfied() override; std::string GetDebugMessage() const override; }; DictionaryMatchStatusChecker::DictionaryMatchStatusChecker() : MultiClientStatusChangeChecker( sync_datatype_helper::test()->GetSyncServices()) {} DictionaryMatchStatusChecker::~DictionaryMatchStatusChecker() {} bool DictionaryMatchStatusChecker::IsExitConditionSatisfied() { return DictionariesMatch(); } std::string DictionaryMatchStatusChecker::GetDebugMessage() const { return "Waiting for matching dictionaries"; } // Helper class used in the implementation of AwaitNumDictionaryEntries. class NumDictionaryEntriesStatusChecker : public SingleClientStatusChangeChecker { public: NumDictionaryEntriesStatusChecker(int index, size_t num_words); ~NumDictionaryEntriesStatusChecker() override; bool IsExitConditionSatisfied() override; std::string GetDebugMessage() const override; private: int index_; size_t num_words_; }; NumDictionaryEntriesStatusChecker::NumDictionaryEntriesStatusChecker( int index, size_t num_words) : SingleClientStatusChangeChecker( sync_datatype_helper::test()->GetSyncService(index)), index_(index), num_words_(num_words) {} NumDictionaryEntriesStatusChecker::~NumDictionaryEntriesStatusChecker() {} bool NumDictionaryEntriesStatusChecker::IsExitConditionSatisfied() { return GetDictionarySize(index_) == num_words_; } std::string NumDictionaryEntriesStatusChecker::GetDebugMessage() const { return base::StringPrintf( "Waiting for client %d: %" PRIuS " / %" PRIuS " words downloaded", index_, GetDictionarySize(index_), num_words_); } } // namespace bool AwaitDictionariesMatch() { DictionaryMatchStatusChecker checker; checker.Wait(); return !checker.TimedOut(); } bool AwaitNumDictionaryEntries(int index, size_t num_words) { NumDictionaryEntriesStatusChecker checker(index, num_words); checker.Wait(); return !checker.TimedOut(); } bool DictionaryMatchesVerifier(int index) { const chrome::spellcheck_common::WordSet& expected = GetVerifierDictionary()->GetWords(); const chrome::spellcheck_common::WordSet& actual = GetDictionary(index)->GetWords(); return expected.size() == actual.size() && std::equal(expected.begin(), expected.end(), actual.begin()); } bool AddWord(int index, const std::string& word) { SpellcheckCustomDictionary::Change dictionary_change; dictionary_change.AddWord(word); bool result = DictionarySyncIntegrationTestHelper::ApplyChange( GetDictionary(index), dictionary_change); if (sync_datatype_helper::test()->use_verifier()) { result &= DictionarySyncIntegrationTestHelper::ApplyChange( GetVerifierDictionary(), dictionary_change); } return result; } bool RemoveWord(int index, const std::string& word) { SpellcheckCustomDictionary::Change dictionary_change; dictionary_change.RemoveWord(word); bool result = DictionarySyncIntegrationTestHelper::ApplyChange( GetDictionary(index), dictionary_change); if (sync_datatype_helper::test()->use_verifier()) { result &= DictionarySyncIntegrationTestHelper::ApplyChange( GetVerifierDictionary(), dictionary_change); } return result; } } // namespace dictionary_helper