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