Home | History | Annotate | Download | only in browser
      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.method = base::ASCIIToUTF16("POST");
    189   form.origin = GURL("https://www.example.com/origin.html");
    190   form.action = GURL("https://www.example.com/action.html");
    191   form.user_submitted = true;
    192 
    193   // Parse the input line by line.
    194   std::vector<std::string> lines;
    195   Tokenize(profiles, "\n", &lines);
    196   for (size_t i = 0; i < lines.size(); ++i) {
    197     std::string line = lines[i];
    198 
    199     if (line != kProfileSeparator) {
    200       // Add a field to the current profile.
    201       size_t separator_pos = line.find(kFieldSeparator);
    202       ASSERT_NE(std::string::npos, separator_pos);
    203       base::string16 field_type =
    204           base::UTF8ToUTF16(line.substr(0, separator_pos));
    205       base::string16 value =
    206           base::UTF8ToUTF16(line.substr(separator_pos + kFieldOffset));
    207 
    208       FormFieldData field;
    209       field.label = field_type;
    210       field.name = field_type;
    211       field.value = value;
    212       field.form_control_type = "text";
    213       form.fields.push_back(field);
    214     }
    215 
    216     // The first line is always a profile separator, and the last profile is not
    217     // followed by an explicit separator.
    218     if ((i > 0 && line == kProfileSeparator) || i == lines.size() - 1) {
    219       // Reached the end of a profile.  Try to import it.
    220       FormStructure form_structure(form);
    221       for (size_t i = 0; i < form_structure.field_count(); ++i) {
    222         // Set the heuristic type for each field, which is currently serialized
    223         // into the field's name.
    224         AutofillField* field =
    225             const_cast<AutofillField*>(form_structure.field(i));
    226         ServerFieldType type =
    227             StringToFieldType(base::UTF16ToUTF8(field->name));
    228         field->set_heuristic_type(type);
    229       }
    230 
    231       // Import the profile.
    232       scoped_ptr<CreditCard> imported_credit_card;
    233       personal_data_.ImportFormData(form_structure, &imported_credit_card);
    234       EXPECT_EQ(static_cast<CreditCard*>(NULL), imported_credit_card.get());
    235 
    236       // Clear the |form| to start a new profile.
    237       form.fields.clear();
    238     }
    239   }
    240 
    241   *merged_profiles = SerializeProfiles(personal_data_.web_profiles());
    242 }
    243 
    244 ServerFieldType AutofillMergeTest::StringToFieldType(const std::string& str) {
    245   return string_to_field_type_map_[str];
    246 }
    247 
    248 TEST_F(AutofillMergeTest, DataDrivenMergeProfiles) {
    249   RunDataDrivenTest(GetInputDirectory(kTestName), GetOutputDirectory(kTestName),
    250                     kFileNamePattern);
    251 }
    252 
    253 }  // namespace autofill
    254