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_test_utils.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 "url/gurl.h" 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 33 const ServerFieldType kProfileFieldTypes[] = { 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 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 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) { 66 ServerFieldType type = kProfileFieldTypes[j]; 67 std::vector<base::string16> values; 68 profiles[i]->GetRawMultiInfo(type, &values); 69 for (size_t k = 0; k < values.size(); ++k) { 70 result += AutofillType(type).ToString(); 71 result += kFieldSeparator; 72 result += base::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 std::string SaveImportedProfile( 91 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 100 PersonalDataManagerMock::PersonalDataManagerMock() 101 : PersonalDataManager("en-US") { 102 } 103 104 PersonalDataManagerMock::~PersonalDataManagerMock() { 105 } 106 107 void PersonalDataManagerMock::Reset() { 108 profiles_.clear(); 109 } 110 111 std::string PersonalDataManagerMock::SaveImportedProfile( 112 const AutofillProfile& profile) { 113 std::vector<AutofillProfile> profiles; 114 std::string merged_guid = 115 MergeProfile(profile, profiles_.get(), "en-US", &profiles); 116 if (merged_guid == profile.guid()) 117 profiles_.push_back(new AutofillProfile(profile)); 118 return merged_guid; 119 } 120 121 const std::vector<AutofillProfile*>& PersonalDataManagerMock::web_profiles() 122 const { 123 return profiles_.get(); 124 } 125 126 } // namespace 127 128 // A data-driven test for verifying merging of Autofill profiles. Each input is 129 // a structured dump of a set of implicitly detected autofill profiles. The 130 // corresponding output file is a dump of the saved profiles that result from 131 // importing the input profiles. The output file format is identical to the 132 // input format. 133 class AutofillMergeTest : public testing::Test, 134 public DataDrivenTest { 135 protected: 136 AutofillMergeTest(); 137 virtual ~AutofillMergeTest(); 138 139 // testing::Test: 140 virtual void SetUp(); 141 142 // DataDrivenTest: 143 virtual void GenerateResults(const std::string& input, 144 std::string* output) OVERRIDE; 145 146 // Deserializes a set of Autofill profiles from |profiles|, imports each 147 // sequentially, and fills |merged_profiles| with the serialized result. 148 void MergeProfiles(const std::string& profiles, std::string* merged_profiles); 149 150 // Deserializes |str| into a field type. 151 ServerFieldType StringToFieldType(const std::string& str); 152 153 PersonalDataManagerMock personal_data_; 154 155 private: 156 std::map<std::string, ServerFieldType> string_to_field_type_map_; 157 158 DISALLOW_COPY_AND_ASSIGN(AutofillMergeTest); 159 }; 160 161 AutofillMergeTest::AutofillMergeTest() : DataDrivenTest(GetTestDataDir()) { 162 for (size_t i = NO_SERVER_DATA; i < MAX_VALID_FIELD_TYPE; ++i) { 163 ServerFieldType field_type = static_cast<ServerFieldType>(i); 164 string_to_field_type_map_[AutofillType(field_type).ToString()] = field_type; 165 } 166 } 167 168 AutofillMergeTest::~AutofillMergeTest() { 169 } 170 171 void AutofillMergeTest::SetUp() { 172 test::DisableSystemServices(NULL); 173 } 174 175 void AutofillMergeTest::GenerateResults(const std::string& input, 176 std::string* output) { 177 MergeProfiles(input, output); 178 } 179 180 void AutofillMergeTest::MergeProfiles(const std::string& profiles, 181 std::string* merged_profiles) { 182 // Start with no saved profiles. 183 personal_data_.Reset(); 184 185 // Create a test form. 186 FormData form; 187 form.name = base::ASCIIToUTF16("MyTestForm"); 188 form.origin = GURL("https://www.example.com/origin.html"); 189 form.action = GURL("https://www.example.com/action.html"); 190 form.user_submitted = true; 191 192 // Parse the input line by line. 193 std::vector<std::string> lines; 194 Tokenize(profiles, "\n", &lines); 195 for (size_t i = 0; i < lines.size(); ++i) { 196 std::string line = lines[i]; 197 198 if (line != kProfileSeparator) { 199 // Add a field to the current profile. 200 size_t separator_pos = line.find(kFieldSeparator); 201 ASSERT_NE(std::string::npos, separator_pos); 202 base::string16 field_type = 203 base::UTF8ToUTF16(line.substr(0, separator_pos)); 204 base::string16 value = 205 base::UTF8ToUTF16(line.substr(separator_pos + kFieldOffset)); 206 207 FormFieldData field; 208 field.label = field_type; 209 field.name = field_type; 210 field.value = value; 211 field.form_control_type = "text"; 212 form.fields.push_back(field); 213 } 214 215 // The first line is always a profile separator, and the last profile is not 216 // followed by an explicit separator. 217 if ((i > 0 && line == kProfileSeparator) || i == lines.size() - 1) { 218 // Reached the end of a profile. Try to import it. 219 FormStructure form_structure(form); 220 for (size_t i = 0; i < form_structure.field_count(); ++i) { 221 // Set the heuristic type for each field, which is currently serialized 222 // into the field's name. 223 AutofillField* field = 224 const_cast<AutofillField*>(form_structure.field(i)); 225 ServerFieldType type = 226 StringToFieldType(base::UTF16ToUTF8(field->name)); 227 field->set_heuristic_type(type); 228 } 229 230 // Import the profile. 231 scoped_ptr<CreditCard> imported_credit_card; 232 personal_data_.ImportFormData(form_structure, &imported_credit_card); 233 EXPECT_EQ(static_cast<CreditCard*>(NULL), imported_credit_card.get()); 234 235 // Clear the |form| to start a new profile. 236 form.fields.clear(); 237 } 238 } 239 240 *merged_profiles = SerializeProfiles(personal_data_.web_profiles()); 241 } 242 243 ServerFieldType AutofillMergeTest::StringToFieldType(const std::string& str) { 244 return string_to_field_type_map_[str]; 245 } 246 247 TEST_F(AutofillMergeTest, DataDrivenMergeProfiles) { 248 RunDataDrivenTest(GetInputDirectory(kTestName), GetOutputDirectory(kTestName), 249 kFileNamePattern); 250 } 251 252 } // namespace autofill 253