// Copyright 2013 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 "components/autofill/core/browser/contact_info.h"

#include "base/basictypes.h"
#include "base/format_macros.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "testing/gtest/include/gtest/gtest.h"

using base::ASCIIToUTF16;

namespace autofill {

struct FullNameTestCase {
  std::string full_name_input;
  std::string given_name_output;
  std::string middle_name_output;
  std::string family_name_output;
} full_name_test_cases[] = {
  { "", "", "", "" },
  { "John Smith", "John", "", "Smith" },
  { "Julien van der Poel", "Julien", "", "van der Poel" },
  { "John J Johnson", "John", "J", "Johnson" },
  { "John Smith, Jr.", "John", "", "Smith" },
  { "Mr John Smith", "John", "", "Smith" },
  { "Mr. John Smith", "John", "", "Smith" },
  { "Mr. John Smith, M.D.", "John", "", "Smith" },
  { "Mr. John Smith, MD", "John", "", "Smith" },
  { "Mr. John Smith MD", "John", "", "Smith" },
  { "William Hubert J.R.", "William", "Hubert", "J.R." },
  { "John Ma", "John", "", "Ma" },
  { "John Smith, MA", "John", "", "Smith" },
  { "John Jacob Jingleheimer Smith", "John Jacob", "Jingleheimer", "Smith" },
  { "Virgil", "Virgil", "", "" },
  { "Murray Gell-Mann", "Murray", "", "Gell-Mann" },
  { "Mikhail Yevgrafovich Saltykov-Shchedrin", "Mikhail", "Yevgrafovich",
    "Saltykov-Shchedrin" },
  { "Arthur Ignatius Conan Doyle", "Arthur Ignatius", "Conan", "Doyle" },
};

TEST(NameInfoTest, SetFullName) {
  for (size_t i = 0; i < arraysize(full_name_test_cases); ++i) {
    const FullNameTestCase& test_case = full_name_test_cases[i];
    SCOPED_TRACE(test_case.full_name_input);

    NameInfo name;
    name.SetInfo(AutofillType(NAME_FULL),
                 ASCIIToUTF16(test_case.full_name_input),
                 "en-US");
    EXPECT_EQ(ASCIIToUTF16(test_case.given_name_output),
              name.GetInfo(AutofillType(NAME_FIRST), "en-US"));
    EXPECT_EQ(ASCIIToUTF16(test_case.middle_name_output),
              name.GetInfo(AutofillType(NAME_MIDDLE), "en-US"));
    EXPECT_EQ(ASCIIToUTF16(test_case.family_name_output),
              name.GetInfo(AutofillType(NAME_LAST), "en-US"));
    EXPECT_EQ(ASCIIToUTF16(test_case.full_name_input),
              name.GetInfo(AutofillType(NAME_FULL), "en-US"));
  }
}

TEST(NameInfoTest, GetFullName) {
  NameInfo name;
  name.SetRawInfo(NAME_FIRST, ASCIIToUTF16("First"));
  name.SetRawInfo(NAME_MIDDLE, base::string16());
  name.SetRawInfo(NAME_LAST, base::string16());
  EXPECT_EQ(ASCIIToUTF16("First"), name.GetRawInfo(NAME_FIRST));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_MIDDLE));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_LAST));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_FULL));
  EXPECT_EQ(ASCIIToUTF16("First"),
            name.GetInfo(AutofillType(NAME_FULL), "en-US"));

  name.SetRawInfo(NAME_FIRST, base::string16());
  name.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("Middle"));
  name.SetRawInfo(NAME_LAST, base::string16());
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_FIRST));
  EXPECT_EQ(ASCIIToUTF16("Middle"), name.GetRawInfo(NAME_MIDDLE));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_LAST));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_FULL));
  EXPECT_EQ(ASCIIToUTF16("Middle"),
            name.GetInfo(AutofillType(NAME_FULL), "en-US"));

  name.SetRawInfo(NAME_FIRST, base::string16());
  name.SetRawInfo(NAME_MIDDLE, base::string16());
  name.SetRawInfo(NAME_LAST, ASCIIToUTF16("Last"));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_FIRST));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_MIDDLE));
  EXPECT_EQ(ASCIIToUTF16("Last"), name.GetRawInfo(NAME_LAST));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_FULL));
  EXPECT_EQ(ASCIIToUTF16("Last"),
            name.GetInfo(AutofillType(NAME_FULL), "en-US"));

  name.SetRawInfo(NAME_FIRST, ASCIIToUTF16("First"));
  name.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("Middle"));
  name.SetRawInfo(NAME_LAST, base::string16());
  EXPECT_EQ(ASCIIToUTF16("First"), name.GetRawInfo(NAME_FIRST));
  EXPECT_EQ(ASCIIToUTF16("Middle"), name.GetRawInfo(NAME_MIDDLE));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_LAST));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_FULL));
  EXPECT_EQ(ASCIIToUTF16("First Middle"),
            name.GetInfo(AutofillType(NAME_FULL), "en-US"));

  name.SetRawInfo(NAME_FIRST, ASCIIToUTF16("First"));
  name.SetRawInfo(NAME_MIDDLE, base::string16());
  name.SetRawInfo(NAME_LAST, ASCIIToUTF16("Last"));
  EXPECT_EQ(ASCIIToUTF16("First"), name.GetRawInfo(NAME_FIRST));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_MIDDLE));
  EXPECT_EQ(ASCIIToUTF16("Last"), name.GetRawInfo(NAME_LAST));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_FULL));
  EXPECT_EQ(ASCIIToUTF16("First Last"),
            name.GetInfo(AutofillType(NAME_FULL), "en-US"));

  name.SetRawInfo(NAME_FIRST, base::string16());
  name.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("Middle"));
  name.SetRawInfo(NAME_LAST, ASCIIToUTF16("Last"));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_FIRST));
  EXPECT_EQ(ASCIIToUTF16("Middle"), name.GetRawInfo(NAME_MIDDLE));
  EXPECT_EQ(ASCIIToUTF16("Last"), name.GetRawInfo(NAME_LAST));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_FULL));
  EXPECT_EQ(ASCIIToUTF16("Middle Last"),
            name.GetInfo(AutofillType(NAME_FULL), "en-US"));

  name.SetRawInfo(NAME_FIRST, ASCIIToUTF16("First"));
  name.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("Middle"));
  name.SetRawInfo(NAME_LAST, ASCIIToUTF16("Last"));
  EXPECT_EQ(ASCIIToUTF16("First"), name.GetRawInfo(NAME_FIRST));
  EXPECT_EQ(ASCIIToUTF16("Middle"), name.GetRawInfo(NAME_MIDDLE));
  EXPECT_EQ(ASCIIToUTF16("Last"), name.GetRawInfo(NAME_LAST));
  EXPECT_EQ(base::string16(), name.GetRawInfo(NAME_FULL));
  EXPECT_EQ(ASCIIToUTF16("First Middle Last"),
            name.GetInfo(AutofillType(NAME_FULL), "en-US"));

  name.SetRawInfo(NAME_FULL, ASCIIToUTF16("First Middle Last, MD"));
  EXPECT_EQ(name.GetRawInfo(NAME_FIRST), ASCIIToUTF16("First"));
  EXPECT_EQ(name.GetRawInfo(NAME_MIDDLE), ASCIIToUTF16("Middle"));
  EXPECT_EQ(name.GetRawInfo(NAME_LAST), ASCIIToUTF16("Last"));
  EXPECT_EQ(name.GetRawInfo(NAME_FULL), ASCIIToUTF16("First Middle Last, MD"));
  EXPECT_EQ(ASCIIToUTF16("First Middle Last, MD"),
            name.GetInfo(AutofillType(NAME_FULL), "en-US"));

  // Setting a name to the value it already has: no change.
  name.SetInfo(AutofillType(NAME_FIRST), ASCIIToUTF16("First"), "en-US");
  EXPECT_EQ(name.GetRawInfo(NAME_FIRST), ASCIIToUTF16("First"));
  EXPECT_EQ(name.GetRawInfo(NAME_MIDDLE), ASCIIToUTF16("Middle"));
  EXPECT_EQ(name.GetRawInfo(NAME_LAST), ASCIIToUTF16("Last"));
  EXPECT_EQ(name.GetRawInfo(NAME_FULL), ASCIIToUTF16("First Middle Last, MD"));
  EXPECT_EQ(ASCIIToUTF16("First Middle Last, MD"),
            name.GetInfo(AutofillType(NAME_FULL), "en-US"));

  // Setting raw info: no change. (Even though this leads to a slightly
  // inconsitent state.)
  name.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Second"));
  EXPECT_EQ(name.GetRawInfo(NAME_FIRST), ASCIIToUTF16("Second"));
  EXPECT_EQ(name.GetRawInfo(NAME_MIDDLE), ASCIIToUTF16("Middle"));
  EXPECT_EQ(name.GetRawInfo(NAME_LAST), ASCIIToUTF16("Last"));
  EXPECT_EQ(name.GetRawInfo(NAME_FULL), ASCIIToUTF16("First Middle Last, MD"));
  EXPECT_EQ(ASCIIToUTF16("First Middle Last, MD"),
            name.GetInfo(AutofillType(NAME_FULL), "en-US"));

  // Changing something (e.g., the first name) clears the stored full name.
  name.SetInfo(AutofillType(NAME_FIRST), ASCIIToUTF16("Third"), "en-US");
  EXPECT_EQ(name.GetRawInfo(NAME_FIRST), ASCIIToUTF16("Third"));
  EXPECT_EQ(name.GetRawInfo(NAME_MIDDLE), ASCIIToUTF16("Middle"));
  EXPECT_EQ(name.GetRawInfo(NAME_LAST), ASCIIToUTF16("Last"));
  EXPECT_EQ(ASCIIToUTF16("Third Middle Last"),
            name.GetInfo(AutofillType(NAME_FULL), "en-US"));
}

