autofill_merge_unittest.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
1// Copyright 2013 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 <vector>
6
7#include "base/basictypes.h"
8#include "base/files/file_path.h"
9#include "base/strings/string_util.h"
10#include "base/strings/utf_string_conversions.h"
11#include "components/autofill/core/browser/autofill_common_test.h"
12#include "components/autofill/core/browser/autofill_type.h"
13#include "components/autofill/core/browser/data_driven_test.h"
14#include "components/autofill/core/browser/form_structure.h"
15#include "components/autofill/core/browser/personal_data_manager.h"
16#include "components/autofill/core/common/form_data.h"
17#include "testing/gtest/include/gtest/gtest.h"
18#include "third_party/WebKit/public/web/WebInputElement.h"
19#include "url/gurl.h"
20
21namespace autofill {
22
23namespace {
24
25const base::FilePath::CharType kTestName[] = FILE_PATH_LITERAL("merge");
26const base::FilePath::CharType kFileNamePattern[] = FILE_PATH_LITERAL("*.in");
27
28const char kFieldSeparator[] = ": ";
29const char kProfileSeparator[] = "---";
30const size_t kFieldOffset = arraysize(kFieldSeparator) - 1;
31
32const AutofillFieldType kProfileFieldTypes[] = {
33  NAME_FIRST,
34  NAME_MIDDLE,
35  NAME_LAST,
36  EMAIL_ADDRESS,
37  COMPANY_NAME,
38  ADDRESS_HOME_LINE1,
39  ADDRESS_HOME_LINE2,
40  ADDRESS_HOME_CITY,
41  ADDRESS_HOME_STATE,
42  ADDRESS_HOME_ZIP,
43  ADDRESS_HOME_COUNTRY,
44  PHONE_HOME_WHOLE_NUMBER
45};
46
47// Serializes the |profiles| into a string.
48std::string SerializeProfiles(const std::vector<AutofillProfile*>& profiles) {
49  std::string result;
50  for (size_t i = 0; i < profiles.size(); ++i) {
51    result += kProfileSeparator;
52    result += "\n";
53    for (size_t j = 0; j < arraysize(kProfileFieldTypes); ++j) {
54      AutofillFieldType type = kProfileFieldTypes[j];
55      std::vector<base::string16> values;
56      profiles[i]->GetRawMultiInfo(type, &values);
57      for (size_t k = 0; k < values.size(); ++k) {
58        result += AutofillType::FieldTypeToString(type);
59        result += kFieldSeparator;
60        result += UTF16ToUTF8(values[k]);
61        result += "\n";
62      }
63    }
64  }
65
66  return result;
67}
68
69class PersonalDataManagerMock : public PersonalDataManager {
70 public:
71  PersonalDataManagerMock();
72  virtual ~PersonalDataManagerMock();
73
74  // Reset the saved profiles.
75  void Reset();
76
77  // PersonalDataManager:
78  virtual void SaveImportedProfile(const AutofillProfile& profile) OVERRIDE;
79  virtual const std::vector<AutofillProfile*>& web_profiles() const OVERRIDE;
80
81 private:
82  ScopedVector<AutofillProfile> profiles_;
83
84  DISALLOW_COPY_AND_ASSIGN(PersonalDataManagerMock);
85};
86
87PersonalDataManagerMock::PersonalDataManagerMock()
88    : PersonalDataManager("en-US") {
89}
90
91PersonalDataManagerMock::~PersonalDataManagerMock() {
92}
93
94void PersonalDataManagerMock::Reset() {
95  profiles_.clear();
96}
97
98void PersonalDataManagerMock::SaveImportedProfile(
99    const AutofillProfile& profile) {
100  std::vector<AutofillProfile> profiles;
101  if (!MergeProfile(profile, profiles_.get(), "en-US", &profiles))
102    profiles_.push_back(new AutofillProfile(profile));
103}
104
105const std::vector<AutofillProfile*>& PersonalDataManagerMock::web_profiles()
106    const {
107  return profiles_.get();
108}
109
110}  // namespace
111
112// A data-driven test for verifying merging of Autofill profiles. Each input is
113// a structured dump of a set of implicitly detected autofill profiles. The
114// corresponding output file is a dump of the saved profiles that result from
115// importing the input profiles. The output file format is identical to the
116// input format.
117class AutofillMergeTest : public testing::Test,
118                          public DataDrivenTest {
119 protected:
120  AutofillMergeTest();
121  virtual ~AutofillMergeTest();
122
123  // testing::Test:
124  virtual void SetUp();
125
126  // DataDrivenTest:
127  virtual void GenerateResults(const std::string& input,
128                               std::string* output) OVERRIDE;
129
130  // Deserializes a set of Autofill profiles from |profiles|, imports each
131  // sequentially, and fills |merged_profiles| with the serialized result.
132  void MergeProfiles(const std::string& profiles, std::string* merged_profiles);
133
134  PersonalDataManagerMock personal_data_;
135
136 private:
137  DISALLOW_COPY_AND_ASSIGN(AutofillMergeTest);
138};
139
140AutofillMergeTest::AutofillMergeTest() : DataDrivenTest() {
141}
142
143AutofillMergeTest::~AutofillMergeTest() {
144}
145
146void AutofillMergeTest::SetUp() {
147  test::DisableSystemServices(NULL);
148}
149
150void AutofillMergeTest::GenerateResults(const std::string& input,
151                                        std::string* output) {
152  MergeProfiles(input, output);
153}
154
155void AutofillMergeTest::MergeProfiles(const std::string& profiles,
156                                      std::string* merged_profiles) {
157  // Start with no saved profiles.
158  personal_data_.Reset();
159
160  // Create a test form.
161  FormData form;
162  form.name = ASCIIToUTF16("MyTestForm");
163  form.method = ASCIIToUTF16("POST");
164  form.origin = GURL("https://www.example.com/origin.html");
165  form.action = GURL("https://www.example.com/action.html");
166  form.user_submitted = true;
167
168  // Parse the input line by line.
169  std::vector<std::string> lines;
170  Tokenize(profiles, "\n", &lines);
171  for (size_t i = 0; i < lines.size(); ++i) {
172    std::string line = lines[i];
173
174    if (line != kProfileSeparator) {
175      // Add a field to the current profile.
176      size_t separator_pos = line.find(kFieldSeparator);
177      ASSERT_NE(std::string::npos, separator_pos);
178      base::string16 field_type = UTF8ToUTF16(line.substr(0, separator_pos));
179      base::string16 value =
180          UTF8ToUTF16(line.substr(separator_pos + kFieldOffset));
181
182      FormFieldData field;
183      field.label = field_type;
184      field.name = field_type;
185      field.value = value;
186      field.form_control_type = "text";
187      form.fields.push_back(field);
188    }
189
190    // The first line is always a profile separator, and the last profile is not
191    // followed by an explicit separator.
192    if ((i > 0 && line == kProfileSeparator) || i == lines.size() - 1) {
193      // Reached the end of a profile.  Try to import it.
194      FormStructure form_structure(form, std::string());
195      for (size_t i = 0; i < form_structure.field_count(); ++i) {
196        // Set the heuristic type for each field, which is currently serialized
197        // into the field's name.
198        AutofillField* field =
199            const_cast<AutofillField*>(form_structure.field(i));
200        AutofillFieldType type =
201            AutofillType::StringToFieldType(UTF16ToUTF8(field->name));
202        field->set_heuristic_type(type);
203      }
204
205      // Import the profile.
206      const CreditCard* imported_credit_card;
207      personal_data_.ImportFormData(form_structure, &imported_credit_card);
208      EXPECT_EQ(static_cast<const CreditCard*>(NULL), imported_credit_card);
209
210      // Clear the |form| to start a new profile.
211      form.fields.clear();
212    }
213  }
214
215  *merged_profiles = SerializeProfiles(personal_data_.web_profiles());
216}
217
218TEST_F(AutofillMergeTest, DataDrivenMergeProfiles) {
219  RunDataDrivenTest(GetInputDirectory(kTestName), GetOutputDirectory(kTestName),
220                    kFileNamePattern);
221}
222
223}  // namespace autofill
224