// Copyright 2013 The Chromium Authors
// 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/geo/autofill_country.h"

#include <set>
#include <string>

#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/country_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/geo/address_i18n.h"
#include "components/autofill/core/browser/geo/country_data.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_metadata.h"
#if defined(ANDROID)
#include "base/android/android_info.h"
#endif

namespace autofill {
namespace {

using ::base::ASCIIToUTF16;
using ::i18n::addressinput::AddressField;

// Test the constructor and accessors
TEST(AutofillCountryTest, AutofillCountry) {
  AutofillCountry united_states_en("US", "en_US");
  EXPECT_EQ(united_states_en.country_code(), "US");
  EXPECT_EQ(united_states_en.name(), u"United States");

  AutofillCountry united_states_es("US", "es");
  EXPECT_EQ(united_states_es.country_code(), "US");
  EXPECT_EQ(united_states_es.name(), u"Estados Unidos");

  AutofillCountry great_britain_uk_alias("UK", "en_GB");
  EXPECT_EQ(great_britain_uk_alias.country_code(), "GB");
  EXPECT_EQ(great_britain_uk_alias.country_code(), "GB");
  EXPECT_EQ(great_britain_uk_alias.name(), u"United Kingdom");

  AutofillCountry canada_en("CA", "en_US");
  EXPECT_EQ(canada_en.country_code(), "CA");
  EXPECT_EQ(canada_en.name(), u"Canada");

  AutofillCountry canada_hu("CA", "hu");
  EXPECT_EQ(canada_hu.country_code(), "CA");
  EXPECT_EQ(canada_hu.name(), u"Kanada");

  // Unrecognizable country codes remain that way.
  AutofillCountry unknown("Unknown", "en_US");
  EXPECT_EQ(unknown.country_code(), "Unknown");

  // If no locale is provided, no `name()` is returned.
  AutofillCountry empty_locale("AT");
  EXPECT_EQ(empty_locale.country_code(), "AT");
  EXPECT_TRUE(empty_locale.name().empty());
}

// Test locale to country code mapping.
TEST(AutofillCountryTest, CountryCodeForLocale) {
  EXPECT_EQ(AutofillCountry::CountryCodeForLocale("en_US"), "US");
  EXPECT_EQ(AutofillCountry::CountryCodeForLocale("fr_CA"), "CA");
  EXPECT_EQ(AutofillCountry::CountryCodeForLocale("fr"), "FR");
  EXPECT_EQ(AutofillCountry::CountryCodeForLocale("Unknown"), "US");
  // "es-419" isn't associated with a country. See base/l10n/l10n_util.cc
  // for details about this locale. Default to US.
  EXPECT_EQ(AutofillCountry::CountryCodeForLocale("es-419"), "US");
}

// Test that the correct country code is retrieved from the app locale if no
// geo ip country code could be retrieved.
TEST(AutofillCountryTest, GetDefaultCountryCodeForNewAddressFromAppLocale) {
  EXPECT_EQ(AutofillCountry::GetDefaultCountryCodeForNewAddress(
                GeoIpCountryCode(""), "en_US")
                .value(),
            "US");
}

// Test that the country code is is set as the geo ip country code,
// and that it is not extracted from the app locale.
TEST(AutofillCountryTest, GetDefaultCountryCodeForNewAddressFromGeoIp) {
  EXPECT_EQ(AutofillCountry::GetDefaultCountryCodeForNewAddress(
                GeoIpCountryCode("DE"), "en_US")
                .value(),
            "DE");
}

// Test the address requirement methods for the US.
TEST(AutofillCountryTest, UsaAddressRequirements) {
  // The US requires a zip, state, city and line1 entry.
  AutofillCountry country("US", "en_US");

  EXPECT_FALSE(country.requires_zip_or_state());
  EXPECT_TRUE(country.requires_zip());
  EXPECT_TRUE(country.requires_state());
  EXPECT_TRUE(country.requires_city());
  EXPECT_TRUE(country.requires_line1());

  // The same expectations via FieldType.
  EXPECT_TRUE(country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_ZIP));
  EXPECT_TRUE(country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_STATE));
  EXPECT_TRUE(country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_CITY));
  EXPECT_TRUE(
      country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_STREET_ADDRESS));
}

// Test that unknown country codes have US requirements.
TEST(AutofillCountryTest, UnknownAddressRequirements) {
  AutofillCountry us_autofill_country("US", "en_US");
  AutofillCountry unknown_autofill_country("Unknown", "en_US");

  EXPECT_EQ(us_autofill_country.requires_zip_or_state(),
            unknown_autofill_country.requires_zip_or_state());
  EXPECT_EQ(us_autofill_country.requires_zip(),
            unknown_autofill_country.requires_zip());
  EXPECT_EQ(us_autofill_country.requires_state(),
            unknown_autofill_country.requires_state());
  EXPECT_EQ(us_autofill_country.requires_city(),
            unknown_autofill_country.requires_city());
  EXPECT_EQ(us_autofill_country.requires_line1(),
            unknown_autofill_country.requires_line1());
}

