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

[Autofill][Leipzig] Merging of structured addresses.

This CL adds merging support of structured address tokens.
When two profiles are merged, the substructure that corresponds
to address line that is merged into the new profile is used.
If the feature |kAutofillAddressEnhancementVotes| is disabled,
the structure is dropped in the merging process.

Change-Id: Ifc24c0a65b40fad0ae32b1001cc6560ad946cb6b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2353267
Commit-Queue: Matthias Körber <koerber@google.com>
Reviewed-by: default avatarChristoph Schwering <schwering@google.com>
Cr-Commit-Position: refs/heads/master@{#798578}
parent f0a14007
......@@ -30,36 +30,29 @@ namespace autofill {
using structured_address::VerificationStatus;
Address::Address() {}
Address::Address() = default;
Address::Address(const Address& address) {
*this = address;
}
Address::~Address() {}
Address::Address(const Address& address) = default;
Address& Address::operator=(const Address& address) {
if (this == &address)
return *this;
Address::~Address() = default;
street_address_ = address.street_address_;
dependent_locality_ = address.dependent_locality_;
city_ = address.city_;
state_ = address.state_;
country_code_ = address.country_code_;
zip_code_ = address.zip_code_;
sorting_code_ = address.sorting_code_;
return *this;
}
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.
return street_address_ == other.street_address_ &&
dependent_locality_ == other.dependent_locality_ &&
city_ == other.city_ && state_ == other.state_ &&
zip_code_ == other.zip_code_ && sorting_code_ == other.sorting_code_ &&
country_code_ == other.country_code_;
country_code_ == other.country_code_ &&
street_name_ == other.street_name_ &&
dependent_street_name_ == other.dependent_street_name_ &&
house_number_ == other.house_number_ &&
premise_name_ == other.premise_name_ &&
subpremise_ == other.subpremise_;
}
base::string16 Address::GetRawInfo(ServerFieldType type) const {
......
......@@ -188,6 +188,25 @@ int32_t NormalizingIterator::GetNextChar() {
return iter_.get();
}
// Copies the address line information and structured tokens from |source| to
// |target|.
void CopyAddressLineInformationFromProfile(const AutofillProfile& source,
Address* target) {
ServerFieldTypeSet types_to_copy;
if (base::FeatureList::IsEnabled(
features::kAutofillAddressEnhancementVotes)) {
types_to_copy = {
ADDRESS_HOME_STREET_ADDRESS, ADDRESS_HOME_STREET_NAME,
ADDRESS_HOME_DEPENDENT_STREET_NAME, ADDRESS_HOME_HOUSE_NUMBER,
ADDRESS_HOME_PREMISE_NAME, ADDRESS_HOME_SUBPREMISE};
} else {
types_to_copy = {ADDRESS_HOME_STREET_ADDRESS};
}
for (const auto& type : types_to_copy)
target->SetRawInfo(type, source.GetRawInfo(type));
}
} // namespace
AutofillProfileComparator::AutofillProfileComparator(
......@@ -791,17 +810,17 @@ bool AutofillProfileComparator::MergeAddresses(const AutofillProfile& p1,
const base::string16& address2 = p2.GetInfo(kStreetAddress, app_locale_);
// If one of the addresses is empty then use the other.
if (address1.empty()) {
address->SetInfo(kStreetAddress, address2, app_locale_);
CopyAddressLineInformationFromProfile(p2, address);
} else if (address2.empty()) {
address->SetInfo(kStreetAddress, address1, app_locale_);
CopyAddressLineInformationFromProfile(p1, address);
} else {
// Prefer the multi-line address if one is multi-line and the other isn't.
bool address1_multiline = ContainsNewline(address1);
bool address2_multiline = ContainsNewline(address2);
if (address1_multiline && !address2_multiline) {
address->SetInfo(kStreetAddress, address1, app_locale_);
CopyAddressLineInformationFromProfile(p1, address);
} else if (address2_multiline && !address1_multiline) {
address->SetInfo(kStreetAddress, address2, app_locale_);
CopyAddressLineInformationFromProfile(p2, address);
} else {
// Prefer the one with more tokens if they're both single-line or both
// multi-line addresses, making sure to apply address normalization and
......@@ -812,19 +831,20 @@ bool AutofillProfileComparator::MergeAddresses(const AutofillProfile& p1,
switch (result) {
case SAME_TOKENS:
// They have the same set of unique tokens. Let's pick the one that's
// longer.
address->SetInfo(
kStreetAddress,
(p2.use_date() > p1.use_date() ? address2 : address1),
app_locale_);
// newer.
if (p2.use_date() > p1.use_date()) {
CopyAddressLineInformationFromProfile(p2, address);
} else {
CopyAddressLineInformationFromProfile(p1, address);
}
break;
case S1_CONTAINS_S2:
// address1 has more unique tokens than address2.
address->SetInfo(kStreetAddress, address1, app_locale_);
CopyAddressLineInformationFromProfile(p1, address);
break;
case S2_CONTAINS_S1:
// address2 has more unique tokens than address1.
address->SetInfo(kStreetAddress, address2, app_locale_);
CopyAddressLineInformationFromProfile(p2, address);
break;
case DIFFERENT_TOKENS:
default:
......
......@@ -59,8 +59,9 @@ namespace {
const char kLocale[] = "en-US";
class AutofillProfileComparatorTest : public testing::Test,
public testing::WithParamInterface<bool> {
class AutofillProfileComparatorTest
: public testing::Test,
public testing::WithParamInterface<std::tuple<bool, bool>> {
public:
// Expose the protected methods of autofill::AutofillProfileComparator for
// testing.
......@@ -288,6 +289,29 @@ class AutofillProfileComparatorTest : public testing::Test,
actual.GetInfo(AutofillType(ADDRESS_HOME_ZIP), kLocale));
EXPECT_EQ(expected.GetInfo(AutofillType(ADDRESS_HOME_COUNTRY), kLocale),
actual.GetInfo(AutofillType(ADDRESS_HOME_COUNTRY), kLocale));
EXPECT_EQ(expected.GetInfo(AutofillType(autofill::ADDRESS_HOME_STREET_NAME),
kLocale),
actual.GetInfo(AutofillType(autofill::ADDRESS_HOME_STREET_NAME),
kLocale));
EXPECT_EQ(expected.GetInfo(
AutofillType(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME),
kLocale),
actual.GetInfo(
AutofillType(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME),
kLocale));
EXPECT_EQ(expected.GetInfo(
AutofillType(autofill::ADDRESS_HOME_HOUSE_NUMBER), kLocale),
actual.GetInfo(AutofillType(autofill::ADDRESS_HOME_HOUSE_NUMBER),
kLocale));
EXPECT_EQ(expected.GetInfo(
AutofillType(autofill::ADDRESS_HOME_PREMISE_NAME), kLocale),
actual.GetInfo(AutofillType(autofill::ADDRESS_HOME_PREMISE_NAME),
kLocale));
EXPECT_EQ(expected.GetInfo(AutofillType(autofill::ADDRESS_HOME_SUBPREMISE),
kLocale),
actual.GetInfo(AutofillType(autofill::ADDRESS_HOME_SUBPREMISE),
kLocale));
}
AutofillProfileComparator comparator_{kLocale};
......@@ -296,17 +320,36 @@ class AutofillProfileComparatorTest : public testing::Test,
void SetUp() override { InitializeFeatures(); }
void InitializeFeatures() {
structured_names_enabled_ = GetParam();
structured_names_enabled_ = std::get<0>(GetParam());
address_enhancement_votes_enabled_ = std::get<1>(GetParam());
std::vector<base::Feature> enabled_features;
std::vector<base::Feature> disabled_features;
if (structured_names_enabled_) {
scoped_features_.InitAndEnableFeature(
enabled_features.push_back(
autofill::features::kAutofillEnableSupportForMoreStructureInNames);
} else {
scoped_features_.InitAndDisableFeature(
disabled_features.push_back(
autofill::features::kAutofillEnableSupportForMoreStructureInNames);
}
if (address_enhancement_votes_enabled_) {
enabled_features.push_back(
autofill::features::kAutofillAddressEnhancementVotes);
} else {
disabled_features.push_back(
autofill::features::kAutofillAddressEnhancementVotes);
}
scoped_features_.InitWithFeatures(enabled_features, disabled_features);
}
bool StructuredNames() const { return structured_names_enabled_; }
bool AddressEnhancementVotes() const {
return address_enhancement_votes_enabled_;
}
bool address_enhancement_votes_enabled_;
bool structured_names_enabled_;
base::test::ScopedFeatureList scoped_features_;
......@@ -1167,9 +1210,33 @@ TEST_P(AutofillProfileComparatorTest, MergeAddresses) {
TEST_P(AutofillProfileComparatorTest, MergeAddressesMostUniqueTokens) {
AutofillProfile p1 = CreateProfileWithAddress(
"1 Some Street", "Unit 3", "Carver", "CA - California", "90210", "US");
p1.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
base::UTF8ToUTF16("StreetName"));
p1.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::UTF8ToUTF16("DependentStreetName"));
p1.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
base::UTF8ToUTF16("HouseNumber"));
p1.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
base::UTF8ToUTF16("PremiseName"));
p1.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
base::UTF8ToUTF16("Subpremise"));
AutofillProfile p2 = CreateProfileWithAddress(
"1 Some Other Street", "Unit 3", "Carver City", "ca", "90210-1234", "us");
p2.set_use_date(p1.use_date() + base::TimeDelta::FromMinutes(1));
p2.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
base::UTF8ToUTF16("StreetName2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::UTF8ToUTF16("DependentStreetName2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
base::UTF8ToUTF16("HouseNumber2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
base::UTF8ToUTF16("PremiseName2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
base::UTF8ToUTF16("Subpremise2"));
Address expected;
expected.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("1 Some Other Street"));
expected.SetRawInfo(ADDRESS_HOME_LINE2, UTF8ToUTF16("Unit 3"));
......@@ -1178,6 +1245,78 @@ TEST_P(AutofillProfileComparatorTest, MergeAddressesMostUniqueTokens) {
expected.SetRawInfo(ADDRESS_HOME_ZIP, UTF8ToUTF16("90210-1234"));
expected.SetRawInfo(ADDRESS_HOME_COUNTRY, UTF8ToUTF16("US"));
// If address enhancement votes are enabled, it is expecfted that the
// substructure from p2 since it is a superset of p1.
// Otherwise the fields are expected to be empty after the merge process.
if (AddressEnhancementVotes()) {
expected.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
base::UTF8ToUTF16("StreetName2"));
expected.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::UTF8ToUTF16("DependentStreetName2"));
expected.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
base::UTF8ToUTF16("HouseNumber2"));
expected.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
base::UTF8ToUTF16("PremiseName2"));
expected.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
base::UTF8ToUTF16("Subpremise2"));
}
MergeAddressesAndExpect(p1, p2, expected);
MergeAddressesAndExpect(p2, p1, expected);
}
TEST_P(AutofillProfileComparatorTest, MergeAddressesWithStructure) {
AutofillProfile p1 = CreateProfileWithAddress(
"6543 CH BACON", "APP 3", "MONTRÉAL", "QUÉBEC", "HHH999", "ca");
p1.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
base::UTF8ToUTF16("StreetName"));
p1.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::UTF8ToUTF16("DependentStreetName"));
p1.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
base::UTF8ToUTF16("HouseNumber"));
p1.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
base::UTF8ToUTF16("PremiseName"));
p1.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
base::UTF8ToUTF16("Subpremise"));
AutofillProfile p2 = CreateProfileWithAddress(
"6543, Bacon Rd", "", "Montreal", "QC", "hhh 999", "CA");
p2.set_use_date(p1.use_date() + base::TimeDelta::FromMinutes(1));
p2.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
base::UTF8ToUTF16("StreetName2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::UTF8ToUTF16("DependentStreetName2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
base::UTF8ToUTF16("HouseNumber2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
base::UTF8ToUTF16("PremiseName2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
base::UTF8ToUTF16("Subpremise2"));
Address expected;
expected.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("6543 CH BACON"));
expected.SetRawInfo(ADDRESS_HOME_LINE2, UTF8ToUTF16("APP 3"));
expected.SetRawInfo(ADDRESS_HOME_CITY, UTF8ToUTF16("Montreal"));
expected.SetRawInfo(ADDRESS_HOME_STATE, UTF8ToUTF16("QC"));
expected.SetRawInfo(ADDRESS_HOME_ZIP, UTF8ToUTF16("hhh 999"));
expected.SetRawInfo(ADDRESS_HOME_COUNTRY, UTF8ToUTF16("CA"));
// If address enhancement votes are enabled, it is expecfted that the
// substructure from p1 is used since it is most recent.
// Otherwise the fields are expected to be empty after the merge process.
if (AddressEnhancementVotes()) {
expected.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
base::UTF8ToUTF16("StreetName"));
expected.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::UTF8ToUTF16("DependentStreetName"));
expected.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
base::UTF8ToUTF16("HouseNumber"));
expected.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
base::UTF8ToUTF16("PremiseName"));
expected.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
base::UTF8ToUTF16("Subpremise"));
}
MergeAddressesAndExpect(p1, p2, expected);
MergeAddressesAndExpect(p2, p1, expected);
}
......@@ -1185,8 +1324,31 @@ TEST_P(AutofillProfileComparatorTest, MergeAddressesMostUniqueTokens) {
TEST_P(AutofillProfileComparatorTest, MergeAddressesWithRewrite) {
AutofillProfile p1 = CreateProfileWithAddress(
"6543 CH BACON", "APP 3", "MONTRÉAL", "QUÉBEC", "HHH999", "ca");
p1.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
base::UTF8ToUTF16("StreetName"));
p1.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::UTF8ToUTF16("DependentStreetName"));
p1.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
base::UTF8ToUTF16("HouseNumber"));
p1.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
base::UTF8ToUTF16("PremiseName"));
p1.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
base::UTF8ToUTF16("Subpremise"));
AutofillProfile p2 = CreateProfileWithAddress(
"6543, Bacon Rd", "", "Montreal", "QC", "hhh 999", "CA");
p2.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
base::UTF8ToUTF16("StreetName2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::UTF8ToUTF16("DependentStreetName2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
base::UTF8ToUTF16("HouseNumber2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
base::UTF8ToUTF16("PremiseName2"));
p2.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
base::UTF8ToUTF16("Subpremise2"));
p2.set_use_date(p1.use_date() + base::TimeDelta::FromMinutes(1));
Address expected;
......@@ -1197,6 +1359,21 @@ TEST_P(AutofillProfileComparatorTest, MergeAddressesWithRewrite) {
expected.SetRawInfo(ADDRESS_HOME_ZIP, UTF8ToUTF16("hhh 999"));
expected.SetRawInfo(ADDRESS_HOME_COUNTRY, UTF8ToUTF16("CA"));
// If address enhancement votes are enabled, it is expecfted that the
// substructure from p1 is used since it has more tokens.
if (AddressEnhancementVotes()) {
expected.SetRawInfo(autofill::ADDRESS_HOME_STREET_NAME,
base::UTF8ToUTF16("StreetName"));
expected.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_STREET_NAME,
base::UTF8ToUTF16("DependentStreetName"));
expected.SetRawInfo(autofill::ADDRESS_HOME_HOUSE_NUMBER,
base::UTF8ToUTF16("HouseNumber"));
expected.SetRawInfo(autofill::ADDRESS_HOME_PREMISE_NAME,
base::UTF8ToUTF16("PremiseName"));
expected.SetRawInfo(autofill::ADDRESS_HOME_SUBPREMISE,
base::UTF8ToUTF16("Subpremise"));
}
MergeAddressesAndExpect(p1, p2, expected);
MergeAddressesAndExpect(p2, p1, expected);
}
......@@ -1233,4 +1410,6 @@ TEST_P(AutofillProfileComparatorTest,
INSTANTIATE_TEST_SUITE_P(
All,
AutofillProfileComparatorTest,
testing::Bool()); // Test with and without structured names.
testing::Combine(testing::Bool(),
testing::Bool())); // Test with and without structured
// names and address enhancement votes.
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