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