1 // Copyright 2018 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 "components/autofill/core/browser/webdata/autofill_sync_bridge_util.h"
6 
7 #include <vector>
8 
9 #include "base/strings/utf_string_conversions.h"
10 #include "components/autofill/core/browser/data_model/autofill_profile.h"
11 #include "components/autofill/core/browser/data_model/credit_card.h"
12 #include "components/autofill/core/browser/data_model/credit_card_cloud_token_data.h"
13 #include "components/autofill/core/browser/payments/payments_customer_data.h"
14 #include "components/autofill/core/browser/test_autofill_clock.h"
15 #include "components/autofill/core/browser/webdata/autofill_sync_bridge_test_util.h"
16 #include "components/autofill/core/browser/webdata/autofill_table.h"
17 #include "components/autofill/core/common/autofill_constants.h"
18 #include "components/sync/base/client_tag_hash.h"
19 #include "components/sync/model/entity_data.h"
20 #include "components/sync/protocol/sync.pb.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 namespace autofill {
24 namespace {
25 
26 using syncer::EntityChange;
27 using syncer::EntityData;
28 
29 class TestAutofillTable : public AutofillTable {
30  public:
TestAutofillTable(std::vector<CreditCard> cards_on_disk)31   explicit TestAutofillTable(std::vector<CreditCard> cards_on_disk)
32       : cards_on_disk_(cards_on_disk) {}
33 
~TestAutofillTable()34   ~TestAutofillTable() override {}
35 
GetServerCreditCards(std::vector<std::unique_ptr<CreditCard>> * cards) const36   bool GetServerCreditCards(
37       std::vector<std::unique_ptr<CreditCard>>* cards) const override {
38     for (const auto& card_on_disk : cards_on_disk_)
39       cards->push_back(std::make_unique<CreditCard>(card_on_disk));
40     return true;
41   }
42 
43  private:
44   std::vector<CreditCard> cards_on_disk_;
45 
46   DISALLOW_COPY_AND_ASSIGN(TestAutofillTable);
47 };
48 
SpecificsToEntity(const sync_pb::AutofillWalletSpecifics & specifics,const std::string & client_tag)49 EntityData SpecificsToEntity(const sync_pb::AutofillWalletSpecifics& specifics,
50                              const std::string& client_tag) {
51   syncer::EntityData data;
52   *data.specifics.mutable_autofill_wallet() = specifics;
53   data.client_tag_hash = syncer::ClientTagHash::FromUnhashed(
54       syncer::AUTOFILL_WALLET_DATA, client_tag);
55   return data;
56 }
57 
58 class AutofillSyncBridgeUtilTest : public testing::Test {
59  public:
AutofillSyncBridgeUtilTest()60   AutofillSyncBridgeUtilTest() {}
~AutofillSyncBridgeUtilTest()61   ~AutofillSyncBridgeUtilTest() override {}
62 
63  private:
64   DISALLOW_COPY_AND_ASSIGN(AutofillSyncBridgeUtilTest);
65 };
66 
67 // Tests that PopulateWalletTypesFromSyncData behaves as expected.
TEST_F(AutofillSyncBridgeUtilTest,PopulateWalletTypesFromSyncData)68 TEST_F(AutofillSyncBridgeUtilTest, PopulateWalletTypesFromSyncData) {
69   // Add an address first.
70   syncer::EntityChangeList entity_data;
71   std::string address_id("address1");
72   entity_data.push_back(EntityChange::CreateAdd(
73       address_id,
74       SpecificsToEntity(CreateAutofillWalletSpecificsForAddress(address_id),
75                         /*client_tag=*/"address-address1")));
76   // Add the first card that has its billing address id set to the address's id.
77   // No nickname is set.
78   entity_data.push_back(EntityChange::CreateAdd(
79       "card_with_billing_address_id",
80       SpecificsToEntity(CreateAutofillWalletSpecificsForCard(
81                             /*id=*/"card_with_billing_address_id",
82                             /*billing_address_id=*/address_id),
83                         /*client_tag=*/"card-card1")));
84   // Add the second card that has nickname.
85   std::string nickname("Grocery card");
86   entity_data.push_back(EntityChange::CreateAdd(
87       "card_with_nickname",
88       SpecificsToEntity(CreateAutofillWalletSpecificsForCard(
89                             /*id=*/"card_with_nickname",
90                             /*billing_address_id=*/"", /*nickname=*/nickname),
91                         /*client_tag=*/"card-card2")));
92   entity_data.push_back(EntityChange::CreateAdd(
93       "deadbeef",
94       SpecificsToEntity(CreateAutofillWalletSpecificsForPaymentsCustomerData(
95                             /*specifics_id=*/"deadbeef"),
96                         /*client_tag=*/"customer-deadbeef")));
97   entity_data.push_back(EntityChange::CreateAdd(
98       "data1", SpecificsToEntity(
99                    CreateAutofillWalletSpecificsForCreditCardCloudTokenData(
100                        /*specifics_id=*/"data1"),
101                    /*client_tag=*/"token-data1")));
102 
103   std::vector<CreditCard> wallet_cards;
104   std::vector<AutofillProfile> wallet_addresses;
105   std::vector<PaymentsCustomerData> customer_data;
106   std::vector<CreditCardCloudTokenData> cloud_token_data;
107   PopulateWalletTypesFromSyncData(entity_data, &wallet_cards, &wallet_addresses,
108                                   &customer_data, &cloud_token_data);
109 
110   ASSERT_EQ(2U, wallet_cards.size());
111   ASSERT_EQ(1U, wallet_addresses.size());
112 
113   EXPECT_EQ("deadbeef", customer_data.back().customer_id);
114 
115   EXPECT_EQ("data1", cloud_token_data.back().instrument_token);
116 
117   // Make sure the first card's billing address id is equal to the address'
118   // server id.
119   EXPECT_EQ(wallet_addresses.back().server_id(),
120             wallet_cards.front().billing_address_id());
121   // The first card's nickname is empty.
122   EXPECT_TRUE(wallet_cards.front().nickname().empty());
123 
124   // Make sure the second card's nickname is correctly populated from sync data.
125   EXPECT_EQ(base::UTF8ToUTF16(nickname), wallet_cards.back().nickname());
126 }
127 
128 // Verify that the billing address id from the card saved on disk is kept if it
129 // is a local profile guid.
TEST_F(AutofillSyncBridgeUtilTest,CopyRelevantWalletMetadataFromDisk_KeepLocalAddresses)130 TEST_F(AutofillSyncBridgeUtilTest,
131        CopyRelevantWalletMetadataFromDisk_KeepLocalAddresses) {
132   std::vector<CreditCard> cards_on_disk;
133   std::vector<CreditCard> wallet_cards;
134 
135   // Create a local profile to be used as a billing address.
136   AutofillProfile billing_address;
137 
138   // Create a card on disk that refers to that local profile as its billing
139   // address.
140   cards_on_disk.push_back(CreditCard());
141   cards_on_disk.back().set_billing_address_id(billing_address.guid());
142 
143   // Create a card pulled from wallet with the same id, but a different billing
144   // address id.
145   wallet_cards.push_back(CreditCard(cards_on_disk.back()));
146   wallet_cards.back().set_billing_address_id("1234");
147 
148   // Setup the TestAutofillTable with the cards_on_disk.
149   TestAutofillTable table(cards_on_disk);
150 
151   CopyRelevantWalletMetadataFromDisk(table, &wallet_cards);
152 
153   ASSERT_EQ(1U, wallet_cards.size());
154 
155   // Make sure the wallet card replace its billing address id for the one that
156   // was saved on disk.
157   EXPECT_EQ(cards_on_disk.back().billing_address_id(),
158             wallet_cards.back().billing_address_id());
159 }
160 
161 // Verify that the billing address id from the card saved on disk is overwritten
162 // if it does not refer to a local profile.
TEST_F(AutofillSyncBridgeUtilTest,CopyRelevantWalletMetadataFromDisk_OverwriteOtherAddresses)163 TEST_F(AutofillSyncBridgeUtilTest,
164        CopyRelevantWalletMetadataFromDisk_OverwriteOtherAddresses) {
165   std::string old_billing_id = "1234";
166   std::string new_billing_id = "9876";
167   std::vector<CreditCard> cards_on_disk;
168   std::vector<CreditCard> wallet_cards;
169 
170   // Create a card on disk that does not refer to a local profile (which have 36
171   // chars ids).
172   cards_on_disk.push_back(CreditCard());
173   cards_on_disk.back().set_billing_address_id(old_billing_id);
174 
175   // Create a card pulled from wallet with the same id, but a different billing
176   // address id.
177   wallet_cards.push_back(CreditCard(cards_on_disk.back()));
178   wallet_cards.back().set_billing_address_id(new_billing_id);
179 
180   // Setup the TestAutofillTable with the cards_on_disk.
181   TestAutofillTable table(cards_on_disk);
182 
183   CopyRelevantWalletMetadataFromDisk(table, &wallet_cards);
184 
185   ASSERT_EQ(1U, wallet_cards.size());
186 
187   // Make sure the local address billing id that was saved on disk did not
188   // replace the new one.
189   EXPECT_EQ(new_billing_id, wallet_cards.back().billing_address_id());
190 }
191 
192 // Verify that the use stats on disk are kept when server cards are synced.
TEST_F(AutofillSyncBridgeUtilTest,CopyRelevantWalletMetadataFromDisk_KeepUseStats)193 TEST_F(AutofillSyncBridgeUtilTest,
194        CopyRelevantWalletMetadataFromDisk_KeepUseStats) {
195   TestAutofillClock test_clock;
196   base::Time arbitrary_time = base::Time::FromDoubleT(25);
197   base::Time disk_time = base::Time::FromDoubleT(10);
198   test_clock.SetNow(arbitrary_time);
199 
200   std::vector<CreditCard> cards_on_disk;
201   std::vector<CreditCard> wallet_cards;
202 
203   // Create a card on disk with specific use stats.
204   cards_on_disk.push_back(CreditCard());
205   cards_on_disk.back().set_use_count(3U);
206   cards_on_disk.back().set_use_date(disk_time);
207 
208   // Create a card pulled from wallet with the same id, but a different billing
209   // address id.
210   wallet_cards.push_back(CreditCard());
211   wallet_cards.back().set_use_count(10U);
212 
213   // Setup the TestAutofillTable with the cards_on_disk.
214   TestAutofillTable table(cards_on_disk);
215 
216   CopyRelevantWalletMetadataFromDisk(table, &wallet_cards);
217 
218   ASSERT_EQ(1U, wallet_cards.size());
219 
220   // Make sure the use stats from disk were kept
221   EXPECT_EQ(3U, wallet_cards.back().use_count());
222   EXPECT_EQ(disk_time, wallet_cards.back().use_date());
223 }
224 
225 }  // namespace
226 }  // namespace autofill
227