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 21 namespace { 22 23 const FilePath::CharType kTestName[] = FILE_PATH_LITERAL("merge"); 24 const FilePath::CharType kFileNamePattern[] = FILE_PATH_LITERAL("*.in"); 25 26 const char kFieldSeparator[] = ": "; 27 const char kProfileSeparator[] = "---"; 28 const size_t kFieldOffset = arraysize(kFieldSeparator) - 1; 29 30 const 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_WHOLE_NUMBER, 43 PHONE_FAX_WHOLE_NUMBER, 44 }; 45 46 // Serializes the |profiles| into a string. 47 std::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 std::vector<string16> values; 55 profiles[i]->GetMultiInfo(type, &values); 56 for (size_t k = 0; k < values.size(); ++k) { 57 result += AutofillType::FieldTypeToString(type); 58 result += kFieldSeparator; 59 result += UTF16ToUTF8(values[k]); 60 result += "\n"; 61 } 62 } 63 } 64 65 return result; 66 } 67 68 class PersonalDataManagerMock : public PersonalDataManager { 69 public: 70 PersonalDataManagerMock(); 71 virtual ~PersonalDataManagerMock(); 72 73 // Reset the saved profiles. 74 void Reset(); 75 76 // PersonalDataManager: 77 virtual void SaveImportedProfile(const AutofillProfile& profile) OVERRIDE; 78 virtual const std::vector<AutofillProfile*>& web_profiles() OVERRIDE; 79 80 private: 81 ScopedVector<AutofillProfile> profiles_; 82 83 DISALLOW_COPY_AND_ASSIGN(PersonalDataManagerMock); 84 }; 85 86 PersonalDataManagerMock::PersonalDataManagerMock() : PersonalDataManager() { 87 } 88 89 PersonalDataManagerMock::~PersonalDataManagerMock() { 90 } 91 92 void PersonalDataManagerMock::Reset() { 93 profiles_.reset(); 94 } 95 96 void PersonalDataManagerMock::SaveImportedProfile( 97 const AutofillProfile& profile) { 98 std::vector<AutofillProfile> profiles; 99 if (!MergeProfile(profile, profiles_.get(), &profiles)) 100 profiles_.push_back(new AutofillProfile(profile)); 101 } 102 103 const std::vector<AutofillProfile*>& PersonalDataManagerMock::web_profiles() { 104 return profiles_.get(); 105 } 106 107 } // namespace 108 109 // A data-driven test for verifying merging of Autofill profiles. Each input is 110 // a structured dump of a set of implicitly detected autofill profiles. The 111 // corresponding output file is a dump of the saved profiles that result from 112 // importing the input profiles. The output file format is identical to the 113 // input format. 114 class AutofillMergeTest : public testing::Test, public DataDrivenTest { 115 protected: 116 AutofillMergeTest(); 117 virtual ~AutofillMergeTest(); 118 119 // testing::Test: 120 virtual void SetUp(); 121 122 // DataDrivenTest: 123 virtual void GenerateResults(const std::string& input, 124 std::string* output) OVERRIDE; 125 126 // Deserializes a set of Autofill profiles from |profiles|, imports each 127 // sequentially, and fills |merged_profiles| with the serialized result. 128 void MergeProfiles(const std::string& profiles, std::string* merged_profiles); 129 130 scoped_refptr<PersonalDataManagerMock> personal_data_; 131 132 private: 133 DISALLOW_COPY_AND_ASSIGN(AutofillMergeTest); 134 }; 135 136 AutofillMergeTest::AutofillMergeTest() : DataDrivenTest() { 137 } 138 139 AutofillMergeTest::~AutofillMergeTest() { 140 } 141 142 void AutofillMergeTest::SetUp() { 143 autofill_test::DisableSystemServices(NULL); 144 145 personal_data_ = new PersonalDataManagerMock(); 146 } 147 148 void AutofillMergeTest::GenerateResults(const std::string& input, 149 std::string* output) { 150 MergeProfiles(input, output); 151 } 152 153 void AutofillMergeTest::MergeProfiles(const std::string& profiles, 154 std::string* merged_profiles) { 155 // Start with no saved profiles. 156 personal_data_->Reset(); 157 158 // Create a test form. 159 webkit_glue::FormData form; 160 form.name = ASCIIToUTF16("MyTestForm"); 161 form.method = ASCIIToUTF16("POST"); 162 form.origin = GURL("https://www.example.com/origin.html"); 163 form.action = GURL("https://www.example.com/action.html"); 164 form.user_submitted = true; 165 166 // Parse the input line by line. 167 std::vector<std::string> lines; 168 Tokenize(profiles, "\n", &lines); 169 for (size_t i = 0; i < lines.size(); ++i) { 170 std::string line = lines[i]; 171 172 if (line != kProfileSeparator) { 173 // Add a field to the current profile. 174 size_t separator_pos = line.find(kFieldSeparator); 175 ASSERT_NE(std::string::npos, separator_pos); 176 string16 field_type = UTF8ToUTF16(line.substr(0, separator_pos)); 177 string16 value = UTF8ToUTF16(line.substr(separator_pos + kFieldOffset)); 178 179 webkit_glue::FormField field(field_type, 180 field_type, 181 value, 182 ASCIIToUTF16("text"), 183 WebKit::WebInputElement::defaultMaxLength(), 184 false); 185 form.fields.push_back(field); 186 } 187 188 // The first line is always a profile separator, and the last profile is not 189 // followed by an explicit separator. 190 if ((i > 0 && line == kProfileSeparator) || i == lines.size() - 1) { 191 // Reached the end of a profile. Try to import it. 192 FormStructure form_structure(form); 193 for (size_t i = 0; i < form_structure.field_count(); ++i) { 194 // Set the heuristic type for each field, which is currently serialized 195 // into the field's name. 196 AutofillField* field = 197 const_cast<AutofillField*>(form_structure.field(i)); 198 AutofillFieldType type = 199 AutofillType::StringToFieldType(UTF16ToUTF8(field->name)); 200 field->set_heuristic_type(type); 201 } 202 std::vector<const FormStructure*> form_structures(1, &form_structure); 203 204 // Import the profile. 205 const CreditCard* imported_credit_card; 206 personal_data_->ImportFormData(form_structures, &imported_credit_card); 207 EXPECT_FALSE(imported_credit_card); 208 209 // Clear the |form| to start a new profile. 210 form.fields.clear(); 211 } 212 } 213 214 *merged_profiles = SerializeProfiles(personal_data_->web_profiles()); 215 } 216 217 TEST_F(AutofillMergeTest, DataDrivenMergeProfiles) { 218 RunDataDrivenTest(GetInputDirectory(kTestName), GetOutputDirectory(kTestName), 219 kFileNamePattern); 220 } 221