Commit eb9e9ed6 authored by Hui(Andy) Wu's avatar Hui(Andy) Wu Committed by Commit Bot

[Autofill] Move phone number rationalization to filling phase.

Current rationalization logic of phone numbers runs in fields detection
phase, where the fields' is_focusable state might be obselete. The
rationalization use this state to determine if the logic will run.

Some form have phone fields initally non-focusable, then present them
dynamically, the rationalization will skip those fields. Moving the logic
to filling phase should address this issue.

Bug: 784935
Change-Id: I579a3dab6efad3c2f09a72562b8ae7ab4c376311
Reviewed-on: https://chromium-review.googlesource.com/768295Reviewed-by: default avatarRoger McFarlane <rogerm@chromium.org>
Reviewed-by: default avatarSebastien Seguin-Gagnon <sebsg@chromium.org>
Commit-Queue: Hui Wu <wuandy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#517159}
parent 52a9831d
...@@ -129,6 +129,8 @@ static_library("browser") { ...@@ -129,6 +129,8 @@ static_library("browser") {
"phone_number_i18n.cc", "phone_number_i18n.cc",
"phone_number_i18n.h", "phone_number_i18n.h",
"popup_item_ids.h", "popup_item_ids.h",
"rationalization_util.cc",
"rationalization_util.h",
"region_combobox_model.cc", "region_combobox_model.cc",
"region_combobox_model.h", "region_combobox_model.h",
"region_data_loader.h", "region_data_loader.h",
...@@ -398,6 +400,7 @@ source_set("unit_tests") { ...@@ -398,6 +400,7 @@ source_set("unit_tests") {
"phone_field_unittest.cc", "phone_field_unittest.cc",
"phone_number_i18n_unittest.cc", "phone_number_i18n_unittest.cc",
"phone_number_unittest.cc", "phone_number_unittest.cc",
"rationalization_util_unittest.cc",
"region_combobox_model_unittest.cc", "region_combobox_model_unittest.cc",
"subkey_requester_unittest.cc", "subkey_requester_unittest.cc",
"ui/card_unmask_prompt_controller_impl_unittest.cc", "ui/card_unmask_prompt_controller_impl_unittest.cc",
......
...@@ -1398,6 +1398,11 @@ void AutofillManager::FillOrPreviewDataModelForm( ...@@ -1398,6 +1398,11 @@ void AutofillManager::FillOrPreviewDataModelForm(
} }
DCHECK_EQ(form_structure->field_count(), form.fields.size()); DCHECK_EQ(form_structure->field_count(), form.fields.size());
if (base::FeatureList::IsEnabled(kAutofillRationalizeFieldTypePredictions)) {
form_structure->RationalizePhoneNumbersInSection(autofill_field->section());
}
for (size_t i = 0; i < form_structure->field_count(); ++i) { for (size_t i = 0; i < form_structure->field_count(); ++i) {
if (form_structure->field(i)->section() != autofill_field->section()) if (form_structure->field(i)->section() != autofill_field->section())
continue; continue;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "components/autofill/core/browser/field_candidates.h" #include "components/autofill/core/browser/field_candidates.h"
#include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_field.h" #include "components/autofill/core/browser/form_field.h"
#include "components/autofill/core/browser/rationalization_util.h"
#include "components/autofill/core/browser/validation.h" #include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/autofill_util.h"
...@@ -303,151 +304,6 @@ bool AllTypesCaptured(const FormStructure& form, ...@@ -303,151 +304,6 @@ bool AllTypesCaptured(const FormStructure& form,
return true; return true;
} }
// Helper function that rationalizes phone numbers fields in the given
// vector of fields. The vector of fields are expected to have all fields
// for a certain section.
void RationalizePhoneNumberFieldPredictionsInSection(
std::vector<AutofillField*>* fields_in_section) {
AutofillField* found_number_field = nullptr;
AutofillField* found_number_field_second = nullptr;
AutofillField* found_city_code_field = nullptr;
AutofillField* found_country_code_field = nullptr;
AutofillField* found_city_and_number_field = nullptr;
AutofillField* found_whole_number_field = nullptr;
bool phone_number_found = false;
bool phone_number_separate_fields = false;
// Iterate through all given fields. Iteration stops when it first finds a
// valid set of fields that can compose a whole number. The |found_*| pointers
// will be set to that set of fields when iteration finishes.
for (AutofillField* field : *fields_in_section) {
if (!field->is_focusable)
continue;
ServerFieldType current_field_type = field->Type().GetStorableType();
switch (current_field_type) {
case PHONE_HOME_NUMBER:
case PHONE_BILLING_NUMBER:
if (!found_number_field) {
found_number_field = field;
if (field->max_length < 5) {
phone_number_separate_fields = true;
} else {
phone_number_found = true;
}
break;
}
// If the form has phone number separated into exchange and subscriber
// number we mark both of them as number fields.
// TODO(wuandy): A less hacky solution to have dedicated enum for
// exchange and subscriber number.
DCHECK(phone_number_separate_fields);
DCHECK(!found_number_field_second);
found_number_field_second = field;
phone_number_found = true;
break;
case PHONE_HOME_CITY_CODE:
case PHONE_BILLING_CITY_CODE:
if (!found_city_code_field)
found_city_code_field = field;
break;
case PHONE_HOME_COUNTRY_CODE:
case PHONE_BILLING_COUNTRY_CODE:
if (!found_country_code_field)
found_country_code_field = field;
break;
case PHONE_HOME_CITY_AND_NUMBER:
case PHONE_BILLING_CITY_AND_NUMBER:
DCHECK(!phone_number_found && !found_city_and_number_field);
found_city_and_number_field = field;
phone_number_found = true;
break;
case PHONE_HOME_WHOLE_NUMBER:
case PHONE_BILLING_WHOLE_NUMBER:
DCHECK(!phone_number_found && !found_whole_number_field);
found_whole_number_field = field;
phone_number_found = true;
break;
default:
break;
}
if (phone_number_found)
break;
}
// The first number of found may be the whole number field, the
// city and number field, or neither. But it cannot be both.
DCHECK(!(found_whole_number_field && found_city_and_number_field));
// Prefer to fill the first complete phone number found. The whole number
// and city_and_number fields are only set if they represent the first
// complete number found; otherwise, a complete number is present as
// component input fields. These scenarios are mutually exclusive, so
// clean up any inconsistencies.
if (found_whole_number_field) {
found_number_field = nullptr;
found_number_field_second = nullptr;
found_city_code_field = nullptr;
found_country_code_field = nullptr;
} else if (found_city_and_number_field) {
found_number_field = nullptr;
found_number_field_second = nullptr;
found_city_code_field = nullptr;
}
// A second update pass.
// At this point, either |phone_number_found| is false and we should do a
// best-effort filling for the field whose types we have seen a first time.
// Or |phone_number_found| is true and the pointers to the fields that
// compose the first valid phone number are set to not-NULL, specifically:
// 1. |found_whole_number_field| is not NULL, other pointers set to NULL, or
// 2. |found_city_and_number_field| is not NULL, |found_country_code_field| is
// probably not NULL, and other pointers set to NULL, or
// 3. |found_city_code_field| and |found_number_field| are not NULL,
// |found_country_code_field| is probably not NULL, and other pointers are
// NULL.
// 4. |found_city_code_field|, |found_number_field| and
// |found_number_field_second|
// are not NULL, |found_country_code_field| is probably not NULL, and other
// pointers are NULL.
// For all above cases, in the update pass, if one field is phone
// number related but not one of the found fields from first pass, set their
// |only_fill_when_focused| field to true.
for (auto it = fields_in_section->begin(); it != fields_in_section->end();
++it) {
AutofillField* field = *it;
ServerFieldType current_field_type = field->Type().GetStorableType();
switch (current_field_type) {
case PHONE_HOME_NUMBER:
case PHONE_BILLING_NUMBER:
if (field != found_number_field && field != found_number_field_second)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_CITY_CODE:
case PHONE_BILLING_CITY_CODE:
if (field != found_city_code_field)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_COUNTRY_CODE:
case PHONE_BILLING_COUNTRY_CODE:
if (field != found_country_code_field)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_CITY_AND_NUMBER:
case PHONE_BILLING_CITY_AND_NUMBER:
if (field != found_city_and_number_field)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_WHOLE_NUMBER:
case PHONE_BILLING_WHOLE_NUMBER:
if (field != found_whole_number_field)
field->set_only_fill_when_focused(true);
break;
default:
break;
}
}
}
} // namespace } // namespace
FormStructure::FormStructure(const FormData& form) FormStructure::FormStructure(const FormData& form)
...@@ -1326,20 +1182,21 @@ void FormStructure::RationalizeCreditCardFieldPredictions() { ...@@ -1326,20 +1182,21 @@ void FormStructure::RationalizeCreditCardFieldPredictions() {
} }
} }
void FormStructure::RationalizePhoneNumberFieldPredictions() { void FormStructure::RationalizePhoneNumbersInSection(std::string section) {
auto section_to_fields_map = if (phone_rationalized_[section])
std::map<std::string, std::vector<AutofillField*>>(); return;
for (const auto& field : fields_) { std::vector<AutofillField*> fields;
section_to_fields_map[field->section()].push_back(field.get()); for (size_t i = 0; i < field_count(); ++i) {
} if (field(i)->section() != section)
for (auto& it : section_to_fields_map) { continue;
RationalizePhoneNumberFieldPredictionsInSection(&it.second); fields.push_back(field(i));
} }
rationalization_util::RationalizePhoneNumberFields(fields);
phone_rationalized_[section] = true;
} }
void FormStructure::RationalizeFieldTypePredictions() { void FormStructure::RationalizeFieldTypePredictions() {
RationalizeCreditCardFieldPredictions(); RationalizeCreditCardFieldPredictions();
RationalizePhoneNumberFieldPredictions();
} }
void FormStructure::EncodeFormForQuery( void FormStructure::EncodeFormForQuery(
......
...@@ -24,11 +24,7 @@ ...@@ -24,11 +24,7 @@
#include "components/autofill/core/browser/proto/server.pb.h" #include "components/autofill/core/browser/proto/server.pb.h"
#include "url/gurl.h" #include "url/gurl.h"
enum UploadRequired { enum UploadRequired { UPLOAD_NOT_REQUIRED, UPLOAD_REQUIRED, USE_UPLOAD_RATES };
UPLOAD_NOT_REQUIRED,
UPLOAD_REQUIRED,
USE_UPLOAD_RATES
};
namespace base { namespace base {
class TimeTicks; class TimeTicks;
...@@ -167,6 +163,10 @@ class FormStructure { ...@@ -167,6 +163,10 @@ class FormStructure {
// the contents of a text input or the currently selected <option>. // the contents of a text input or the currently selected <option>.
base::string16 GetUniqueValue(HtmlFieldType type) const; base::string16 GetUniqueValue(HtmlFieldType type) const;
// Rationalize phone number fields in a given section, that is only fill
// the fields that are considered composing a first complete phone number.
void RationalizePhoneNumbersInSection(std::string section);
const AutofillField* field(size_t index) const; const AutofillField* field(size_t index) const;
AutofillField* field(size_t index); AutofillField* field(size_t index);
size_t field_count() const; size_t field_count() const;
...@@ -239,17 +239,13 @@ class FormStructure { ...@@ -239,17 +239,13 @@ class FormStructure {
friend class FormStructureTest; friend class FormStructureTest;
FRIEND_TEST_ALL_PREFIXES(AutofillDownloadTest, QueryAndUploadTest); FRIEND_TEST_ALL_PREFIXES(AutofillDownloadTest, QueryAndUploadTest);
FRIEND_TEST_ALL_PREFIXES(FormStructureTest, FindLongestCommonPrefix); FRIEND_TEST_ALL_PREFIXES(FormStructureTest, FindLongestCommonPrefix);
FRIEND_TEST_ALL_PREFIXES(FormStructureTest,
RationalizePhoneNumber_RunsOncePerSection);
// A function to fine tune the credit cards related predictions. For example: // A function to fine tune the credit cards related predictions. For example:
// lone credit card fields in an otherwise non-credit-card related form is // lone credit card fields in an otherwise non-credit-card related form is
// unlikely to be correct, the function will override that prediction. // unlikely to be correct, the function will override that prediction.
void RationalizeCreditCardFieldPredictions(); void RationalizeCreditCardFieldPredictions();
// A function that detects if predictions suggest there are more phone fields
// than one valid phone number can fill, then mark those extranous fields
// as fill-only-when-user-highlight.
void RationalizePhoneNumberFieldPredictions();
// A helper function to review the predictions and do appropriate adjustments // A helper function to review the predictions and do appropriate adjustments
// when it considers neccessary. // when it considers neccessary.
void RationalizeFieldTypePredictions(); void RationalizeFieldTypePredictions();
...@@ -350,6 +346,9 @@ class FormStructure { ...@@ -350,6 +346,9 @@ class FormStructure {
// When a form is parsed on this page. // When a form is parsed on this page.
base::TimeTicks form_parsed_timestamp_; base::TimeTicks form_parsed_timestamp_;
// If phone number rationalization has been performed for a given section.
std::map<std::string, bool> phone_rationalized_;
DISALLOW_COPY_AND_ASSIGN(FormStructure); DISALLOW_COPY_AND_ASSIGN(FormStructure);
}; };
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill/core/browser/rationalization_util.h"
#include "base/logging.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_type.h"
namespace autofill {
namespace rationalization_util {
void RationalizePhoneNumberFields(
std::vector<AutofillField*>& fields_in_section) {
AutofillField* found_number_field = nullptr;
AutofillField* found_number_field_second = nullptr;
AutofillField* found_city_code_field = nullptr;
AutofillField* found_country_code_field = nullptr;
AutofillField* found_city_and_number_field = nullptr;
AutofillField* found_whole_number_field = nullptr;
bool phone_number_found = false;
bool phone_number_separate_fields = false;
// Iterate through all given fields. Iteration stops when it first finds a
// valid set of fields that can compose a whole number. The |found_*| pointers
// will be set to that set of fields when iteration finishes.
for (AutofillField* field : fields_in_section) {
if (!field->is_focusable)
continue;
ServerFieldType current_field_type = field->Type().GetStorableType();
switch (current_field_type) {
case PHONE_HOME_NUMBER:
case PHONE_BILLING_NUMBER:
if (!found_number_field) {
found_number_field = field;
if (field->max_length < 5) {
phone_number_separate_fields = true;
} else {
phone_number_found = true;
}
break;
}
// If the form has phone number separated into exchange and subscriber
// number we mark both of them as number fields.
// TODO(wuandy): A less hacky solution to have dedicated enum for
// exchange and subscriber number.
DCHECK(phone_number_separate_fields);
DCHECK(!found_number_field_second);
found_number_field_second = field;
phone_number_found = true;
break;
case PHONE_HOME_CITY_CODE:
case PHONE_BILLING_CITY_CODE:
if (!found_city_code_field)
found_city_code_field = field;
break;
case PHONE_HOME_COUNTRY_CODE:
case PHONE_BILLING_COUNTRY_CODE:
if (!found_country_code_field)
found_country_code_field = field;
break;
case PHONE_HOME_CITY_AND_NUMBER:
case PHONE_BILLING_CITY_AND_NUMBER:
DCHECK(!phone_number_found && !found_city_and_number_field);
found_city_and_number_field = field;
phone_number_found = true;
break;
case PHONE_HOME_WHOLE_NUMBER:
case PHONE_BILLING_WHOLE_NUMBER:
DCHECK(!phone_number_found && !found_whole_number_field);
found_whole_number_field = field;
phone_number_found = true;
break;
default:
break;
}
if (phone_number_found)
break;
}
// The first number of found may be the whole number field, the
// city and number field, or neither. But it cannot be both.
DCHECK(!(found_whole_number_field && found_city_and_number_field));
// Prefer to fill the first complete phone number found. The whole number
// and city_and_number fields are only set if they represent the first
// complete number found; otherwise, a complete number is present as
// component input fields. These scenarios are mutually exclusive, so
// clean up any inconsistencies.
if (found_whole_number_field) {
found_number_field = nullptr;
found_number_field_second = nullptr;
found_city_code_field = nullptr;
found_country_code_field = nullptr;
} else if (found_city_and_number_field) {
found_number_field = nullptr;
found_number_field_second = nullptr;
found_city_code_field = nullptr;
}
// A second update pass.
// At this point, either |phone_number_found| is false and we should do a
// best-effort filling for the field whose types we have seen a first time.
// Or |phone_number_found| is true and the pointers to the fields that
// compose the first valid phone number are set to not-NULL, specifically:
// 1. |found_whole_number_field| is not NULL, other pointers set to NULL, or
// 2. |found_city_and_number_field| is not NULL, |found_country_code_field| is
// probably not NULL, and other pointers set to NULL, or
// 3. |found_city_code_field| and |found_number_field| are not NULL,
// |found_country_code_field| is probably not NULL, and other pointers are
// NULL.
// 4. |found_city_code_field|, |found_number_field| and
// |found_number_field_second|
// are not NULL, |found_country_code_field| is probably not NULL, and other
// pointers are NULL.
// For all above cases, in the update pass, if one field is phone
// number related but not one of the found fields from first pass, set their
// |only_fill_when_focused| field to true.
for (auto it = fields_in_section.begin(); it != fields_in_section.end();
++it) {
AutofillField* field = *it;
ServerFieldType current_field_type = field->Type().GetStorableType();
switch (current_field_type) {
case PHONE_HOME_NUMBER:
case PHONE_BILLING_NUMBER:
if (field != found_number_field && field != found_number_field_second)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_CITY_CODE:
case PHONE_BILLING_CITY_CODE:
if (field != found_city_code_field)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_COUNTRY_CODE:
case PHONE_BILLING_COUNTRY_CODE:
if (field != found_country_code_field)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_CITY_AND_NUMBER:
case PHONE_BILLING_CITY_AND_NUMBER:
if (field != found_city_and_number_field)
field->set_only_fill_when_focused(true);
break;
case PHONE_HOME_WHOLE_NUMBER:
case PHONE_BILLING_WHOLE_NUMBER:
if (field != found_whole_number_field)
field->set_only_fill_when_focused(true);
break;
default:
break;
}
}
}
} // namespace rationalization_util
} // namespace autofill
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_RATIONALIZATION_UTIL_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_RATIONALIZATION_UTIL_H_
#include <vector>
namespace autofill {
class AutofillField;
namespace rationalization_util {
// Helper function that rationalizes phone numbers fields in the given
// vector of fields. The vector of fields are expected to have all fields
// for a certain section.
void RationalizePhoneNumberFields(
std::vector<AutofillField*>& fields_in_section);
} // namespace rationalization_util
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_RATIONALIZATION_UTIL_H_
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill/core/browser/rationalization_util.h"
#include <stddef.h>
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
using base::StringToInt;
using base::UTF8ToUTF16;
namespace autofill {
class AutofillRationalizationUtilTest : public testing::Test {};
TEST_F(AutofillRationalizationUtilTest, PhoneNumber_FirstNumberIsWholeNumber) {
std::vector<AutofillField*> field_list;
AutofillField field0;
field0.SetTypeTo(NAME_FULL);
field_list.push_back(&field0);
AutofillField field1;
field1.SetTypeTo(ADDRESS_HOME_LINE1);
field_list.push_back(&field1);
AutofillField field2;
field2.SetTypeTo(PHONE_HOME_WHOLE_NUMBER);
field_list.push_back(&field2);
AutofillField field3;
field3.SetTypeTo(PHONE_HOME_CITY_AND_NUMBER);
field_list.push_back(&field3);
rationalization_util::RationalizePhoneNumberFields(field_list);
EXPECT_FALSE(field_list[0]->only_fill_when_focused());
EXPECT_FALSE(field_list[1]->only_fill_when_focused());
EXPECT_FALSE(field_list[2]->only_fill_when_focused());
EXPECT_TRUE(field_list[3]->only_fill_when_focused());
}
TEST_F(AutofillRationalizationUtilTest,
PhoneNumber_FirstNumberIsComponentized) {
std::vector<AutofillField*> field_list;
AutofillField field0;
field0.SetTypeTo(NAME_FULL);
field_list.push_back(&field0);
AutofillField field1;
field1.SetTypeTo(ADDRESS_HOME_LINE1);
field_list.push_back(&field1);
AutofillField field2;
field2.max_length = 2;
field2.SetTypeTo(PHONE_HOME_COUNTRY_CODE);
field_list.push_back(&field2);
AutofillField field3;
field3.max_length = 3;
field3.SetTypeTo(PHONE_HOME_CITY_CODE);
field_list.push_back(&field3);
AutofillField field4;
field4.max_length = 7;
field4.SetTypeTo(PHONE_HOME_NUMBER);
field_list.push_back(&field4);
AutofillField field5;
field5.max_length = 2;
field5.SetTypeTo(PHONE_HOME_COUNTRY_CODE);
field_list.push_back(&field5);
AutofillField field6;
field6.max_length = 3;
field6.SetTypeTo(PHONE_HOME_CITY_CODE);
field_list.push_back(&field6);
AutofillField field7;
field7.max_length = 7;
field7.SetTypeTo(PHONE_HOME_NUMBER);
field_list.push_back(&field7);
rationalization_util::RationalizePhoneNumberFields(field_list);
EXPECT_FALSE(field_list[0]->only_fill_when_focused());
EXPECT_FALSE(field_list[1]->only_fill_when_focused());
EXPECT_FALSE(field_list[2]->only_fill_when_focused());
EXPECT_FALSE(field_list[3]->only_fill_when_focused());
EXPECT_FALSE(field_list[4]->only_fill_when_focused());
EXPECT_TRUE(field_list[5]->only_fill_when_focused());
EXPECT_TRUE(field_list[6]->only_fill_when_focused());
EXPECT_TRUE(field_list[7]->only_fill_when_focused());
}
TEST_F(AutofillRationalizationUtilTest,
PhoneNumber_BestEffortWhenNoCompleteNumberIsFound) {
std::vector<AutofillField*> field_list;
AutofillField field0;
field0.SetTypeTo(NAME_FULL);
field_list.push_back(&field0);
AutofillField field1;
field1.SetTypeTo(ADDRESS_HOME_LINE1);
field_list.push_back(&field1);
AutofillField field2;
field2.SetTypeTo(PHONE_HOME_COUNTRY_CODE);
field_list.push_back(&field2);
AutofillField field3;
field3.SetTypeTo(PHONE_HOME_CITY_CODE);
field_list.push_back(&field3);
rationalization_util::RationalizePhoneNumberFields(field_list);
EXPECT_FALSE(field_list[0]->only_fill_when_focused());
EXPECT_FALSE(field_list[1]->only_fill_when_focused());
EXPECT_FALSE(field_list[2]->only_fill_when_focused());
EXPECT_FALSE(field_list[3]->only_fill_when_focused());
}
TEST_F(AutofillRationalizationUtilTest, PhoneNumber_FillPhonePartsOnceOnly) {
std::vector<AutofillField*> field_list;
AutofillField field0;
field0.SetTypeTo(NAME_FULL);
field_list.push_back(&field0);
AutofillField field1;
field1.SetTypeTo(ADDRESS_HOME_LINE1);
field_list.push_back(&field1);
AutofillField field2;
field2.SetTypeTo(PHONE_HOME_CITY_CODE);
field_list.push_back(&field2);
AutofillField field3;
field3.max_length = 10;
field3.SetTypeTo(PHONE_HOME_NUMBER);
field_list.push_back(&field3);
AutofillField field4;
field4.max_length = 12;
field4.SetTypeTo(PHONE_HOME_WHOLE_NUMBER);
field_list.push_back(&field4);
AutofillField field5;
field5.SetTypeTo(PHONE_HOME_CITY_CODE);
field_list.push_back(&field5);
rationalization_util::RationalizePhoneNumberFields(field_list);
EXPECT_FALSE(field_list[0]->only_fill_when_focused());
EXPECT_FALSE(field_list[1]->only_fill_when_focused());
EXPECT_FALSE(field_list[2]->only_fill_when_focused());
EXPECT_FALSE(field_list[3]->only_fill_when_focused());
EXPECT_TRUE(field_list[4]->only_fill_when_focused());
EXPECT_TRUE(field_list[5]->only_fill_when_focused());
}
TEST_F(AutofillRationalizationUtilTest,
PhoneNumber_SkipHiddenPhoneNumberFields) {
std::vector<AutofillField*> field_list;
AutofillField field0;
field0.SetTypeTo(NAME_FULL);
field_list.push_back(&field0);
AutofillField field1;
field1.SetTypeTo(ADDRESS_HOME_LINE1);
field_list.push_back(&field1);
AutofillField field2;
field2.is_focusable = false;
field2.SetTypeTo(PHONE_HOME_CITY_AND_NUMBER);
field_list.push_back(&field2);
AutofillField field3;
field3.SetTypeTo(PHONE_HOME_WHOLE_NUMBER);
field_list.push_back(&field3);
rationalization_util::RationalizePhoneNumberFields(field_list);
EXPECT_FALSE(field_list[0]->only_fill_when_focused());
EXPECT_FALSE(field_list[1]->only_fill_when_focused());
EXPECT_TRUE(field_list[2]->only_fill_when_focused());
EXPECT_FALSE(field_list[3]->only_fill_when_focused());
}
} // namespace autofill
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