// 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 #include #include #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; class AddressValidatorTest : public testing::Test, LoadRulesListener { protected: AddressValidatorTest() : validator_( new AddressValidator(scoped_ptr(new TestdataSource(true)), scoped_ptr(new NullStorage), this)) { validator_->LoadRules("US"); } virtual ~AddressValidatorTest() {} const scoped_ptr validator_; private: // LoadRulesListener implementation. virtual 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(success, 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(scoped_ptr(new TestdataSource(true)), scoped_ptr(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, RegionHasRules) { const std::vector& 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 expected_suggestions; expected_suggestions.insert("MA"); expected_suggestions.insert("Maine"); expected_suggestions.insert("Marshall Islands"); expected_suggestions.insert("Maryland"); for (std::vector::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 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 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 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 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 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 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 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 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 suggestions(1, address); EXPECT_EQ(AddressValidator::SUCCESS, validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions)); EXPECT_TRUE(suggestions.empty()); } TEST_F(AddressValidatorTest, CanonicalizeUsAdminAreaName) { AddressData address; address.region_code = "US"; address.administrative_area = "cALIFORNIa"; EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address)); EXPECT_EQ("CA", address.administrative_area); } TEST_F(AddressValidatorTest, CanonicalizeUsAdminAreaKey) { AddressData address; address.region_code = "US"; address.administrative_area = "CA"; EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address)); EXPECT_EQ("CA", address.administrative_area); } TEST_F(AddressValidatorTest, CanonicalizeJpAdminAreaKey) { validator_->LoadRules("JP"); AddressData address; address.region_code = "JP"; address.administrative_area = "東京都"; EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address)); EXPECT_EQ("東京都", address.administrative_area); } TEST_F(AddressValidatorTest, CanonicalizeJpAdminAreaLatinName) { validator_->LoadRules("JP"); AddressData address; address.region_code = "JP"; address.administrative_area = "tOKYo"; EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address)); EXPECT_EQ("TOKYO", address.administrative_area); } TEST_F(AddressValidatorTest, TokushimaSuggestionIsValid) { validator_->LoadRules("JP"); AddressData address; address.region_code = "JP"; address.administrative_area = "Toku"; address.language_code = "ja-Latn"; std::vector 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(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 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, DoNotValidateRequiredFieldsWithoutRulesWhenErorrIsFiltered) { // 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( scoped_ptr< ::i18n::addressinput::Source> source, scoped_ptr< ::i18n::addressinput::Storage> storage, LoadRulesListener* load_rules_listener) : AddressValidator(source.Pass(), storage.Pass(), load_rules_listener) {} virtual ~TestAddressValidator() {} protected: virtual 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: explicit 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. virtual 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(scoped_ptr(source_), scoped_ptr(new NullStorage), this)), load_rules_success_(false) {} virtual ~FailingAddressValidatorTest() {} FailingSource* source_; // Owned by |validator_|. scoped_ptr validator_; bool load_rules_success_; private: // LoadRulesListener implementation. virtual 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