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