// 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);
}