// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <vector> #include "base/basictypes.h" #include "base/file_path.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/autofill/autofill_common_test.h" #include "chrome/browser/autofill/autofill_type.h" #include "chrome/browser/autofill/data_driven_test.h" #include "chrome/browser/autofill/form_structure.h" #include "chrome/browser/autofill/personal_data_manager.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h" #include "webkit/glue/form_data.h" namespace { const FilePath::CharType kTestName[] = FILE_PATH_LITERAL("merge"); const FilePath::CharType kFileNamePattern[] = FILE_PATH_LITERAL("*.in"); const char kFieldSeparator[] = ": "; const char kProfileSeparator[] = "---"; const size_t kFieldOffset = arraysize(kFieldSeparator) - 1; const AutofillFieldType kProfileFieldTypes[] = { NAME_FIRST, NAME_MIDDLE, NAME_LAST, EMAIL_ADDRESS, COMPANY_NAME, ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2, ADDRESS_HOME_CITY, ADDRESS_HOME_STATE, ADDRESS_HOME_ZIP, ADDRESS_HOME_COUNTRY, PHONE_HOME_WHOLE_NUMBER, PHONE_FAX_WHOLE_NUMBER, }; // Serializes the |profiles| into a string. std::string SerializeProfiles(const std::vector<AutofillProfile*>& profiles) { std::string result; for (size_t i = 0; i < profiles.size(); ++i) { result += kProfileSeparator; result += "\n"; for (size_t j = 0; j < arraysize(kProfileFieldTypes); ++j) { AutofillFieldType type = kProfileFieldTypes[j]; std::vector<string16> values; profiles[i]->GetMultiInfo(type, &values); for (size_t k = 0; k < values.size(); ++k) { result += AutofillType::FieldTypeToString(type); result += kFieldSeparator; result += UTF16ToUTF8(values[k]); result += "\n"; } } } return result; } class PersonalDataManagerMock : public PersonalDataManager { public: PersonalDataManagerMock(); virtual ~PersonalDataManagerMock(); // Reset the saved profiles. void Reset(); // PersonalDataManager: virtual void SaveImportedProfile(const AutofillProfile& profile) OVERRIDE; virtual const std::vector<AutofillProfile*>& web_profiles() OVERRIDE; private: ScopedVector<AutofillProfile> profiles_; DISALLOW_COPY_AND_ASSIGN(PersonalDataManagerMock); }; PersonalDataManagerMock::PersonalDataManagerMock() : PersonalDataManager() { } PersonalDataManagerMock::~PersonalDataManagerMock() { } void PersonalDataManagerMock::Reset() { profiles_.reset(); } void PersonalDataManagerMock::SaveImportedProfile( const AutofillProfile& profile) { std::vector<AutofillProfile> profiles; if (!MergeProfile(profile, profiles_.get(), &profiles)) profiles_.push_back(new AutofillProfile(profile)); } const std::vector<AutofillProfile*>& PersonalDataManagerMock::web_profiles() { return profiles_.get(); } } // namespace // A data-driven test for verifying merging of Autofill profiles. Each input is // a structured dump of a set of implicitly detected autofill profiles. The // corresponding output file is a dump of the saved profiles that result from // importing the input profiles. The output file format is identical to the // input format. class AutofillMergeTest : public testing::Test, public DataDrivenTest { protected: AutofillMergeTest(); virtual ~AutofillMergeTest(); // testing::Test: virtual void SetUp(); // DataDrivenTest: virtual void GenerateResults(const std::string& input, std::string* output) OVERRIDE; // Deserializes a set of Autofill profiles from |profiles|, imports each // sequentially, and fills |merged_profiles| with the serialized result. void MergeProfiles(const std::string& profiles, std::string* merged_profiles); scoped_refptr<PersonalDataManagerMock> personal_data_; private: DISALLOW_COPY_AND_ASSIGN(AutofillMergeTest); }; AutofillMergeTest::AutofillMergeTest() : DataDrivenTest() { } AutofillMergeTest::~AutofillMergeTest() { } void AutofillMergeTest::SetUp() { autofill_test::DisableSystemServices(NULL); personal_data_ = new PersonalDataManagerMock(); } void AutofillMergeTest::GenerateResults(const std::string& input, std::string* output) { MergeProfiles(input, output); } void AutofillMergeTest::MergeProfiles(const std::string& profiles, std::string* merged_profiles) { // Start with no saved profiles. personal_data_->Reset(); // Create a test form. webkit_glue::FormData form; form.name = ASCIIToUTF16("MyTestForm"); form.method = ASCIIToUTF16("POST"); form.origin = GURL("https://www.example.com/origin.html"); form.action = GURL("https://www.example.com/action.html"); form.user_submitted = true; // Parse the input line by line. std::vector<std::string> lines; Tokenize(profiles, "\n", &lines); for (size_t i = 0; i < lines.size(); ++i) { std::string line = lines[i]; if (line != kProfileSeparator) { // Add a field to the current profile. size_t separator_pos = line.find(kFieldSeparator); ASSERT_NE(std::string::npos, separator_pos); string16 field_type = UTF8ToUTF16(line.substr(0, separator_pos)); string16 value = UTF8ToUTF16(line.substr(separator_pos + kFieldOffset)); webkit_glue::FormField field(field_type, field_type, value, ASCIIToUTF16("text"), WebKit::WebInputElement::defaultMaxLength(), false); form.fields.push_back(field); } // The first line is always a profile separator, and the last profile is not // followed by an explicit separator. if ((i > 0 && line == kProfileSeparator) || i == lines.size() - 1) { // Reached the end of a profile. Try to import it. FormStructure form_structure(form); for (size_t i = 0; i < form_structure.field_count(); ++i) { // Set the heuristic type for each field, which is currently serialized // into the field's name. AutofillField* field = const_cast<AutofillField*>(form_structure.field(i)); AutofillFieldType type = AutofillType::StringToFieldType(UTF16ToUTF8(field->name)); field->set_heuristic_type(type); } std::vector<const FormStructure*> form_structures(1, &form_structure); // Import the profile. const CreditCard* imported_credit_card; personal_data_->ImportFormData(form_structures, &imported_credit_card); EXPECT_FALSE(imported_credit_card); // Clear the |form| to start a new profile. form.fields.clear(); } } *merged_profiles = SerializeProfiles(personal_data_->web_profiles()); } TEST_F(AutofillMergeTest, DataDrivenMergeProfiles) { RunDataDrivenTest(GetInputDirectory(kTestName), GetOutputDirectory(kTestName), kFileNamePattern); }