TEST(NameInfoTest, ParsedNamesAreEqual) {
  struct TestCase {
    std::string starting_names[3];
    std::string additional_names[3];
    bool expected_result;
  };

  struct TestCase test_cases[] = {
      // Identical name comparison.
      {{"Marion", "Mitchell", "Morrison"},
       {"Marion", "Mitchell", "Morrison"},
       true},

      // Case-insensative comparisons.
      {{"Marion", "Mitchell", "Morrison"},
       {"Marion", "Mitchell", "MORRISON"},
       true},
      {{"Marion", "Mitchell", "Morrison"},
       {"MARION", "Mitchell", "MORRISON"},
       true},
      {{"Marion", "Mitchell", "Morrison"},
       {"MARION", "MITCHELL", "MORRISON"},
       true},
      {{"Marion", "", "Mitchell Morrison"},
       {"MARION", "", "MITCHELL MORRISON"},
       true},
      {{"Marion Mitchell", "", "Morrison"},
       {"MARION MITCHELL", "", "MORRISON"},
       true},

      // Identical full names but different canonical forms.
      {{"Marion", "Mitchell", "Morrison"},
       {"Marion", "", "Mitchell Morrison"},
       false},
      {{"Marion", "Mitchell", "Morrison"},
       {"Marion Mitchell", "", "MORRISON"},
       false},

      // Different names.
      {{"Marion", "Mitchell", "Morrison"}, {"Marion", "M.", "Morrison"}, false},
      {{"Marion", "Mitchell", "Morrison"}, {"MARION", "M.", "MORRISON"}, false},
      {{"Marion", "Mitchell", "Morrison"},
       {"David", "Mitchell", "Morrison"},
       false},
  };

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    SCOPED_TRACE(base::StringPrintf("i: %" PRIuS, i));

    // Construct the starting_profile.
    NameInfo starting_profile;
    starting_profile.SetRawInfo(NAME_FIRST,
                                ASCIIToUTF16(test_cases[i].starting_names[0]));
    starting_profile.SetRawInfo(NAME_MIDDLE,
                                ASCIIToUTF16(test_cases[i].starting_names[1]));
    starting_profile.SetRawInfo(NAME_LAST,
                                ASCIIToUTF16(test_cases[i].starting_names[2]));

    // Construct the additional_profile.
    NameInfo additional_profile;
    additional_profile.SetRawInfo(
        NAME_FIRST, ASCIIToUTF16(test_cases[i].additional_names[0]));
    additional_profile.SetRawInfo(
        NAME_MIDDLE, ASCIIToUTF16(test_cases[i].additional_names[1]));
    additional_profile.SetRawInfo(
        NAME_LAST, ASCIIToUTF16(test_cases[i].additional_names[2]));

    // Verify the test expectations.
    EXPECT_EQ(test_cases[i].expected_result,
              starting_profile.ParsedNamesAreEqual(additional_profile));
  }
}

}  // namespace autofill
