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 "chrome/browser/sync/test/integration/search_engines_helper.h"
6
7#include <vector>
8
9#include "base/strings/string_util.h"
10#include "base/strings/stringprintf.h"
11#include "base/strings/utf_string_conversions.h"
12#include "base/time/time.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/search_engines/template_url_service_factory.h"
15#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
16#include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
17#include "chrome/browser/sync/test/integration/sync_test.h"
18#include "components/search_engines/template_url.h"
19#include "components/search_engines/template_url_service.h"
20
21using sync_datatype_helper::test;
22
23namespace {
24
25GUIDToTURLMap CreateGUIDToTURLMap(TemplateURLService* service) {
26  CHECK(service);
27
28  GUIDToTURLMap map;
29  TemplateURLService::TemplateURLVector turls = service->GetTemplateURLs();
30  for (TemplateURLService::TemplateURLVector::iterator it = turls.begin();
31       it != turls.end(); ++it) {
32    CHECK(*it);
33    CHECK(map.find((*it)->sync_guid()) == map.end());
34    map[(*it)->sync_guid()] = *it;
35  }
36
37  return map;
38}
39
40std::string GetTURLInfoString(const TemplateURL* turl) {
41  DCHECK(turl);
42  return "TemplateURL: shortname: " + base::UTF16ToASCII(turl->short_name()) +
43      " keyword: " + base::UTF16ToASCII(turl->keyword()) + " url: " +
44      turl->url();
45}
46
47bool TURLsMatch(const TemplateURL* turl1, const TemplateURL* turl2) {
48  CHECK(turl1);
49  CHECK(turl2);
50  bool result = (turl1->url() == turl2->url()) &&
51      (turl1->keyword() == turl2->keyword()) &&
52      (turl1->short_name() == turl2->short_name());
53
54  // Print some useful debug info.
55  if (!result) {
56    LOG(ERROR) << "TemplateURLs did not match: " << GetTURLInfoString(turl1)
57               << " vs " << GetTURLInfoString(turl2);
58  }
59
60  return result;
61}
62
63bool ServicesMatch(int profile_a, int profile_b) {
64  TemplateURLService* service_a =
65      search_engines_helper::GetServiceForBrowserContext(profile_a);
66  TemplateURLService* service_b =
67      search_engines_helper::GetServiceForBrowserContext(profile_b);
68  CHECK(service_a);
69  CHECK(service_b);
70
71  // Services that have synced should have identical TURLs, including the GUIDs.
72  // Make sure we compare those fields in addition to the user-visible fields.
73  GUIDToTURLMap a_turls = CreateGUIDToTURLMap(service_a);
74  GUIDToTURLMap b_turls = CreateGUIDToTURLMap(service_b);
75
76  if (a_turls.size() != b_turls.size()) {
77    LOG(ERROR) << "Service a and b do not match in size: " << a_turls.size()
78               << " vs " << b_turls.size() << " respectively.";
79    return false;
80  }
81
82  for (GUIDToTURLMap::iterator it = a_turls.begin();
83       it != a_turls.end(); ++it) {
84    if (b_turls.find(it->first) == b_turls.end()) {
85      LOG(ERROR) << "TURL GUID from a not found in b's TURLs: " << it->first;
86      return false;
87    }
88    if (!TURLsMatch(b_turls[it->first], it->second))
89      return false;
90  }
91
92  const TemplateURL* default_a = service_a->GetDefaultSearchProvider();
93  const TemplateURL* default_b = service_b->GetDefaultSearchProvider();
94  CHECK(default_a);
95  CHECK(default_b);
96  if (!TURLsMatch(default_a, default_b)) {
97    LOG(ERROR) << "Default search providers do not match: A's default: "
98               << default_a->keyword() << " B's default: "
99               << default_b->keyword();
100    return false;
101  } else {
102    LOG(INFO) << "A had default with URL: " << default_a->url()
103              << " and keyword: " << default_a->keyword();
104  }
105
106  return true;
107}
108
109// Convenience helper for consistently generating the same keyword for a given
110// seed.
111base::string16 CreateKeyword(int seed) {
112  return base::ASCIIToUTF16(base::StringPrintf("test%d", seed));
113}
114
115}  // namespace
116
117namespace search_engines_helper {
118
119TemplateURLService* GetServiceForBrowserContext(int profile_index) {
120  return TemplateURLServiceFactory::GetForProfile(
121      test()->GetProfile(profile_index));
122}
123
124TemplateURLService* GetVerifierService() {
125  return TemplateURLServiceFactory::GetForProfile(test()->verifier());
126}
127
128bool ServiceMatchesVerifier(int profile_index) {
129  TemplateURLService* verifier = GetVerifierService();
130  TemplateURLService* other = GetServiceForBrowserContext(profile_index);
131
132  CHECK(verifier);
133  CHECK(other);
134
135  TemplateURLService::TemplateURLVector verifier_turls =
136      verifier->GetTemplateURLs();
137  if (verifier_turls.size() != other->GetTemplateURLs().size()) {
138    LOG(ERROR) << "Verifier and other service have a different count of TURLs: "
139               << verifier_turls.size() << " vs "
140               << other->GetTemplateURLs().size() << " respectively.";
141    return false;
142  }
143
144  for (size_t i = 0; i < verifier_turls.size(); ++i) {
145    const TemplateURL* verifier_turl = verifier_turls.at(i);
146    CHECK(verifier_turl);
147    const TemplateURL* other_turl = other->GetTemplateURLForKeyword(
148        verifier_turl->keyword());
149
150    if (!other_turl) {
151      LOG(ERROR) << "The other service did not contain a TURL with keyword: "
152                 << verifier_turl->keyword();
153      return false;
154    }
155    if (!TURLsMatch(verifier_turl, other_turl))
156      return false;
157  }
158
159  return true;
160}
161
162bool AllServicesMatch() {
163  // Use 0 as the baseline.
164  if (test()->use_verifier() && !ServiceMatchesVerifier(0)) {
165    LOG(ERROR) << "TemplateURLService 0 does not match verifier.";
166    return false;
167  }
168
169  for (int it = 1; it < test()->num_clients(); ++it) {
170    if (!ServicesMatch(0, it)) {
171      LOG(ERROR) << "TemplateURLService " << it << " does not match with "
172                 << "service 0.";
173      return false;
174    }
175  }
176  return true;
177}
178
179TemplateURL* CreateTestTemplateURL(Profile* profile, int seed) {
180  return CreateTestTemplateURL(profile, seed, CreateKeyword(seed),
181                               base::StringPrintf("0000-0000-0000-%04d", seed));
182}
183
184TemplateURL* CreateTestTemplateURL(Profile* profile,
185                                   int seed,
186                                   const base::string16& keyword,
187                                   const std::string& sync_guid) {
188  return CreateTestTemplateURL(profile, seed, keyword,
189      base::StringPrintf("http://www.test%d.com/", seed), sync_guid);
190}
191
192TemplateURL* CreateTestTemplateURL(Profile* profile,
193                                   int seed,
194                                   const base::string16& keyword,
195                                   const std::string& url,
196                                   const std::string& sync_guid) {
197  TemplateURLData data;
198  data.short_name = CreateKeyword(seed);
199  data.SetKeyword(keyword);
200  data.SetURL(url);
201  data.favicon_url = GURL("http://favicon.url");
202  data.safe_for_autoreplace = true;
203  data.date_created = base::Time::FromTimeT(100);
204  data.last_modified = base::Time::FromTimeT(100);
205  data.prepopulate_id = 999999;
206  data.sync_guid = sync_guid;
207  return new TemplateURL(data);
208}
209
210void AddSearchEngine(int profile_index, int seed) {
211  Profile* profile = test()->GetProfile(profile_index);
212  TemplateURLServiceFactory::GetForProfile(profile)->Add(
213      CreateTestTemplateURL(profile, seed));
214  if (test()->use_verifier())
215    GetVerifierService()->Add(CreateTestTemplateURL(profile, seed));
216}
217
218void EditSearchEngine(int profile_index,
219                      const base::string16& keyword,
220                      const base::string16& short_name,
221                      const base::string16& new_keyword,
222                      const std::string& url) {
223  DCHECK(!url.empty());
224  TemplateURLService* service = GetServiceForBrowserContext(profile_index);
225  TemplateURL* turl = service->GetTemplateURLForKeyword(keyword);
226  EXPECT_TRUE(turl);
227  ASSERT_FALSE(new_keyword.empty());
228  service->ResetTemplateURL(turl, short_name, new_keyword, url);
229  // Make sure we do the same on the verifier.
230  if (test()->use_verifier()) {
231    TemplateURL* verifier_turl =
232        GetVerifierService()->GetTemplateURLForKeyword(keyword);
233    EXPECT_TRUE(verifier_turl);
234    GetVerifierService()->ResetTemplateURL(verifier_turl, short_name,
235                                           new_keyword, url);
236  }
237}
238
239void DeleteSearchEngineBySeed(int profile_index, int seed) {
240  TemplateURLService* service = GetServiceForBrowserContext(profile_index);
241  base::string16 keyword(CreateKeyword(seed));
242  TemplateURL* turl = service->GetTemplateURLForKeyword(keyword);
243  EXPECT_TRUE(turl);
244  service->Remove(turl);
245  // Make sure we do the same on the verifier.
246  if (test()->use_verifier()) {
247    TemplateURL* verifier_turl =
248        GetVerifierService()->GetTemplateURLForKeyword(keyword);
249    EXPECT_TRUE(verifier_turl);
250    GetVerifierService()->Remove(verifier_turl);
251  }
252}
253
254void ChangeDefaultSearchProvider(int profile_index, int seed) {
255  TemplateURLService* service = GetServiceForBrowserContext(profile_index);
256  ASSERT_TRUE(service);
257  TemplateURL* turl = service->GetTemplateURLForKeyword(CreateKeyword(seed));
258  ASSERT_TRUE(turl);
259  service->SetUserSelectedDefaultSearchProvider(turl);
260  if (test()->use_verifier()) {
261    TemplateURL* verifier_turl =
262        GetVerifierService()->GetTemplateURLForKeyword(CreateKeyword(seed));
263    ASSERT_TRUE(verifier_turl);
264    GetVerifierService()->SetUserSelectedDefaultSearchProvider(verifier_turl);
265  }
266}
267
268}  // namespace search_engines_helper
269