summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvabr <vabr@chromium.org>2016-01-25 03:34:07 -0800
committerCommit bot <commit-bot@chromium.org>2016-01-25 11:34:59 +0000
commitf39cbace358fe626f0f07e32f4e66b78ca589038 (patch)
tree3c327995a1d3dbca8566ad46d5e5dcc4bab86675
parent65729cfa6e6eccba09d62b9c6829e7941a0528ed (diff)
downloadchromium_src-f39cbace358fe626f0f07e32f4e66b78ca589038.zip
chromium_src-f39cbace358fe626f0f07e32f4e66b78ca589038.tar.gz
chromium_src-f39cbace358fe626f0f07e32f4e66b78ca589038.tar.bz2
CountryNames: Separate data creation from usage
==Goal== Fix a race condition in CountryNames-related code without complicating it significantly. ==Non-goal== Any deeper refactoring not necessary to fix the above race condition. A discussion is needed to see whether once could avoid the Singleton business and use some more common ways to store the country names data (a database?), as well as whether it is necessary to compute it in run-time. But that is explicitly out of scope of this CL. ==Content== This CL makes CountryNames create its data (mappings from country names to country codes and the appropriate collators for hashing the country names) on construction, rather than on demand. The main purpose of this change is to eliminate race conditions. Before this CL, multiple threads could have trigger the data creation, and it is believed to have caused data corruption and crashes. Because the CountryNames creation is guaranteed by Singleton to only happen once, it solves the threading issues. However, there are caveats: (Caveat A) CountryNames cannot get constructor arguments, being created through Singleton's get(). But it needs to know which locale Chrome is using. To circumvent this, it gets the information from a global static string, and relies on the callsites of CountryNames to ensure initialisation of this string. To make that happen, every instance of AutofillManager ensures on its construction, that said string is initialised. This is a bit clumsy (there is an AutofillManager for each tab, but this pointer only needs to be initialised once per Chrome's execution), but works -- CountryNames are never used earlier than the first AutofillManager is constructed. Also, while initialising the string is not guarded by any mutex, it is safe -- AutofillManager gets constructed on the UI thread, so there are not more concurrent constructions. And once the string is set, it is never set again, so a constructed CountryNames can read it safely on any thread. (Caveat B) Before this CL, the code was capable of generating more data for a newly added locale on the fly. After this CL, it will only work for the locale of the program during the CountryNames creation (and en_US as a fallback). Note that Chrome does not seem to be able to change the language without restart, so this should be no concern. The only unknown for me is CrOS -- I'm not sure whether a new CountryNames instance is created for each user session. But my suggestion is to wait with making the code more flexible until the more systematic fix to the way it generates and stores the CountryNames data. Finally, this CL adds a way to construct CountryNames with an explicit locale in tests, and uses it in the appropriate unit tests. BUG=571610 Review URL: https://codereview.chromium.org/1582353006 Cr-Commit-Position: refs/heads/master@{#371226}
-rw-r--r--chrome/browser/autofill/android/personal_data_manager_android.cc3
-rw-r--r--chrome/browser/sync/profile_sync_service_autofill_unittest.cc9
-rw-r--r--chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc23
-rw-r--r--chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc5
-rw-r--r--components/autofill/core/browser/address.cc6
-rw-r--r--components/autofill/core/browser/address_unittest.cc26
-rw-r--r--components/autofill/core/browser/autofill_field.cc12
-rw-r--r--components/autofill/core/browser/autofill_field_unittest.cc64
-rw-r--r--components/autofill/core/browser/autofill_manager.cc3
-rw-r--r--components/autofill/core/browser/autofill_merge_unittest.cc2
-rw-r--r--components/autofill/core/browser/country_names.cc163
-rw-r--r--components/autofill/core/browser/country_names.h63
-rw-r--r--components/autofill/core/browser/country_names_unittest.cc86
-rw-r--r--components/autofill/core/browser/personal_data_manager.cc3
-rw-r--r--components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc13
-rw-r--r--components/autofill/core/browser/webdata/autofill_profile_syncable_service.h3
-rw-r--r--components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc5
17 files changed, 282 insertions, 207 deletions
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc
index f136014..a1f1150 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.cc
+++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -352,8 +352,7 @@ static ScopedJavaLocalRef<jstring> ToCountryCode(
const JavaParamRef<jstring>& jcountry_name) {
return ConvertUTF8ToJavaString(
env, CountryNames::GetInstance()->GetCountryCode(
- base::android::ConvertJavaStringToUTF16(env, jcountry_name),
- g_browser_process->GetApplicationLocale()));
+ base::android::ConvertJavaStringToUTF16(env, jcountry_name)));
}
static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
diff --git a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
index 706d28c..ccd554d 100644
--- a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
@@ -39,6 +39,7 @@
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/country_names.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
@@ -429,7 +430,9 @@ class ProfileSyncServiceAutofillTest
ProfileSyncServiceAutofillTest()
: profile_manager_(TestingBrowserProcess::GetGlobal()),
debug_ptr_factory_(this) {
+ autofill::CountryNames::SetLocaleString("en-US");
}
+
~ProfileSyncServiceAutofillTest() override {}
void SetUp() override {
@@ -607,7 +610,7 @@ class ProfileSyncServiceAutofillTest
AutofillProfile p;
p.set_guid(autofill.profile().guid());
AutofillProfileSyncableService::OverwriteProfileWithServerData(
- autofill.profile(), &p, "en-US");
+ autofill.profile(), &p);
profiles->push_back(p);
}
child_id = child_node.GetSuccessorId();
@@ -633,8 +636,8 @@ class ProfileSyncServiceAutofillTest
child_node.GetEntitySpecifics().autofill_profile());
AutofillProfile p;
p.set_guid(autofill.guid());
- AutofillProfileSyncableService::OverwriteProfileWithServerData(
- autofill, &p, "en-US");
+ AutofillProfileSyncableService::OverwriteProfileWithServerData(autofill,
+ &p);
profiles->push_back(p);
child_id = child_node.GetSuccessorId();
}
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
index e8fa7cc..2fa1379 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -161,8 +161,8 @@ base::string16 GetInfoFromInputs(const FieldValueMap& inputs,
info = it->second;
if (!info.empty() && type.html_type() == HTML_TYPE_COUNTRY_CODE) {
- info = base::ASCIIToUTF16(CountryNames::GetInstance()->GetCountryCode(
- info, g_browser_process->GetApplicationLocale()));
+ info =
+ base::ASCIIToUTF16(CountryNames::GetInstance()->GetCountryCode(info));
}
return info;
@@ -241,8 +241,8 @@ ServerFieldType CountryTypeForSection(DialogSection section) {
ValidityMessage GetPhoneValidityMessage(const base::string16& country_name,
const base::string16& number) {
- std::string region = CountryNames::GetInstance()->GetCountryCode(
- country_name, g_browser_process->GetApplicationLocale());
+ std::string region =
+ CountryNames::GetInstance()->GetCountryCode(country_name);
i18n::PhoneObject phone_object(number, region);
ValidityMessage phone_message(base::string16(), true);
@@ -627,8 +627,8 @@ void AutofillDialogControllerImpl::ResetSectionInput(DialogSection section) {
} else if (!it->initial_value.empty() &&
(it->type == ADDRESS_BILLING_COUNTRY ||
it->type == ADDRESS_HOME_COUNTRY)) {
- GetValidator()->LoadRules(CountryNames::GetInstance()->GetCountryCode(
- it->initial_value, g_browser_process->GetApplicationLocale()));
+ GetValidator()->LoadRules(
+ CountryNames::GetInstance()->GetCountryCode(it->initial_value));
}
}
}
@@ -1918,8 +1918,7 @@ std::string AutofillDialogControllerImpl::CountryCodeForSection(
country = outputs[CountryTypeForSection(section)];
}
- return CountryNames::GetInstance()->GetCountryCode(
- country, g_browser_process->GetApplicationLocale());
+ return CountryNames::GetInstance()->GetCountryCode(country);
}
bool AutofillDialogControllerImpl::RebuildInputsForCountry(
@@ -1930,8 +1929,8 @@ bool AutofillDialogControllerImpl::RebuildInputsForCountry(
if (!model)
return false;
- std::string country_code = CountryNames::GetInstance()->GetCountryCode(
- country_name, g_browser_process->GetApplicationLocale());
+ std::string country_code =
+ CountryNames::GetInstance()->GetCountryCode(country_name);
DCHECK(CanAcceptCountry(section, country_code));
if (view_ && !should_clobber) {
@@ -1949,8 +1948,8 @@ bool AutofillDialogControllerImpl::RebuildInputsForCountry(
MutableAddressLanguageCodeForSection(section));
if (!country_code.empty()) {
- GetValidator()->LoadRules(CountryNames::GetInstance()->GetCountryCode(
- country_name, g_browser_process->GetApplicationLocale()));
+ GetValidator()->LoadRules(
+ CountryNames::GetInstance()->GetCountryCode(country_name));
}
return true;
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
index e39dba5..4bc98b4 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
@@ -39,6 +39,7 @@
#include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/country_names.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_pref_names.h"
@@ -313,7 +314,9 @@ class TestAutofillDialogController
class AutofillDialogControllerTest : public ChromeRenderViewHostTestHarness {
protected:
- AutofillDialogControllerTest(): form_structure_(NULL) {}
+ AutofillDialogControllerTest() : form_structure_(NULL) {
+ CountryNames::SetLocaleString("en-US");
+ }
// testing::Test implementation:
void SetUp() override {
diff --git a/components/autofill/core/browser/address.cc b/components/autofill/core/browser/address.cc
index 88d6dfd..428d9f5 100644
--- a/components/autofill/core/browser/address.cc
+++ b/components/autofill/core/browser/address.cc
@@ -170,8 +170,7 @@ bool Address::SetInfo(const AutofillType& type,
ServerFieldType storable_type = type.GetStorableType();
if (storable_type == ADDRESS_HOME_COUNTRY && !value.empty()) {
- country_code_ =
- CountryNames::GetInstance()->GetCountryCode(value, app_locale);
+ country_code_ = CountryNames::GetInstance()->GetCountryCode(value);
return !country_code_.empty();
}
@@ -196,8 +195,7 @@ void Address::GetMatchingTypes(const base::string16& text,
FormGroup::GetMatchingTypes(text, app_locale, matching_types);
// Check to see if the |text| canonicalized as a country name is a match.
- std::string country_code =
- CountryNames::GetInstance()->GetCountryCode(text, app_locale);
+ std::string country_code = CountryNames::GetInstance()->GetCountryCode(text);
if (!country_code.empty() && country_code_ == country_code)
matching_types->insert(ADDRESS_HOME_COUNTRY);
}
diff --git a/components/autofill/core/browser/address_unittest.cc b/components/autofill/core/browser/address_unittest.cc
index d728dbf..d178f04 100644
--- a/components/autofill/core/browser/address_unittest.cc
+++ b/components/autofill/core/browser/address_unittest.cc
@@ -11,15 +11,21 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/address.h"
#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/country_names.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
namespace autofill {
+class AddressTest : public testing::Test {
+ public:
+ AddressTest() { CountryNames::SetLocaleString("en-US"); }
+};
+
// Test that country data can be properly returned as either a country code or a
// localized country name.
-TEST(AddressTest, GetCountry) {
+TEST_F(AddressTest, GetCountry) {
Address address;
EXPECT_EQ(base::string16(), address.GetRawInfo(ADDRESS_HOME_COUNTRY));
@@ -51,7 +57,7 @@ TEST(AddressTest, GetCountry) {
}
// Test that we properly detect country codes appropriate for each country.
-TEST(AddressTest, SetCountry) {
+TEST_F(AddressTest, SetCountry) {
Address address;
EXPECT_EQ(base::string16(), address.GetRawInfo(ADDRESS_HOME_COUNTRY));
@@ -115,7 +121,7 @@ TEST(AddressTest, SetCountry) {
}
// Test that we properly match typed values to stored country data.
-TEST(AddressTest, IsCountry) {
+TEST_F(AddressTest, IsCountry) {
Address address;
address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
@@ -155,7 +161,7 @@ TEST(AddressTest, IsCountry) {
}
// Verifies that Address::GetInfo() correctly combines address lines.
-TEST(AddressTest, GetStreetAddress) {
+TEST_F(AddressTest, GetStreetAddress) {
const AutofillType type = AutofillType(ADDRESS_HOME_STREET_ADDRESS);
// Address has no address lines.
@@ -215,7 +221,7 @@ TEST(AddressTest, GetStreetAddress) {
// Verifies that overwriting an address with N lines with one that has fewer
// than N lines does not result in an address with blank lines at the end.
-TEST(AddressTest, GetStreetAddressAfterOverwritingLongAddressWithShorterOne) {
+TEST_F(AddressTest, GetStreetAddressAfterOverwritingLongAddressWithShorterOne) {
// Start with an address that has two lines.
Address address;
address.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("123 Example Ave."));
@@ -232,7 +238,7 @@ TEST(AddressTest, GetStreetAddressAfterOverwritingLongAddressWithShorterOne) {
}
// Verifies that Address::SetRawInfo() is able to split address lines correctly.
-TEST(AddressTest, SetRawStreetAddress) {
+TEST_F(AddressTest, SetRawStreetAddress) {
const base::string16 empty_street_address;
const base::string16 short_street_address = ASCIIToUTF16("456 Nowhere Ln.");
const base::string16 long_street_address =
@@ -265,7 +271,7 @@ TEST(AddressTest, SetRawStreetAddress) {
}
// Street addresses should be set properly.
-TEST(AddressTest, SetStreetAddress) {
+TEST_F(AddressTest, SetStreetAddress) {
const base::string16 empty_street_address;
const base::string16 multi_line_street_address =
ASCIIToUTF16("789 Fancy Pkwy.\n"
@@ -311,7 +317,7 @@ TEST(AddressTest, SetStreetAddress) {
// Verifies that Address::SetInfio() rejects setting data for
// ADDRESS_HOME_STREET_ADDRESS if the data has any interior blank lines.
-TEST(AddressTest, SetStreetAddressRejectsAddressesWithInteriorBlankLines) {
+TEST_F(AddressTest, SetStreetAddressRejectsAddressesWithInteriorBlankLines) {
// Start with a non-empty address.
Address address;
address.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("123 Example Ave."));
@@ -334,7 +340,7 @@ TEST(AddressTest, SetStreetAddressRejectsAddressesWithInteriorBlankLines) {
// Verifies that Address::SetInfio() rejects setting data for
// ADDRESS_HOME_STREET_ADDRESS if the data has any leading blank lines.
-TEST(AddressTest, SetStreetAddressRejectsAddressesWithLeadingBlankLines) {
+TEST_F(AddressTest, SetStreetAddressRejectsAddressesWithLeadingBlankLines) {
// Start with a non-empty address.
Address address;
address.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("123 Example Ave."));
@@ -357,7 +363,7 @@ TEST(AddressTest, SetStreetAddressRejectsAddressesWithLeadingBlankLines) {
// Verifies that Address::SetInfio() rejects setting data for
// ADDRESS_HOME_STREET_ADDRESS if the data has any trailing blank lines.
-TEST(AddressTest, SetStreetAddressRejectsAddressesWithTrailingBlankLines) {
+TEST_F(AddressTest, SetStreetAddressRejectsAddressesWithTrailingBlankLines) {
// Start with a non-empty address.
Address address;
address.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("123 Example Ave."));
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 145d7a0..9ef2e2b 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -174,10 +174,8 @@ bool FillStateSelectControl(const base::string16& value,
}
bool FillCountrySelectControl(const base::string16& value,
- const std::string& app_locale,
FormFieldData* field_data) {
- std::string country_code =
- CountryNames::GetInstance()->GetCountryCode(value, app_locale);
+ std::string country_code = CountryNames::GetInstance()->GetCountryCode(value);
if (country_code.empty())
return false;
@@ -188,10 +186,8 @@ bool FillCountrySelectControl(const base::string16& value,
// target country code.
base::string16 value = field_data->option_values[i];
base::string16 contents = field_data->option_contents[i];
- if (country_code ==
- CountryNames::GetInstance()->GetCountryCode(value, app_locale) ||
- country_code ==
- CountryNames::GetInstance()->GetCountryCode(contents, app_locale)) {
+ if (country_code == CountryNames::GetInstance()->GetCountryCode(value) ||
+ country_code == CountryNames::GetInstance()->GetCountryCode(contents)) {
field_data->value = value;
return true;
}
@@ -349,7 +345,7 @@ bool FillSelectControl(const AutofillType& type,
if (storable_type == ADDRESS_HOME_STATE) {
return FillStateSelectControl(value, field);
} else if (storable_type == ADDRESS_HOME_COUNTRY) {
- return FillCountrySelectControl(value, app_locale, field);
+ return FillCountrySelectControl(value, field);
} else if (storable_type == CREDIT_CARD_EXP_2_DIGIT_YEAR ||
storable_type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
return FillYearSelectControl(value, field);
diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc
index 10b1d96..9ef7d7f 100644
--- a/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/components/autofill/core/browser/autofill_field_unittest.cc
@@ -11,6 +11,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/country_names.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/common/autofill_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -138,7 +139,12 @@ size_t GetNumberOffset(size_t index, const TestCase& test) {
return result;
}
-TEST(AutofillFieldTest, Type) {
+class AutofillFieldTest : public testing::Test {
+ public:
+ AutofillFieldTest() { CountryNames::SetLocaleString("en-US"); }
+};
+
+TEST_F(AutofillFieldTest, Type) {
AutofillField field;
ASSERT_EQ(NO_SERVER_DATA, field.server_type());
ASSERT_EQ(UNKNOWN_TYPE, field.heuristic_type());
@@ -162,7 +168,7 @@ TEST(AutofillFieldTest, Type) {
EXPECT_EQ(NAME, field.Type().group());
}
-TEST(AutofillFieldTest, IsEmpty) {
+TEST_F(AutofillFieldTest, IsEmpty) {
AutofillField field;
ASSERT_EQ(base::string16(), field.value);
@@ -174,7 +180,7 @@ TEST(AutofillFieldTest, IsEmpty) {
EXPECT_FALSE(field.IsEmpty());
}
-TEST(AutofillFieldTest, FieldSignature) {
+TEST_F(AutofillFieldTest, FieldSignature) {
AutofillField field;
ASSERT_EQ(base::string16(), field.name);
ASSERT_EQ(std::string(), field.form_control_type);
@@ -199,7 +205,7 @@ TEST(AutofillFieldTest, FieldSignature) {
EXPECT_EQ("502192749", field.FieldSignature());
}
-TEST(AutofillFieldTest, IsFieldFillable) {
+TEST_F(AutofillFieldTest, IsFieldFillable) {
AutofillField field;
ASSERT_EQ(UNKNOWN_TYPE, field.Type().GetStorableType());
@@ -228,7 +234,7 @@ TEST(AutofillFieldTest, IsFieldFillable) {
// Verify that non credit card related fields with the autocomplete attribute
// set to off don't get filled on desktop.
-TEST(AutofillFieldTest, FillFormField_AutocompleteOff_AddressField) {
+TEST_F(AutofillFieldTest, FillFormField_AutocompleteOff_AddressField) {
AutofillField field;
field.should_autocomplete = false;
@@ -246,7 +252,7 @@ TEST(AutofillFieldTest, FillFormField_AutocompleteOff_AddressField) {
// Verify that credit card related fields with the autocomplete attribute
// set to off get filled.
-TEST(AutofillFieldTest, FillFormField_AutocompleteOff_CreditCardField) {
+TEST_F(AutofillFieldTest, FillFormField_AutocompleteOff_CreditCardField) {
AutofillField field;
field.should_autocomplete = false;
@@ -259,7 +265,7 @@ TEST(AutofillFieldTest, FillFormField_AutocompleteOff_CreditCardField) {
EXPECT_EQ(ASCIIToUTF16("4111111111111111"), field.value);
}
-TEST(AutofillFieldTest, FillPhoneNumber) {
+TEST_F(AutofillFieldTest, FillPhoneNumber) {
AutofillField field;
field.SetHtmlType(HTML_TYPE_TEL_LOCAL_PREFIX, HtmlFieldMode());
@@ -284,7 +290,7 @@ TEST(AutofillFieldTest, FillPhoneNumber) {
EXPECT_EQ(ASCIIToUTF16("1234"), field.value);
}
-TEST(AutofillFieldTest, FillSelectControlByValue) {
+TEST_F(AutofillFieldTest, FillSelectControlByValue) {
std::vector<const char*> kOptions = {
"Eenie", "Meenie", "Miney", "Mo",
};
@@ -301,7 +307,7 @@ TEST(AutofillFieldTest, FillSelectControlByValue) {
EXPECT_EQ(ASCIIToUTF16("Meenie"), field.value);
}
-TEST(AutofillFieldTest, FillSelectControlByContents) {
+TEST_F(AutofillFieldTest, FillSelectControlByContents) {
std::vector<const char*> kOptions = {
"Eenie", "Meenie", "Miney", "Mo",
};
@@ -318,7 +324,7 @@ TEST(AutofillFieldTest, FillSelectControlByContents) {
EXPECT_EQ(ASCIIToUTF16("2"), field.value); // Corresponds to "Miney".
}
-TEST(AutofillFieldTest, FillSelectControlWithFullCountryNames) {
+TEST_F(AutofillFieldTest, FillSelectControlWithFullCountryNames) {
std::vector<const char*> kCountries = {"Albania", "Canada"};
AutofillField field(
GenerateSelectFieldWithOptions(kCountries, kCountries.size()),
@@ -330,7 +336,7 @@ TEST(AutofillFieldTest, FillSelectControlWithFullCountryNames) {
EXPECT_EQ(ASCIIToUTF16("Canada"), field.value);
}
-TEST(AutofillFieldTest, FillSelectControlWithAbbreviatedCountryNames) {
+TEST_F(AutofillFieldTest, FillSelectControlWithAbbreviatedCountryNames) {
std::vector<const char*> kCountries = {"AL", "CA"};
AutofillField field(
GenerateSelectFieldWithOptions(kCountries, kCountries.size()),
@@ -342,7 +348,7 @@ TEST(AutofillFieldTest, FillSelectControlWithAbbreviatedCountryNames) {
EXPECT_EQ(ASCIIToUTF16("CA"), field.value);
}
-TEST(AutofillFieldTest, FillSelectControlWithFullStateNames) {
+TEST_F(AutofillFieldTest, FillSelectControlWithFullStateNames) {
std::vector<const char*> kStates = {"Alabama", "California"};
AutofillField field(GenerateSelectFieldWithOptions(kStates, kStates.size()),
base::string16());
@@ -353,7 +359,7 @@ TEST(AutofillFieldTest, FillSelectControlWithFullStateNames) {
EXPECT_EQ(ASCIIToUTF16("California"), field.value);
}
-TEST(AutofillFieldTest, FillSelectControlWithAbbreviateStateNames) {
+TEST_F(AutofillFieldTest, FillSelectControlWithAbbreviateStateNames) {
std::vector<const char*> kStates = {"AL", "CA"};
AutofillField field(GenerateSelectFieldWithOptions(kStates, kStates.size()),
base::string16());
@@ -364,7 +370,7 @@ TEST(AutofillFieldTest, FillSelectControlWithAbbreviateStateNames) {
EXPECT_EQ(ASCIIToUTF16("CA"), field.value);
}
-TEST(AutofillFieldTest, FillSelectControlWithInexactFullStateNames) {
+TEST_F(AutofillFieldTest, FillSelectControlWithInexactFullStateNames) {
{
std::vector<const char*> kStates = {
"SC - South Carolina", "CA - California", "NC - North Carolina",
@@ -425,7 +431,7 @@ TEST(AutofillFieldTest, FillSelectControlWithInexactFullStateNames) {
}
}
-TEST(AutofillFieldTest, FillSelectControlWithInexactAbbreviations) {
+TEST_F(AutofillFieldTest, FillSelectControlWithInexactAbbreviations) {
{
std::vector<const char*> kStates = {
"NC - North Carolina", "CA - California",
@@ -454,7 +460,7 @@ TEST(AutofillFieldTest, FillSelectControlWithInexactAbbreviations) {
}
}
-TEST(AutofillFieldTest, FillSelectControlWithExpirationMonth) {
+TEST_F(AutofillFieldTest, FillSelectControlWithExpirationMonth) {
typedef struct {
std::vector<const char*> select_values;
std::vector<const char*> select_contents;
@@ -490,7 +496,7 @@ TEST(AutofillFieldTest, FillSelectControlWithExpirationMonth) {
}
}
-TEST(AutofillFieldTest, FillSelectControlWithAbbreviatedMonthName) {
+TEST_F(AutofillFieldTest, FillSelectControlWithAbbreviatedMonthName) {
std::vector<const char*> kMonthsAbbreviated = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
@@ -505,7 +511,7 @@ TEST(AutofillFieldTest, FillSelectControlWithAbbreviatedMonthName) {
EXPECT_EQ(ASCIIToUTF16("Apr"), field.value);
}
-TEST(AutofillFieldTest, FillSelectControlWithFullMonthName) {
+TEST_F(AutofillFieldTest, FillSelectControlWithFullMonthName) {
std::vector<const char*> kMonthsFull = {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December",
@@ -520,7 +526,7 @@ TEST(AutofillFieldTest, FillSelectControlWithFullMonthName) {
EXPECT_EQ(ASCIIToUTF16("April"), field.value);
}
-TEST(AutofillFieldTest, FillSelectControlWithFrenchMonthName) {
+TEST_F(AutofillFieldTest, FillSelectControlWithFrenchMonthName) {
std::vector<const char*> kMonthsFrench = {"JANV", "FÉVR.", "MARS",
"décembre"};
AutofillField field(
@@ -541,7 +547,7 @@ TEST(AutofillFieldTest, FillSelectControlWithFrenchMonthName) {
EXPECT_EQ(UTF8ToUTF16("décembre"), field.value);
}
-TEST(AutofillFieldTest, FillSelectControlWithNumericMonthSansLeadingZero) {
+TEST_F(AutofillFieldTest, FillSelectControlWithNumericMonthSansLeadingZero) {
std::vector<const char*> kMonthsNumeric = {
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
};
@@ -555,7 +561,7 @@ TEST(AutofillFieldTest, FillSelectControlWithNumericMonthSansLeadingZero) {
EXPECT_EQ(ASCIIToUTF16("4"), field.value);
}
-TEST(AutofillFieldTest, FillSelectControlWithTwoDigitCreditCardYear) {
+TEST_F(AutofillFieldTest, FillSelectControlWithTwoDigitCreditCardYear) {
std::vector<const char*> kYears = {"12", "13", "14", "15",
"16", "17", "18", "19"};
AutofillField field(GenerateSelectFieldWithOptions(kYears, kYears.size()),
@@ -567,7 +573,7 @@ TEST(AutofillFieldTest, FillSelectControlWithTwoDigitCreditCardYear) {
EXPECT_EQ(ASCIIToUTF16("17"), field.value);
}
-TEST(AutofillFieldTest, FillSelectControlWithCreditCardType) {
+TEST_F(AutofillFieldTest, FillSelectControlWithCreditCardType) {
std::vector<const char*> kCreditCardTypes = {"Visa", "Master Card", "AmEx",
"discover"};
AutofillField field(
@@ -596,7 +602,7 @@ TEST(AutofillFieldTest, FillSelectControlWithCreditCardType) {
EXPECT_EQ(ASCIIToUTF16("discover"), field.value);
}
-TEST(AutofillFieldTest, FillMonthControl) {
+TEST_F(AutofillFieldTest, FillMonthControl) {
AutofillField field;
field.form_control_type = "month";
@@ -616,7 +622,7 @@ TEST(AutofillFieldTest, FillMonthControl) {
EXPECT_EQ(ASCIIToUTF16("2018-04"), field.value);
}
-TEST(AutofillFieldTest, FillStreetAddressTextArea) {
+TEST_F(AutofillFieldTest, FillStreetAddressTextArea) {
AutofillField field;
field.form_control_type = "textarea";
@@ -631,7 +637,7 @@ TEST(AutofillFieldTest, FillStreetAddressTextArea) {
EXPECT_EQ(ja_value, field.value);
}
-TEST(AutofillFieldTest, FillStreetAddressTextField) {
+TEST_F(AutofillFieldTest, FillStreetAddressTextField) {
AutofillField field;
field.form_control_type = "text";
field.set_server_type(ADDRESS_HOME_STREET_ADDRESS);
@@ -650,7 +656,7 @@ TEST(AutofillFieldTest, FillStreetAddressTextField) {
EXPECT_EQ(UTF8ToUTF16("桜丘町26-1セルリアンタワー6階"), field.value);
}
-TEST(AutofillFieldTest, FillCreditCardNumberWithoutSplits) {
+TEST_F(AutofillFieldTest, FillCreditCardNumberWithoutSplits) {
// Case 1: card number without any spilt.
AutofillField cc_number_full;
cc_number_full.set_heuristic_type(CREDIT_CARD_NUMBER);
@@ -665,7 +671,7 @@ TEST(AutofillFieldTest, FillCreditCardNumberWithoutSplits) {
EXPECT_EQ(0U, cc_number_full.credit_card_number_offset());
}
-TEST(AutofillFieldTest, FillCreditCardNumberWithEqualSizeSplits) {
+TEST_F(AutofillFieldTest, FillCreditCardNumberWithEqualSizeSplits) {
// Case 2: card number broken up into four equal groups, of length 4.
TestCase test;
test.card_number_ = "5187654321098765";
@@ -708,7 +714,7 @@ TEST(AutofillFieldTest, FillCreditCardNumberWithEqualSizeSplits) {
EXPECT_EQ(ASCIIToUTF16(test.card_number_), cc_number_full.value);
}
-TEST(AutofillFieldTest, FillCreditCardNumberWithUnequalSizeSplits) {
+TEST_F(AutofillFieldTest, FillCreditCardNumberWithUnequalSizeSplits) {
// Case 3: card with 15 digits number, broken up into three unequal groups, of
// lengths 4, 6, and 5.
TestCase test;
@@ -754,7 +760,7 @@ TEST(AutofillFieldTest, FillCreditCardNumberWithUnequalSizeSplits) {
EXPECT_EQ(ASCIIToUTF16(test.card_number_), cc_number_full.value);
}
-TEST(AutofillFieldTest, FindValueInSelectControl) {
+TEST_F(AutofillFieldTest, FindValueInSelectControl) {
const size_t kBadIndex = 1000;
{
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 5440ed0..594ca1e 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -40,6 +40,7 @@
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/country_names.h"
#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_structure.h"
@@ -129,6 +130,7 @@ AutofillManager::AutofillManager(
if (enable_download_manager == ENABLE_AUTOFILL_DOWNLOAD_MANAGER) {
download_manager_.reset(new AutofillDownloadManager(driver, this));
}
+ CountryNames::SetLocaleString(app_locale_);
}
AutofillManager::~AutofillManager() {}
@@ -1135,6 +1137,7 @@ AutofillManager::AutofillManager(AutofillDriver* driver,
weak_ptr_factory_(this) {
DCHECK(driver_);
DCHECK(client_);
+ CountryNames::SetLocaleString(app_locale_);
}
bool AutofillManager::RefreshDataModels() {
diff --git a/components/autofill/core/browser/autofill_merge_unittest.cc b/components/autofill/core/browser/autofill_merge_unittest.cc
index 0592f95..d0c5a66 100644
--- a/components/autofill/core/browser/autofill_merge_unittest.cc
+++ b/components/autofill/core/browser/autofill_merge_unittest.cc
@@ -15,6 +15,7 @@
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/country_names.h"
#include "components/autofill/core/browser/data_driven_test.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/personal_data_manager.h"
@@ -157,6 +158,7 @@ class AutofillMergeTest : public testing::Test,
};
AutofillMergeTest::AutofillMergeTest() : DataDrivenTest(GetTestDataDir()) {
+ CountryNames::SetLocaleString("en-US");
for (size_t i = NO_SERVER_DATA; i < MAX_VALID_FIELD_TYPE; ++i) {
ServerFieldType field_type = static_cast<ServerFieldType>(i);
string_to_field_type_map_[AutofillType(field_type).ToString()] = field_type;
diff --git a/components/autofill/core/browser/country_names.cc b/components/autofill/core/browser/country_names.cc
index ce94dbb..f5b4cdf 100644
--- a/components/autofill/core/browser/country_names.cc
+++ b/components/autofill/core/browser/country_names.cc
@@ -7,6 +7,7 @@
#include <stdint.h>
#include <utility>
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
@@ -21,6 +22,11 @@
namespace autofill {
namespace {
+// A copy of the application locale string, which should be ready for
+// CountryName's construction.
+static base::LazyInstance<std::string> g_application_locale =
+ LAZY_INSTANCE_INITIALIZER;
+
// Returns the ICU sort key corresponding to |str| for the given |collator|.
// Uses |buffer| as temporary storage, and might resize |buffer| as a side-
// effect. |buffer_size| should specify the |buffer|'s size, and is updated if
@@ -74,6 +80,60 @@ std::map<std::string, std::string> GetCommonNames() {
return common_names;
}
+// Creates collator for |locale| and sets its attributes as needed.
+scoped_ptr<icu::Collator> CreateCollator(const icu::Locale& locale) {
+ scoped_ptr<icu::Collator> collator(
+ autofill::l10n::GetCollatorForLocale(locale));
+ if (!collator)
+ return nullptr;
+
+ // Compare case-insensitively and ignoring punctuation.
+ UErrorCode ignored = U_ZERO_ERROR;
+ collator->setAttribute(UCOL_STRENGTH, UCOL_SECONDARY, ignored);
+ ignored = U_ZERO_ERROR;
+ collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, ignored);
+
+ return collator;
+}
+
+// If |locale| is different from "en_US", returns a collator for "en_US" and
+// sets its attributes as appropriate. Otherwise returns null.
+scoped_ptr<icu::Collator> CreateDefaultCollator(const icu::Locale& locale) {
+ icu::Locale default_locale("en_US");
+
+ if (default_locale != locale)
+ return CreateCollator(default_locale);
+
+ return nullptr;
+}
+
+// Returns the mapping of country names localized to |locale| to their
+// corresponding country codes. The provided |collator| should be suitable for
+// the locale. The collator being null is handled gracefully by returning an
+// empty map, to account for the very rare cases when the collator fails to
+// initialize.
+std::map<std::string, std::string> GetLocalizedNames(
+ const std::string& locale,
+ const icu::Collator* collator) {
+ if (!collator)
+ return std::map<std::string, std::string>();
+
+ std::map<std::string, std::string> localized_names;
+ int32_t buffer_size = 1000;
+ scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
+
+ for (const std::string& country_code :
+ CountryDataMap::GetInstance()->country_codes()) {
+ base::string16 country_name =
+ l10n_util::GetDisplayNameForCountry(country_code, locale);
+ std::string sort_key =
+ GetSortKey(*collator, country_name, &buffer, &buffer_size);
+
+ localized_names.insert(std::make_pair(sort_key, country_code));
+ }
+ return localized_names;
+}
+
} // namespace
// static
@@ -81,12 +141,35 @@ CountryNames* CountryNames::GetInstance() {
return base::Singleton<CountryNames>::get();
}
-CountryNames::CountryNames() : common_names_(GetCommonNames()) {}
+// static
+void CountryNames::SetLocaleString(std::string locale) {
+ DCHECK(!locale.empty());
+ // Application locale should never be empty. The empty value of
+ // |g_application_locale| means that it has not been initialized yet.
+ std::string* storage = g_application_locale.Pointer();
+ if (storage->empty()) {
+ *storage = std::move(locale);
+ }
+ // TODO(crbug.com/579971) CountryNames currently cannot adapt to changed
+ // locale without Chrome's restart.
+}
+
+CountryNames::CountryNames(const std::string& locale_name)
+ : locale_(locale_name.c_str()),
+ collator_(CreateCollator(locale_)),
+ default_collator_(CreateDefaultCollator(locale_)),
+ common_names_(GetCommonNames()),
+ localized_names_(GetLocalizedNames(locale_name, collator_.get())),
+ default_localized_names_(
+ GetLocalizedNames("en_US", default_collator_.get())) {}
+
+CountryNames::CountryNames() : CountryNames(g_application_locale.Get()) {
+ DCHECK(!g_application_locale.Get().empty());
+}
CountryNames::~CountryNames() = default;
-const std::string CountryNames::GetCountryCode(const base::string16& country,
- const std::string& locale_name) {
+const std::string CountryNames::GetCountryCode(const base::string16& country) {
// First, check common country names, including 2- and 3-letter country codes.
std::string country_utf8 = base::UTF16ToUTF8(base::ToUpperASCII(country));
const auto result = common_names_.find(country_utf8);
@@ -94,66 +177,33 @@ const std::string CountryNames::GetCountryCode(const base::string16& country,
return result->second;
// Next, check country names localized to the current locale.
- icu::Locale locale(locale_name.c_str());
- std::string country_code = GetCountryCodeForLocalizedName(country, locale);
+ std::string country_code =
+ GetCountryCodeForLocalizedName(country, localized_names_, *collator_);
if (!country_code.empty())
return country_code;
- icu::Locale default_locale("en_US");
// Finally, check country names localized to US English, unless done already.
- if (default_locale != locale)
- return GetCountryCodeForLocalizedName(country, default_locale);
-
- return std::string();
-}
-
-void CountryNames::AddLocalizedNamesForLocale(const std::string& locale,
- const icu::Collator& collator) {
- // Nothing to do if we've previously added the localized names for the given
- // |locale|.
- if (locales_to_localized_names_.count(locale))
- return;
-
- std::map<std::string, std::string> localized_names;
- int32_t buffer_size = 1000;
- scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
-
- for (const std::string& country_code :
- CountryDataMap::GetInstance()->country_codes()) {
- base::string16 country_name =
- l10n_util::GetDisplayNameForCountry(country_code, locale);
- std::string sort_key =
- GetSortKey(collator, country_name, &buffer, &buffer_size);
-
- localized_names.insert(std::make_pair(sort_key, country_code));
+ if (default_collator_) {
+ return GetCountryCodeForLocalizedName(country, default_localized_names_,
+ *default_collator_);
}
- locales_to_localized_names_.insert(std::make_pair(locale, localized_names));
+ return std::string();
}
const std::string CountryNames::GetCountryCodeForLocalizedName(
const base::string16& country_name,
- const icu::Locale& locale) {
- const icu::Collator* collator = GetCollatorForLocale(locale);
- // In very rare cases, the collator fails to initialize.
- if (!collator)
- return std::string();
-
- std::string locale_name = locale.getName();
- AddLocalizedNamesForLocale(locale_name, *collator);
-
+ const std::map<std::string, std::string>& localized_names,
+ const icu::Collator& collator) {
// As recommended[1] by ICU, initialize the buffer size to four times the
// source string length.
// [1] http://userguide.icu-project.org/collation/api#TOC-Examples
int32_t buffer_size = country_name.size() * 4;
scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
std::string sort_key =
- GetSortKey(*collator, country_name, &buffer, &buffer_size);
+ GetSortKey(collator, country_name, &buffer, &buffer_size);
- const std::map<std::string, std::string>& localized_names =
- locales_to_localized_names_[locale_name];
- std::map<std::string, std::string>::const_iterator result =
- localized_names.find(sort_key);
+ auto result = localized_names.find(sort_key);
if (result != localized_names.end())
return result->second;
@@ -161,25 +211,4 @@ const std::string CountryNames::GetCountryCodeForLocalizedName(
return std::string();
}
-const icu::Collator* CountryNames::GetCollatorForLocale(
- const icu::Locale& locale) {
- std::string locale_name = locale.getName();
- if (!ContainsKey(collators_, locale_name)) {
- scoped_ptr<icu::Collator> collator(
- autofill::l10n::GetCollatorForLocale(locale));
- if (!collator)
- return nullptr;
-
- // Compare case-insensitively and ignoring punctuation.
- UErrorCode ignored = U_ZERO_ERROR;
- collator->setAttribute(UCOL_STRENGTH, UCOL_SECONDARY, ignored);
- ignored = U_ZERO_ERROR;
- collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, ignored);
-
- collators_[locale_name] = std::move(collator);
- }
-
- return collators_[locale_name].get();
-}
-
} // namespace autofill
diff --git a/components/autofill/core/browser/country_names.h b/components/autofill/core/browser/country_names.h
index 9ca5937..a073352 100644
--- a/components/autofill/core/browser/country_names.h
+++ b/components/autofill/core/browser/country_names.h
@@ -26,50 +26,67 @@ namespace autofill {
// corresponding country codes.
class CountryNames {
public:
+ // The first call to this function, causing the creation of CountryNames,
+ // is expensive.
static CountryNames* GetInstance();
+ // Tells CountryNames, what is the application locale. Only the first supplied
+ // value is used, further calls result in no changes. Call this on the UI
+ // thread, before first using CountryNames. |locale| must not be empty.
+ static void SetLocaleString(std::string locale);
+
// Returns the country code corresponding to |country|, which should be a
- // country code or country name localized to |locale_name|. This function
- // can be expensive so use judiciously.
- const std::string GetCountryCode(const base::string16& country,
- const std::string& locale_name);
+ // country code or country name localized to |locale_name|.
+ const std::string GetCountryCode(const base::string16& country);
+
+ protected:
+ // Create CountryNames for |locale_name|. Protected for testing.
+ explicit CountryNames(const std::string& locale_name);
+
+ // Protected for testing.
+ ~CountryNames();
private:
+ // Create CountryNames for the default locale.
CountryNames();
- ~CountryNames();
- friend struct base::DefaultSingletonTraits<CountryNames>;
- // Populates |locales_to_localized_names_| with the mapping of country names
- // localized to |locale| to their corresponding country codes. Uses a
- // |collator| which is suitable for the locale.
- void AddLocalizedNamesForLocale(const std::string& locale,
- const icu::Collator& collator);
+ friend struct base::DefaultSingletonTraits<CountryNames>;
- // Interprets |country_name| as a full country name localized to the given
- // |locale| and returns the corresponding country code stored in
- // |locales_to_localized_names_|, or an empty string if there is none.
+ // Looks up |country_name| in |localized_names|, using |collator| and
+ // returns the corresponding country code or an empty string if there is
+ // none.
const std::string GetCountryCodeForLocalizedName(
const base::string16& country_name,
- const icu::Locale& locale);
+ const std::map<std::string, std::string>& localized_names,
+ const icu::Collator& collator);
// Returns an ICU collator -- i.e. string comparator -- appropriate for the
// given |locale|, or null if no collator is available.
const icu::Collator* GetCollatorForLocale(const icu::Locale& locale);
+ // The locale object for the application locale string.
+ const icu::Locale locale_;
+
+ // Collator for the application locale.
+ const scoped_ptr<icu::Collator> collator_;
+
+ // Collator for the "en_US" locale, if different from the application
+ // locale, null otherwise.
+ const scoped_ptr<icu::Collator> default_collator_;
+
// Maps from common country names, including 2- and 3-letter country codes,
// to the corresponding 2-letter country codes. The keys are uppercase ASCII
// strings.
const std::map<std::string, std::string> common_names_;
- // The outer map keys are ICU locale identifiers.
- // The inner maps map from localized country names to their corresponding
- // country codes. The inner map keys are ICU collation sort keys corresponding
- // to the target localized country name.
- std::map<std::string, std::map<std::string, std::string>>
- locales_to_localized_names_;
+ // Maps from localized country names (in the application locale) to their
+ // corresponding country codes. The keys are ICU collation sort keys
+ // corresponding to the target localized country name.
+ const std::map<std::string, std::string> localized_names_;
- // Maps ICU locale names to their corresponding collators.
- std::map<std::string, scoped_ptr<icu::Collator>> collators_;
+ // The same as |localized_names_| but for the "en_US" locale. Empty if
+ // "en_US" is the application locale already.
+ const std::map<std::string, std::string> default_localized_names_;
DISALLOW_COPY_AND_ASSIGN(CountryNames);
};
diff --git a/components/autofill/core/browser/country_names_unittest.cc b/components/autofill/core/browser/country_names_unittest.cc
index 65e0bfd..93c25bc 100644
--- a/components/autofill/core/browser/country_names_unittest.cc
+++ b/components/autofill/core/browser/country_names_unittest.cc
@@ -12,56 +12,66 @@
using base::ASCIIToUTF16;
namespace autofill {
+namespace {
+
+class TestCountryNames : public CountryNames {
+ public:
+ explicit TestCountryNames(const std::string& locale_name)
+ : CountryNames(locale_name) {}
+
+ ~TestCountryNames() = default;
+};
+
+} // namespace
// Test mapping of localized country names to country codes.
-TEST(CountryNamesTest, GetCountryCode) {
- // Basic mapping
- EXPECT_EQ("US", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("United States"), "en_US"));
- EXPECT_EQ("CA", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("Canada"), "en_US"));
+TEST(CountryNamesTest, GetCountryCode_BasicMapping) {
+ TestCountryNames en_us_names("en_US");
+ EXPECT_EQ("US", en_us_names.GetCountryCode(ASCIIToUTF16("United States")));
+ EXPECT_EQ("CA", en_us_names.GetCountryCode(ASCIIToUTF16("Canada")));
+}
- // Case-insensitive mapping
- EXPECT_EQ("US", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("united states"), "en_US"));
+TEST(CountryNamesTest, GetCountryCode_CaseInsensitiveMapping) {
+ EXPECT_EQ("US", TestCountryNames("en_US")
+ .GetCountryCode(ASCIIToUTF16("united states")));
+}
- // Country codes should map to themselves, independent of locale.
- EXPECT_EQ("US", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("US"), "en_US"));
- EXPECT_EQ("HU", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("hu"), "en_US"));
- EXPECT_EQ("CA", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("CA"), "fr_CA"));
- EXPECT_EQ("MX", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("mx"), "fr_CA"));
+TEST(CountryNamesTest, GetCountryCode_CodesMapToThemselves) {
+ TestCountryNames en_us_names("en_US");
+ TestCountryNames fr_ca_names("fr_CA");
+ EXPECT_EQ("US", en_us_names.GetCountryCode(ASCIIToUTF16("US")));
+ EXPECT_EQ("HU", en_us_names.GetCountryCode(ASCIIToUTF16("hu")));
+ EXPECT_EQ("CA", fr_ca_names.GetCountryCode(ASCIIToUTF16("CA")));
+ EXPECT_EQ("MX", fr_ca_names.GetCountryCode(ASCIIToUTF16("mx")));
+}
- // Basic synonyms
- EXPECT_EQ("US", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("United States of America"), "en_US"));
- EXPECT_EQ("US", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("USA"), "en_US"));
+TEST(CountryNamesTest, GetCountryCode_BasicSynonyms) {
+ TestCountryNames en_us_names("en_US");
+ EXPECT_EQ("US", en_us_names.GetCountryCode(
+ ASCIIToUTF16("United States of America")));
+ EXPECT_EQ("US", en_us_names.GetCountryCode(ASCIIToUTF16("USA")));
+}
- // Other locales
- EXPECT_EQ("US", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("Estados Unidos"), "es"));
- EXPECT_EQ("IT", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("Italia"), "it"));
- EXPECT_EQ("DE", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("duitsland"), "nl"));
+TEST(CountryNamesTest, GetCountryCode_OtherLocales) {
+ EXPECT_EQ("US", TestCountryNames("es")
+ .GetCountryCode(ASCIIToUTF16("Estados Unidos")));
+ EXPECT_EQ("IT",
+ TestCountryNames("it").GetCountryCode(ASCIIToUTF16("Italia")));
+ EXPECT_EQ("DE",
+ TestCountryNames("nl").GetCountryCode(ASCIIToUTF16("duitsland")));
+}
- // Should fall back to "en_US" locale if all else fails.
- EXPECT_EQ("US", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("United States"), "es"));
- EXPECT_EQ("US", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("united states"), "es"));
- EXPECT_EQ("US", CountryNames::GetInstance()->GetCountryCode(
- ASCIIToUTF16("USA"), "es"));
+TEST(CountryNamesTest, GetCountryCode_EnUsFallback) {
+ TestCountryNames es_names("es");
+ EXPECT_EQ("US", es_names.GetCountryCode(ASCIIToUTF16("United States")));
+ EXPECT_EQ("US", es_names.GetCountryCode(ASCIIToUTF16("united states")));
+ EXPECT_EQ("US", es_names.GetCountryCode(ASCIIToUTF16("USA")));
}
// Test mapping of empty country name to country code.
TEST(CountryNamesTest, EmptyCountryNameHasEmptyCountryCode) {
std::string country_code =
- CountryNames::GetInstance()->GetCountryCode(base::string16(), "en");
+ TestCountryNames("en").GetCountryCode(base::string16());
EXPECT_TRUE(country_code.empty()) << country_code;
}
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 75888ec..6f6b29a 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -26,6 +26,7 @@
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/country_data.h"
+#include "components/autofill/core/browser/country_names.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/personal_data_manager_observer.h"
#include "components/autofill/core/browser/phone_number.h"
@@ -218,6 +219,8 @@ void PersonalDataManager::Init(scoped_refptr<AutofillWebDataService> database,
AccountTrackerService* account_tracker,
SigninManagerBase* signin_manager,
bool is_off_the_record) {
+ CountryNames::SetLocaleString(app_locale_);
+
database_ = database;
SetPrefService(pref_service);
account_tracker_ = account_tracker;
diff --git a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
index dcbeda2..ef74148 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
@@ -305,8 +305,7 @@ bool AutofillProfileSyncableService::SaveChangesToWebData(
// static
bool AutofillProfileSyncableService::OverwriteProfileWithServerData(
const sync_pb::AutofillProfileSpecifics& specifics,
- AutofillProfile* profile,
- const std::string& app_locale) {
+ AutofillProfile* profile) {
bool diff = false;
if (specifics.has_origin() && profile->origin() != specifics.origin()) {
bool was_verified = profile->IsVerified();
@@ -367,8 +366,8 @@ bool AutofillProfileSyncableService::OverwriteProfileWithServerData(
// version of Chrome).
base::string16 country_name_or_code =
ASCIIToUTF16(specifics.address_home_country());
- std::string country_code = CountryNames::GetInstance()->GetCountryCode(
- country_name_or_code, app_locale);
+ std::string country_code =
+ CountryNames::GetInstance()->GetCountryCode(country_name_or_code);
diff = UpdateField(ADDRESS_HOME_COUNTRY, country_code, profile) || diff;
// Update the street address. In newer versions of Chrome (M34+), this data
@@ -497,8 +496,8 @@ AutofillProfileSyncableService::CreateOrUpdateProfile(
autofill_specifics.guid());
if (existing_profile != profile_map->end()) {
// The synced profile already exists locally. It might need to be updated.
- if (OverwriteProfileWithServerData(
- autofill_specifics, existing_profile->second, app_locale_)) {
+ if (OverwriteProfileWithServerData(autofill_specifics,
+ existing_profile->second)) {
bundle->profiles_to_update.push_back(existing_profile->second);
}
return existing_profile;
@@ -507,7 +506,7 @@ AutofillProfileSyncableService::CreateOrUpdateProfile(
// New profile synced.
AutofillProfile* new_profile = new AutofillProfile(
autofill_specifics.guid(), autofill_specifics.origin());
- OverwriteProfileWithServerData(autofill_specifics, new_profile, app_locale_);
+ OverwriteProfileWithServerData(autofill_specifics, new_profile);
// Check if profile appears under a different guid. Compares only profile
// contents. (Ignores origin and language code in comparison.)
diff --git a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
index 3c069d9..757ff7f 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
+++ b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
@@ -129,8 +129,7 @@ class AutofillProfileSyncableService
// |specifics|.
static bool OverwriteProfileWithServerData(
const sync_pb::AutofillProfileSpecifics& specifics,
- AutofillProfile* profile,
- const std::string& app_locale);
+ AutofillProfile* profile);
// Writes |profile| data into supplied |profile_specifics|.
static void WriteAutofillProfile(const AutofillProfile& profile,
diff --git a/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc b/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
index e218103..0558211 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
@@ -11,6 +11,7 @@
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/country_names.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
#include "sync/api/sync_error_factory.h"
#include "sync/api/sync_error_factory_mock.h"
@@ -209,7 +210,9 @@ syncer::SyncData ConstructCompleteSyncData() {
class AutofillProfileSyncableServiceTest : public testing::Test {
public:
- AutofillProfileSyncableServiceTest() {}
+ AutofillProfileSyncableServiceTest() {
+ CountryNames::SetLocaleString("en-US");
+ }
void SetUp() override { sync_processor_.reset(new MockSyncChangeProcessor); }