blob: 4116f5da91e5755787a9af337f67e3eb8683904a [file] [log] [blame]
// Copyright 2014 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 "third_party/libaddressinput/chromium/chrome_address_validator.h"
#include <stddef.h>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_problem.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
#include "third_party/libaddressinput/src/cpp/test/testdata_source.h"
namespace autofill {
using ::i18n::addressinput::AddressData;
using ::i18n::addressinput::AddressField;
using ::i18n::addressinput::AddressProblem;
using ::i18n::addressinput::BuildCallback;
using ::i18n::addressinput::FieldProblemMap;
using ::i18n::addressinput::GetRegionCodes;
using ::i18n::addressinput::NullStorage;
using ::i18n::addressinput::Source;
using ::i18n::addressinput::Storage;
using ::i18n::addressinput::TestdataSource;
using ::i18n::addressinput::COUNTRY;
using ::i18n::addressinput::ADMIN_AREA;
using ::i18n::addressinput::LOCALITY;
using ::i18n::addressinput::DEPENDENT_LOCALITY;
using ::i18n::addressinput::SORTING_CODE;
using ::i18n::addressinput::POSTAL_CODE;
using ::i18n::addressinput::STREET_ADDRESS;
using ::i18n::addressinput::RECIPIENT;
using ::i18n::addressinput::INVALID_FORMAT;
using ::i18n::addressinput::MISMATCHING_VALUE;
using ::i18n::addressinput::MISSING_REQUIRED_FIELD;
using ::i18n::addressinput::UNEXPECTED_FIELD;
using ::i18n::addressinput::UNKNOWN_VALUE;
using ::i18n::addressinput::USES_P_O_BOX;
// This class should always succeed in getting the rules.
class AddressValidatorTest : public testing::Test, LoadRulesListener {
protected:
AddressValidatorTest()
: validator_(new AddressValidator(
std::unique_ptr<Source>(new TestdataSource(true)),
std::unique_ptr<Storage>(new NullStorage),
this)) {
validator_->LoadRules("US");
}
void set_expected_status(AddressValidator::Status expected_status) {
expected_status_ = expected_status;
}
virtual ~AddressValidatorTest() {}
const std::unique_ptr<AddressValidator> validator_;
private:
// LoadRulesListener implementation.
void OnAddressValidationRulesLoaded(const std::string& country_code,
bool success) override {
AddressData address_data;
address_data.region_code = country_code;
FieldProblemMap dummy;
AddressValidator::Status status =
validator_->ValidateAddress(address_data, NULL, &dummy);
ASSERT_EQ(expected_status_, status);
}
AddressValidator::Status expected_status_ = AddressValidator::SUCCESS;
DISALLOW_COPY_AND_ASSIGN(AddressValidatorTest);
};
// Use this test fixture if you're going to use a region with a large set of
// validation rules. All rules should be loaded in SetUpTestCase().
class LargeAddressValidatorTest : public testing::Test {
protected:
LargeAddressValidatorTest() {}
virtual ~LargeAddressValidatorTest() {}
static void SetUpTestCase() {
validator_ =
new AddressValidator(std::unique_ptr<Source>(new TestdataSource(true)),
std::unique_ptr<Storage>(new NullStorage), NULL);
validator_->LoadRules("CN");
validator_->LoadRules("KR");
validator_->LoadRules("TW");
}
static void TearDownTestcase() {
delete validator_;
validator_ = NULL;
}
// Owned shared instance of validator with large sets validation rules.
static AddressValidator* validator_;
private:
DISALLOW_COPY_AND_ASSIGN(LargeAddressValidatorTest);
};
AddressValidator* LargeAddressValidatorTest::validator_ = NULL;
TEST_F(AddressValidatorTest, SubKeysLoaded) {
const std::string country_code = "US";
const std::string state_code = "AL";
const std::string state_name = "Alabama";
const std::string language = "en";
validator_->LoadRules(country_code);
std::vector<std::pair<std::string, std::string>> sub_keys =
validator_->GetRegionSubKeys(country_code, language);
ASSERT_FALSE(sub_keys.empty());
ASSERT_EQ(state_code, sub_keys[0].first);
ASSERT_EQ(state_name, sub_keys[0].second);
}
TEST_F(AddressValidatorTest, SubKeysLoaded_DefaultLanguage) {
const std::string country_code = "CA";
const std::string province_code = "BC";
const std::string province_name = "British Columbia";
const std::string language = "en";
validator_->LoadRules(country_code);
std::vector<std::pair<std::string, std::string>> sub_keys =
validator_->GetRegionSubKeys(country_code, language);
ASSERT_FALSE(sub_keys.empty());
ASSERT_EQ(province_code, sub_keys[1].first);
ASSERT_EQ(province_name, sub_keys[1].second);
}
TEST_F(AddressValidatorTest, SubKeysLoaded_NonDefaultLanguage) {
const std::string country_code = "CA";
const std::string province_code = "BC";
const std::string province_name = "Colombie-Britannique";
const std::string language = "fr";
validator_->LoadRules(country_code);
std::vector<std::pair<std::string, std::string>> sub_keys =
validator_->GetRegionSubKeys(country_code, language);
ASSERT_FALSE(sub_keys.empty());
ASSERT_EQ(province_code, sub_keys[1].first);
ASSERT_EQ(province_name, sub_keys[1].second);
}
TEST_F(AddressValidatorTest, SubKeysLoaded_LanguageNotAvailable) {
const std::string country_code = "CA";
const std::string province_code = "BC";
const std::string province_name = "British Columbia";
const std::string language = "es";
validator_->LoadRules(country_code);
std::vector<std::pair<std::string, std::string>> sub_keys =
validator_->GetRegionSubKeys(country_code, language);
ASSERT_FALSE(sub_keys.empty());
ASSERT_EQ(province_code, sub_keys[1].first);
ASSERT_EQ(province_name, sub_keys[1].second);
}
TEST_F(AddressValidatorTest, SubKeysLoaded_NamesNotAvailable) {
const std::string country_code = "ES";
const std::string province_code = "A Coruña";
const std::string province_name = "A Coruña";
const std::string language = "es";
validator_->LoadRules(country_code);
std::vector<std::pair<std::string, std::string>> sub_keys =
validator_->GetRegionSubKeys(country_code, language);
ASSERT_FALSE(sub_keys.empty());
ASSERT_EQ(province_code, sub_keys[0].first);
ASSERT_EQ(province_name, sub_keys[0].second);
}
TEST_F(AddressValidatorTest, SubKeysNotExist) {
const std::string country_code = "OZ";
const std::string language = "en";
set_expected_status(AddressValidator::RULES_UNAVAILABLE);
validator_->LoadRules(country_code);
std::vector<std::pair<std::string, std::string>> sub_keys =
validator_->GetRegionSubKeys(country_code, language);
ASSERT_TRUE(sub_keys.empty());
}
TEST_F(AddressValidatorTest, RegionHasRules) {
const std::vector<std::string>& region_codes = GetRegionCodes();
AddressData address;
for (size_t i = 0; i < region_codes.size(); ++i) {
SCOPED_TRACE("For region: " + region_codes[i]);
validator_->LoadRules(region_codes[i]);
address.region_code = region_codes[i];
FieldProblemMap dummy;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &dummy));
}
}
TEST_F(AddressValidatorTest, EmptyAddressNoFatalFailure) {
AddressData address;
address.region_code = "US";
FieldProblemMap dummy;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &dummy));
}
TEST_F(AddressValidatorTest, UsStateNamesAreValidEntries) {
AddressData address;
address.region_code = "US";
address.administrative_area = "California";
FieldProblemMap filter;
filter.insert(std::make_pair(ADMIN_AREA, UNKNOWN_VALUE));
FieldProblemMap problems;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, &filter, &problems));
EXPECT_TRUE(problems.empty());
}
TEST_F(AddressValidatorTest, USZipCode) {
AddressData address;
address.recipient = "Mr. Smith";
address.address_line.push_back("340 Main St.");
address.locality = "Venice";
address.administrative_area = "CA";
address.region_code = "US";
// Valid Californian zip code.
address.postal_code = "90291";
FieldProblemMap problems;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_TRUE(problems.empty());
problems.clear();
// An extended, valid Californian zip code.
address.postal_code = "90210-1234";
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_TRUE(problems.empty());
problems.clear();
// New York zip code (which is invalid for California).
address.postal_code = "12345";
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_EQ(1U, problems.size());
EXPECT_EQ(problems.begin()->first, POSTAL_CODE);
EXPECT_EQ(problems.begin()->second, MISMATCHING_VALUE);
problems.clear();
// A zip code with a "90" in the middle.
address.postal_code = "12903";
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_EQ(1U, problems.size());
EXPECT_EQ(problems.begin()->first, POSTAL_CODE);
EXPECT_EQ(problems.begin()->second, MISMATCHING_VALUE);
problems.clear();
// Invalid zip code (too many digits).
address.postal_code = "902911";
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_EQ(1U, problems.size());
EXPECT_EQ(problems.begin()->first, POSTAL_CODE);
EXPECT_EQ(problems.begin()->second, INVALID_FORMAT);
problems.clear();
// Invalid zip code (too few digits).
address.postal_code = "9029";
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_EQ(1U, problems.size());
EXPECT_EQ(problems.begin()->first, POSTAL_CODE);
EXPECT_EQ(problems.begin()->second, INVALID_FORMAT);
}
TEST_F(AddressValidatorTest, BasicValidation) {
// US rules should always be available, even though this load call fails.
validator_->LoadRules("US");
AddressData address;
address.region_code = "US";
address.language_code = "en";
address.administrative_area = "TX";
address.locality = "Paris";
address.postal_code = "75461";
address.address_line.push_back("123 Main St");
address.recipient = "Mr. Smith";
FieldProblemMap problems;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_TRUE(problems.empty());
// The display name works as well as the key.
address.administrative_area = "Texas";
problems.clear();
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_TRUE(problems.empty());
// Ignore capitalization.
address.administrative_area = "tx";
problems.clear();
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_TRUE(problems.empty());
// Ignore capitalization.
address.administrative_area = "teXas";
problems.clear();
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_TRUE(problems.empty());
// Ignore diacriticals.
address.administrative_area = base::WideToUTF8(L"T\u00E9xas");
problems.clear();
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_TRUE(problems.empty());
}
TEST_F(AddressValidatorTest, BasicValidationFailure) {
// US rules should always be available, even though this load call fails.
validator_->LoadRules("US");
AddressData address;
address.region_code = "US";
address.language_code = "en";
address.administrative_area = "XT";
address.locality = "Paris";
address.postal_code = "75461";
address.address_line.push_back("123 Main St");
address.recipient = "Mr. Smith";
FieldProblemMap problems;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(address, NULL, &problems));
ASSERT_EQ(1U, problems.size());
EXPECT_EQ(UNKNOWN_VALUE, problems.begin()->second);
EXPECT_EQ(ADMIN_AREA, problems.begin()->first);
}
TEST_F(AddressValidatorTest, NoNullSuggestionsCrash) {
AddressData address;
address.region_code = "US";
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, COUNTRY, 1, NULL));
}
TEST_F(AddressValidatorTest, SuggestAdminAreaForPostalCode) {
AddressData address;
address.region_code = "US";
address.postal_code = "90291";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("CA", suggestions[0].administrative_area);
EXPECT_EQ("90291", suggestions[0].postal_code);
}
TEST_F(LargeAddressValidatorTest, SuggestLocalityForPostalCodeWithAdminArea) {
AddressData address;
address.region_code = "TW";
address.postal_code = "515";
address.administrative_area = "Changhua";
address.language_code = "zh-Latn";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("Dacun Township", suggestions[0].locality);
EXPECT_EQ("Changhua County", suggestions[0].administrative_area);
EXPECT_EQ("515", suggestions[0].postal_code);
}
TEST_F(LargeAddressValidatorTest, SuggestAdminAreaForPostalCodeWithLocality) {
AddressData address;
address.region_code = "TW";
address.postal_code = "515";
address.locality = "Dacun";
address.language_code = "zh-Latn";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("Dacun Township", suggestions[0].locality);
EXPECT_EQ("Changhua County", suggestions[0].administrative_area);
EXPECT_EQ("515", suggestions[0].postal_code);
}
TEST_F(AddressValidatorTest, NoSuggestForPostalCodeWithWrongAdminArea) {
AddressData address;
address.region_code = "US";
address.postal_code = "90066";
address.postal_code = "TX";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
EXPECT_TRUE(suggestions.empty());
}
TEST_F(LargeAddressValidatorTest, SuggestForLocality) {
AddressData address;
address.region_code = "CN";
address.locality = "Anqin";
address.language_code = "zh-Latn";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, LOCALITY, 10, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("Anqing Shi", suggestions[0].locality);
EXPECT_EQ("Anhui Sheng", suggestions[0].administrative_area);
}
TEST_F(LargeAddressValidatorTest, SuggestForLocalityAndAdminArea) {
AddressData address;
address.region_code = "CN";
address.locality = "Anqing";
address.administrative_area = "Anhui";
address.language_code = "zh-Latn";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, LOCALITY, 10, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_TRUE(suggestions[0].dependent_locality.empty());
EXPECT_EQ("Anqing Shi", suggestions[0].locality);
EXPECT_EQ("Anhui Sheng", suggestions[0].administrative_area);
}
TEST_F(LargeAddressValidatorTest, SuggestForAdminAreaAndLocality) {
AddressData address;
address.region_code = "CN";
address.locality = "Anqing";
address.administrative_area = "Anhui";
address.language_code = "zh-Latn";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_TRUE(suggestions[0].dependent_locality.empty());
EXPECT_TRUE(suggestions[0].locality.empty());
EXPECT_EQ("Anhui Sheng", suggestions[0].administrative_area);
}
TEST_F(LargeAddressValidatorTest, SuggestForDependentLocality) {
AddressData address;
address.region_code = "CN";
address.dependent_locality = "Zongyang";
address.language_code = "zh-Latn";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(
address, DEPENDENT_LOCALITY, 10, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("Zongyang Xian", suggestions[0].dependent_locality);
EXPECT_EQ("Anqing Shi", suggestions[0].locality);
EXPECT_EQ("Anhui Sheng", suggestions[0].administrative_area);
}
TEST_F(LargeAddressValidatorTest,
NoSuggestForDependentLocalityWithWrongAdminArea) {
AddressData address;
address.region_code = "CN";
address.dependent_locality = "Zongyang";
address.administrative_area = "Sichuan Sheng";
address.language_code = "zh-Latn";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(
address, DEPENDENT_LOCALITY, 10, &suggestions));
EXPECT_TRUE(suggestions.empty());
}
TEST_F(AddressValidatorTest, EmptySuggestionsOverLimit) {
AddressData address;
address.region_code = "US";
address.administrative_area = "A";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, ADMIN_AREA, 1, &suggestions));
EXPECT_TRUE(suggestions.empty());
}
TEST_F(AddressValidatorTest, PreferShortSuggestions) {
AddressData address;
address.region_code = "US";
address.administrative_area = "CA";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("CA", suggestions[0].administrative_area);
}
TEST_F(AddressValidatorTest, SuggestTheSingleMatchForFullMatchName) {
AddressData address;
address.region_code = "US";
address.administrative_area = "Texas";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("Texas", suggestions[0].administrative_area);
}
TEST_F(AddressValidatorTest, SuggestAdminArea) {
AddressData address;
address.region_code = "US";
address.administrative_area = "Cali";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("California", suggestions[0].administrative_area);
}
TEST_F(AddressValidatorTest, MultipleSuggestions) {
AddressData address;
address.region_code = "US";
address.administrative_area = "MA";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions));
EXPECT_LT(1U, suggestions.size());
// Massachusetts should not be a suggestion, because it's already covered
// under MA.
std::set<std::string> expected_suggestions;
expected_suggestions.insert("MA");
expected_suggestions.insert("Maine");
expected_suggestions.insert("Marshall Islands");
expected_suggestions.insert("Maryland");
for (std::vector<AddressData>::const_iterator it = suggestions.begin();
it != suggestions.end();
++it) {
expected_suggestions.erase(it->administrative_area);
}
EXPECT_TRUE(expected_suggestions.empty());
}
TEST_F(LargeAddressValidatorTest, SuggestNonLatinKeyWhenLanguageMatches) {
AddressData address;
address.language_code = "ko";
address.region_code = "KR";
address.postal_code = "210-210";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("강원도", suggestions[0].administrative_area);
EXPECT_EQ("210-210", suggestions[0].postal_code);
}
TEST_F(LargeAddressValidatorTest, SuggestNonLatinKeyWhenUserInputIsNotLatin) {
AddressData address;
address.language_code = "en";
address.region_code = "KR";
address.administrative_area = "강원";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, ADMIN_AREA, 1, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("강원도", suggestions[0].administrative_area);
}
TEST_F(LargeAddressValidatorTest,
SuggestLatinNameWhenLanguageDiffersAndLatinNameAvailable) {
AddressData address;
address.language_code = "ko-Latn";
address.region_code = "KR";
address.postal_code = "210-210";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("Gangwon", suggestions[0].administrative_area);
EXPECT_EQ("210-210", suggestions[0].postal_code);
}
TEST_F(AddressValidatorTest, NoSuggestionsForEmptyAddress) {
AddressData address;
address.region_code = "US";
std::vector<AddressData> suggestions;
EXPECT_EQ(
AddressValidator::SUCCESS,
validator_->GetSuggestions(address, POSTAL_CODE, 999, &suggestions));
EXPECT_TRUE(suggestions.empty());
}
TEST_F(AddressValidatorTest, SuggestionIncludesCountry) {
AddressData address;
address.region_code = "US";
address.postal_code = "90291";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("US", suggestions[0].region_code);
}
TEST_F(AddressValidatorTest, InvalidPostalCodeNoSuggestions) {
AddressData address;
address.region_code = "US";
address.postal_code = "0";
std::vector<AddressData> suggestions;
EXPECT_EQ(
AddressValidator::SUCCESS,
validator_->GetSuggestions(address, POSTAL_CODE, 999, &suggestions));
EXPECT_TRUE(suggestions.empty());
}
TEST_F(AddressValidatorTest, MismatchedPostalCodeNoSuggestions) {
AddressData address;
address.region_code = "US";
address.administrative_area = "TX";
address.postal_code = "90291";
std::vector<AddressData> suggestions;
EXPECT_EQ(
AddressValidator::SUCCESS,
validator_->GetSuggestions(address, POSTAL_CODE, 999, &suggestions));
EXPECT_TRUE(suggestions.empty());
}
TEST_F(AddressValidatorTest, SuggestOnlyForAdministrativeAreasAndPostalCode) {
AddressData address;
address.region_code = "US";
address.administrative_area = "CA";
address.locality = "Los Angeles";
address.dependent_locality = "Venice";
address.postal_code = "90291";
address.sorting_code = "123";
address.address_line.push_back("123 Main St");
address.recipient = "Jon Smith";
// Fields that should not have suggestions in US.
static const AddressField kNoSugestFields[] = {
COUNTRY,
LOCALITY,
DEPENDENT_LOCALITY,
SORTING_CODE,
STREET_ADDRESS,
RECIPIENT
};
static const size_t kNumNoSuggestFields =
sizeof kNoSugestFields / sizeof (AddressField);
for (size_t i = 0; i < kNumNoSuggestFields; ++i) {
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(
address, kNoSugestFields[i], 999, &suggestions));
EXPECT_TRUE(suggestions.empty());
}
}
TEST_F(AddressValidatorTest, SuggestionsAreCleared) {
AddressData address;
address.region_code = "US";
std::vector<AddressData> suggestions(1, address);
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
EXPECT_TRUE(suggestions.empty());
}
TEST_F(AddressValidatorTest, NormalizeUsAdminAreaName) {
AddressData address;
address.region_code = "US";
address.administrative_area = "cALIFORNIa";
EXPECT_TRUE(validator_->NormalizeAddress(&address));
EXPECT_EQ("CA", address.administrative_area);
}
TEST_F(AddressValidatorTest, NormalizeUsAdminAreaKey) {
AddressData address;
address.region_code = "US";
address.administrative_area = "CA";
EXPECT_TRUE(validator_->NormalizeAddress(&address));
EXPECT_EQ("CA", address.administrative_area);
}
TEST_F(AddressValidatorTest, NormalizeJpAdminAreaKey) {
validator_->LoadRules("JP");
AddressData address;
address.region_code = "JP";
address.administrative_area = "東京都";
EXPECT_TRUE(validator_->NormalizeAddress(&address));
EXPECT_EQ("東京都", address.administrative_area);
}
TEST_F(AddressValidatorTest, NormalizeJpAdminAreaLatinName) {
validator_->LoadRules("JP");
AddressData address;
address.region_code = "JP";
address.administrative_area = "tOKYo";
EXPECT_TRUE(validator_->NormalizeAddress(&address));
EXPECT_EQ("TOKYO", address.administrative_area);
}
TEST_F(AddressValidatorTest, AreRulesLoadedForRegion_NotLoaded) {
EXPECT_FALSE(validator_->AreRulesLoadedForRegion("JP"));
}
TEST_F(AddressValidatorTest, AreRulesLoadedForRegion_Loaded) {
validator_->LoadRules("JP");
EXPECT_TRUE(validator_->AreRulesLoadedForRegion("JP"));
}
TEST_F(AddressValidatorTest, TokushimaSuggestionIsValid) {
validator_->LoadRules("JP");
AddressData address;
address.region_code = "JP";
address.administrative_area = "Toku";
address.language_code = "ja-Latn";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, ADMIN_AREA, 1, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("TOKUSHIMA", suggestions[0].administrative_area);
FieldProblemMap filter;
for (int i = UNEXPECTED_FIELD; i <= USES_P_O_BOX; ++i)
filter.insert(std::make_pair(ADMIN_AREA, static_cast<AddressProblem>(i)));
FieldProblemMap problems;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->ValidateAddress(suggestions[0], &filter, &problems));
EXPECT_TRUE(problems.empty());
}
TEST_F(AddressValidatorTest, ValidPostalCodeInSuggestion) {
validator_->LoadRules("US");
AddressData address;
address.region_code = "US";
address.administrative_area = "New";
address.postal_code = "13699";
std::vector<AddressData> suggestions;
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, ADMIN_AREA, 999, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("New York", suggestions[0].administrative_area);
address.administrative_area = "New";
address.postal_code = "03755";
EXPECT_EQ(AddressValidator::SUCCESS,
validator_->GetSuggestions(address, ADMIN_AREA, 999, &suggestions));
ASSERT_EQ(1U, suggestions.size());
EXPECT_EQ("New Hampshire", suggestions[0].administrative_area);
}
TEST_F(AddressValidatorTest, ValidateRequiredFieldsWithoutRules) {
// Do not load the rules for JP.
AddressData address;
address.region_code = "JP";
FieldProblemMap problems;
EXPECT_EQ(AddressValidator::RULES_UNAVAILABLE,
validator_->ValidateAddress(address, NULL, &problems));
EXPECT_FALSE(problems.empty());
for (FieldProblemMap::const_iterator it = problems.begin();
it != problems.end();
++it) {
EXPECT_EQ(MISSING_REQUIRED_FIELD, it->second);
}
}
TEST_F(AddressValidatorTest,
DoNotValidateRequiredFieldsWithoutRulesWhenErrorIsFiltered) {
// Do not load the rules for JP.
AddressData address;
address.region_code = "JP";
FieldProblemMap filter;
filter.insert(std::make_pair(COUNTRY, UNKNOWN_VALUE));
FieldProblemMap problems;
EXPECT_EQ(AddressValidator::RULES_UNAVAILABLE,
validator_->ValidateAddress(address, &filter, &problems));
EXPECT_TRUE(problems.empty());
}
// Use this test fixture for configuring the number of failed attempts to load
// rules.
class FailingAddressValidatorTest : public testing::Test, LoadRulesListener {
protected:
// A validator that retries loading rules without delay.
class TestAddressValidator : public AddressValidator {
public:
// Takes ownership of |source| and |storage|.
TestAddressValidator(std::unique_ptr<::i18n::addressinput::Source> source,
std::unique_ptr<::i18n::addressinput::Storage> storage,
LoadRulesListener* load_rules_listener)
: AddressValidator(std::move(source),
std::move(storage),
load_rules_listener) {}
virtual ~TestAddressValidator() {}
protected:
base::TimeDelta GetBaseRetryPeriod() const override {
return base::TimeDelta::FromSeconds(0);
}
private:
DISALLOW_COPY_AND_ASSIGN(TestAddressValidator);
};
// A source that always fails |failures_number| times before downloading
// data.
class FailingSource : public Source {
public:
FailingSource()
: failures_number_(0), attempts_number_(0), actual_source_(true) {}
virtual ~FailingSource() {}
// Sets the number of times to fail before downloading data.
void set_failures_number(int failures_number) {
failures_number_ = failures_number;
}
// Source implementation.
// Always fails for the first |failures_number| times.
void Get(const std::string& url, const Callback& callback) const override {
++attempts_number_;
// |callback| takes ownership of the |new std::string|.
if (failures_number_-- > 0)
callback(false, url, new std::string);
else
actual_source_.Get(url, callback);
}
// Returns the number of download attempts.
int attempts_number() const { return attempts_number_; }
private:
// The number of times to fail before downloading data.
mutable int failures_number_;
// The number of times Get was called.
mutable int attempts_number_;
// The source to use for successful downloads.
TestdataSource actual_source_;
DISALLOW_COPY_AND_ASSIGN(FailingSource);
};
FailingAddressValidatorTest()
: source_(new FailingSource),
validator_(
new TestAddressValidator(std::unique_ptr<Source>(source_),
std::unique_ptr<Storage>(new NullStorage),
this)),
load_rules_success_(false) {}
virtual ~FailingAddressValidatorTest() {}
FailingSource* source_; // Owned by |validator_|.
std::unique_ptr<AddressValidator> validator_;
bool load_rules_success_;
private:
// LoadRulesListener implementation.
void OnAddressValidationRulesLoaded(const std::string&, bool success) override {
load_rules_success_ = success;
}
base::MessageLoop ui_;
DISALLOW_COPY_AND_ASSIGN(FailingAddressValidatorTest);
};
// The validator will attempt to load rules at most 8 times.
TEST_F(FailingAddressValidatorTest, RetryLoadingRulesHasLimit) {
source_->set_failures_number(99);
validator_->LoadRules("CH");
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(load_rules_success_);
EXPECT_EQ(8, source_->attempts_number());
}
// The validator will load rules successfully if the source returns data
// before the maximum number of retries.
TEST_F(FailingAddressValidatorTest, RuleRetryingWillSucceed) {
source_->set_failures_number(4);
validator_->LoadRules("CH");
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(load_rules_success_);
EXPECT_EQ(5, source_->attempts_number());
}
// The delayed task to retry loading rules should stop (instead of crashing) if
// the validator is destroyed before it fires.
TEST_F(FailingAddressValidatorTest, DestroyedValidatorStopsRetries) {
source_->set_failures_number(4);
validator_->LoadRules("CH");
// Destroy the validator.
validator_.reset();
// Fire the delayed task to retry loading rules.
EXPECT_NO_FATAL_FAILURE(base::RunLoop().RunUntilIdle());
}
// Each call to LoadRules should reset the number of retry attempts. If the
// first call to LoadRules exceeded the maximum number of retries, the second
// call to LoadRules should start counting the retries from zero.
TEST_F(FailingAddressValidatorTest, LoadingRulesSecondTimeSucceeds) {
source_->set_failures_number(11);
validator_->LoadRules("CH");
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(load_rules_success_);
EXPECT_EQ(8, source_->attempts_number());
validator_->LoadRules("CH");
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(load_rules_success_);
EXPECT_EQ(12, source_->attempts_number());
}
// Calling LoadRules("CH") and LoadRules("GB") simultaneously should attempt to
// load both rules up to the maximum number of attempts for each region.
TEST_F(FailingAddressValidatorTest, RegionsShouldRetryIndividually) {
source_->set_failures_number(99);
validator_->LoadRules("CH");
validator_->LoadRules("GB");
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(load_rules_success_);
EXPECT_EQ(16, source_->attempts_number());
}
} // namespace autofill