// Test the address requirement method for Brazil.
TEST(AutofillCountryTest, BrAddressRequirements) {
  // Brazil only requires a zip entry.
  AutofillCountry country("BR", "en_US");

  EXPECT_FALSE(country.requires_zip_or_state());
  EXPECT_TRUE(country.requires_zip());
  EXPECT_TRUE(country.requires_state());
  EXPECT_TRUE(country.requires_city());
  EXPECT_TRUE(country.requires_line1());

  // The same expectations via FieldType.
  EXPECT_TRUE(country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_ZIP));
  EXPECT_TRUE(country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_STATE));
  EXPECT_TRUE(country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_CITY));
  EXPECT_TRUE(
      country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_STREET_ADDRESS));
}

// Test the address requirement method for Turkey.
TEST(AutofillCountryTest, TrAddressRequirements) {
  // Brazil only requires a zip entry.
  AutofillCountry country("TR", "en_US");

  // Although ZIP codes are existing in Turkey, they are commonly used.
  EXPECT_FALSE(country.requires_zip());
  // In Turkey, a district is the largest level of the address hierarchy and
  // mapped to the Autofill state.
  EXPECT_TRUE(country.requires_state());
  // And the province as the second largest level is mapped to city.
  EXPECT_TRUE(country.requires_city());
  EXPECT_TRUE(country.requires_line1());

  // The same expectations via FieldType.
  EXPECT_FALSE(country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_ZIP));
  EXPECT_TRUE(country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_STATE));
  EXPECT_TRUE(country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_CITY));
  EXPECT_TRUE(
      country.IsAddressFieldRequired(FieldType::ADDRESS_HOME_STREET_ADDRESS));
}

// Test mapping all country codes to country names.
TEST(AutofillCountryTest, AllCountryCodesHaveCountryName) {
  std::set<std::string> expected_failures;
#if defined(ANDROID)
  if (base::android::android_info::sdk_int() <
      base::android::android_info::SDK_VERSION_KITKAT) {
    expected_failures.insert("BQ");
    expected_failures.insert("SS");
    expected_failures.insert("XK");
  }
#endif
  const std::vector<std::string>& country_codes =
      CountryDataMap::GetInstance()->country_codes();
  for (const std::string& country_code : country_codes) {
    if (expected_failures.contains(country_code)) {
      continue;
    }
    SCOPED_TRACE("Country code '" + country_code + "' should have a name.");
    EXPECT_NE(AutofillCountry(country_code, "en").name(),
              ASCIIToUTF16(country_code));
  }
}

// Test alias mappings for falsely existing country codes.
TEST(AutofillCountryTest, AliasMappingsForCountryData) {
  CountryDataMap* country_data_map = CountryDataMap::GetInstance();

  // There should be country data for the "GB".
  EXPECT_TRUE(country_data_map->HasRequiredFieldsForAddressImport("GB"));

  // Check the correctness of the alias definitions.
  EXPECT_TRUE(country_data_map->HasCountryCodeAlias("UK"));
  EXPECT_FALSE(country_data_map->HasCountryCodeAlias("does_not_exist"));

  // Query not existing mapping.
  auto expected_country_code = std::string();
  auto actual_country_code =
      country_data_map->GetCountryCodeForAlias("does_not_exist");
  EXPECT_EQ(expected_country_code, actual_country_code);

  // UK should map the GB.
  expected_country_code = "GB";
  actual_country_code = country_data_map->GetCountryCodeForAlias("UK");
  EXPECT_EQ(expected_country_code, actual_country_code);
}

// Verifies that all address format extensions correspond to types that are
// not part of libaddressinputs expected types, but that they are placed
// after a field that is present in libaddressinput.
TEST(AutofillCountryTest, VerifyAddressFormatExtensions) {
  CountryDataMap* country_data_map = CountryDataMap::GetInstance();
  for (const std::string& country_code : country_data_map->country_codes()) {
    AutofillCountry country(country_code);
    for (const AutofillCountry::AddressFormatExtension& rule :
         country.address_format_extensions()) {
      // The separator should not be empty.
      EXPECT_FALSE(rule.separator_before_label.empty());
      // `rule.type` is not part of `country_code`'s address format, but
      // `rule.placed_after` is.
      ::i18n::addressinput::AddressField libaddressinput_field;
      bool is_valid_field =
          i18n::FieldForType(rule.type, &libaddressinput_field);
      EXPECT_TRUE(!is_valid_field || !::i18n::addressinput::IsFieldUsed(
                                         libaddressinput_field, country_code));

      ::i18n::addressinput::AddressField libaddressinput_place_after;
      ASSERT_TRUE(
          i18n::FieldForType(rule.placed_after, &libaddressinput_place_after));
      EXPECT_TRUE(::i18n::addressinput::IsFieldUsed(libaddressinput_place_after,
                                                    country_code));
      // `IsAddressFieldSettingAccessible` considers `rule.type`
      // setting-accessible.
      EXPECT_TRUE(country.IsAddressFieldSettingAccessible(rule.type));
    }
  }
}

// Test the address requirement method for Poland.
TEST(AutofillCountryTest, PLAddressRequirements) {
  AutofillCountry country("PL", "pl_PL");

  EXPECT_FALSE(country.requires_state());
  EXPECT_TRUE(
      country.IsAddressFieldSettingAccessible(FieldType::ADDRESS_HOME_STATE));
}

}  // namespace
}  // namespace autofill
