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