1// Copyright (c) 2011 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 "chrome/browser/sync/test/integration/dictionary_helper.h"
6
7#include <algorithm>
8
9#include "base/format_macros.h"
10#include "base/strings/stringprintf.h"
11#include "chrome/browser/profiles/profile.h"
12#include "chrome/browser/spellchecker/spellcheck_factory.h"
13#include "chrome/browser/spellchecker/spellcheck_service.h"
14#include "chrome/browser/sync/test/integration/dictionary_load_observer.h"
15#include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h"
16#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
17#include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
18#include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
19#include "chrome/browser/sync/test/integration/sync_test.h"
20#include "chrome/common/chrome_switches.h"
21#include "chrome/common/spellcheck_common.h"
22#include "content/public/test/test_utils.h"
23
24class DictionarySyncIntegrationTestHelper {
25 public:
26  // Same as SpellcheckCustomDictionary::AddWord/RemoveWord, except does not
27  // write to disk.
28  static bool ApplyChange(
29      SpellcheckCustomDictionary* dictionary,
30      SpellcheckCustomDictionary::Change& change) {
31    int result = change.Sanitize(dictionary->GetWords());
32    dictionary->Apply(change);
33    dictionary->Notify(change);
34    dictionary->Sync(change);
35    return !result;
36  }
37
38  DISALLOW_COPY_AND_ASSIGN(DictionarySyncIntegrationTestHelper);
39};
40
41
42namespace dictionary_helper {
43namespace {
44
45SpellcheckCustomDictionary* GetDictionary(int index) {
46  return SpellcheckServiceFactory::GetForContext(
47      sync_datatype_helper::test()->GetProfile(index))->GetCustomDictionary();
48}
49
50SpellcheckCustomDictionary* GetVerifierDictionary() {
51  return SpellcheckServiceFactory::GetForContext(
52      sync_datatype_helper::test()->verifier())->GetCustomDictionary();
53}
54
55void LoadDictionary(SpellcheckCustomDictionary* dictionary) {
56  if (dictionary->IsLoaded())
57    return;
58  base::RunLoop run_loop;
59  DictionaryLoadObserver observer(content::GetQuitTaskForRunLoop(&run_loop));
60  dictionary->AddObserver(&observer);
61  dictionary->Load();
62  content::RunThisRunLoop(&run_loop);
63  dictionary->RemoveObserver(&observer);
64  ASSERT_TRUE(dictionary->IsLoaded());
65}
66
67}  // namespace
68
69
70void LoadDictionaries() {
71  for (int i = 0; i < sync_datatype_helper::test()->num_clients(); ++i)
72    LoadDictionary(GetDictionary(i));
73  if (sync_datatype_helper::test()->use_verifier())
74    LoadDictionary(GetVerifierDictionary());
75}
76
77size_t GetDictionarySize(int index) {
78  return GetDictionary(index)->GetWords().size();
79}
80
81size_t GetVerifierDictionarySize() {
82  return GetVerifierDictionary()->GetWords().size();
83}
84
85bool DictionariesMatch() {
86  const chrome::spellcheck_common::WordSet& reference =
87      sync_datatype_helper::test()->use_verifier()
88          ? GetVerifierDictionary()->GetWords()
89          : GetDictionary(0)->GetWords();
90  for (int i = 0; i < sync_datatype_helper::test()->num_clients(); ++i) {
91    const chrome::spellcheck_common::WordSet& dictionary =
92        GetDictionary(i)->GetWords();
93    if (reference.size() != dictionary.size() ||
94        !std::equal(reference.begin(), reference.end(), dictionary.begin())) {
95      return false;
96    }
97  }
98  return true;
99}
100
101namespace {
102
103// Helper class used in the implementation of AwaitDictionariesMatch.
104class DictionaryMatchStatusChecker : public MultiClientStatusChangeChecker {
105 public:
106  DictionaryMatchStatusChecker();
107  virtual ~DictionaryMatchStatusChecker();
108
109  virtual bool IsExitConditionSatisfied() OVERRIDE;
110  virtual std::string GetDebugMessage() const OVERRIDE;
111};
112
113DictionaryMatchStatusChecker::DictionaryMatchStatusChecker()
114    : MultiClientStatusChangeChecker(
115        sync_datatype_helper::test()->GetSyncServices()) {}
116
117DictionaryMatchStatusChecker::~DictionaryMatchStatusChecker() {}
118
119bool DictionaryMatchStatusChecker::IsExitConditionSatisfied() {
120  return DictionariesMatch();
121}
122
123std::string DictionaryMatchStatusChecker::GetDebugMessage() const {
124  return "Waiting for matching dictionaries";
125}
126
127// Helper class used in the implementation of AwaitNumDictionaryEntries.
128class NumDictionaryEntriesStatusChecker
129    : public SingleClientStatusChangeChecker {
130 public:
131  NumDictionaryEntriesStatusChecker(int index, size_t num_words);
132  virtual ~NumDictionaryEntriesStatusChecker();
133
134  virtual bool IsExitConditionSatisfied() OVERRIDE;
135  virtual std::string GetDebugMessage() const OVERRIDE;
136 private:
137  int index_;
138  size_t num_words_;
139};
140
141NumDictionaryEntriesStatusChecker::NumDictionaryEntriesStatusChecker(
142    int index, size_t num_words)
143  : SingleClientStatusChangeChecker(
144      sync_datatype_helper::test()->GetSyncService(index)),
145  index_(index),
146  num_words_(num_words) {}
147
148NumDictionaryEntriesStatusChecker::~NumDictionaryEntriesStatusChecker() {}
149
150bool NumDictionaryEntriesStatusChecker::IsExitConditionSatisfied() {
151  return GetDictionarySize(index_) == num_words_;
152}
153
154std::string NumDictionaryEntriesStatusChecker::GetDebugMessage() const {
155  return base::StringPrintf(
156      "Waiting for client %d: %" PRIuS " / %" PRIuS " words downloaded",
157      index_, GetDictionarySize(index_), num_words_);
158}
159
160}  // namespace
161
162bool AwaitDictionariesMatch() {
163  DictionaryMatchStatusChecker checker;
164  checker.Wait();
165  return !checker.TimedOut();
166}
167
168bool AwaitNumDictionaryEntries(int index, size_t num_words) {
169  NumDictionaryEntriesStatusChecker checker(index, num_words);
170  checker.Wait();
171  return !checker.TimedOut();
172}
173
174bool DictionaryMatchesVerifier(int index) {
175  const chrome::spellcheck_common::WordSet& expected =
176      GetVerifierDictionary()->GetWords();
177  const chrome::spellcheck_common::WordSet& actual =
178      GetDictionary(index)->GetWords();
179  return expected.size() == actual.size() &&
180         std::equal(expected.begin(), expected.end(), actual.begin());
181}
182
183bool AddWord(int index, const std::string& word) {
184  SpellcheckCustomDictionary::Change dictionary_change;
185  dictionary_change.AddWord(word);
186  bool result = DictionarySyncIntegrationTestHelper::ApplyChange(
187      GetDictionary(index), dictionary_change);
188  if (sync_datatype_helper::test()->use_verifier()) {
189    result &= DictionarySyncIntegrationTestHelper::ApplyChange(
190        GetVerifierDictionary(), dictionary_change);
191  }
192  return result;
193}
194
195bool RemoveWord(int index, const std::string& word) {
196  SpellcheckCustomDictionary::Change dictionary_change;
197  dictionary_change.RemoveWord(word);
198  bool result = DictionarySyncIntegrationTestHelper::ApplyChange(
199      GetDictionary(index), dictionary_change);
200  if (sync_datatype_helper::test()->use_verifier()) {
201    result &= DictionarySyncIntegrationTestHelper::ApplyChange(
202        GetVerifierDictionary(), dictionary_change);
203  }
204  return result;
205}
206
207}  // namespace dictionary_helper
208