Commit 63a521a3 authored by Matthias Körber's avatar Matthias Körber Committed by Commit Bot

[Autofill][Leipzig] Integrate structured address into AutofillProfile

This CL adds the structured address representation into the
AutofillProfile and implements functions to test the mergeability,
invoke the merging and return the structured address tree.

Bug: 1128367
Change-Id: I0c8704c49b59170261359478b03208f072ee83ee
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2418409Reviewed-by: default avatarDominic Battré <battre@chromium.org>
Commit-Queue: Matthias Körber <koerber@google.com>
Cr-Commit-Position: refs/heads/master@{#808812}
parent f92938c9
......@@ -20,6 +20,7 @@
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/autofill_profile_comparator.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
#include "components/autofill/core/browser/geo/autofill_country.h"
#include "components/autofill/core/browser/geo/country_names.h"
#include "components/autofill/core/browser/geo/state_names.h"
......@@ -41,8 +42,12 @@ Address& Address::operator=(const Address& address) = default;
bool Address::operator==(const Address& other) const {
if (this == &other)
return true;
// Note that the structured address tokens are not evaluated for profile
// comparison.
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
if (structured_address::StructuredAddressesEnabled()) {
return structured_address_ == other.structured_address_;
}
return street_address_ == other.street_address_ &&
dependent_locality_ == other.dependent_locality_ &&
city_ == other.city_ && state_ == other.state_ &&
......@@ -55,8 +60,38 @@ bool Address::operator==(const Address& other) const {
subpremise_ == other.subpremise_;
}
bool Address::FinalizeAfterImport(bool profile_is_verified) {
// TODO(crbug.com/1130194): Remove feature check once structured addresses are
// fully launched.
if (structured_address::StructuredAddressesEnabled()) {
structured_address_.MigrateLegacyStructure(profile_is_verified);
return structured_address_.CompleteFullTree();
}
return true;
}
bool Address::MergeStructuredAddress(const Address& newer,
bool newer_was_more_recently_used) {
return structured_address_.MergeWithComponent(newer.GetStructuredAddress(),
newer_was_more_recently_used);
}
bool Address::IsStructuredAddressMergeable(const Address& newer) const {
return structured_address_.IsMergeableWithComponent(
newer.GetStructuredAddress());
}
const structured_address::Address& Address::GetStructuredAddress() const {
return structured_address_;
}
base::string16 Address::GetRawInfo(ServerFieldType type) const {
DCHECK_EQ(ADDRESS_HOME, AutofillType(type).group());
// For structured addresses, the value can be directly retrieved.
if (structured_address::StructuredAddressesEnabled())
return structured_address_.GetValueForType(type);
switch (type) {
case ADDRESS_HOME_LINE1:
return street_address_.size() > 0 ? street_address_[0] : base::string16();
......@@ -118,6 +153,15 @@ void Address::SetRawInfoWithVerificationStatus(ServerFieldType type,
const base::string16& value,
VerificationStatus status) {
DCHECK_EQ(ADDRESS_HOME, AutofillType(type).group());
// For structured addresses, the value can directly be set.
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
if (structured_address::StructuredAddressesEnabled()) {
structured_address_.SetValueForTypeIfPossible(type, value, status);
return;
}
switch (type) {
// If any of the address lines change, the structured tokens must be
// reset.
......@@ -226,11 +270,21 @@ void Address::GetMatchingTypes(const base::string16& text,
ServerFieldTypeSet* matching_types) const {
FormGroup::GetMatchingTypes(text, app_locale, matching_types);
// Check to see if the |text| canonicalized as a country name is a match.
// Get the country code stored in the profile either from the structured
// address if enabled or from the legacy field.
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
std::string country_code =
structured_address::StructuredAddressesEnabled()
? base::UTF16ToUTF8(
structured_address_.GetValueForType(ADDRESS_HOME_COUNTRY))
: country_code_;
// Check to see if the |text| canonicalized as a country name is a match.
std::string entered_country_code =
CountryNames::GetInstance()->GetCountryCodeForLocalizedCountryName(
text, app_locale);
if (!country_code.empty() && country_code_ == country_code)
if (!entered_country_code.empty() && country_code == entered_country_code)
matching_types->insert(ADDRESS_HOME_COUNTRY);
AutofillProfileComparator comparator(app_locale);
......@@ -267,7 +321,8 @@ void Address::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
supported_types->insert(ADDRESS_HOME_COUNTRY);
// If those types are not added, no votes will be generated.
if (base::FeatureList::IsEnabled(
features::kAutofillAddressEnhancementVotes)) {
features::kAutofillAddressEnhancementVotes) ||
structured_address::StructuredAddressesEnabled()) {
supported_types->insert(ADDRESS_HOME_STREET_NAME);
supported_types->insert(ADDRESS_HOME_DEPENDENT_STREET_NAME);
supported_types->insert(ADDRESS_HOME_HOUSE_NUMBER);
......@@ -278,12 +333,23 @@ void Address::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
base::string16 Address::GetInfoImpl(const AutofillType& type,
const std::string& locale) const {
if (type.html_type() == HTML_TYPE_COUNTRY_CODE)
return base::ASCIIToUTF16(country_code_);
// Get the country code stored in the profile either from the structured
// address if enabled or from the legacy field.
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
std::string country_code =
structured_address::StructuredAddressesEnabled()
? base::UTF16ToUTF8(
structured_address_.GetValueForType(ADDRESS_HOME_COUNTRY))
: country_code_;
if (type.html_type() == HTML_TYPE_COUNTRY_CODE) {
return base::ASCIIToUTF16(country_code);
}
ServerFieldType storable_type = type.GetStorableType();
if (storable_type == ADDRESS_HOME_COUNTRY && !country_code_.empty())
return AutofillCountry(country_code_, locale).name();
if (storable_type == ADDRESS_HOME_COUNTRY && !country_code.empty())
return AutofillCountry(country_code, locale).name();
return GetRawInfo(storable_type);
}
......@@ -292,8 +358,14 @@ bool Address::SetInfoWithVerificationStatusImpl(const AutofillType& type,
const base::string16& value,
const std::string& locale,
VerificationStatus status) {
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
bool use_structured_address =
structured_address::StructuredAddressesEnabled();
if (type.html_type() == HTML_TYPE_COUNTRY_CODE) {
if (!data_util::IsValidCountryCode(base::i18n::ToUpper(value))) {
std::string country_code = base::ToUpperASCII(base::UTF16ToASCII(value));
if (!data_util::IsValidCountryCode(country_code)) {
// Some popular websites use the HTML_TYPE_COUNTRY_CODE attribute for
// full text names (e.g. alliedelec.com). Try to convert the value to a
// country code as a fallback.
......@@ -301,20 +373,27 @@ bool Address::SetInfoWithVerificationStatusImpl(const AutofillType& type,
features::kAutofillAllowHtmlTypeCountryCodesWithFullNames)) {
CountryNames* country_names =
!value.empty() ? CountryNames::GetInstance() : nullptr;
country_code_ =
country_code =
country_names
? country_names->GetCountryCodeForLocalizedCountryName(value,
locale)
: std::string();
return !country_code_.empty();
} else {
country_code_ = std::string();
return false;
country_code = std::string();
}
}
country_code_ = base::ToUpperASCII(base::UTF16ToASCII(value));
return true;
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
if (use_structured_address) {
structured_address_.SetValueForTypeIfPossible(ADDRESS_HOME_COUNTRY,
country_code, status);
} else {
country_code_ = country_code;
}
return !country_code.empty();
}
if (type.html_type() == HTML_TYPE_FULL_ADDRESS) {
// Parsing a full address is too hard.
return false;
......@@ -322,9 +401,17 @@ bool Address::SetInfoWithVerificationStatusImpl(const AutofillType& type,
ServerFieldType storable_type = type.GetStorableType();
if (storable_type == ADDRESS_HOME_COUNTRY && !value.empty()) {
country_code_ =
std::string country_code =
CountryNames::GetInstance()->GetCountryCodeForLocalizedCountryName(
value, locale);
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
if (use_structured_address) {
structured_address_.SetValueForTypeIfPossible(ADDRESS_HOME_COUNTRY,
country_code, status);
} else {
country_code_ = country_code;
}
return !country_code_.empty();
}
......@@ -333,15 +420,30 @@ bool Address::SetInfoWithVerificationStatusImpl(const AutofillType& type,
// Give up when importing addresses with any entirely blank lines.
// There's a good chance that this formatting is not intentional, but it's
// also not obviously safe to just strip the newlines.
if (storable_type == ADDRESS_HOME_STREET_ADDRESS &&
base::Contains(street_address_, base::string16())) {
street_address_.clear();
return false;
if (storable_type == ADDRESS_HOME_STREET_ADDRESS) {
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
if (structured_address::StructuredAddressesEnabled()) {
return structured_address_.IsValueForTypeValid(
ADDRESS_HOME_STREET_ADDRESS, /*wipe_if_not=*/true);
} else if (base::Contains(street_address_, base::string16())) {
street_address_.clear();
return false;
}
}
return true;
}
VerificationStatus Address::GetVerificationStatusImpl(
ServerFieldType type) const {
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
if (structured_address::StructuredAddressesEnabled())
return structured_address_.GetVerificationStatusForType(type);
return VerificationStatus::kNoStatus;
}
void Address::TrimStreetAddress() {
while (!street_address_.empty() && street_address_.back().empty()) {
street_address_.pop_back();
......
......@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/strings/string16.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address.h"
#include "components/autofill/core/browser/data_model/form_group.h"
namespace autofill {
......@@ -37,6 +38,27 @@ class Address : public FormGroup {
void ResetStructuredTokes();
// Derives all missing tokens in the structured representation of the address
// either parsing missing tokens from their assigned parent or by formatting
// them from their assigned children.
bool FinalizeAfterImport(bool profile_is_verified);
// Convenience wrapper to invoke finalization for unverified profiles.
bool FinalizeAfterImport() { return FinalizeAfterImport(false); }
// For structured addresses, merges |newer| into |this|. For some values
// within the structured address tree the more recently used profile gets
// precedence. |newer_was_more_recently_used| indicates if the newer was also
// more recently used.
bool MergeStructuredAddress(const Address& newer,
bool newer_was_more_recently_used);
// For structured addresses, returns true if |this| is mergeable with |newer|.
bool IsStructuredAddressMergeable(const Address& newer) const;
// Returns a constant reference to |structured_address_|.
const structured_address::Address& GetStructuredAddress() const;
private:
// FormGroup:
void GetSupportedTypes(ServerFieldTypeSet* supported_types) const override;
......@@ -48,9 +70,15 @@ class Address : public FormGroup {
const std::string& locale,
structured_address::VerificationStatus status) override;
// Return the verification status of a structured name value.
structured_address::VerificationStatus GetVerificationStatusImpl(
ServerFieldType type) const override;
// Trims any trailing newlines from |street_address_|.
void TrimStreetAddress();
// TODO(crbug.com/1130194): Clean legacy implementation once structured
// addresses are fully launched.
// The lines of the street address.
std::vector<base::string16> street_address_;
// A subdivision of city, e.g. inner-city district or suburb.
......@@ -73,6 +101,10 @@ class Address : public FormGroup {
// The ISO 3166 2-letter country code, or an empty string if there is no
// country data specified for this address.
std::string country_code_;
// This data structure holds the address information if the structured address
// feature is enabled.
structured_address::Address structured_address_;
};
} // namespace autofill
......
......@@ -20,14 +20,34 @@ using base::ASCIIToUTF16;
namespace autofill {
class AddressTest : public testing::Test {
class AddressTest : public testing::Test,
public testing::WithParamInterface<bool> {
public:
AddressTest() { CountryNames::SetLocaleString("en-US"); }
bool StructuredAddresses() const { return structured_addresses_enabled_; }
private:
void SetUp() override { InitializeFeatures(); }
void InitializeFeatures() {
structured_addresses_enabled_ = GetParam();
if (structured_addresses_enabled_) {
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillEnableSupportForMoreStructureInAddresses);
} else {
scoped_feature_list_.InitAndDisableFeature(
features::kAutofillEnableSupportForMoreStructureInAddresses);
}
}
bool structured_addresses_enabled_;
base::test::ScopedFeatureList scoped_feature_list_;
};
// Test that country data can be properly returned as either a country code or a
// localized country name.
TEST_F(AddressTest, GetCountry) {
TEST_P(AddressTest, GetCountry) {
Address address;
EXPECT_EQ(base::string16(), address.GetRawInfo(ADDRESS_HOME_COUNTRY));
......@@ -60,7 +80,7 @@ TEST_F(AddressTest, GetCountry) {
// Test that country data can be properly returned as either a country code or a
// full country name that can even be localized.
TEST_F(AddressTest, SetHtmlCountryCodeTypeWithFullCountryName) {
TEST_P(AddressTest, SetHtmlCountryCodeTypeWithFullCountryName) {
Address address;
EXPECT_EQ(base::string16(), address.GetRawInfo(ADDRESS_HOME_COUNTRY));
......@@ -126,7 +146,7 @@ TEST_F(AddressTest, SetHtmlCountryCodeTypeWithFullCountryName) {
}
// Test that we properly detect country codes appropriate for each country.
TEST_F(AddressTest, SetCountry) {
TEST_P(AddressTest, SetCountry) {
Address address;
EXPECT_EQ(base::string16(), address.GetRawInfo(ADDRESS_HOME_COUNTRY));
......@@ -189,119 +209,176 @@ TEST_F(AddressTest, SetCountry) {
}
// Test setting and getting the new structured address tokens
TEST_F(AddressTest, StructuredAddressTokens){
TEST_P(AddressTest, StructuredAddressTokens) {
// Activate the feature to support the new structured address tokens.
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kAutofillAddressEnhancementVotes);
scoped_feature_list.InitAndEnableFeature(
features::kAutofillAddressEnhancementVotes);
Address address;
// Set the address tokens.
address.SetRawInfo(ADDRESS_HOME_STREET_NAME, base::ASCIIToUTF16("StreetName"));
address.SetRawInfo(ADDRESS_HOME_HOUSE_NUMBER, base::ASCIIToUTF16("HouseNumber"));
address.SetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME, base::ASCIIToUTF16("DependentStreetName"));
address.SetRawInfo(ADDRESS_HOME_PREMISE_NAME, base::ASCIIToUTF16("PremiseNmae"));
address.SetRawInfo(ADDRESS_HOME_STREET_NAME,
base::ASCIIToUTF16("StreetName"));
address.SetRawInfo(ADDRESS_HOME_HOUSE_NUMBER,
base::ASCIIToUTF16("HouseNumber"));
address.SetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::ASCIIToUTF16("DependentStreetName"));
address.SetRawInfo(ADDRESS_HOME_PREMISE_NAME,
base::ASCIIToUTF16("PremiseNmae"));
address.SetRawInfo(ADDRESS_HOME_SUBPREMISE, base::ASCIIToUTF16("SubPremise"));
// Retrieve the tokens and verify that they are correct.
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME), base::ASCIIToUTF16("StreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER), base::ASCIIToUTF16("HouseNumber"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME), base::ASCIIToUTF16("DependentStreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME), base::ASCIIToUTF16("PremiseNmae"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE), base::ASCIIToUTF16("SubPremise"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),
base::ASCIIToUTF16("StreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
base::ASCIIToUTF16("HouseNumber"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),
base::ASCIIToUTF16("DependentStreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME),
base::ASCIIToUTF16("PremiseNmae"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE),
base::ASCIIToUTF16("SubPremise"));
}
// Test setting and getting the new structured address tokens
TEST_F(AddressTest, StructuredAddressTokens_ResetOnChangedUnstructuredInformation){
// Activate the feature to support the new structured address tokens.
TEST_P(AddressTest,
StructuredAddressTokens_ResetOnChangedUnstructuredInformation) {
// Activate the feature to support the new structured address tokens for
// voting. The feature to actively support structured addresses must be turned
// of.
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kAutofillAddressEnhancementVotes);
scoped_feature_list.InitWithFeatures(
{features::kAutofillAddressEnhancementVotes},
{features::kAutofillEnableSupportForMoreStructureInAddresses});
Address address;
// Set the address tokens.
address.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, base::ASCIIToUTF16("Line1\nLine2"));
address.SetRawInfo(ADDRESS_HOME_STREET_NAME, base::ASCIIToUTF16("StreetName"));
address.SetRawInfo(ADDRESS_HOME_HOUSE_NUMBER, base::ASCIIToUTF16("HouseNumber"));
address.SetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME, base::ASCIIToUTF16("DependentStreetName"));
address.SetRawInfo(ADDRESS_HOME_PREMISE_NAME, base::ASCIIToUTF16("PremiseNmae"));
address.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
base::ASCIIToUTF16("Line1\nLine2"));
address.SetRawInfo(ADDRESS_HOME_STREET_NAME,
base::ASCIIToUTF16("StreetName"));
address.SetRawInfo(ADDRESS_HOME_HOUSE_NUMBER,
base::ASCIIToUTF16("HouseNumber"));
address.SetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::ASCIIToUTF16("DependentStreetName"));
address.SetRawInfo(ADDRESS_HOME_PREMISE_NAME,
base::ASCIIToUTF16("PremiseNmae"));
address.SetRawInfo(ADDRESS_HOME_SUBPREMISE, base::ASCIIToUTF16("SubPremise"));
// Retrieve the tokens and verify that they are correct.
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE1), base::ASCIIToUTF16("Line1"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE2), base::ASCIIToUTF16("Line2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS), base::ASCIIToUTF16("Line1\nLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME), base::ASCIIToUTF16("StreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER), base::ASCIIToUTF16("HouseNumber"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME), base::ASCIIToUTF16("DependentStreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME), base::ASCIIToUTF16("PremiseNmae"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE), base::ASCIIToUTF16("SubPremise"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE1),
base::ASCIIToUTF16("Line1"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE2),
base::ASCIIToUTF16("Line2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS),
base::ASCIIToUTF16("Line1\nLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),
base::ASCIIToUTF16("StreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
base::ASCIIToUTF16("HouseNumber"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),
base::ASCIIToUTF16("DependentStreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME),
base::ASCIIToUTF16("PremiseNmae"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE),
base::ASCIIToUTF16("SubPremise"));
// Set the unstructured address information to the same values as they already
// are.
address.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, base::ASCIIToUTF16("Line1\nLine2"));
address.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
base::ASCIIToUTF16("Line1\nLine2"));
address.SetRawInfo(ADDRESS_HOME_LINE1, base::ASCIIToUTF16("Line1"));
address.SetRawInfo(ADDRESS_HOME_LINE2, base::ASCIIToUTF16("Line2"));
// Verify that the structured tokens are still set.
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME), base::ASCIIToUTF16("StreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER), base::ASCIIToUTF16("HouseNumber"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME), base::ASCIIToUTF16("DependentStreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME), base::ASCIIToUTF16("PremiseNmae"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE), base::ASCIIToUTF16("SubPremise"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),
base::ASCIIToUTF16("StreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),
base::ASCIIToUTF16("HouseNumber"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),
base::ASCIIToUTF16("DependentStreetName"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME),
base::ASCIIToUTF16("PremiseNmae"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE),
base::ASCIIToUTF16("SubPremise"));
// Now, change the address by changing HOME_ADDRESS_LINE1 and verify that the
// structured tokens are reset.
address.SetRawInfo(ADDRESS_HOME_LINE1, base::ASCIIToUTF16("NewLine1"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE1), base::ASCIIToUTF16("NewLine1"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE2), base::ASCIIToUTF16("Line2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS), base::ASCIIToUTF16("NewLine1\nLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE1),
base::ASCIIToUTF16("NewLine1"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE2),
base::ASCIIToUTF16("Line2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS),
base::ASCIIToUTF16("NewLine1\nLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME), base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER), base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),
base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME), base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE), base::string16());
// Reset the structured tokens and perform the same step for
// HOME_ADDRESS_LINE2.
address.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, base::ASCIIToUTF16("Line1\nLine2"));
address.SetRawInfo(ADDRESS_HOME_STREET_NAME, base::ASCIIToUTF16("StreetName"));
address.SetRawInfo(ADDRESS_HOME_HOUSE_NUMBER, base::ASCIIToUTF16("HouseNumber"));
address.SetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME, base::ASCIIToUTF16("DependentStreetName"));
address.SetRawInfo(ADDRESS_HOME_PREMISE_NAME, base::ASCIIToUTF16("PremiseNmae"));
address.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
base::ASCIIToUTF16("Line1\nLine2"));
address.SetRawInfo(ADDRESS_HOME_STREET_NAME,
base::ASCIIToUTF16("StreetName"));
address.SetRawInfo(ADDRESS_HOME_HOUSE_NUMBER,
base::ASCIIToUTF16("HouseNumber"));
address.SetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::ASCIIToUTF16("DependentStreetName"));
address.SetRawInfo(ADDRESS_HOME_PREMISE_NAME,
base::ASCIIToUTF16("PremiseNmae"));
address.SetRawInfo(ADDRESS_HOME_SUBPREMISE, base::ASCIIToUTF16("SubPremise"));
address.SetRawInfo(ADDRESS_HOME_LINE2, base::ASCIIToUTF16("NewLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE1), base::ASCIIToUTF16("Line1"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE2), base::ASCIIToUTF16("NewLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS), base::ASCIIToUTF16("Line1\nNewLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE1),
base::ASCIIToUTF16("Line1"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE2),
base::ASCIIToUTF16("NewLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS),
base::ASCIIToUTF16("Line1\nNewLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME), base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER), base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),
base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME), base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE), base::string16());
// And once again for ADDRESS_HOME_STREET_ADDRESS.
address.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, base::ASCIIToUTF16("Line1\nLine2"));
address.SetRawInfo(ADDRESS_HOME_STREET_NAME, base::ASCIIToUTF16("StreetName"));
address.SetRawInfo(ADDRESS_HOME_HOUSE_NUMBER, base::ASCIIToUTF16("HouseNumber"));
address.SetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME, base::ASCIIToUTF16("DependentStreetName"));
address.SetRawInfo(ADDRESS_HOME_PREMISE_NAME, base::ASCIIToUTF16("PremiseNmae"));
address.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
base::ASCIIToUTF16("Line1\nLine2"));
address.SetRawInfo(ADDRESS_HOME_STREET_NAME,
base::ASCIIToUTF16("StreetName"));
address.SetRawInfo(ADDRESS_HOME_HOUSE_NUMBER,
base::ASCIIToUTF16("HouseNumber"));
address.SetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::ASCIIToUTF16("DependentStreetName"));
address.SetRawInfo(ADDRESS_HOME_PREMISE_NAME,
base::ASCIIToUTF16("PremiseNmae"));
address.SetRawInfo(ADDRESS_HOME_SUBPREMISE, base::ASCIIToUTF16("SubPremise"));
address.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, base::ASCIIToUTF16("NewLine1\nNewLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE1), base::ASCIIToUTF16("NewLine1"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE2), base::ASCIIToUTF16("NewLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS), base::ASCIIToUTF16("NewLine1\nNewLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME),base::string16() );
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE),base::string16() );
address.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
base::ASCIIToUTF16("NewLine1\nNewLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE1),
base::ASCIIToUTF16("NewLine1"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_LINE2),
base::ASCIIToUTF16("NewLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS),
base::ASCIIToUTF16("NewLine1\nNewLine2"));
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_STREET_NAME), base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER), base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_DEPENDENT_STREET_NAME),
base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_PREMISE_NAME), base::string16());
EXPECT_EQ(address.GetRawInfo(ADDRESS_HOME_SUBPREMISE), base::string16());
}
// Test that we properly match typed values to stored country data.
TEST_F(AddressTest, IsCountry) {
TEST_P(AddressTest, IsCountry) {
Address address;
address.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
......@@ -332,7 +409,7 @@ TEST_F(AddressTest, IsCountry) {
}
// Verifies that Address::GetInfo() correctly combines address lines.
TEST_F(AddressTest, GetStreetAddress) {
TEST_P(AddressTest, GetStreetAddress) {
const AutofillType type = AutofillType(ADDRESS_HOME_STREET_ADDRESS);
// Address has no address lines.
......@@ -392,7 +469,7 @@ TEST_F(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_F(AddressTest, GetStreetAddressAfterOverwritingLongAddressWithShorterOne) {
TEST_P(AddressTest, GetStreetAddressAfterOverwritingLongAddressWithShorterOne) {
// Start with an address that has two lines.
Address address;
address.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("123 Example Ave."));
......@@ -409,7 +486,7 @@ TEST_F(AddressTest, GetStreetAddressAfterOverwritingLongAddressWithShorterOne) {
}
// Verifies that Address::SetRawInfo() is able to split address lines correctly.
TEST_F(AddressTest, SetRawStreetAddress) {
TEST_P(AddressTest, SetRawStreetAddress) {
const base::string16 empty_street_address;
const base::string16 short_street_address = ASCIIToUTF16("456 Nowhere Ln.");
const base::string16 long_street_address = ASCIIToUTF16(
......@@ -442,7 +519,7 @@ TEST_F(AddressTest, SetRawStreetAddress) {
}
// Street addresses should be set properly.
TEST_F(AddressTest, SetStreetAddress) {
TEST_P(AddressTest, SetStreetAddress) {
const base::string16 empty_street_address;
const base::string16 multi_line_street_address = ASCIIToUTF16(
"789 Fancy Pkwy.\n"
......@@ -488,7 +565,7 @@ TEST_F(AddressTest, SetStreetAddress) {
// Verifies that Address::SetInfio() rejects setting data for
// ADDRESS_HOME_STREET_ADDRESS if the data has any interior blank lines.
TEST_F(AddressTest, SetStreetAddressRejectsAddressesWithInteriorBlankLines) {
TEST_P(AddressTest, SetStreetAddressRejectsAddressesWithInteriorBlankLines) {
// Start with a non-empty address.
Address address;
address.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("123 Example Ave."));
......@@ -511,7 +588,7 @@ TEST_F(AddressTest, SetStreetAddressRejectsAddressesWithInteriorBlankLines) {
// Verifies that Address::SetInfio() rejects setting data for
// ADDRESS_HOME_STREET_ADDRESS if the data has any leading blank lines.
TEST_F(AddressTest, SetStreetAddressRejectsAddressesWithLeadingBlankLines) {
TEST_P(AddressTest, SetStreetAddressRejectsAddressesWithLeadingBlankLines) {
// Start with a non-empty address.
Address address;
address.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("123 Example Ave."));
......@@ -534,7 +611,7 @@ TEST_F(AddressTest, SetStreetAddressRejectsAddressesWithLeadingBlankLines) {
// Verifies that Address::SetInfio() rejects setting data for
// ADDRESS_HOME_STREET_ADDRESS if the data has any trailing blank lines.
TEST_F(AddressTest, SetStreetAddressRejectsAddressesWithTrailingBlankLines) {
TEST_P(AddressTest, SetStreetAddressRejectsAddressesWithTrailingBlankLines) {
// Start with a non-empty address.
Address address;
address.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("123 Example Ave."));
......@@ -555,4 +632,65 @@ TEST_F(AddressTest, SetStreetAddressRejectsAddressesWithTrailingBlankLines) {
EXPECT_EQ(base::string16(), address.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS));
}
// Verifies that the merging-related methods for structured addresses are
// implemented correctly. This is not a test of the merging logic itself.
TEST_P(AddressTest, TestMergeStructuredAddresses) {
// This test is only applicable for structured addresses.
if (!StructuredAddresses())
return;
Address address1;
Address address2;
// Two empty addresses are mergeable by default.
EXPECT_TRUE(address1.IsStructuredAddressMergeable(address2));
// The two zip codes have a is-substring relation and are mergeable.
address1.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("12345"));
address2.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("1234"));
EXPECT_TRUE(address2.IsStructuredAddressMergeable(address1));
EXPECT_TRUE(address1.IsStructuredAddressMergeable(address2));
// The merging should maintain the value because address2 is not more
// recently used.
address1.MergeStructuredAddress(address2,
/*newer_use_more_recently_used=*/false);
EXPECT_EQ(address1.GetRawInfo(ADDRESS_HOME_ZIP), base::UTF8ToUTF16("12345"));
// Once it is more recently used, the value from address2 should be copied
// into address1.
address1.MergeStructuredAddress(address2,
/*newer_use_more_recently_used=*/true);
EXPECT_EQ(address1.GetRawInfo(ADDRESS_HOME_ZIP), base::UTF8ToUTF16("1234"));
// With a second incompatible ZIP code the addresses are not mergeable
// anymore.
Address address3;
address3.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("67890"));
EXPECT_FALSE(address1.IsStructuredAddressMergeable(address3));
}
// Tests the retrieval of the structured address.
TEST_P(AddressTest, TestGettingTheStructuredAddress) {
// This test is only applicable for structured addresses.
if (!StructuredAddresses())
return;
// Create the address and set a test value.
Address address1;
address1.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16("12345"));
// Get the structured address and verify that it has the same test value set.
structured_address::Address structured_address =
address1.GetStructuredAddress();
EXPECT_EQ(structured_address.GetValueForType(ADDRESS_HOME_ZIP),
base::UTF8ToUTF16("12345"));
}
// Runs the suite with the feature
// |kAutofillSupportForStructuredStructuredNames| enabled and disabled.
// TODO(crbug.com/1130194): Remove parameterized test once structured addresses
// are fully launched.
INSTANTIATE_TEST_SUITE_P(, AddressTest, testing::Bool());
} // namespace autofill
......@@ -461,8 +461,11 @@ int AutofillProfile::Compare(const AutofillProfile& profile) const {
return 1;
}
// TODO(crbug.com/1130194): Remove feature check once structured addresses are
// fully launched.
if (base::FeatureList::IsEnabled(
features::kAutofillAddressEnhancementVotes)) {
features::kAutofillAddressEnhancementVotes) ||
structured_address::StructuredAddressesEnabled()) {
const ServerFieldType new_types[] = {
ADDRESS_HOME_HOUSE_NUMBER,
ADDRESS_HOME_STREET_NAME,
......@@ -1342,6 +1345,21 @@ std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
<< UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1)) << " "
<< UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2)) << " "
<< UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE3)) << " "
<< UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)) << " "
<< "("
<< base::NumberToString(
profile.GetVerificationStatusInt(ADDRESS_HOME_STREET_ADDRESS))
<< ") " << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STREET_NAME))
<< " "
<< "("
<< base::NumberToString(
profile.GetVerificationStatusInt(ADDRESS_HOME_STREET_NAME))
<< ") " << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_HOUSE_NUMBER))
<< " "
<< "("
<< base::NumberToString(
profile.GetVerificationStatusInt(ADDRESS_HOME_HOUSE_NUMBER))
<< ") "
<< UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))
<< " " << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY)) << " "
<< UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE)) << " "
......@@ -1359,6 +1377,8 @@ bool AutofillProfile::FinalizeAfterImport() {
bool success = true;
if (!name_.FinalizeAfterImport(IsVerified()))
success = false;
if (!address_.FinalizeAfterImport(IsVerified()))
success = false;
return success;
}
......
......@@ -296,6 +296,9 @@ class AutofillProfile : public AutofillDataModel {
// Returns a constant reference to the |name_| field.
const NameInfo& GetNameInfo() const { return name_; }
// Returns a constant reference to the |address_| field.
const Address& GetAddress() const { return address_; }
private:
typedef std::vector<const FormGroup*> FormGroupList;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment