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