autofill_profile_syncable_service_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright 2014 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 "base/location.h"
6#include "base/message_loop/message_loop.h"
7#include "base/strings/utf_string_conversions.h"
8#include "components/autofill/core/browser/autofill_profile.h"
9#include "components/autofill/core/browser/webdata/autofill_change.h"
10#include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
11#include "content/public/test/test_browser_thread.h"
12#include "sync/api/sync_error_factory.h"
13#include "sync/api/sync_error_factory_mock.h"
14#include "sync/protocol/sync.pb.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace autofill {
19
20using ::testing::_;
21using ::testing::DoAll;
22using ::testing::Eq;
23using ::testing::Return;
24using ::testing::Property;
25using base::ASCIIToUTF16;
26using content::BrowserThread;
27
28namespace {
29
30// Some guids for testing.
31const char kGuid1[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
32const char kGuid2[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44C";
33const char kGuid3[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44D";
34const char kGuid4[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44E";
35const char kHttpOrigin[] = "http://www.example.com/";
36const char kHttpsOrigin[] = "https://www.example.com/";
37const char kSettingsOrigin[] = "Chrome settings";
38
39class MockAutofillProfileSyncableService
40    : public AutofillProfileSyncableService {
41 public:
42  MockAutofillProfileSyncableService() {}
43  virtual ~MockAutofillProfileSyncableService() {}
44
45  using AutofillProfileSyncableService::DataBundle;
46  using AutofillProfileSyncableService::set_sync_processor;
47  using AutofillProfileSyncableService::CreateData;
48
49  MOCK_METHOD1(LoadAutofillData, bool(std::vector<AutofillProfile*>*));
50  MOCK_METHOD1(SaveChangesToWebData,
51               bool(const AutofillProfileSyncableService::DataBundle&));
52};
53
54ACTION_P(CopyData, data) {
55  arg0->resize(data->size());
56  std::copy(data->begin(), data->end(), arg0->begin());
57}
58
59MATCHER_P(CheckSyncChanges, n_sync_changes_list, "") {
60  if (arg.size() != n_sync_changes_list.size())
61    return false;
62  syncer::SyncChangeList::const_iterator passed, expected;
63  for (passed = arg.begin(), expected = n_sync_changes_list.begin();
64       passed != arg.end() && expected != n_sync_changes_list.end();
65       ++passed, ++expected) {
66    DCHECK(passed->IsValid());
67    if (passed->change_type() != expected->change_type())
68      return false;
69    if (passed->sync_data().GetSpecifics().SerializeAsString() !=
70            expected->sync_data().GetSpecifics().SerializeAsString()) {
71      return false;
72    }
73  }
74  return true;
75}
76
77MATCHER_P(DataBundleCheck, n_bundle, "") {
78  if ((arg.profiles_to_delete.size() != n_bundle.profiles_to_delete.size()) ||
79      (arg.profiles_to_update.size() != n_bundle.profiles_to_update.size()) ||
80      (arg.profiles_to_add.size() != n_bundle.profiles_to_add.size()))
81    return false;
82  for (size_t i = 0; i < arg.profiles_to_delete.size(); ++i) {
83    if (arg.profiles_to_delete[i] != n_bundle.profiles_to_delete[i])
84      return false;
85  }
86  for (size_t i = 0; i < arg.profiles_to_update.size(); ++i) {
87    if (*arg.profiles_to_update[i] != *n_bundle.profiles_to_update[i])
88      return false;
89  }
90  for (size_t i = 0; i < arg.profiles_to_add.size(); ++i) {
91    if (*arg.profiles_to_add[i] != *n_bundle.profiles_to_add[i])
92      return false;
93  }
94  return true;
95}
96
97class MockSyncChangeProcessor : public syncer::SyncChangeProcessor {
98 public:
99  MockSyncChangeProcessor() {}
100  virtual ~MockSyncChangeProcessor() {}
101
102  MOCK_METHOD2(ProcessSyncChanges,
103               syncer::SyncError(const tracked_objects::Location&,
104                                 const syncer::SyncChangeList&));
105  virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type)
106      const OVERRIDE { return syncer::SyncDataList(); }
107};
108
109class TestSyncChangeProcessor : public syncer::SyncChangeProcessor {
110 public:
111  TestSyncChangeProcessor() {}
112  virtual ~TestSyncChangeProcessor() {}
113
114  virtual syncer::SyncError ProcessSyncChanges(
115      const tracked_objects::Location& location,
116      const syncer::SyncChangeList& changes) OVERRIDE {
117    changes_ = changes;
118    return syncer::SyncError();
119  }
120
121  virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const
122      OVERRIDE {
123    return syncer::SyncDataList();
124  }
125
126  const syncer::SyncChangeList& changes() { return changes_; }
127
128 private:
129  syncer::SyncChangeList changes_;
130};
131
132// Returns a profile with all fields set.  Contains identical data to the data
133// returned from ConstructCompleteSyncData().
134scoped_ptr<AutofillProfile> ConstructCompleteProfile() {
135  scoped_ptr<AutofillProfile> profile(
136      new AutofillProfile(kGuid1, kHttpsOrigin));
137
138  std::vector<base::string16> names;
139  names.push_back(ASCIIToUTF16("John K. Doe"));
140  names.push_back(ASCIIToUTF16("Jane Luise Smith"));
141  profile->SetRawMultiInfo(NAME_FULL, names);
142
143  std::vector<base::string16> emails;
144  emails.push_back(ASCIIToUTF16("user@example.com"));
145  emails.push_back(ASCIIToUTF16("superuser@example.org"));
146  profile->SetRawMultiInfo(EMAIL_ADDRESS, emails);
147
148  std::vector<base::string16> phones;
149  phones.push_back(ASCIIToUTF16("1.800.555.1234"));
150  phones.push_back(ASCIIToUTF16("1.866.650.0000"));
151  profile->SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, phones);
152
153  profile->SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
154                      ASCIIToUTF16("123 Fake St.\n"
155                                   "Apt. 42"));
156  EXPECT_EQ(ASCIIToUTF16("123 Fake St."),
157            profile->GetRawInfo(ADDRESS_HOME_LINE1));
158  EXPECT_EQ(ASCIIToUTF16("Apt. 42"), profile->GetRawInfo(ADDRESS_HOME_LINE2));
159
160  profile->SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Google, Inc."));
161  profile->SetRawInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Mountain View"));
162  profile->SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California"));
163  profile->SetRawInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("94043"));
164  profile->SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
165  profile->SetRawInfo(ADDRESS_HOME_SORTING_CODE, ASCIIToUTF16("CEDEX"));
166  profile->SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY,
167                      ASCIIToUTF16("Santa Clara"));
168  return profile.Pass();
169}
170
171// Returns SyncData with all Autofill profile fields set.  Contains identical
172// data to the data returned from ConstructCompleteProfile().
173syncer::SyncData ConstructCompleteSyncData() {
174  sync_pb::EntitySpecifics entity_specifics;
175  sync_pb::AutofillProfileSpecifics* specifics =
176      entity_specifics.mutable_autofill_profile();
177
178  specifics->set_guid(kGuid1);
179  specifics->set_origin(kHttpsOrigin);
180
181  specifics->add_name_first("John");
182  specifics->add_name_middle("K.");
183  specifics->add_name_last("Doe");
184
185  specifics->add_name_first("Jane");
186  specifics->add_name_middle("Luise");
187  specifics->add_name_last("Smith");
188
189  specifics->add_email_address("user@example.com");
190  specifics->add_email_address("superuser@example.org");
191
192  specifics->add_phone_home_whole_number("1.800.555.1234");
193  specifics->add_phone_home_whole_number("1.866.650.0000");
194
195  specifics->set_address_home_line1("123 Fake St.");
196  specifics->set_address_home_line2("Apt. 42");
197  specifics->set_address_home_street_address("123 Fake St.\n"
198                                             "Apt. 42");
199
200  specifics->set_company_name("Google, Inc.");
201  specifics->set_address_home_city("Mountain View");
202  specifics->set_address_home_state("California");
203  specifics->set_address_home_zip("94043");
204  specifics->set_address_home_country("US");
205  specifics->set_address_home_sorting_code("CEDEX");
206  specifics->set_address_home_dependent_locality("Santa Clara");
207
208  return syncer::SyncData::CreateLocalData(kGuid1, kGuid1, entity_specifics);
209}
210
211}  // namespace
212
213class AutofillProfileSyncableServiceTest : public testing::Test {
214 public:
215  AutofillProfileSyncableServiceTest()
216    : ui_thread_(BrowserThread::UI, &message_loop_),
217      db_thread_(BrowserThread::DB, &message_loop_) {}
218
219  virtual void SetUp() OVERRIDE {
220    sync_processor_.reset(new MockSyncChangeProcessor);
221  }
222
223  // Wrapper around AutofillProfileSyncableService::MergeDataAndStartSyncing()
224  // that also verifies expectations.
225  void MergeDataAndStartSyncing(
226      const std::vector<AutofillProfile*>& profiles_from_web_db,
227      const syncer::SyncDataList& data_list,
228      const MockAutofillProfileSyncableService::DataBundle& expected_bundle,
229      const syncer::SyncChangeList& expected_change_list) {
230    EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_))
231        .Times(1)
232        .WillOnce(DoAll(CopyData(&profiles_from_web_db), Return(true)));
233    EXPECT_CALL(autofill_syncable_service_,
234                SaveChangesToWebData(DataBundleCheck(expected_bundle)))
235        .Times(1)
236        .WillOnce(Return(true));
237    if (expected_change_list.empty()) {
238      EXPECT_CALL(*sync_processor_, ProcessSyncChanges(_, _)).Times(0);
239    } else {
240      ON_CALL(*sync_processor_, ProcessSyncChanges(_, _))
241          .WillByDefault(Return(syncer::SyncError()));
242      EXPECT_CALL(*sync_processor_,
243                  ProcessSyncChanges(_, CheckSyncChanges(expected_change_list)))
244          .Times(1)
245          .WillOnce(Return(syncer::SyncError()));
246    }
247
248    // Takes ownership of sync_processor_.
249    autofill_syncable_service_.MergeDataAndStartSyncing(
250        syncer::AUTOFILL_PROFILE, data_list,
251        sync_processor_.PassAs<syncer::SyncChangeProcessor>(),
252        scoped_ptr<syncer::SyncErrorFactory>(
253            new syncer::SyncErrorFactoryMock()));
254  }
255
256 protected:
257  base::MessageLoop message_loop_;
258  content::TestBrowserThread ui_thread_;
259  content::TestBrowserThread db_thread_;
260  MockAutofillProfileSyncableService autofill_syncable_service_;
261  scoped_ptr<MockSyncChangeProcessor> sync_processor_;
262};
263
264TEST_F(AutofillProfileSyncableServiceTest, MergeDataAndStartSyncing) {
265  std::vector<AutofillProfile*> profiles_from_web_db;
266  std::string guid_present1 = kGuid1;
267  std::string guid_present2 = kGuid2;
268  std::string guid_synced1 = kGuid3;
269  std::string guid_synced2 = kGuid4;
270  std::string origin_present1 = kHttpOrigin;
271  std::string origin_present2 = std::string();
272  std::string origin_synced1 = kHttpsOrigin;
273  std::string origin_synced2 = kSettingsOrigin;
274
275  profiles_from_web_db.push_back(
276      new AutofillProfile(guid_present1, origin_present1));
277  profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
278  profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1,
279                                          ASCIIToUTF16("1 1st st"));
280  profiles_from_web_db.push_back(
281      new AutofillProfile(guid_present2, origin_present2));
282  profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
283  profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1,
284                                          ASCIIToUTF16("2 2nd st"));
285
286  syncer::SyncDataList data_list;
287  AutofillProfile profile1(guid_synced1, origin_synced1);
288  profile1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
289  data_list.push_back(autofill_syncable_service_.CreateData(profile1));
290  AutofillProfile profile2(guid_synced2, origin_synced2);
291  profile2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Harry"));
292  data_list.push_back(autofill_syncable_service_.CreateData(profile2));
293  // This one will have the name and origin updated.
294  AutofillProfile profile3(guid_present2, origin_synced2);
295  profile3.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom Doe"));
296  data_list.push_back(autofill_syncable_service_.CreateData(profile3));
297
298  syncer::SyncChangeList expected_change_list;
299  expected_change_list.push_back(
300      syncer::SyncChange(FROM_HERE,
301                         syncer::SyncChange::ACTION_ADD,
302                         MockAutofillProfileSyncableService::CreateData(
303                             *profiles_from_web_db.front())));
304
305  MockAutofillProfileSyncableService::DataBundle expected_bundle;
306  expected_bundle.profiles_to_add.push_back(&profile1);
307  expected_bundle.profiles_to_add.push_back(&profile2);
308  expected_bundle.profiles_to_update.push_back(&profile3);
309
310  MergeDataAndStartSyncing(
311      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
312  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
313}
314
315TEST_F(AutofillProfileSyncableServiceTest, MergeIdenticalProfiles) {
316  std::vector<AutofillProfile*> profiles_from_web_db;
317  std::string guid_present1 = kGuid1;
318  std::string guid_present2 = kGuid2;
319  std::string guid_synced1 = kGuid3;
320  std::string guid_synced2 = kGuid4;
321  std::string origin_present1 = kHttpOrigin;
322  std::string origin_present2 = kSettingsOrigin;
323  std::string origin_synced1 = kHttpsOrigin;
324  std::string origin_synced2 = kHttpsOrigin;
325
326  profiles_from_web_db.push_back(
327      new AutofillProfile(guid_present1, origin_present1));
328  profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
329  profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1,
330                                          ASCIIToUTF16("1 1st st"));
331  profiles_from_web_db.push_back(
332      new AutofillProfile(guid_present2, origin_present2));
333  profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
334  profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1,
335                                          ASCIIToUTF16("2 2nd st"));
336
337  // The synced profiles are identical to the local ones, except that the guids
338  // are different.
339  syncer::SyncDataList data_list;
340  AutofillProfile profile1(guid_synced1, origin_synced1);
341  profile1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
342  profile1.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 1st st"));
343  data_list.push_back(autofill_syncable_service_.CreateData(profile1));
344  AutofillProfile profile2(guid_synced2, origin_synced2);
345  profile2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
346  profile2.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("2 2nd st"));
347  data_list.push_back(autofill_syncable_service_.CreateData(profile2));
348
349  AutofillProfile expected_profile(profile2);
350  expected_profile.set_origin(kSettingsOrigin);
351  syncer::SyncChangeList expected_change_list;
352  expected_change_list.push_back(
353      syncer::SyncChange(FROM_HERE,
354                         syncer::SyncChange::ACTION_UPDATE,
355                         MockAutofillProfileSyncableService::CreateData(
356                             expected_profile)));
357
358  MockAutofillProfileSyncableService::DataBundle expected_bundle;
359  expected_bundle.profiles_to_delete.push_back(guid_present1);
360  expected_bundle.profiles_to_delete.push_back(guid_present2);
361  expected_bundle.profiles_to_add.push_back(&profile1);
362  expected_bundle.profiles_to_add.push_back(&expected_profile);
363
364  MergeDataAndStartSyncing(
365      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
366  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
367}
368
369TEST_F(AutofillProfileSyncableServiceTest, MergeSimilarProfiles) {
370  std::vector<AutofillProfile*> profiles_from_web_db;
371  std::string guid_present1 = kGuid1;
372  std::string guid_present2 = kGuid2;
373  std::string guid_synced1 = kGuid3;
374  std::string guid_synced2 = kGuid4;
375  std::string origin_present1 = kHttpOrigin;
376  std::string origin_present2 = kSettingsOrigin;
377  std::string origin_synced1 = kHttpsOrigin;
378  std::string origin_synced2 = kHttpsOrigin;
379
380  profiles_from_web_db.push_back(
381      new AutofillProfile(guid_present1, origin_present1));
382  profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
383  profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1,
384                                          ASCIIToUTF16("1 1st st"));
385  profiles_from_web_db.push_back(
386      new AutofillProfile(guid_present2, origin_present2));
387  profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
388  profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1,
389                                          ASCIIToUTF16("2 2nd st"));
390
391  // The synced profiles are identical to the local ones, except that the guids
392  // are different.
393  syncer::SyncDataList data_list;
394  AutofillProfile profile1(guid_synced1, origin_synced1);
395  profile1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
396  profile1.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 1st st"));
397  profile1.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
398  data_list.push_back(autofill_syncable_service_.CreateData(profile1));
399  AutofillProfile profile2(guid_synced2, origin_synced2);
400  profile2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
401  profile2.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("2 2nd st"));
402  profile2.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Fizzbang, LLC."));
403  data_list.push_back(autofill_syncable_service_.CreateData(profile2));
404
405  // The first profile should have its origin updated.
406  // The second profile should remain as-is, because an unverified profile
407  // should never overwrite a verified one.
408  AutofillProfile expected_profile(profile1);
409  expected_profile.set_origin(origin_present1);
410  syncer::SyncChangeList expected_change_list;
411  expected_change_list.push_back(
412      syncer::SyncChange(FROM_HERE,
413                         syncer::SyncChange::ACTION_ADD,
414                         MockAutofillProfileSyncableService::CreateData(
415                             *profiles_from_web_db.back())));
416  expected_change_list.push_back(
417      syncer::SyncChange(FROM_HERE,
418                         syncer::SyncChange::ACTION_UPDATE,
419                         MockAutofillProfileSyncableService::CreateData(
420                             expected_profile)));
421
422  MockAutofillProfileSyncableService::DataBundle expected_bundle;
423  expected_bundle.profiles_to_delete.push_back(guid_present1);
424  expected_bundle.profiles_to_add.push_back(&expected_profile);
425  expected_bundle.profiles_to_add.push_back(&profile2);
426
427  MergeDataAndStartSyncing(
428      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
429  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
430}
431
432// Ensure that no Sync events are generated to fill in missing origins from Sync
433// with explicitly present empty ones.  This ensures that the migration to add
434// origins to profiles does not generate lots of needless Sync updates.
435TEST_F(AutofillProfileSyncableServiceTest, MergeDataEmptyOrigins) {
436  std::vector<AutofillProfile*> profiles_from_web_db;
437
438  // Create a profile with an empty origin.
439  AutofillProfile profile(kGuid1, std::string());
440  profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
441  profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 1st st"));
442
443  profiles_from_web_db.push_back(new AutofillProfile(profile));
444
445  // Create a Sync profile identical to |profile|, except with no origin set.
446  sync_pb::EntitySpecifics specifics;
447  sync_pb::AutofillProfileSpecifics* autofill_specifics =
448      specifics.mutable_autofill_profile();
449  autofill_specifics->set_guid(profile.guid());
450  autofill_specifics->add_name_first("John");
451  autofill_specifics->add_name_middle(std::string());
452  autofill_specifics->add_name_last(std::string());
453  autofill_specifics->add_email_address(std::string());
454  autofill_specifics->add_phone_home_whole_number(std::string());
455  autofill_specifics->set_address_home_line1("1 1st st");
456  EXPECT_FALSE(autofill_specifics->has_origin());
457
458  syncer::SyncDataList data_list;
459  data_list.push_back(
460      syncer::SyncData::CreateLocalData(
461          profile.guid(), profile.guid(), specifics));
462
463  MockAutofillProfileSyncableService::DataBundle expected_bundle;
464  syncer::SyncChangeList expected_change_list;
465  MergeDataAndStartSyncing(
466      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
467  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
468}
469
470TEST_F(AutofillProfileSyncableServiceTest, GetAllSyncData) {
471  std::vector<AutofillProfile*> profiles_from_web_db;
472  std::string guid_present1 = kGuid1;
473  std::string guid_present2 = kGuid2;
474
475  profiles_from_web_db.push_back(
476      new AutofillProfile(guid_present1, kHttpOrigin));
477  profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
478  profiles_from_web_db.push_back(
479      new AutofillProfile(guid_present2, kHttpsOrigin));
480  profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
481
482  syncer::SyncChangeList expected_change_list;
483  expected_change_list.push_back(
484      syncer::SyncChange(FROM_HERE,
485                         syncer::SyncChange::ACTION_ADD,
486                         MockAutofillProfileSyncableService::CreateData(
487                             *profiles_from_web_db.front())));
488  expected_change_list.push_back(
489      syncer::SyncChange(FROM_HERE,
490                         syncer::SyncChange::ACTION_ADD,
491                         MockAutofillProfileSyncableService::CreateData(
492                             *profiles_from_web_db.back())));
493
494  MockAutofillProfileSyncableService::DataBundle expected_bundle;
495  syncer::SyncDataList data_list;
496  MergeDataAndStartSyncing(
497      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
498
499  syncer::SyncDataList data =
500      autofill_syncable_service_.GetAllSyncData(syncer::AUTOFILL_PROFILE);
501
502  ASSERT_EQ(2U, data.size());
503  EXPECT_EQ(guid_present1, data[0].GetSpecifics().autofill_profile().guid());
504  EXPECT_EQ(guid_present2, data[1].GetSpecifics().autofill_profile().guid());
505  EXPECT_EQ(kHttpOrigin, data[0].GetSpecifics().autofill_profile().origin());
506  EXPECT_EQ(kHttpsOrigin, data[1].GetSpecifics().autofill_profile().origin());
507
508  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
509}
510
511TEST_F(AutofillProfileSyncableServiceTest, ProcessSyncChanges) {
512  std::vector<AutofillProfile *> profiles_from_web_db;
513  std::string guid_present = kGuid1;
514  std::string guid_synced = kGuid2;
515
516  syncer::SyncChangeList change_list;
517  AutofillProfile profile(guid_synced, kHttpOrigin);
518  profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
519  change_list.push_back(
520      syncer::SyncChange(
521          FROM_HERE,
522          syncer::SyncChange::ACTION_ADD,
523          MockAutofillProfileSyncableService::CreateData(profile)));
524  AutofillProfile empty_profile(guid_present, kHttpsOrigin);
525  change_list.push_back(
526      syncer::SyncChange(
527          FROM_HERE,
528          syncer::SyncChange::ACTION_DELETE,
529          MockAutofillProfileSyncableService::CreateData(empty_profile)));
530
531  MockAutofillProfileSyncableService::DataBundle expected_bundle;
532  expected_bundle.profiles_to_delete.push_back(guid_present);
533  expected_bundle.profiles_to_add.push_back(&profile);
534
535  EXPECT_CALL(autofill_syncable_service_, SaveChangesToWebData(
536              DataBundleCheck(expected_bundle)))
537      .Times(1)
538      .WillOnce(Return(true));
539
540  autofill_syncable_service_.set_sync_processor(sync_processor_.release());
541  syncer::SyncError error = autofill_syncable_service_.ProcessSyncChanges(
542      FROM_HERE, change_list);
543
544  EXPECT_FALSE(error.IsSet());
545}
546
547TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileAdded) {
548  // Will be owned by the syncable service.  Keep a reference available here for
549  // verifying test expectations.
550  TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
551  autofill_syncable_service_.set_sync_processor(sync_change_processor);
552
553  AutofillProfile profile(kGuid1, kHttpsOrigin);
554  profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
555  AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile);
556  autofill_syncable_service_.AutofillProfileChanged(change);
557
558  ASSERT_EQ(1U, sync_change_processor->changes().size());
559  syncer::SyncChange result = sync_change_processor->changes()[0];
560  EXPECT_EQ(syncer::SyncChange::ACTION_ADD, result.change_type());
561
562  sync_pb::AutofillProfileSpecifics specifics =
563      result.sync_data().GetSpecifics().autofill_profile();
564  EXPECT_EQ(kGuid1, specifics.guid());
565  EXPECT_EQ(kHttpsOrigin, specifics.origin());
566  EXPECT_THAT(specifics.name_first(), testing::ElementsAre("Jane"));
567}
568
569TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileDeleted) {
570  // Will be owned by the syncable service.  Keep a reference available here for
571  // verifying test expectations.
572  TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
573  autofill_syncable_service_.set_sync_processor(sync_change_processor);
574
575  AutofillProfileChange change(AutofillProfileChange::REMOVE, kGuid2, NULL);
576  autofill_syncable_service_.AutofillProfileChanged(change);
577
578  ASSERT_EQ(1U, sync_change_processor->changes().size());
579  syncer::SyncChange result = sync_change_processor->changes()[0];
580  EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, result.change_type());
581  sync_pb::AutofillProfileSpecifics specifics =
582      result.sync_data().GetSpecifics().autofill_profile();
583  EXPECT_EQ(kGuid2, specifics.guid());
584}
585
586TEST_F(AutofillProfileSyncableServiceTest, UpdateField) {
587  AutofillProfile profile(kGuid1, kSettingsOrigin);
588  std::string company1 = "A Company";
589  std::string company2 = "Another Company";
590  profile.SetRawInfo(COMPANY_NAME, ASCIIToUTF16(company1));
591  EXPECT_FALSE(AutofillProfileSyncableService::UpdateField(
592      COMPANY_NAME, company1, &profile));
593  EXPECT_EQ(profile.GetRawInfo(COMPANY_NAME), ASCIIToUTF16(company1));
594  EXPECT_TRUE(AutofillProfileSyncableService::UpdateField(
595      COMPANY_NAME, company2, &profile));
596  EXPECT_EQ(profile.GetRawInfo(COMPANY_NAME), ASCIIToUTF16(company2));
597  EXPECT_FALSE(AutofillProfileSyncableService::UpdateField(
598      COMPANY_NAME, company2, &profile));
599  EXPECT_EQ(profile.GetRawInfo(COMPANY_NAME), ASCIIToUTF16(company2));
600}
601
602TEST_F(AutofillProfileSyncableServiceTest, UpdateMultivaluedField) {
603  AutofillProfile profile(kGuid1, kHttpsOrigin);
604
605  std::vector<base::string16> values;
606  values.push_back(ASCIIToUTF16("1@1.com"));
607  values.push_back(ASCIIToUTF16("2@1.com"));
608  profile.SetRawMultiInfo(EMAIL_ADDRESS, values);
609
610  ::google::protobuf::RepeatedPtrField<std::string> specifics_fields;
611  specifics_fields.AddAllocated(new std::string("2@1.com"));
612  specifics_fields.AddAllocated(new std::string("3@1.com"));
613
614  EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField(
615      EMAIL_ADDRESS, specifics_fields, &profile));
616  profile.GetRawMultiInfo(EMAIL_ADDRESS, &values);
617  ASSERT_TRUE(values.size() == 2);
618  EXPECT_EQ(values[0], ASCIIToUTF16("2@1.com"));
619  EXPECT_EQ(values[1], ASCIIToUTF16("3@1.com"));
620
621  EXPECT_FALSE(AutofillProfileSyncableService::UpdateMultivaluedField(
622      EMAIL_ADDRESS, specifics_fields, &profile));
623  profile.GetRawMultiInfo(EMAIL_ADDRESS, &values);
624  ASSERT_EQ(values.size(), 2U);
625  EXPECT_EQ(values[0], ASCIIToUTF16("2@1.com"));
626  EXPECT_EQ(values[1], ASCIIToUTF16("3@1.com"));
627  EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField(
628      EMAIL_ADDRESS, ::google::protobuf::RepeatedPtrField<std::string>(),
629      &profile));
630  profile.GetRawMultiInfo(EMAIL_ADDRESS, &values);
631  ASSERT_EQ(values.size(), 1U);  // Always have at least an empty string.
632  EXPECT_EQ(values[0], ASCIIToUTF16(""));
633}
634
635TEST_F(AutofillProfileSyncableServiceTest, MergeProfile) {
636  AutofillProfile profile1(kGuid1, kHttpOrigin);
637  profile1.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("111 First St."));
638
639  std::vector<base::string16> values;
640  values.push_back(ASCIIToUTF16("1@1.com"));
641  values.push_back(ASCIIToUTF16("2@1.com"));
642  profile1.SetRawMultiInfo(EMAIL_ADDRESS, values);
643
644  AutofillProfile profile2(kGuid2, kHttpsOrigin);
645  profile2.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("111 First St."));
646
647  // |values| now is [ "1@1.com", "2@1.com", "3@1.com" ].
648  values.push_back(ASCIIToUTF16("3@1.com"));
649  profile2.SetRawMultiInfo(EMAIL_ADDRESS, values);
650
651  values.clear();
652  values.push_back(ASCIIToUTF16("John"));
653  profile1.SetRawMultiInfo(NAME_FIRST, values);
654  values.push_back(ASCIIToUTF16("Jane"));
655  profile2.SetRawMultiInfo(NAME_FIRST, values);
656
657  values.clear();
658  values.push_back(ASCIIToUTF16("Doe"));
659  profile1.SetRawMultiInfo(NAME_LAST, values);
660  values.push_back(ASCIIToUTF16("Other"));
661  profile2.SetRawMultiInfo(NAME_LAST, values);
662
663  values.clear();
664  values.push_back(ASCIIToUTF16("650234567"));
665  profile2.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, values);
666
667  EXPECT_FALSE(AutofillProfileSyncableService::MergeProfile(profile2,
668                                                            &profile1,
669                                                            "en-US"));
670
671  profile1.GetRawMultiInfo(NAME_FIRST, &values);
672  ASSERT_EQ(values.size(), 2U);
673  EXPECT_EQ(values[0], ASCIIToUTF16("John"));
674  EXPECT_EQ(values[1], ASCIIToUTF16("Jane"));
675
676  profile1.GetRawMultiInfo(NAME_LAST, &values);
677  ASSERT_EQ(values.size(), 2U);
678  EXPECT_EQ(values[0], ASCIIToUTF16("Doe"));
679  EXPECT_EQ(values[1], ASCIIToUTF16("Other"));
680
681  profile1.GetRawMultiInfo(EMAIL_ADDRESS, &values);
682  ASSERT_EQ(values.size(), 3U);
683  EXPECT_EQ(values[0], ASCIIToUTF16("1@1.com"));
684  EXPECT_EQ(values[1], ASCIIToUTF16("2@1.com"));
685  EXPECT_EQ(values[2], ASCIIToUTF16("3@1.com"));
686
687  profile1.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values);
688  ASSERT_EQ(values.size(), 1U);
689  EXPECT_EQ(values[0], ASCIIToUTF16("650234567"));
690
691  EXPECT_EQ(profile2.origin(), profile1.origin());
692
693  AutofillProfile profile3(kGuid3, kHttpOrigin);
694  profile3.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("111 First St."));
695
696  values.clear();
697  values.push_back(ASCIIToUTF16("Jane"));
698  profile3.SetRawMultiInfo(NAME_FIRST, values);
699
700  values.clear();
701  values.push_back(ASCIIToUTF16("Doe"));
702  profile3.SetRawMultiInfo(NAME_LAST, values);
703
704  EXPECT_TRUE(AutofillProfileSyncableService::MergeProfile(profile3,
705                                                           &profile1,
706                                                            "en-US"));
707
708  profile1.GetRawMultiInfo(NAME_FIRST, &values);
709  ASSERT_EQ(values.size(), 3U);
710  EXPECT_EQ(values[0], ASCIIToUTF16("John"));
711  EXPECT_EQ(values[1], ASCIIToUTF16("Jane"));
712  EXPECT_EQ(values[2], ASCIIToUTF16("Jane"));
713
714  profile1.GetRawMultiInfo(NAME_LAST, &values);
715  ASSERT_EQ(values.size(), 3U);
716  EXPECT_EQ(values[0], ASCIIToUTF16("Doe"));
717  EXPECT_EQ(values[1], ASCIIToUTF16("Other"));
718  EXPECT_EQ(values[2], ASCIIToUTF16("Doe"));
719
720  // Middle name should have three entries as well.
721  profile1.GetRawMultiInfo(NAME_MIDDLE, &values);
722  ASSERT_EQ(values.size(), 3U);
723  EXPECT_TRUE(values[0].empty());
724  EXPECT_TRUE(values[1].empty());
725  EXPECT_TRUE(values[2].empty());
726
727  profile1.GetRawMultiInfo(EMAIL_ADDRESS, &values);
728  ASSERT_EQ(values.size(), 3U);
729  EXPECT_EQ(values[0], ASCIIToUTF16("1@1.com"));
730  EXPECT_EQ(values[1], ASCIIToUTF16("2@1.com"));
731  EXPECT_EQ(values[2], ASCIIToUTF16("3@1.com"));
732
733  profile1.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values);
734  ASSERT_EQ(values.size(), 1U);
735  EXPECT_EQ(values[0], ASCIIToUTF16("650234567"));
736}
737
738// Ensure that all profile fields are able to be synced up from the client to
739// the server.
740TEST_F(AutofillProfileSyncableServiceTest, SyncAllFieldsToServer) {
741  std::vector<AutofillProfile*> profiles_from_web_db;
742
743  // Create a profile with all fields set.
744  profiles_from_web_db.push_back(ConstructCompleteProfile().release());
745
746  // Set up expectations: No changes to the WebDB, and all fields correctly
747  // copied to Sync.
748  MockAutofillProfileSyncableService::DataBundle expected_bundle;
749  syncer::SyncChangeList expected_change_list;
750  expected_change_list.push_back(
751      syncer::SyncChange(FROM_HERE,
752                         syncer::SyncChange::ACTION_ADD,
753                         ConstructCompleteSyncData()));
754
755  // Verify the expectations.
756  syncer::SyncDataList data_list;
757  MergeDataAndStartSyncing(
758      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
759  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
760}
761
762// Ensure that all profile fields are able to be synced down from the server to
763// the client.
764TEST_F(AutofillProfileSyncableServiceTest, SyncAllFieldsToClient) {
765  // Create a profile with all fields set.
766  syncer::SyncDataList data_list;
767  data_list.push_back(ConstructCompleteSyncData());
768
769  // Set up expectations: All fields correctly copied to the WebDB, and no
770  // changes propagated to Sync.
771  syncer::SyncChangeList expected_change_list;
772  scoped_ptr<AutofillProfile> expected_profile = ConstructCompleteProfile();
773  MockAutofillProfileSyncableService::DataBundle expected_bundle;
774  expected_bundle.profiles_to_add.push_back(expected_profile.get());
775
776  // Verify the expectations.
777  std::vector<AutofillProfile*> profiles_from_web_db;
778  MergeDataAndStartSyncing(
779      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
780  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
781}
782
783// Ensure that the street address field takes precedence over the address line 1
784// and line 2 fields, even though these are expected to always be in sync in
785// practice.
786TEST_F(AutofillProfileSyncableServiceTest,
787       StreetAddressTakesPrecedenceOverAddressLines) {
788  // Create a Sync profile with conflicting address data in the street address
789  // field vs. the address line 1 and address line 2 fields.
790  sync_pb::EntitySpecifics specifics;
791  sync_pb::AutofillProfileSpecifics* autofill_specifics =
792      specifics.mutable_autofill_profile();
793  autofill_specifics->set_guid(kGuid1);
794  autofill_specifics->set_origin(kHttpsOrigin);
795  autofill_specifics->add_name_first(std::string());
796  autofill_specifics->add_name_middle(std::string());
797  autofill_specifics->add_name_last(std::string());
798  autofill_specifics->add_email_address(std::string());
799  autofill_specifics->add_phone_home_whole_number(std::string());
800  autofill_specifics->set_address_home_line1("123 Example St.");
801  autofill_specifics->set_address_home_line2("Apt. 42");
802  autofill_specifics->set_address_home_street_address("456 El Camino Real\n"
803                                                      "Suite #1337");
804
805  syncer::SyncDataList data_list;
806  data_list.push_back(
807      syncer::SyncData::CreateLocalData(kGuid1, kGuid1, specifics));
808
809  // Set up expectations: Full street address takes precedence over address
810  // lines.
811  syncer::SyncChangeList expected_change_list;
812  AutofillProfile expected_profile(kGuid1, kHttpsOrigin);
813  expected_profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
814                              ASCIIToUTF16("456 El Camino Real\n"
815                                           "Suite #1337"));
816  EXPECT_EQ(ASCIIToUTF16("456 El Camino Real"),
817            expected_profile.GetRawInfo(ADDRESS_HOME_LINE1));
818  EXPECT_EQ(ASCIIToUTF16("Suite #1337"),
819            expected_profile.GetRawInfo(ADDRESS_HOME_LINE2));
820  MockAutofillProfileSyncableService::DataBundle expected_bundle;
821  expected_bundle.profiles_to_add.push_back(&expected_profile);
822
823  // Verify the expectations.
824  std::vector<AutofillProfile*> profiles_from_web_db;
825  MergeDataAndStartSyncing(
826      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
827  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
828}
829
830// Ensure that no Sync events are generated to fill in missing street address
831// fields from Sync with explicitly present ones identical to the data stored in
832// the line1 and line2 fields.  This ensures that the migration to add the
833// street address field to profiles does not generate lots of needless Sync
834// updates.
835TEST_F(AutofillProfileSyncableServiceTest, MergeDataEmptyStreetAddress) {
836  std::vector<AutofillProfile*> profiles_from_web_db;
837
838  // Create a profile with the street address set.
839  AutofillProfile profile(kGuid1, kHttpsOrigin);
840  profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
841                     ASCIIToUTF16("123 Example St.\n"
842                                  "Apt. 42"));
843  EXPECT_EQ(ASCIIToUTF16("123 Example St."),
844            profile.GetRawInfo(ADDRESS_HOME_LINE1));
845  EXPECT_EQ(ASCIIToUTF16("Apt. 42"), profile.GetRawInfo(ADDRESS_HOME_LINE2));
846
847  profiles_from_web_db.push_back(new AutofillProfile(profile));
848
849  // Create a Sync profile identical to |profile|, except without street address
850  // explicitly set.
851  sync_pb::EntitySpecifics specifics;
852  sync_pb::AutofillProfileSpecifics* autofill_specifics =
853      specifics.mutable_autofill_profile();
854  autofill_specifics->set_guid(profile.guid());
855  autofill_specifics->set_origin(profile.origin());
856  autofill_specifics->add_name_first(std::string());
857  autofill_specifics->add_name_middle(std::string());
858  autofill_specifics->add_name_last(std::string());
859  autofill_specifics->add_email_address(std::string());
860  autofill_specifics->add_phone_home_whole_number(std::string());
861  autofill_specifics->set_address_home_line1("123 Example St.");
862  autofill_specifics->set_address_home_line2("Apt. 42");
863  EXPECT_FALSE(autofill_specifics->has_address_home_street_address());
864
865  syncer::SyncDataList data_list;
866  data_list.push_back(
867      syncer::SyncData::CreateLocalData(
868          profile.guid(), profile.guid(), specifics));
869
870  MockAutofillProfileSyncableService::DataBundle expected_bundle;
871  syncer::SyncChangeList expected_change_list;
872  MergeDataAndStartSyncing(
873      profiles_from_web_db, data_list, expected_bundle, expected_change_list);
874  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
875}
876
877}  // namespace autofill
878