blob: 017bcb158ca02b41bb33b053bb953d244fa3d9db [file] [log] [blame]
// 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/autofill_manager.h"
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <tuple>
#include <utility>
#include <vector>
#include "base/base64.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/metrics_hashes.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/autofill/core/browser/autocomplete_history_manager.h"
#include "components/autofill/core/browser/autofill_download_manager.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/metrics/form_events.h"
#include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_strike_database.h"
#include "components/autofill/core/browser/payments/test_payments_client.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/browser/test_autofill_clock.h"
#include "components/autofill/core/browser/test_autofill_download_manager.h"
#include "components/autofill/core/browser/test_autofill_driver.h"
#include "components/autofill/core/browser/test_autofill_external_delegate.h"
#include "components/autofill/core/browser/test_autofill_manager.h"
#include "components/autofill/core/browser/test_form_data_importer.h"
#include "components/autofill/core/browser/test_form_structure.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/browser/ui/popup_item_ids.h"
#include "components/autofill/core/browser/ui/suggestion.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/prefs/pref_service.h"
#include "components/security_interstitials/core/pref_names.h"
#include "components/security_state/core/security_state.h"
#include "components/strings/grit/components_strings.h"
#include "components/sync/driver/test_sync_service.h"
#include "components/variations/variations_associated_data.h"
#include "components/version_info/channel.h"
#include "net/base/url_util.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
#include "url/url_canon.h"
using base::ASCIIToUTF16;
using base::UTF8ToUTF16;
using testing::_;
using testing::AnyOf;
using testing::AtLeast;
using testing::Contains;
using testing::DoAll;
using testing::ElementsAre;
using testing::HasSubstr;
using testing::Not;
using testing::Return;
using testing::SaveArg;
using testing::UnorderedElementsAre;
namespace autofill {
using features::kAutofillRestrictUnownedFieldsToFormlessCheckout;
using mojom::SubmissionIndicatorEvent;
using mojom::SubmissionSource;
namespace {
const int kDefaultPageID = 137;
const std::string kArbitraryNickname = "Grocery Card";
class MockAutofillClient : public TestAutofillClient {
public:
MockAutofillClient() {
ON_CALL(*this, GetChannel())
.WillByDefault(Return(version_info::Channel::UNKNOWN));
}
MockAutofillClient(const MockAutofillClient&) = delete;
MockAutofillClient& operator=(const MockAutofillClient&) = delete;
~MockAutofillClient() override = default;
MOCK_METHOD0(ShouldShowSigninPromo, bool());
MOCK_CONST_METHOD0(GetChannel, version_info::Channel());
MOCK_METHOD2(ConfirmSaveUpiIdLocally,
void(const std::string& upi_id,
base::OnceCallback<void(bool user_decision)> callback));
};
class MockAutofillDownloadManager : public TestAutofillDownloadManager {
public:
MockAutofillDownloadManager(AutofillDriver* driver,
AutofillDownloadManager::Observer* observer)
: TestAutofillDownloadManager(driver, observer) {}
MockAutofillDownloadManager(const MockAutofillDownloadManager&) = delete;
MockAutofillDownloadManager& operator=(const MockAutofillDownloadManager&) =
delete;
MOCK_METHOD6(StartUploadRequest,
bool(const FormStructure&,
bool,
const ServerFieldTypeSet&,
const std::string&,
bool,
PrefService*));
};
void ExpectFilledField(const char* expected_label,
const char* expected_name,
const char* expected_value,
const char* expected_form_control_type,
const FormFieldData& field) {
SCOPED_TRACE(expected_label);
EXPECT_EQ(UTF8ToUTF16(expected_label), field.label);
EXPECT_EQ(UTF8ToUTF16(expected_name), field.name);
EXPECT_EQ(UTF8ToUTF16(expected_value), field.value);
EXPECT_EQ(expected_form_control_type, field.form_control_type);
}
// Verifies that the |filled_form| has been filled with the given data.
// Verifies address fields if |has_address_fields| is true, and verifies
// credit card fields if |has_credit_card_fields| is true. Verifies both if both
// are true. |use_month_type| is used for credit card input month type.
void ExpectFilledForm(int page_id,
const FormData& filled_form,
int expected_page_id,
const char* first,
const char* middle,
const char* last,
const char* address1,
const char* address2,
const char* city,
const char* state,
const char* postal_code,
const char* country,
const char* phone,
const char* email,
const char* name_on_card,
const char* card_number,
const char* expiration_month,
const char* expiration_year,
bool has_address_fields,
bool has_credit_card_fields,
bool use_month_type) {
// The number of fields in the address and credit card forms created above.
const size_t kAddressFormSize = 11;
const size_t kCreditCardFormSize = use_month_type ? 4 : 5;
EXPECT_EQ(expected_page_id, page_id);
EXPECT_EQ(ASCIIToUTF16("MyForm"), filled_form.name);
EXPECT_EQ(GURL("https://myform.com/form.html"), filled_form.url);
EXPECT_EQ(GURL("https://myform.com/submit.html"), filled_form.action);
size_t form_size = 0;
if (has_address_fields)
form_size += kAddressFormSize;
if (has_credit_card_fields)
form_size += kCreditCardFormSize;
ASSERT_EQ(form_size, filled_form.fields.size());
if (has_address_fields) {
ExpectFilledField("First Name", "firstname", first, "text",
filled_form.fields[0]);
ExpectFilledField("Middle Name", "middlename", middle, "text",
filled_form.fields[1]);
ExpectFilledField("Last Name", "lastname", last, "text",
filled_form.fields[2]);
ExpectFilledField("Address Line 1", "addr1", address1, "text",
filled_form.fields[3]);
ExpectFilledField("Address Line 2", "addr2", address2, "text",
filled_form.fields[4]);
ExpectFilledField("City", "city", city, "text", filled_form.fields[5]);
ExpectFilledField("State", "state", state, "text", filled_form.fields[6]);
ExpectFilledField("Postal Code", "zipcode", postal_code, "text",
filled_form.fields[7]);
ExpectFilledField("Country", "country", country, "text",
filled_form.fields[8]);
ExpectFilledField("Phone Number", "phonenumber", phone, "tel",
filled_form.fields[9]);
ExpectFilledField("Email", "email", email, "email", filled_form.fields[10]);
}
if (has_credit_card_fields) {
size_t offset = has_address_fields ? kAddressFormSize : 0;
ExpectFilledField("Name on Card", "nameoncard", name_on_card, "text",
filled_form.fields[offset + 0]);
ExpectFilledField("Card Number", "cardnumber", card_number, "text",
filled_form.fields[offset + 1]);
if (use_month_type) {
std::string exp_year = expiration_year;
std::string exp_month = expiration_month;
std::string date;
if (!exp_year.empty() && !exp_month.empty())
date = exp_year + "-" + exp_month;
ExpectFilledField("Expiration Date", "ccmonth", date.c_str(), "month",
filled_form.fields[offset + 2]);
} else {
ExpectFilledField("Expiration Date", "ccmonth", expiration_month, "text",
filled_form.fields[offset + 2]);
ExpectFilledField("", "ccyear", expiration_year, "text",
filled_form.fields[offset + 3]);
}
}
}
void ExpectFilledAddressFormElvis(int page_id,
const FormData& filled_form,
int expected_page_id,
bool has_credit_card_fields) {
ExpectFilledForm(page_id, filled_form, expected_page_id, "Elvis", "Aaron",
"Presley", "3734 Elvis Presley Blvd.", "Apt. 10", "Memphis",
"Tennessee", "38116", "United States", "12345678901",
"theking@gmail.com", "", "", "", "", true,
has_credit_card_fields, false);
}
void ExpectFilledCreditCardFormElvis(int page_id,
const FormData& filled_form,
int expected_page_id,
bool has_address_fields) {
ExpectFilledForm(page_id, filled_form, expected_page_id, "", "", "", "", "",
"", "", "", "", "", "", "Elvis Presley", "4234567890123456",
"04", "2999", has_address_fields, true, false);
}
void ExpectFilledCreditCardYearMonthWithYearMonth(int page_id,
const FormData& filled_form,
int expected_page_id,
bool has_address_fields,
const char* year,
const char* month) {
ExpectFilledForm(page_id, filled_form, expected_page_id, "", "", "", "", "",
"", "", "", "", "", "", "Miku Hatsune", "4234567890654321",
month, year, has_address_fields, true, true);
}
void CheckThatOnlyFieldByIndexHasThisPossibleType(
const FormStructure& form_structure,
size_t field_index,
ServerFieldType type,
FieldPropertiesMask mask) {
EXPECT_TRUE(field_index < form_structure.field_count());
for (size_t i = 0; i < form_structure.field_count(); i++) {
if (i == field_index) {
EXPECT_THAT(form_structure.field(i)->possible_types(), ElementsAre(type));
EXPECT_EQ(mask, form_structure.field(i)->properties_mask);
} else {
EXPECT_THAT(form_structure.field(i)->possible_types(),
Not(Contains(type)));
}
}
}
void CheckThatNoFieldHasThisPossibleType(const FormStructure& form_structure,
ServerFieldType type) {
for (size_t i = 0; i < form_structure.field_count(); i++) {
EXPECT_THAT(form_structure.field(i)->possible_types(), Not(Contains(type)));
}
}
class MockAutofillDriver : public TestAutofillDriver {
public:
MockAutofillDriver() = default;
MockAutofillDriver(const MockAutofillDriver&) = delete;
MockAutofillDriver& operator=(const MockAutofillDriver&) = delete;
// Mock methods to enable testability.
MOCK_METHOD3(SendFormDataToRenderer,
void(int query_id,
RendererFormDataAction action,
const FormData& data));
MOCK_METHOD1(SendAutofillTypePredictionsToRenderer,
void(const std::vector<FormStructure*>& forms));
};
} // namespace
class AutofillManagerTest : public testing::Test {
public:
AutofillManagerTest() = default;
void SetUp() override {
autofill_client_.SetPrefs(test::PrefServiceForTesting());
personal_data_.Init(/*profile_database=*/database_,
/*account_database=*/nullptr,
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*is_off_the_record=*/false);
personal_data_.SetPrefService(autofill_client_.GetPrefs());
autocomplete_history_manager_ =
std::make_unique<MockAutocompleteHistoryManager>();
autocomplete_history_manager_->Init(
/*profile_database=*/database_,
/*is_off_the_record=*/false);
autofill_driver_ =
std::make_unique<testing::NiceMock<MockAutofillDriver>>();
payments::TestPaymentsClient* payments_client =
new payments::TestPaymentsClient(
autofill_driver_->GetURLLoaderFactory(),
autofill_client_.GetIdentityManager(), &personal_data_);
autofill_client_.set_test_payments_client(
std::unique_ptr<payments::TestPaymentsClient>(payments_client));
TestCreditCardSaveManager* credit_card_save_manager =
new TestCreditCardSaveManager(autofill_driver_.get(), &autofill_client_,
payments_client, &personal_data_);
credit_card_save_manager->SetCreditCardUploadEnabled(true);
TestFormDataImporter* test_form_data_importer = new TestFormDataImporter(
&autofill_client_, payments_client,
std::unique_ptr<CreditCardSaveManager>(credit_card_save_manager),
&personal_data_, "en-US");
autofill_client_.set_test_form_data_importer(
std::unique_ptr<autofill::TestFormDataImporter>(
test_form_data_importer));
autofill_manager_ = std::make_unique<TestAutofillManager>(
autofill_driver_.get(), &autofill_client_, &personal_data_,
autocomplete_history_manager_.get());
auto download_manager = std::make_unique<MockAutofillDownloadManager>(
autofill_driver_.get(), autofill_manager_.get());
download_manager_ = download_manager.get();
autofill_manager_->set_download_manager_for_test(
std::move(download_manager));
auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
external_delegate_ = external_delegate.get();
autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
auto test_strike_database = std::make_unique<TestStrikeDatabase>();
strike_database_ = test_strike_database.get();
autofill_client_.set_test_strike_database(std::move(test_strike_database));
// Initialize the TestPersonalDataManager with some default data.
CreateTestAutofillProfiles();
CreateTestCreditCards();
}
void CreateTestServerCreditCards() {
personal_data_.ClearCreditCards();
CreditCard masked_server_card;
test::SetCreditCardInfo(&masked_server_card, "Elvis Presley",
"4234567890123456", // Visa
"04", "2999", "1");
masked_server_card.set_guid("00000000-0000-0000-0000-000000000007");
masked_server_card.set_record_type(CreditCard::MASKED_SERVER_CARD);
personal_data_.AddServerCreditCard(masked_server_card);
CreditCard full_server_card;
test::SetCreditCardInfo(&full_server_card, "Buddy Holly",
"5187654321098765", // Mastercard
"10", "2998", "1");
full_server_card.set_guid("00000000-0000-0000-0000-000000000008");
full_server_card.set_record_type(CreditCard::FULL_SERVER_CARD);
personal_data_.AddServerCreditCard(full_server_card);
}
void CreateTestServerAndLocalCreditCards() {
personal_data_.ClearCreditCards();
CreditCard masked_server_card;
test::SetCreditCardInfo(&masked_server_card, "Elvis Presley",
"4234567890123456", // Visa
"04", "2999", "1");
masked_server_card.set_guid("00000000-0000-0000-0000-000000000007");
masked_server_card.set_record_type(CreditCard::MASKED_SERVER_CARD);
personal_data_.AddServerCreditCard(masked_server_card);
CreditCard full_server_card;
test::SetCreditCardInfo(&full_server_card, "Buddy Holly",
"5187654321098765", // Mastercard
"10", "2998", "1");
full_server_card.set_guid("00000000-0000-0000-0000-000000000008");
full_server_card.set_record_type(CreditCard::FULL_SERVER_CARD);
personal_data_.AddServerCreditCard(full_server_card);
CreditCard local_card;
test::SetCreditCardInfo(&local_card, "Elvis Presley",
"4234567890123456", // Visa
"04", "2999", "1");
local_card.set_guid("00000000-0000-0000-0000-000000000009");
local_card.set_record_type(CreditCard::LOCAL_CARD);
personal_data_.AddCreditCard(local_card);
}
void TearDown() override {
// Order of destruction is important as AutofillManager relies on
// PersonalDataManager to be around when it gets destroyed.
autofill_manager_.reset();
personal_data_.SetPrefService(nullptr);
personal_data_.ClearCreditCards();
}
void GetAutofillSuggestions(int query_id,
const FormData& form,
const FormFieldData& field) {
autofill_manager_->OnQueryFormFieldAutofill(
query_id, form, field, gfx::RectF(),
/*autoselect_first_suggestion=*/false);
}
void GetAutofillSuggestions(const FormData& form,
const FormFieldData& field) {
GetAutofillSuggestions(kDefaultPageID, form, field);
}
void AutocompleteSuggestionsReturned(
const std::vector<base::string16>& results,
int query_id = kDefaultPageID) {
std::vector<Suggestion> suggestions;
std::transform(results.begin(), results.end(),
std::back_inserter(suggestions),
[](auto result) { return Suggestion(result); });
autofill_manager_->OnSuggestionsReturned(
query_id, /*autoselect_first_suggestion=*/false, suggestions);
}
void FormsSeen(const std::vector<FormData>& forms) {
autofill_manager_->OnFormsSeen(forms);
}
void FormSubmitted(const FormData& form) {
autofill_manager_->OnFormSubmitted(form, false,
SubmissionSource::FORM_SUBMISSION);
}
void FillAutofillFormData(int query_id,
const FormData& form,
const FormFieldData& field,
int unique_id) {
autofill_manager_->FillOrPreviewForm(AutofillDriver::FORM_DATA_ACTION_FILL,
query_id, form, field, unique_id);
}
// Calls |autofill_manager_->OnFillAutofillFormData()| with the specified
// input parameters after setting up the expectation that the mock driver's
// |SendFormDataToRenderer()| method will be called and saving the parameters
// of that call into the |response_query_id| and |response_data| output
// parameters.
void FillAutofillFormDataAndSaveResults(int input_query_id,
const FormData& input_form,
const FormFieldData& input_field,
int unique_id,
int* response_query_id,
FormData* response_data) {
EXPECT_CALL(*autofill_driver_, SendFormDataToRenderer(_, _, _))
.WillOnce((DoAll(testing::SaveArg<0>(response_query_id),
testing::SaveArg<2>(response_data))));
FillAutofillFormData(input_query_id, input_form, input_field, unique_id);
}
int MakeFrontendID(const std::string& cc_sid,
const std::string& profile_sid) const {
return autofill_manager_->MakeFrontendID(cc_sid, profile_sid);
}
bool WillFillCreditCardNumber(const FormData& form,
const FormFieldData& field) {
return autofill_manager_->WillFillCreditCardNumber(form, field);
}
// Populates |form| with data corresponding to a simple credit card form.
// Note that this actually appends fields to the form data, which can be
// useful for building up more complex test forms.
void CreateTestCreditCardFormData(FormData* form,
bool is_https,
bool use_month_type) {
form->name = ASCIIToUTF16("MyForm");
if (is_https) {
form->url = GURL("https://myform.com/form.html");
form->action = GURL("https://myform.com/submit.html");
} else {
// If we are testing a form that submits over HTTP, we also need to set
// the main frame to HTTP, otherwise mixed form warnings will trigger and
// autofill will be disabled.
GURL::Replacements replacements;
replacements.SetScheme(url::kHttpScheme,
url::Component(0, strlen(url::kHttpScheme)));
autofill_client_.set_form_origin(
autofill_client_.form_origin().ReplaceComponents(replacements));
form->url = GURL("http://myform.com/form.html");
form->action = GURL("http://myform.com/submit.html");
}
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
form->fields.push_back(field);
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
form->fields.push_back(field);
if (use_month_type) {
test::CreateTestFormField("Expiration Date", "ccmonth", "", "month",
&field);
form->fields.push_back(field);
} else {
test::CreateTestFormField("Expiration Date", "ccmonth", "", "text",
&field);
form->fields.push_back(field);
test::CreateTestFormField("", "ccyear", "", "text", &field);
form->fields.push_back(field);
}
test::CreateTestFormField("CVC", "cvc", "", "text", &field);
form->fields.push_back(field);
}
void PrepareForRealPanResponse(FormData* form, CreditCard* card) {
// This line silences the warning from PaymentsClient about matching sync
// and Payments server types.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
"sync-url", "https://google.com");
CreateTestCreditCardFormData(form, true, false);
FormsSeen(std::vector<FormData>(1, *form));
*card = CreditCard(CreditCard::MASKED_SERVER_CARD, "a123");
test::SetCreditCardInfo(card, "John Dillinger", "1881" /* Visa */, "01",
"2017", "1");
card->SetNetworkForMaskedCard(kVisaCard);
EXPECT_CALL(*autofill_driver_, SendFormDataToRenderer(_, _, _))
.Times(AtLeast(1));
autofill_manager_->FillOrPreviewCreditCardForm(
AutofillDriver::FORM_DATA_ACTION_FILL, kDefaultPageID, *form,
form->fields[0], card);
}
void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
const std::string& real_pan) {
payments::FullCardRequest* full_card_request =
autofill_manager_->credit_card_access_manager_->cvc_authenticator_
->full_card_request_.get();
DCHECK(full_card_request);
// Mock user response.
payments::FullCardRequest::UserProvidedUnmaskDetails details;
details.cvc = base::ASCIIToUTF16("123");
full_card_request->OnUnmaskPromptAccepted(details);
// Mock payments response.
payments::PaymentsClient::UnmaskResponseDetails response;
full_card_request->OnDidGetRealPan(result,
response.with_real_pan(real_pan));
}
// Convenience method to cast the FullCardRequest into a CardUnmaskDelegate.
CardUnmaskDelegate* full_card_unmask_delegate() {
payments::FullCardRequest* full_card_request =
autofill_manager_->credit_card_access_manager_
->GetOrCreateCVCAuthenticator()
->full_card_request_.get();
DCHECK(full_card_request);
return static_cast<CardUnmaskDelegate*>(full_card_request);
}
void DisableCreditCardAutofill() {
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillCreditCardAblationExperiment);
}
// Wrappers around the TestAutofillExternalDelegate::GetSuggestions call that
// take a hardcoded number of expected results so callsites are cleaner.
void CheckSuggestions(int expected_page_id, const Suggestion& suggestion0) {
std::vector<Suggestion> suggestion_vector;
suggestion_vector.push_back(suggestion0);
external_delegate_->CheckSuggestions(expected_page_id, 1,
&suggestion_vector[0]);
}
void CheckSuggestions(int expected_page_id,
const Suggestion& suggestion0,
const Suggestion& suggestion1) {
std::vector<Suggestion> suggestion_vector;
suggestion_vector.push_back(suggestion0);
suggestion_vector.push_back(suggestion1);
external_delegate_->CheckSuggestions(expected_page_id, 2,
&suggestion_vector[0]);
}
void CheckSuggestions(int expected_page_id,
const Suggestion& suggestion0,
const Suggestion& suggestion1,
const Suggestion& suggestion2) {
std::vector<Suggestion> suggestion_vector;
suggestion_vector.push_back(suggestion0);
suggestion_vector.push_back(suggestion1);
suggestion_vector.push_back(suggestion2);
external_delegate_->CheckSuggestions(expected_page_id, 3,
&suggestion_vector[0]);
}
protected:
base::test::TaskEnvironment task_environment_;
MockAutofillClient autofill_client_;
std::unique_ptr<MockAutofillDriver> autofill_driver_;
std::unique_ptr<TestAutofillManager> autofill_manager_;
TestAutofillExternalDelegate* external_delegate_;
scoped_refptr<AutofillWebDataService> database_;
MockAutofillDownloadManager* download_manager_;
TestPersonalDataManager personal_data_;
std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_;
base::test::ScopedFeatureList scoped_feature_list_;
TestStrikeDatabase* strike_database_;
private:
int ToHistogramSample(AutofillMetrics::CardUploadDecisionMetric metric) {
for (int sample = 0; sample < metric + 1; ++sample)
if (metric & (1 << sample))
return sample;
NOTREACHED();
return 0;
}
void CreateTestAutofillProfiles() {
AutofillProfile profile1;
test::SetProfileInfo(&profile1, "Elvis", "Aaron", "Presley",
"theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
"Apt. 10", "Memphis", "Tennessee", "38116", "US",
"12345678901");
profile1.set_guid("00000000-0000-0000-0000-000000000001");
personal_data_.AddProfile(profile1);
AutofillProfile profile2;
test::SetProfileInfo(&profile2, "Charles", "Hardin", "Holley",
"buddy@gmail.com", "Decca", "123 Apple St.", "unit 6",
"Lubbock", "Texas", "79401", "US", "23456789012");
profile2.set_guid("00000000-0000-0000-0000-000000000002");
personal_data_.AddProfile(profile2);
AutofillProfile profile3;
test::SetProfileInfo(&profile3, "", "", "", "", "", "", "", "", "", "", "",
"");
profile3.set_guid("00000000-0000-0000-0000-000000000003");
personal_data_.AddProfile(profile3);
}
void CreateTestCreditCards() {
CreditCard credit_card1;
test::SetCreditCardInfo(&credit_card1, "Elvis Presley",
"4234567890123456", // Visa
"04", "2999", "1");
credit_card1.set_guid("00000000-0000-0000-0000-000000000004");
credit_card1.set_use_count(10);
credit_card1.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(5));
personal_data_.AddCreditCard(credit_card1);
CreditCard credit_card2;
test::SetCreditCardInfo(&credit_card2, "Buddy Holly",
"5187654321098765", // Mastercard
"10", "2998", "1");
credit_card2.set_guid("00000000-0000-0000-0000-000000000005");
credit_card2.set_use_count(5);
credit_card2.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(4));
personal_data_.AddCreditCard(credit_card2);
CreditCard credit_card3;
test::SetCreditCardInfo(&credit_card3, "", "", "", "", "");
credit_card3.set_guid("00000000-0000-0000-0000-000000000006");
personal_data_.AddCreditCard(credit_card3);
}
};
// Subclass of AutofillManagerTest that parameterizes the finch flag to enable
// structured names.
// TODO(crbug.com/1103421): Clean legacy implementation once structured names
// are fully launched. Here, the changes applied in CL 2333204 must be reverted
// by deleting this class and use TEST_F(AutofillManagerTest, ) for all test
// cases again.
class AutofillManagerStructuredProfileTest
: public AutofillManagerTest,
public testing::WithParamInterface<bool> {
protected:
void SetUp() override {
InitializeFeatures();
AutofillManagerTest::SetUp();
}
void InitializeFeatures();
bool StructuredNames() const { return structured_names_enabled_; }
private:
bool structured_names_enabled_;
base::test::ScopedFeatureList scoped_features_;
};
void AutofillManagerStructuredProfileTest::InitializeFeatures() {
structured_names_enabled_ = GetParam();
if (structured_names_enabled_) {
scoped_features_.InitAndEnableFeature(
features::kAutofillEnableSupportForMoreStructureInNames);
} else {
scoped_features_.InitAndDisableFeature(
features::kAutofillEnableSupportForMoreStructureInNames);
}
}
class SuggestionMatchingTest
: public AutofillManagerTest,
public testing::WithParamInterface<std::tuple<bool, std::string>> {
protected:
void SetUp() override {
AutofillManagerTest::SetUp();
InitializeFeatures();
}
#if defined(OS_ANDROID) || defined(OS_IOS)
void InitializeFeatures();
#else
void InitializeFeatures();
#endif // defined(OS_ANDROID) || defined(OS_IOS)
std::string MakeLabel(const std::vector<std::string>& parts);
std::string MakeMobileLabel(const std::vector<std::string>& parts);
enum class EnabledFeature { kNone, kDesktop, kMobileShowAll, kMobileShowOne };
EnabledFeature enabled_feature_;
base::test::ScopedFeatureList features_;
};
#if defined(OS_ANDROID) || defined(OS_IOS)
void SuggestionMatchingTest::InitializeFeatures() {
if (std::get<0>(GetParam())) {
std::string variant = std::get<1>(GetParam());
if (variant ==
features::kAutofillUseMobileLabelDisambiguationParameterShowAll) {
enabled_feature_ = EnabledFeature::kMobileShowAll;
} else if (variant ==
features::
kAutofillUseMobileLabelDisambiguationParameterShowOne) {
enabled_feature_ = EnabledFeature::kMobileShowOne;
} else {
NOTREACHED();
}
std::map<std::string, std::string> parameters;
parameters[features::kAutofillUseMobileLabelDisambiguationParameterName] =
variant;
features_.InitAndEnableFeatureWithParameters(
features::kAutofillUseMobileLabelDisambiguation, parameters);
} else {
enabled_feature_ = EnabledFeature::kNone;
}
}
#else
void SuggestionMatchingTest::InitializeFeatures() {
enabled_feature_ = std::get<0>(GetParam()) ? EnabledFeature::kDesktop
: EnabledFeature::kNone;
features_.InitWithFeatureState(
features::kAutofillUseImprovedLabelDisambiguation,
std::get<0>(GetParam()));
}
#endif // defined(OS_ANDROID) || defined(OS_IOS)
std::string SuggestionMatchingTest::MakeLabel(
const std::vector<std::string>& parts) {
return base::JoinString(
parts, l10n_util::GetStringUTF8(IDS_AUTOFILL_SUGGESTION_LABEL_SEPARATOR));
}
std::string SuggestionMatchingTest::MakeMobileLabel(
const std::vector<std::string>& parts) {
return base::JoinString(
parts, l10n_util::GetStringUTF8(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR));
}
// Credit card suggestion tests related with keyboard accessory.
class CreditCardSuggestionTest : public AutofillManagerTest,
public testing::WithParamInterface<bool> {
protected:
CreditCardSuggestionTest() : is_keyboard_accessory_enabled_(GetParam()) {}
void SetUp() override {
AutofillManagerTest::SetUp();
features_.InitWithFeatureState(features::kAutofillKeyboardAccessory,
is_keyboard_accessory_enabled_);
}
private:
base::test::ScopedFeatureList features_;
const bool is_keyboard_accessory_enabled_;
};
// Test that calling OnFormsSeen with an empty set of forms (such as when
// reloading a page or when the renderer processes a set of forms but detects
// no changes) does not load the forms again.
TEST_P(AutofillManagerStructuredProfileTest, OnFormsSeen_Empty) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
FormsSeen(forms);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
0 /* FORMS_LOADED */, 1);
// No more forms, metric is not logged.
forms.clear();
FormsSeen(forms);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
0 /* FORMS_LOADED */, 1);
}
// Test that calling OnFormsSeen consecutively with a different set of forms
// will query for each separately.
TEST_P(AutofillManagerStructuredProfileTest,
OnFormsSeen_DifferentFormStructures) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
base::HistogramTester histogram_tester;
FormsSeen(forms);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
0 /* FORMS_LOADED */, 1);
download_manager_->VerifyLastQueriedForms(forms);
// Different form structure.
FormData form2;
form2.unique_renderer_id.value() = 2;
form2.name = ASCIIToUTF16("MyForm");
form2.url = GURL("https://myform.com/form.html");
form2.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form2.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form2.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "text", &field);
form2.fields.push_back(field);
forms.clear();
forms.push_back(form2);
FormsSeen(forms);
histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
0 /* FORMS_LOADED */, 2);
download_manager_->VerifyLastQueriedForms(forms);
}
// Test that when forms are seen, the renderer is updated with the predicted
// field types
TEST_P(AutofillManagerStructuredProfileTest,
OnFormsSeen_SendAutofillTypePredictionsToRenderer) {
// Set up a queryable form.
FormData form1;
test::CreateTestAddressFormData(&form1);
// Set up a non-queryable form.
FormData form2;
FormFieldData field;
test::CreateTestFormField("Querty", "qwerty", "", "text", &field);
form2.unique_renderer_id.value() = 2;
form2.name = ASCIIToUTF16("NonQueryable");
form2.url = form1.url;
form2.action = GURL("https://myform.com/submit.html");
form2.fields.push_back(field);
// Package the forms for observation.
std::vector<FormData> forms{form1, form2};
// Setup expectations.
EXPECT_CALL(*autofill_driver_, SendAutofillTypePredictionsToRenderer(_))
.Times(2);
FormsSeen(forms);
}
// Test that no autofill suggestions are returned for a field with an
// unrecognized autocomplete attribute.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_UnrecognizedAttribute) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
// Set a valid autocomplete attribute for the first name.
test::CreateTestFormField("First name", "firstname", "", "text", &field);
field.autocomplete_attribute = "given-name";
form.fields.push_back(field);
// Set no autocomplete attribute for the middle name.
test::CreateTestFormField("Middle name", "middle", "", "text", &field);
field.autocomplete_attribute = "";
form.fields.push_back(field);
// Set an unrecognized autocomplete attribute for the last name.
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
field.autocomplete_attribute = "unrecognized";
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Ensure that autocomplete manager is not called for suggestions either.
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions)
.Times(0);
// Suggestions should be returned for the first two fields.
GetAutofillSuggestions(form, form.fields[0]);
external_delegate_->CheckSuggestionCount(kDefaultPageID, 2);
GetAutofillSuggestions(form, form.fields[1]);
external_delegate_->CheckSuggestionCount(kDefaultPageID, 2);
// No suggestions should not be provided for the third field because of its
// unrecognized autocomplete attribute.
GetAutofillSuggestions(form, form.fields[2]);
external_delegate_->CheckNoSuggestions(kDefaultPageID);
}
// Test that when small forms are disabled (min required fields enforced) no
// suggestions are returned when there are less than three fields and none of
// them have an autocomplete attribute.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_MinFieldsEnforced_NoAutocomplete) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Ensure that autocomplete manager is called for both fields.
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions)
.Times(2);
GetAutofillSuggestions(form, form.fields[0]);
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
GetAutofillSuggestions(form, form.fields[1]);
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
// Test that when small forms are disabled (min required fields enforced)
// for a form with two fields with one that has an autocomplete attribute,
// suggestions are only made for the one that has the attribute.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_MinFieldsEnforced_WithOneAutocomplete) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
field.autocomplete_attribute = "given-name";
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
field.autocomplete_attribute = "";
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Check that suggestions are made for the field that has the autocomplete
// attribute.
GetAutofillSuggestions(form, form.fields[0]);
CheckSuggestions(kDefaultPageID, Suggestion("Charles", "", "", 1),
Suggestion("Elvis", "", "", 2));
// Check that there are no suggestions for the field without the autocomplete
// attribute.
GetAutofillSuggestions(form, form.fields[1]);
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
// Test that for a form with two fields with autocomplete attributes,
// suggestions are made for both fields. This is true even if a minimum number
// of fields is enforced.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_SmallFormWithTwoAutocomplete) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
field.autocomplete_attribute = "given-name";
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
field.autocomplete_attribute = "family-name";
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
GetAutofillSuggestions(form, form.fields[0]);
CheckSuggestions(kDefaultPageID,
Suggestion("Charles", "Charles Hardin Holley", "", 1),
Suggestion("Elvis", "Elvis Aaron Presley", "", 2));
GetAutofillSuggestions(form, form.fields[1]);
CheckSuggestions(kDefaultPageID,
Suggestion("Holley", "Charles Hardin Holley", "", 1),
Suggestion("Presley", "Elvis Aaron Presley", "", 2));
}
// Test that the call is properly forwarded to AutocompleteHistoryManager.
TEST_P(AutofillManagerStructuredProfileTest, OnAutocompleteEntrySelected) {
base::string16 test_value = ASCIIToUTF16("TestValue");
EXPECT_CALL(*autocomplete_history_manager_.get(),
OnAutocompleteEntrySelected(test_value))
.Times(1);
autofill_manager_->OnAutocompleteEntrySelected(test_value);
}
// Test that we return all address profile suggestions when all form fields
// are empty.
TEST_P(SuggestionMatchingTest, GetProfileSuggestions_EmptyValue) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const FormFieldData& field = form.fields[0];
GetAutofillSuggestions(form, field);
std::string label1;
std::string label2;
switch (enabled_feature_) {
// 23456789012 is not formatted because it is invalid for the app locale.
// It has an extra digit.
case EnabledFeature::kDesktop:
label1 = MakeLabel(
{"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
label2 = MakeLabel({"3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901",
"theking@gmail.com"});
break;
case EnabledFeature::kMobileShowAll:
label1 = MakeMobileLabel(
{"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
label2 = MakeMobileLabel({"3734 Elvis Presley Blvd., Apt. 10",
"(234) 567-8901", "theking@gmail.com"});
break;
case EnabledFeature::kMobileShowOne:
label1 = "123 Apple St., unit 6";
label2 = "3734 Elvis Presley Blvd., Apt. 10";
break;
case EnabledFeature::kNone:
label1 = "123 Apple St.";
label2 = "3734 Elvis Presley Blvd.";
}
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion("Charles", label1, "", 1),
Suggestion("Elvis", label2, "", 2));
}
// Test that we return only matching address profile suggestions when the
// selected form field has been partially filled out.
TEST_P(SuggestionMatchingTest, GetProfileSuggestions_MatchCharacter) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "E", "text", &field);
GetAutofillSuggestions(form, field);
std::string label;
switch (enabled_feature_) {
case EnabledFeature::kDesktop:
case EnabledFeature::kMobileShowAll:
case EnabledFeature::kMobileShowOne:
label = "3734 Elvis Presley Blvd., Apt. 10";
break;
case EnabledFeature::kNone:
label = "3734 Elvis Presley Blvd.";
}
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion("Elvis", label, "", 1));
}
// Tests that we return address profile suggestions values when the section
// is already autofilled, and that we merge identical values.
TEST_P(SuggestionMatchingTest,
GetProfileSuggestions_AlreadyAutofilledMergeValues) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// First name is already autofilled which will make the section appear as
// "already autofilled".
form.fields[0].is_autofilled = true;
// Two profiles have the same last name, and the third shares the same first
// letter for last name.
AutofillProfile profile1;
profile1.set_guid("00000000-0000-0000-0000-000000000103");
profile1.SetInfo(NAME_FIRST, ASCIIToUTF16("Robin"), "en-US");
profile1.SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
profile1.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
"en-US");
personal_data_.AddProfile(profile1);
AutofillProfile profile2;
profile2.set_guid("00000000-0000-0000-0000-000000000124");
profile2.SetInfo(NAME_FIRST, ASCIIToUTF16("Carl"), "en-US");
profile2.SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
profile2.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
"en-US");
personal_data_.AddProfile(profile2);
AutofillProfile profile3;
profile3.set_guid("00000000-0000-0000-0000-000000000126");
profile3.SetInfo(NAME_FIRST, ASCIIToUTF16("Aaron"), "en-US");
profile3.SetInfo(NAME_LAST, ASCIIToUTF16("Googler"), "en-US");
profile3.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1600 Amphitheater pkwy"),
"en-US");
personal_data_.AddProfile(profile3);
FormFieldData field;
test::CreateTestFormField("Last Name", "lastname", "G", "text", &field);
GetAutofillSuggestions(form, field);
switch (enabled_feature_) {
case EnabledFeature::kDesktop:
case EnabledFeature::kMobileShowAll:
case EnabledFeature::kMobileShowOne:
CheckSuggestions(kDefaultPageID,
Suggestion("Googler", "1600 Amphitheater pkwy", "", 1),
Suggestion("Grimes", "1234 Smith Blvd.", "", 2));
break;
case EnabledFeature::kNone:
// Test that we sent the right values to the external delegate. No labels
// with duplicate values "Grimes" merged.
CheckSuggestions(
kDefaultPageID,
Suggestion("Googler", "1600 Amphitheater pkwy", "", 1),
Suggestion("Grimes", "1234 Smith Blvd., Carl Grimes", "", 2),
Suggestion("Grimes", "1234 Smith Blvd., Robin Grimes", "", 3));
}
}
// Tests that we return address profile suggestions values when the section
// is already autofilled, and that they have no label.
TEST_P(SuggestionMatchingTest,
GetProfileSuggestions_AlreadyAutofilledNoLabels) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// First name is already autofilled which will make the section appear as
// "already autofilled".
form.fields[0].is_autofilled = true;
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "E", "text", &field);
GetAutofillSuggestions(form, field);
std::string label;
switch (enabled_feature_) {
case EnabledFeature::kDesktop:
case EnabledFeature::kMobileShowAll:
case EnabledFeature::kMobileShowOne:
label = "3734 Elvis Presley Blvd., Apt. 10";
break;
case EnabledFeature::kNone:
label = "3734 Elvis Presley Blvd.";
}
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion("Elvis", label, "", 1));
}
// Test that we return no suggestions when the form has no relevant fields.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_UnknownFields) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Username", "username", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Password", "password", "", "password", &field);
form.fields.push_back(field);
test::CreateTestFormField("Quest", "quest", "", "quest", &field);
form.fields.push_back(field);
test::CreateTestFormField("Color", "color", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
GetAutofillSuggestions(form, field);
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
// Test that we cull duplicate profile suggestions.
TEST_P(SuggestionMatchingTest, GetProfileSuggestions_WithDuplicates) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Add a duplicate profile.
AutofillProfile duplicate_profile = *(personal_data_.GetProfileWithGUID(
"00000000-0000-0000-0000-000000000001"));
personal_data_.AddProfile(duplicate_profile);
const FormFieldData& field = form.fields[0];
GetAutofillSuggestions(form, field);
std::string label1;
std::string label2;
switch (enabled_feature_) {
// 23456789012 is not formatted because it is invalid for the app locale.
// It has an extra digit.
case EnabledFeature::kDesktop:
label1 = MakeLabel(
{"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
label2 = MakeLabel({"3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901",
"theking@gmail.com"});
break;
case EnabledFeature::kMobileShowAll:
label1 = MakeMobileLabel(
{"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
label2 = MakeMobileLabel({"3734 Elvis Presley Blvd., Apt. 10",
"(234) 567-8901", "theking@gmail.com"});
break;
case EnabledFeature::kMobileShowOne:
label1 = "123 Apple St., unit 6";
label2 = "3734 Elvis Presley Blvd., Apt. 10";
break;
case EnabledFeature::kNone:
label1 = "123 Apple St.";
label2 = "3734 Elvis Presley Blvd.";
}
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion("Charles", label1, "", 1),
Suggestion("Elvis", label2, "", 2));
}
// Test that we return no suggestions when autofill is disabled.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_AutofillDisabledByUser) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Disable Autofill.
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
const FormFieldData& field = form.fields[0];
GetAutofillSuggestions(form, field);
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
TEST_P(AutofillManagerStructuredProfileTest,
OnSuggestionsReturned_CallsExternalDelegate) {
std::vector<Suggestion> suggestions = {
Suggestion("Charles", "123 Apple St.", "", 1),
Suggestion("Elvis", "3734 Elvis Presley Blvd.", "", 2)};
{
autofill_manager_->OnSuggestionsReturned(
kDefaultPageID, /*autoselect_first_suggestion=*/false, suggestions);
EXPECT_FALSE(external_delegate_->autoselect_first_suggestion());
CheckSuggestions(kDefaultPageID, suggestions[0], suggestions[1]);
}
{
autofill_manager_->OnSuggestionsReturned(
kDefaultPageID, /*autoselect_first_suggestion=*/true, suggestions);
EXPECT_TRUE(external_delegate_->autoselect_first_suggestion());
CheckSuggestions(kDefaultPageID, suggestions[0], suggestions[1]);
}
}
// Test that we return all credit card profile suggestions when all form fields
// are empty.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_EmptyValue) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
const std::string visa_label = std::string("Expires on 04/99");
const std::string master_card_label = std::string("Expires on 10/98");
#endif
// Test that we sent the credit card suggestions to the external delegate.
CheckSuggestions(
kDefaultPageID,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
visa_label, kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
Suggestion(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("8765"),
master_card_label, kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
// Test that we return all credit card profile suggestions when the triggering
// field has whitespace in it.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_Whitespace) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[1];
field.value = ASCIIToUTF16(" ");
GetAutofillSuggestions(form, field);
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
const std::string visa_label = std::string("Expires on 04/99");
const std::string master_card_label = std::string("Expires on 10/98");
#endif
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
visa_label, kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
Suggestion(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("8765"),
master_card_label, kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
// Test that we return all credit card profile suggestions when the triggering
// field has stop characters in it, which should be removed.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_StopCharsOnly) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[1];
field.value = ASCIIToUTF16("____-____-____-____");
GetAutofillSuggestions(form, field);
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
const std::string visa_label = std::string("Expires on 04/99");
const std::string master_card_label = std::string("Expires on 10/98");
#endif
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
visa_label, kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
Suggestion(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("8765"),
master_card_label, kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
// Test that we return all credit card profile suggestions when the triggering
// field has some invisible unicode characters in it.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_InvisibleUnicodeOnly) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[1];
field.value = base::string16({0x200E, 0x200F});
GetAutofillSuggestions(form, field);
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
const std::string visa_label = std::string("Expires on 04/99");
const std::string master_card_label = std::string("Expires on 10/98");
#endif
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
visa_label, kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
Suggestion(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("8765"),
master_card_label, kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
// Test that we return all credit card profile suggestions when the triggering
// field has stop characters in it and some input.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_StopCharsWithInput) {
// Add a credit card with particular numbers that we will attempt to recall.
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "John Smith",
"5255667890123123", // Mastercard
"08", "2017", "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000007");
personal_data_.AddCreditCard(credit_card);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[1];
field.value = ASCIIToUTF16("5255-66__-____-____");
GetAutofillSuggestions(form, field);
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string master_card_label = std::string("08/17");
#else
const std::string master_card_label = std::string("Expires on 08/17");
#endif
// Test that we sent the right value to the external delegate.
CheckSuggestions(kDefaultPageID,
Suggestion(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("3123"),
master_card_label, kMasterCard,
autofill_manager_->GetPackedCreditCardID(7)));
}
// Test that we return only matching credit card profile suggestions when the
// selected form field has been partially filled out.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_MatchCharacter) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Card Number", "cardnumber", "78", "text", &field);
GetAutofillSuggestions(form, field);
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string visa_label = std::string("04/99");
#else
const std::string visa_label = std::string("Expires on 04/99");
#endif
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
visa_label, kVisaCard, autofill_manager_->GetPackedCreditCardID(4)));
}
// Test that we return credit card profile suggestions when the selected form
// field is the credit card number field.
TEST_P(CreditCardSuggestionTest, GetCreditCardSuggestions_CCNumber) {
// Set nickname with the corresponding guid of the Mastercard 8765.
personal_data_.SetNicknameForCardWithGUID(
"00000000-0000-0000-0000-000000000005", kArbitraryNickname);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const FormFieldData& credit_card_number_field = form.fields[1];
GetAutofillSuggestions(form, credit_card_number_field);
const std::string visa_value =
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456");
// Mastercard has a valid nickname. Display nickname + last four in the
// suggestion title.
const std::string master_card_value =
kArbitraryNickname + " " + test::ObfuscatedCardDigitsAsUTF8("8765");
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
const std::string visa_label = std::string("Expires on 04/99");
const std::string master_card_label = std::string("Expires on 10/98");
#endif
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID,
Suggestion(visa_value, visa_label, kVisaCard,
autofill_manager_->GetPackedCreditCardID(4)),
Suggestion(master_card_value, master_card_label, kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
// Test that we return credit card profile suggestions when the selected form
// field is not the credit card number field.
TEST_P(CreditCardSuggestionTest, GetCreditCardSuggestions_NonCCNumber) {
// Set nickname with the corresponding guid of the Mastercard 8765.
personal_data_.SetNicknameForCardWithGUID(
"00000000-0000-0000-0000-000000000005", kArbitraryNickname);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const FormFieldData& cardholder_name_field = form.fields[0];
GetAutofillSuggestions(form, cardholder_name_field);
const std::string obfuscated_last_four_digits1 =
test::ObfuscatedCardDigitsAsUTF8("3456");
const std::string obfuscated_last_four_digits2 =
test::ObfuscatedCardDigitsAsUTF8("8765");
#if defined(OS_ANDROID)
// For Android, when keyboard accessary is enabled, always show obfuscated
// last four. When keyboard accessary is not enabled (drop-down suggestion):
// 1) if nickname feature is enabled and nickname is available, show nickname
// + last four. 2) Otherwise, show network + last four.
// Visa card does not have a nickname.
const std::string visa_label =
IsKeyboardAccessoryEnabled()
? obfuscated_last_four_digits1
: std::string("Visa ") + obfuscated_last_four_digits1;
// Mastercard has a valid nickname.
const std::string master_card_label =
IsKeyboardAccessoryEnabled()
? obfuscated_last_four_digits2
: kArbitraryNickname + " " + obfuscated_last_four_digits2;
#elif defined(OS_IOS)
const std::string visa_label = obfuscated_last_four_digits1;
const std::string master_card_label = obfuscated_last_four_digits2;
#else
// If no nickname available, we will show network.
const std::string visa_label = base::JoinString(
{"Visa ", obfuscated_last_four_digits1, ", expires on 04/99"}, "");
// When nickname is available, show nickname. Otherwise, show network.
const std::string master_card_label =
base::JoinString({kArbitraryNickname + " ", obfuscated_last_four_digits2,
", expires on 10/98"},
"");
#endif
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID,
Suggestion("Elvis Presley", visa_label, kVisaCard,
autofill_manager_->GetPackedCreditCardID(4)),
Suggestion("Buddy Holly", master_card_label, kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_GoogleIssuedCard_CCNumber) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(
autofill::features::kAutofillEnableGoogleIssuedCard);
personal_data_.ClearCreditCards();
// Add a Google Issued Card.
CreditCard google_issued_card;
test::SetCreditCardInfo(&google_issued_card, "Lorem Ispium",
"5555555555554444", // Mastercard
"10", "2998", "1");
google_issued_card.set_guid("00000000-0000-0000-0000-000000000007");
google_issued_card.set_record_type(
CreditCard::RecordType::MASKED_SERVER_CARD);
google_issued_card.set_card_issuer(CreditCard::Issuer::GOOGLE);
personal_data_.AddServerCreditCard(google_issued_card);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Set the field being edited to CC field.
const FormFieldData& credit_card_number_field = form.fields[1];
const std::string google_issued_card_value = "Google";
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string google_issued_card_label = std::string("10/98");
#else
const std::string google_issued_card_label = std::string("Expires on 10/98");
#endif
GetAutofillSuggestions(form, credit_card_number_field);
CheckSuggestions(kDefaultPageID,
Suggestion(google_issued_card_value,
google_issued_card_label, kGoogleIssuedCard,
autofill_manager_->GetPackedCreditCardID(7)));
}
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_GoogleIssuedCard_NonCCNumber) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(
autofill::features::kAutofillEnableGoogleIssuedCard);
personal_data_.ClearCreditCards();
// Add a Google Issued Card.
CreditCard google_issued_card;
test::SetCreditCardInfo(&google_issued_card, "Lorem Ispium",
"5555555555554444", // Mastercard
"10", "2998", "1");
google_issued_card.set_guid("00000000-0000-0000-0000-000000000007");
google_issued_card.set_record_type(
CreditCard::RecordType::MASKED_SERVER_CARD);
google_issued_card.set_card_issuer(CreditCard::Issuer::GOOGLE);
personal_data_.AddServerCreditCard(google_issued_card);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Set the field being edited to the cardholder name field.
const FormFieldData& cardholder_name_field = form.fields[0];
#if defined(OS_ANDROID)
const std::string google_issued_card_label = std::string("Google");
#elif defined(OS_IOS)
const std::string google_issued_card_label =
test::ObfuscatedCardDigitsAsUTF8("4444");
#else
const std::string google_issued_card_label =
std::string("Google, expires on 10/98");
#endif
GetAutofillSuggestions(form, cardholder_name_field);
CheckSuggestions(
kDefaultPageID,
Suggestion("Lorem Ispium", google_issued_card_label, kGoogleIssuedCard,
autofill_manager_->GetPackedCreditCardID(7)));
}
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_GoogleIssuedCardNotPresent_ExpOff) {
base::test::ScopedFeatureList features;
features.InitAndDisableFeature(
autofill::features::kAutofillEnableGoogleIssuedCard);
// Add 2 Server cards.
CreateTestServerCreditCards();
// Add a Google Issued Card.
CreditCard google_issued_card;
test::SetCreditCardInfo(&google_issued_card, "Lorem Ispium",
"5555555555554444", // Mastercard
"10", "2998", "1");
google_issued_card.set_guid("00000000-0000-0000-0000-000000000007");
google_issued_card.set_record_type(
CreditCard::RecordType::MASKED_SERVER_CARD);
google_issued_card.set_card_issuer(CreditCard::Issuer::GOOGLE);
personal_data_.AddServerCreditCard(google_issued_card);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Set the field being edited to CC field.
const FormFieldData& credit_card_number_field = form.fields[1];
GetAutofillSuggestions(form, credit_card_number_field);
// Assert that there are only two credit card suggestions returned.
external_delegate_->CheckSuggestionCount(kDefaultPageID, 2);
}
// Test that we will eventually return the credit card signin promo when there
// are no credit card suggestions and the promo is active. See the tests in
// AutofillExternalDelegateTest that test whether the promo is added.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_OnlySigninPromo) {
personal_data_.ClearCreditCards();
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[1];
ON_CALL(autofill_client_, ShouldShowSigninPromo())
.WillByDefault(Return(true));
EXPECT_CALL(autofill_client_, ShouldShowSigninPromo()).Times(2);
EXPECT_TRUE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
// Autocomplete suggestions are not queried.
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions)
.Times(0);
GetAutofillSuggestions(form, field);
// Test that we sent no values to the external delegate. It will add the promo
// before passing along the results.
external_delegate_->CheckNoSuggestions(kDefaultPageID);
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
// Test that we return a warning explaining that credit card profile suggestions
// are unavailable when the page is secure, but the form action URL is valid but
// not secure.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_SecureContext_FormActionNotHTTPS) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, /* is_https= */ true, false);
// However we set the action (target URL) to be HTTP after all.
form.action = GURL("http://myform.com/submit.html");
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const FormFieldData& field = form.fields[0];
GetAutofillSuggestions(form, field);
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
Suggestion(l10n_util::GetStringUTF8(IDS_AUTOFILL_WARNING_MIXED_FORM), "",
"", -26));
// Clear the test credit cards and try again -- we should still show the
// mixed form warning.
personal_data_.ClearCreditCards();
GetAutofillSuggestions(form, field);
CheckSuggestions(
kDefaultPageID,
Suggestion(l10n_util::GetStringUTF8(IDS_AUTOFILL_WARNING_MIXED_FORM), "",
"", -26));
}
// Test that we return credit card suggestions for secure pages that have an
// empty form action target URL.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_SecureContext_EmptyFormAction) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
// Clear the form action.
form.action = GURL();
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
const std::string visa_label = std::string("Expires on 04/99");
const std::string master_card_label = std::string("Expires on 10/98");
#endif
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
visa_label, kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
Suggestion(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("8765"),
master_card_label, kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
// Test that we return credit card suggestions for secure pages that have a
// form action set to "javascript:something".
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_SecureContext_JavascriptFormAction) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
// Have the form action be a javascript function (which is a valid URL).
form.action = GURL("javascript:alert('Hello');");
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
const std::string visa_label = std::string("Expires on 04/99");
const std::string master_card_label = std::string("Expires on 10/98");
#endif
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
visa_label, kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
Suggestion(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("8765"),
master_card_label, kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
// Test that we return all credit card suggestions in the case that two cards
// have the same obfuscated number.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_RepeatedObfuscatedNumber) {
// Add a credit card with the same obfuscated number as Elvis's.
// |credit_card| will be owned by the mock PersonalDataManager.
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "Elvis Presley",
"5231567890123456", // Mastercard
"05", "2999", "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000007");
credit_card.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(15));
personal_data_.AddCreditCard(credit_card);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label1 = std::string("10/98");
const std::string master_card_label2 = std::string("05/99");
#else
const std::string visa_label = std::string("Expires on 04/99");
const std::string master_card_label1 = std::string("Expires on 10/98");
const std::string master_card_label2 = std::string("Expires on 05/99");
#endif
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
visa_label, kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
Suggestion(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("8765"),
master_card_label1, kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)),
Suggestion(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("3456"),
master_card_label2, kMasterCard,
autofill_manager_->GetPackedCreditCardID(7)));
}
// Test that we return profile and credit card suggestions for combined forms.
TEST_P(SuggestionMatchingTest, GetAddressAndCreditCardSuggestions) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[0];
GetAutofillSuggestions(form, field);
std::string label1;
std::string label2;
switch (enabled_feature_) {
case EnabledFeature::kDesktop:
// 23456789012 is not formatted because it is invalid for the app locale.
// It has an extra digit.
label1 = MakeLabel(
{"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
label2 = MakeLabel({"3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901",
"theking@gmail.com"});
break;
case EnabledFeature::kMobileShowAll:
label1 = MakeMobileLabel(
{"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
label2 = MakeMobileLabel({"3734 Elvis Presley Blvd., Apt. 10",
"(234) 567-8901", "theking@gmail.com"});
break;
case EnabledFeature::kMobileShowOne:
label1 = "123 Apple St., unit 6";
label2 = "3734 Elvis Presley Blvd., Apt. 10";
break;
case EnabledFeature::kNone:
label1 = "123 Apple St.";
label2 = "3734 Elvis Presley Blvd.";
}
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion("Charles", label1, "", 1),
Suggestion("Elvis", label2, "", 2));
const int kPageID2 = 2;
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
GetAutofillSuggestions(kPageID2, form, field);
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
const std::string visa_label = std::string("Expires on 04/99");
const std::string master_card_label = std::string("Expires on 10/98");
#endif
// Test that we sent the credit card suggestions to the external delegate.
CheckSuggestions(
kPageID2,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
visa_label, kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
Suggestion(std::string("Mastercard ") +
test::ObfuscatedCardDigitsAsUTF8("8765"),
master_card_label, kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
// Test that for non-https forms with both address and credit card fields, we
// only return address suggestions. Instead of credit card suggestions, we
// should return a warning explaining that credit card profile suggestions are
// unavailable when the form is not https.
TEST_P(AutofillManagerStructuredProfileTest,
GetAddressAndCreditCardSuggestionsNonHttps) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
CreateTestCreditCardFormData(&form, false, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[0];
GetAutofillSuggestions(form, field);
// Verify that suggestions are returned.
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
const int kPageID2 = 2;
GetAutofillSuggestions(kPageID2, form, field);
// Test that we sent the right values to the external delegate.
CheckSuggestions(kPageID2,
Suggestion(l10n_util::GetStringUTF8(
IDS_AUTOFILL_WARNING_INSECURE_CONNECTION),
"", "", -1));
// Clear the test credit cards and try again -- we shouldn't return a warning.
personal_data_.ClearCreditCards();
GetAutofillSuggestions(form, field);
external_delegate_->CheckNoSuggestions(kDefaultPageID);
}
TEST_P(AutofillManagerStructuredProfileTest,
ShouldShowAddressSuggestionsIfCreditCardAutofillDisabled) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(
features::kAutofillCreditCardAblationExperiment);
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[0];
GetAutofillSuggestions(form, field);
// Verify that suggestions are returned.
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
// Test that the correct section is filled.
TEST_F(AutofillManagerTest, FillTriggeredSection) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
size_t index_of_trigger_field = form.fields.size();
test::CreateTestAddressFormData(&form);
FormsSeen({form});
// Check that the form has been parsed into two sections.
ASSERT_NE(form.fields.size(), 0u);
ASSERT_EQ(index_of_trigger_field, form.fields.size() / 2);
{
FormStructure* form_structure;
AutofillField* autofill_field;
bool found = autofill_manager_->GetCachedFormAndField(
form, form.fields[index_of_trigger_field], &form_structure,
&autofill_field);
ASSERT_TRUE(found);
for (size_t i = 0; i < form.fields.size() / 2; ++i) {
size_t j = form.fields.size() / 2 + i;
ASSERT_EQ(form_structure->field(i)->name, form_structure->field(j)->name);
ASSERT_NE(form_structure->field(i)->section,
form_structure->field(j)->section);
ASSERT_TRUE(form_structure->field(i)->SameFieldAs(form.fields[j]));
ASSERT_TRUE(form_structure->field(j)->SameFieldAs(form.fields[i]));
}
}
const char guid[] = "00000000-0000-0000-0000-000000000001";
AutofillProfile* profile = personal_data_.GetProfileWithGUID(guid);
ASSERT_TRUE(profile);
EXPECT_EQ(1U, profile->use_count());
EXPECT_NE(base::Time(), profile->use_date());
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(
kDefaultPageID, form, form.fields[index_of_trigger_field],
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
// Extract the sections into individual forms to reduce boiler plate code.
size_t mid = response_data.fields.size() / 2;
FormData section1 = response_data;
FormData section2 = response_data;
section1.fields.erase(section1.fields.begin() + mid, section1.fields.end());
section2.fields.erase(section2.fields.begin(), section2.fields.end() - mid);
// First section should be empty, second should be filled.
ExpectFilledForm(response_page_id, section1, kDefaultPageID, "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", true, false,
false);
ExpectFilledAddressFormElvis(response_page_id, section2, kDefaultPageID,
false);
}
// Tests that AutofillManager ignores loss of focus events sent from the
// renderer if the renderer did not have a previously-interacted form.
// TODO(crbug.com/1140473): Remove this test when workaround is no longer
// needed.
TEST_F(AutofillManagerTest,
ShouldIgnoreLossOfFocusWithNoPreviouslyInteractedForm) {
FormData form;
test::CreateTestAddressFormData(&form);
autofill_manager_->UpdatePendingForm(form);
ASSERT_TRUE(autofill_manager_->pending_form_data()->SameFormAs(form));
// Receiving a notification that focus is no longer on the form *without* the
// renderer having a previously-interacted form should not result in
// any changes to the pending form.
autofill_manager_->OnFocusNoLongerOnForm(/*had_interacted_form=*/false);
EXPECT_TRUE(autofill_manager_->pending_form_data()->SameFormAs(form));
}
TEST_F(AutofillManagerTest,
ShouldNotShowCreditCardsSuggestionsIfCreditCardAutofillDisabled) {
DisableCreditCardAutofill();
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[0];
GetAutofillSuggestions(form, field);
// Check that credit card suggestions will not be available.
external_delegate_->CheckNoSuggestions(kDefaultPageID);
}
TEST_F(AutofillManagerTest,
ShouldLogFormSubmitEventIfCreditCardAutofillDisabled) {
DisableCreditCardAutofill();
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[0];
GetAutofillSuggestions(form, field);
base::HistogramTester histogram_tester;
FormSubmitted(form);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE,
1);
}
// Test that we return normal Autofill suggestions when trying to autofill
// already filled forms.
TEST_P(SuggestionMatchingTest, GetFieldSuggestionsWhenFormIsAutofilled) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Mark one of the fields as filled.
form.fields[2].is_autofilled = true;
const FormFieldData& field = form.fields[0];
GetAutofillSuggestions(form, field);
std::string label1;
std::string label2;
switch (enabled_feature_) {
// 23456789012 is not formatted because it is invalid for the app locale.
// It has an extra digit.
case EnabledFeature::kDesktop:
label1 = MakeLabel(
{"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
label2 = MakeLabel({"3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901",
"theking@gmail.com"});
break;
case EnabledFeature::kMobileShowAll:
label1 = MakeMobileLabel(
{"123 Apple St., unit 6", "23456789012", "buddy@gmail.com"});
label2 = MakeMobileLabel({"3734 Elvis Presley Blvd., Apt. 10",
"(234) 567-8901", "theking@gmail.com"});
break;
case EnabledFeature::kMobileShowOne:
label1 = "123 Apple St., unit 6";
label2 = "3734 Elvis Presley Blvd., Apt. 10";
break;
case EnabledFeature::kNone:
label1 = "123 Apple St.";
label2 = "3734 Elvis Presley Blvd.";
}
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion("Charles", label1, "", 1),
Suggestion("Elvis", label2, "", 2));
}
// Test that nothing breaks when there are autocomplete suggestions but no
// autofill suggestions.
TEST_P(AutofillManagerStructuredProfileTest,
GetFieldSuggestionsForAutocompleteOnly) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
FormFieldData field;
test::CreateTestFormField("Some Field", "somefield", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
GetAutofillSuggestions(form, field);
// Add some Autocomplete suggestions.
// This triggers the combined message send.
std::vector<base::string16> suggestions;
suggestions.push_back(ASCIIToUTF16("one"));
suggestions.push_back(ASCIIToUTF16("two"));
AutocompleteSuggestionsReturned(suggestions);
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion("one", "", "", 0),
Suggestion("two", "", "", 0));
}
// Test that we do not return duplicate values drawn from multiple profiles when
// filling an already filled field.
TEST_P(SuggestionMatchingTest, GetFieldSuggestionsWithDuplicateValues) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// |profile| will be owned by the mock PersonalDataManager.
AutofillProfile profile;
test::SetProfileInfo(&profile, "Elvis", "", "", "", "", "", "", "", "", "",
"", "");
profile.set_guid("00000000-0000-0000-0000-000000000101");
personal_data_.AddProfile(profile);
FormFieldData& field = form.fields[0];
field.is_autofilled = true;
field.value = ASCIIToUTF16("Elvis");
GetAutofillSuggestions(form, field);
std::string label;
switch (enabled_feature_) {
case EnabledFeature::kDesktop:
case EnabledFeature::kMobileShowAll:
case EnabledFeature::kMobileShowOne:
label = "3734 Elvis Presley Blvd., Apt. 10";
break;
case EnabledFeature::kNone:
label = "3734 Elvis Presley Blvd.";
}
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion("Elvis", label, "", 1));
}
TEST_P(SuggestionMatchingTest, GetProfileSuggestions_FancyPhone) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
AutofillProfile profile;
profile.set_guid("00000000-0000-0000-0000-000000000103");
profile.SetInfo(NAME_FULL, ASCIIToUTF16("Natty Bumppo"), "en-US");
profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1800PRAIRIE"));
personal_data_.AddProfile(profile);
const FormFieldData& field = form.fields[9];
GetAutofillSuggestions(form, field);
std::string value1;
std::string value2;
std::string value3;
std::string label1;
std::string label2;
std::string label3;
switch (enabled_feature_) {
// 23456789012 is not formatted because it is invalid for the app locale.
// It has an extra digit.
case EnabledFeature::kDesktop:
value1 = "(800) 772-4743";
value2 = "23456789012";
value3 = "(234) 567-8901";
label1 = "Natty Bumppo";
label2 = MakeLabel(
{"Charles Holley", "123 Apple St., unit 6", "buddy@gmail.com"});
label3 = MakeLabel({"Elvis Presley", "3734 Elvis Presley Blvd., Apt. 10",
"theking@gmail.com"});
break;
case EnabledFeature::kMobileShowAll:
value1 = "(800) 772-4743";
value2 = "23456789012";
value3 = "(234) 567-8901";
label1 = "Natty";
label2 = MakeMobileLabel(
{"Charles", "123 Apple St., unit 6", "buddy@gmail.com"});
label3 = MakeMobileLabel(
{"Elvis", "3734 Elvis Presley Blvd., Apt. 10", "theking@gmail.com"});
break;
case EnabledFeature::kMobileShowOne:
value1 = "(800) 772-4743";
value2 = "23456789012";
value3 = "(234) 567-8901";
label1 = "";
label2 = "123 Apple St., unit 6";
label3 = "3734 Elvis Presley Blvd., Apt. 10";
break;
case EnabledFeature::kNone:
value1 = "18007724743"; // 1800PRAIRIE
value2 = "23456789012";
value3 = "12345678901";
label1 = "Natty Bumppo";
label2 = "123 Apple St.";
label3 = "3734 Elvis Presley Blvd.";
}
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion(value1, label1, "", 1),
Suggestion(value2, label2, "", 2),
Suggestion(value3, label3, "", 3));
}
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_ForPhonePrefixOrSuffix) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
struct {
const char* const label;
const char* const name;
size_t max_length;
const char* const autocomplete_attribute;
} test_fields[] = {{"country code", "country_code", 1, "tel-country-code"},
{"area code", "area_code", 3, "tel-area-code"},
{"phone", "phone_prefix", 3, "tel-local-prefix"},
{"-", "phone_suffix", 4, "tel-local-suffix"},
{"Phone Extension", "ext", 5, "tel-extension"}};
FormFieldData field;
for (const auto& test_field : test_fields) {
test::CreateTestFormField(test_field.label, test_field.name, "", "text",
&field);
field.max_length = test_field.max_length;
field.autocomplete_attribute = std::string();
form.fields.push_back(field);
}
std::vector<FormData> forms(1, form);
FormsSeen(forms);
personal_data_.ClearProfiles();
AutofillProfile profile;
profile.set_guid("00000000-0000-0000-0000-000000000104");
profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1800FLOWERS"));
personal_data_.AddProfile(profile);
const FormFieldData& phone_prefix = form.fields[2];
GetAutofillSuggestions(form, phone_prefix);
// Test that we sent the right prefix values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion("356", "1800FLOWERS", "", 1));
const FormFieldData& phone_suffix = form.fields[3];
GetAutofillSuggestions(form, phone_suffix);
// Test that we sent the right suffix values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion("9377", "1800FLOWERS", "", 1));
}
// Tests that we return email profile suggestions values
// when the email field with username autocomplete attribute exist.
TEST_P(AutofillManagerStructuredProfileTest,
GetProfileSuggestions_ForEmailFieldWithUserNameAutocomplete) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
struct {
const char* const label;
const char* const name;
size_t max_length;
const char* const autocomplete_attribute;
} test_fields[] = {{"First Name", "firstname", 30, "given-name"},
{"Last Name", "lastname", 30, "family-name"},
{"Email", "email", 30, "username"},
{"Password", "password", 30, "new-password"}};
FormFieldData field;
for (const auto& test_field : test_fields) {
const char* const field_type =
strcmp(test_field.name, "password") == 0 ? "password" : "text";
test::CreateTestFormField(test_field.label, test_field.name, "", field_type,
&field);
field.max_length = test_field.max_length;
field.autocomplete_attribute = test_field.autocomplete_attribute;
form.fields.push_back(field);
}
std::vector<FormData> forms(1, form);
FormsSeen(forms);
personal_data_.ClearProfiles();
AutofillProfile profile;
profile.set_guid("00000000-0000-0000-0000-000000000103");
profile.SetRawInfo(NAME_FULL, ASCIIToUTF16("Natty Bumppo"));
profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("test@example.com"));
personal_data_.AddProfile(profile);
GetAutofillSuggestions(form, form.fields[2]);
CheckSuggestions(kDefaultPageID,
Suggestion("test@example.com", "Natty Bumppo", "", 1));
}
// Test that we correctly fill an address form.
TEST_P(AutofillManagerStructuredProfileTest, FillAddressForm) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000001";
AutofillProfile* profile = personal_data_.GetProfileWithGUID(guid);
ASSERT_TRUE(profile);
EXPECT_EQ(1U, profile->use_count());
EXPECT_NE(base::Time(), profile->use_date());
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
ExpectFilledAddressFormElvis(response_page_id, response_data, kDefaultPageID,
false);
EXPECT_EQ(2U, profile->use_count());
EXPECT_NE(base::Time(), profile->use_date());
}
TEST_P(AutofillManagerStructuredProfileTest, WillFillCreditCardNumber) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData* number_field = nullptr;
FormFieldData* name_field = nullptr;
FormFieldData* month_field = nullptr;
for (size_t i = 0; i < form.fields.size(); ++i) {
if (form.fields[i].name == ASCIIToUTF16("cardnumber"))
number_field = &form.fields[i];
else if (form.fields[i].name == ASCIIToUTF16("nameoncard"))
name_field = &form.fields[i];
else if (form.fields[i].name == ASCIIToUTF16("ccmonth"))
month_field = &form.fields[i];
}
// Empty form - whole form is Autofilled.
EXPECT_TRUE(WillFillCreditCardNumber(form, *number_field));
EXPECT_TRUE(WillFillCreditCardNumber(form, *name_field));
// If the user has entered a value, it won't be overridden.
number_field->value = ASCIIToUTF16("gibberish");
EXPECT_TRUE(WillFillCreditCardNumber(form, *number_field));
EXPECT_FALSE(WillFillCreditCardNumber(form, *name_field));
// But if that value is removed, it will be Autofilled.
number_field->value.clear();
EXPECT_TRUE(WillFillCreditCardNumber(form, *name_field));
// When the number is already autofilled, we won't fill it.
number_field->is_autofilled = true;
EXPECT_FALSE(WillFillCreditCardNumber(form, *name_field));
EXPECT_TRUE(WillFillCreditCardNumber(form, *number_field));
// If another field is filled, we would still fill other non-filled fields in
// the section.
number_field->is_autofilled = false;
name_field->is_autofilled = true;
EXPECT_TRUE(WillFillCreditCardNumber(form, *name_field));
}
// Test that we correctly log FIELD_WAS_AUTOFILLED event in UserHappiness.
TEST_P(AutofillManagerStructuredProfileTest,
FillCreditCardForm_LogFieldWasAutofill) {
// Set up our form data.
FormData form;
// Construct a form with a 4 fields: cardholder name, card number,
// expiration date and cvc.
CreateTestCreditCardFormData(&form, true, true);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000004";
int response_page_id = 0;
FormData response_data;
base::HistogramTester histogram_tester;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
// Cardholder name, card number, expiration data were autofilled but cvc was
// not be autofilled.
histogram_tester.ExpectBucketCount("Autofill.UserHappiness.CreditCard",
AutofillMetrics::FIELD_WAS_AUTOFILLED, 3);
}
// Test that we correctly fill a credit card form.
TEST_P(AutofillManagerStructuredProfileTest, FillCreditCardForm_Simple) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000004";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
ExpectFilledCreditCardFormElvis(response_page_id, response_data,
kDefaultPageID, false);
}
// Test that whitespace is stripped from the credit card number.
TEST_P(AutofillManagerStructuredProfileTest,
FillCreditCardForm_StripCardNumberWhitespace) {
// Same as the SetUp(), but generate Elvis card with whitespace in credit
// card number. |credit_card| will be owned by the TestPersonalDataManager.
personal_data_.ClearCreditCards();
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "Elvis Presley",
"4234 5678 9012 3456", // Visa
"04", "2999", "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000008");
personal_data_.AddCreditCard(credit_card);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000008";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
ExpectFilledCreditCardFormElvis(response_page_id, response_data,
kDefaultPageID, false);
}
// Test that separator characters are stripped from the credit card number.
TEST_P(AutofillManagerStructuredProfileTest,
FillCreditCardForm_StripCardNumberSeparators) {
// Same as the SetUp(), but generate Elvis card with separator characters in
// credit card number. |credit_card| will be owned by the
// TestPersonalDataManager.
personal_data_.ClearCreditCards();
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "Elvis Presley",
"4234-5678-9012-3456", // Visa
"04", "2999", "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000009");
personal_data_.AddCreditCard(credit_card);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000009";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
ExpectFilledCreditCardFormElvis(response_page_id, response_data,
kDefaultPageID, false);
}
// Test that we correctly fill a credit card form with month input type.
// Test 1 of 4: Empty month, empty year
TEST_P(AutofillManagerStructuredProfileTest, FillCreditCardForm_NoYearNoMonth) {
personal_data_.ClearCreditCards();
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
"4234567890654321", // Visa
"", "", "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000007");
personal_data_.AddCreditCard(credit_card);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, true);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000007";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
ExpectFilledCreditCardYearMonthWithYearMonth(response_page_id, response_data,
kDefaultPageID, false, "", "");
}
// Test that we correctly fill a credit card form with month input type.
// Test 2 of 4: Non-empty month, empty year
TEST_P(AutofillManagerStructuredProfileTest, FillCreditCardForm_NoYearMonth) {
personal_data_.ClearCreditCards();
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
"4234567890654321", // Visa
"04", "", "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000007");
personal_data_.AddCreditCard(credit_card);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, true);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000007";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
ExpectFilledCreditCardYearMonthWithYearMonth(response_page_id, response_data,
kDefaultPageID, false, "", "04");
}
// Test that we correctly fill a credit card form with month input type.
// Test 3 of 4: Empty month, non-empty year
TEST_P(AutofillManagerStructuredProfileTest, FillCreditCardForm_YearNoMonth) {
// Same as the SetUp(), but generate 4 credit cards with year month
// combination.
personal_data_.ClearCreditCards();
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
"4234567890654321", // Visa
"", "2999", "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000007");
personal_data_.AddCreditCard(credit_card);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, true);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000007";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
ExpectFilledCreditCardYearMonthWithYearMonth(
response_page_id, response_data, kDefaultPageID, false, "2999", "");
}
// Test that we correctly fill a credit card form with month input type.
// Test 4 of 4: Non-empty month, non-empty year
TEST_P(AutofillManagerStructuredProfileTest, FillCreditCardForm_YearMonth) {
personal_data_.ClearCreditCards();
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
"4234567890654321", // Visa
"04", "2999", "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000007");
personal_data_.AddCreditCard(credit_card);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, true);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000007";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
ExpectFilledCreditCardYearMonthWithYearMonth(
response_page_id, response_data, kDefaultPageID, false, "2999", "04");
}
// Test that only the first 16 credit card number fields are filled.
TEST_P(AutofillManagerStructuredProfileTest,
FillOnlyFirstNineteenCreditCardNumberFields) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Card Name", "cardname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "cardlastname", "", "text", &field);
form.fields.push_back(field);
// Add 20 credit card number fields with distinct names.
for (int i = 0; i < 20; i++) {
base::string16 field_name =
base::ASCIIToUTF16("Card Number ") + base::NumberToString16(i + 1);
test::CreateTestFormField(base::UTF16ToASCII(field_name).c_str(),
"cardnumber", "", "text", &field);
form.fields.push_back(field);
}
test::CreateTestFormField("CVC", "cvc", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000004";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
ExpectFilledField("Card Name", "cardname", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("Last Name", "cardlastname", "Presley", "text",
response_data.fields[1]);
// Verify that the first 19 credit card number fields are filled.
for (int i = 0; i < 19; i++) {
base::string16 field_name =
base::ASCIIToUTF16("Card Number ") + base::NumberToString16(i + 1);
ExpectFilledField(base::UTF16ToASCII(field_name).c_str(), "cardnumber",
"4234567890123456", "text", response_data.fields[2 + i]);
}
// Verify that the 20th. credit card number field is not filled.
ExpectFilledField("Card Number 20", "cardnumber", "", "text",
response_data.fields[21]);
ExpectFilledField("CVC", "cvc", "", "text", response_data.fields[22]);
}
// Test that only the first 16 of identical fields are filled.
TEST_P(AutofillManagerStructuredProfileTest,
FillOnlyFirstSixteenIdenticalCreditCardNumberFields) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Card Name", "cardname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "cardlastname", "", "text", &field);
form.fields.push_back(field);
// Add 20 identical card number fields.
for (int i = 0; i < 20; i++) {
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
form.fields.push_back(field);
}
test::CreateTestFormField("CVC", "cvc", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000004";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
ExpectFilledField("Card Name", "cardname", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("Last Name", "cardlastname", "Presley", "text",
response_data.fields[1]);
// Verify that the first 19 card number fields are filled.
for (int i = 0; i < 19; i++) {
ExpectFilledField("Card Number", "cardnumber", "4234567890123456", "text",
response_data.fields[2 + i]);
}
// Verify that the 20th. card number field is not filled.
ExpectFilledField("Card Number", "cardnumber", "", "text",
response_data.fields[21]);
ExpectFilledField("CVC", "cvc", "", "text", response_data.fields[22]);
}
// Test the credit card number is filled correctly into single-digit fields.
TEST_P(AutofillManagerStructuredProfileTest,
FillCreditCardNumberIntoSingleDigitFields) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Card Name", "cardname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "cardlastname", "", "text", &field);
form.fields.push_back(field);
// Add 20 identical card number fields.
for (int i = 0; i < 20; i++) {
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
// Limit the length the field to 1.
field.max_length = 1;
form.fields.push_back(field);
}
test::CreateTestFormField("CVC", "cvc", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000004";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
ExpectFilledField("Card Name", "cardname", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("Last Name", "cardlastname", "Presley", "text",
response_data.fields[1]);
// Verify that the first 19 card number fields are filled.
base::string16 card_number = base::ASCIIToUTF16("4234567890123456");
for (unsigned int i = 0; i < 19; i++) {
ExpectFilledField("Card Number", "cardnumber",
i < card_number.length()
? base::UTF16ToASCII(card_number.substr(i, 1)).c_str()
: "4234567890123456",
"text", response_data.fields[2 + i]);
}
// Verify that the 20th. card number field is contains the full value.
ExpectFilledField("Card Number", "cardnumber", "", "text",
response_data.fields[21]);
ExpectFilledField("CVC", "cvc", "", "text", response_data.fields[22]);
}
// Test that we correctly fill a credit card form with first and last cardholder
// name.
TEST_P(AutofillManagerStructuredProfileTest, FillCreditCardForm_SplitName) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Card Name", "cardname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "cardlastname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("CVC", "cvc", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000004";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
ExpectFilledField("Card Name", "cardname", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("Last Name", "cardlastname", "Presley", "text",
response_data.fields[1]);
ExpectFilledField("Card Number", "cardnumber", "4234567890123456", "text",
response_data.fields[2]);
}
// Test that only filled selection boxes are counted for the type filling limit.
TEST_P(AutofillManagerStructuredProfileTest,
OnlyCountFilledSelectionBoxesForTypeFillingLimit) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Middle Name", "middlename", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
// Create a selection box for the state that hat the correct entry to be
// filled with user data. Note, TN is the official abbreviation for Tennessee.
test::CreateTestSelectField("State", "state", "", {"AA", "BB", "TN"},
{"AA", "BB", "TN"}, 3, &field);
form.fields.push_back(field);
// Add 20 selection boxes that can not be filled since the correct entry
// is missing.
for (int i = 0; i < 20; i++) {
test::CreateTestSelectField("State", "state", "", {"AA", "BB", "CC"},
{"AA", "BB", "CC"}, 3, &field);
form.fields.push_back(field);
}
// Add 20 other selection boxes that should be fillable since the correct
// entry is present.
for (int i = 0; i < 20; i++) {
test::CreateTestSelectField("State", "state", "", {"AA", "BB", "TN"},
{"AA", "BB", "TN"}, 3, &field);
form.fields.push_back(field);
}
// Create a selection box for the state that hat the correct entry to be
// filled with user data. Note, TN is the official abbreviation for Tennessee.
for (int i = 0; i < 20; ++i) {
test::CreateTestSelectField("Country", "country", "", {"DE", "FR", "US"},
{"DE", "FR", "US"}, 3, &field);
form.fields.push_back(field);
}
std::vector<FormData> forms(1, form);
FormsSeen(forms);
AutofillProfile profile;
const char guid[] = "00000000-0000-0000-0000-000000000123";
test::SetProfileInfo(&profile, "Elvis", "Aaron", "Presley",
"theking@gmail.com", "1987", "3734 Elvis Presley Blvd.",
"Apt. 10", "Memphis", "Tennessee", "38116", "US",
"12345678901");
profile.set_guid(guid);
personal_data_.AddProfile(profile);
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
// Verify the correct filling of the name entries.
ExpectFilledField("First Name", "firstname", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("Middle Name", "middlename", "Aaron", "text",
response_data.fields[1]);
ExpectFilledField("Last Name", "lastname", "Presley", "text",
response_data.fields[2]);
// Verify that the first selection box is correctly filled.
ExpectFilledField("State", "state", "TN", "select-one",
response_data.fields[3]);
// Verify that the next 20 selection boxes are not filled.
for (int i = 0; i < 20; i++) {
ExpectFilledField("State", "state", "", "select-one",
response_data.fields[4 + i]);
}
// Verify that the remaining selection boxes are correctly filled again
// because there's no limit on filling ADDRESS_HOME_STATE fields.
for (int i = 0; i < 20; i++) {
ExpectFilledField("State", "state", "TN", "select-one",
response_data.fields[24 + i]);
}
// Verify that only the first 9 of the remaining selection boxes are
// correctly filled due to the limit on filling ADDRESS_HOME_COUNTRY fields.
for (int i = 0; i < 20; i++) {
ExpectFilledField("Country", "country", i < 9 ? "US" : "", "select-one",
response_data.fields[44 + i]);
}
}
// Test that we correctly fill a combined address and credit card form.
TEST_P(AutofillManagerStructuredProfileTest, FillAddressAndCreditCardForm) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// First fill the address data.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
{
SCOPED_TRACE("Address");
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
ExpectFilledAddressFormElvis(response_page_id, response_data,
kDefaultPageID, true);
}
// Now fill the credit card data.
const int kPageID2 = 2;
const char guid2[] = "00000000-0000-0000-0000-000000000004";
response_page_id = 0;
{
FillAutofillFormDataAndSaveResults(kPageID2, form, form.fields.back(),
MakeFrontendID(guid2, std::string()),
&response_page_id, &response_data);
SCOPED_TRACE("Credit card");
ExpectFilledCreditCardFormElvis(response_page_id, response_data, kPageID2,
true);
}
}
// Test that a field with an unrecognized autocomplete attribute is not filled.
TEST_P(AutofillManagerStructuredProfileTest,
FillAddressForm_UnrecognizedAttribute) {
FormData address_form;
address_form.name = ASCIIToUTF16("MyForm");
address_form.url = GURL("https://myform.com/form.html");
address_form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
// Set a valid autocomplete attribute for the first name.
test::CreateTestFormField("First name", "firstname", "", "text", &field);
field.autocomplete_attribute = "given-name";
address_form.fields.push_back(field);
// Set no autocomplete attribute for the middle name.
test::CreateTestFormField("Middle name", "middle", "", "text", &field);
field.autocomplete_attribute = "";
address_form.fields.push_back(field);
// Set an unrecognized autocomplete attribute for the last name.
test::CreateTestFormField("Last name", "lastname", "", "text", &field);
field.autocomplete_attribute = "unrecognized";
address_form.fields.push_back(field);
std::vector<FormData> address_forms(1, address_form);
FormsSeen(address_forms);
// Fill the address form.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(
kDefaultPageID, address_form, address_form.fields[0],
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
// The fist and middle names should be filled.
ExpectFilledField("First name", "firstname", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("Middle name", "middle", "Aaron", "text",
response_data.fields[1]);
// The last name should not be filled.
ExpectFilledField("Last name", "lastname", "", "text",
response_data.fields[2]);
}
// Test that non credit card related fields with the autocomplete attribute set
// to off are filled on all platforms when the feature to autofill all addresses
// is enabled (default).
TEST_P(AutofillManagerStructuredProfileTest,
FillAddressForm_AutocompleteOffNotRespected) {
FormData address_form;
address_form.name = ASCIIToUTF16("MyForm");
address_form.url = GURL("https://myform.com/form.html");
address_form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First name", "firstname", "", "text", &field);
address_form.fields.push_back(field);
test::CreateTestFormField("Middle name", "middle", "", "text", &field);
field.should_autocomplete = false;
address_form.fields.push_back(field);
test::CreateTestFormField("Last name", "lastname", "", "text", &field);
field.should_autocomplete = true;
address_form.fields.push_back(field);
test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
field.should_autocomplete = false;
address_form.fields.push_back(field);
std::vector<FormData> address_forms(1, address_form);
FormsSeen(address_forms);
// Fill the address form.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(
kDefaultPageID, address_form, address_form.fields[0],
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
// All fields should be filled.
ExpectFilledField("First name", "firstname", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("Middle name", "middle", "Aaron", "text",
response_data.fields[1]);
ExpectFilledField("Last name", "lastname", "Presley", "text",
response_data.fields[2]);
ExpectFilledField("Address Line 1", "addr1", "3734 Elvis Presley Blvd.",
"text", response_data.fields[3]);
}
// Test that if a company is of a format of a birthyear and the relevant feature
// is enabled, we would not fill it.
TEST_P(AutofillManagerStructuredProfileTest, FillAddressForm_CompanyBirthyear) {
// Set up our form data.
FormData address_form;
address_form.name = ASCIIToUTF16("MyForm");
address_form.url = GURL("https://myform.com/form.html");
address_form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First name", "firstname", "", "text", &field);
address_form.fields.push_back(field);
test::CreateTestFormField("Middle name", "middle", "", "text", &field);
address_form.fields.push_back(field);
test::CreateTestFormField("Last name", "lastname", "", "text", &field);
address_form.fields.push_back(field);
test::CreateTestFormField("Company", "company", "", "text", &field);
address_form.fields.push_back(field);
std::vector<FormData> address_forms(1, address_form);
FormsSeen(address_forms);
AutofillProfile profile;
const char guid[] = "00000000-0000-0000-0000-000000000123";
test::SetProfileInfo(&profile, "Elvis", "Aaron", "Presley",
"theking@gmail.com", "1987", "3734 Elvis Presley Blvd.",
"Apt. 10", "Memphis", "Tennessee", "38116", "US",
"12345678901");
profile.set_guid(guid);
personal_data_.AddProfile(profile);
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(
kDefaultPageID, address_form, *address_form.fields.begin(),
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
// All the fields should be filled except the company.
ExpectFilledField("First name", "firstname", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("Middle name", "middle", "Aaron", "text",
response_data.fields[1]);
ExpectFilledField("Last name", "lastname", "Presley", "text",
response_data.fields[2]);
ExpectFilledField("Company", "company", "", "text", response_data.fields[3]);
}
// Test that a field with a value equal to it's placeholder attribute is filled.
TEST_P(AutofillManagerStructuredProfileTest,
FillAddressForm_PlaceholderEqualsValue) {
FormData address_form;
address_form.name = ASCIIToUTF16("MyForm");
address_form.url = GURL("https://myform.com/form.html");
address_form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
// Set the same placeholder and value for each field.
test::CreateTestFormField("First name", "firstname", "", "text", &field);
field.placeholder = ASCIIToUTF16("First Name");
field.value = ASCIIToUTF16("First Name");
address_form.fields.push_back(field);
test::CreateTestFormField("Middle name", "middle", "", "text", &field);
field.placeholder = ASCIIToUTF16("Middle Name");
field.value = ASCIIToUTF16("Middle Name");
address_form.fields.push_back(field);
test::CreateTestFormField("Last name", "lastname", "", "text", &field);
field.placeholder = ASCIIToUTF16("Last Name");
field.value = ASCIIToUTF16("Last Name");
address_form.fields.push_back(field);
std::vector<FormData> address_forms(1, address_form);
FormsSeen(address_forms);
// Fill the address form.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(
kDefaultPageID, address_form, address_form.fields[0],
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
// All the fields should be filled.
ExpectFilledField("First name", "firstname", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("Middle name", "middle", "Aaron", "text",
response_data.fields[1]);
ExpectFilledField("Last name", "lastname", "Presley", "text",
response_data.fields[2]);
}
// Test that a credit card field with an unrecognized autocomplete attribute
// gets filled.
TEST_P(AutofillManagerStructuredProfileTest,
FillCreditCardForm_UnrecognizedAttribute) {
// Set up the form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
// Set a valid autocomplete attribute on the card name.
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
field.autocomplete_attribute = "cc-name";
form.fields.push_back(field);
// Set no autocomplete attribute on the card number.
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
field.autocomplete_attribute = "";
form.fields.push_back(field);
// Set an unrecognized autocomplete attribute on the expiration month.
test::CreateTestFormField("Expiration Date", "ccmonth", "", "text", &field);
field.autocomplete_attribute = "unrecognized";
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000004";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
// The credit card name and number should be filled.
ExpectFilledField("Name on Card", "nameoncard", "Elvis Presley", "text",
response_data.fields[0]);
ExpectFilledField("Card Number", "cardnumber", "4234567890123456", "text",
response_data.fields[1]);
// The expiration month should be filled.
ExpectFilledField("Expiration Date", "ccmonth", "04/2999", "text",
response_data.fields[2]);
}
// Test that credit card fields are filled even if they have the autocomplete
// attribute set to off.
TEST_P(AutofillManagerStructuredProfileTest,
FillCreditCardForm_AutocompleteOff) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
// Set the autocomplete=off on all fields.
for (FormFieldData field : form.fields)
field.should_autocomplete = false;
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000004";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
// All fields should be filled.
ExpectFilledCreditCardFormElvis(response_page_id, response_data,
kDefaultPageID, false);
}
// Test that selecting an expired credit card fills everything except the
// expiration date.
TEST_P(AutofillManagerStructuredProfileTest, FillCreditCardForm_ExpiredCard) {
personal_data_.ClearCreditCards();
CreditCard expired_card;
test::SetCreditCardInfo(&expired_card, "Homer Simpson",
"4234567890654321", // Visa
"05", "2000", "1");
expired_card.set_guid("00000000-0000-0000-0000-000000000009");
personal_data_.AddCreditCard(expired_card);
// Set up the form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
// Create a credit card form.
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
field.autocomplete_attribute = "cc-name";
form.fields.push_back(field);
std::vector<const char*> kCreditCardTypes = {"Visa", "Mastercard", "AmEx",
"discover"};
test::CreateTestSelectField("Card Type", "cardtype", "", kCreditCardTypes,
kCreditCardTypes, 4, &field);
field.autocomplete_attribute = "cc-type";
form.fields.push_back(field);
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
field.autocomplete_attribute = "cc-number";
form.fields.push_back(field);
test::CreateTestFormField("Expiration Month", "ccmonth", "", "text", &field);
field.autocomplete_attribute = "cc-exp-month";
form.fields.push_back(field);
test::CreateTestFormField("Expiration Year", "ccyear", "", "text", &field);
field.autocomplete_attribute = "cc-exp-year";
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000009";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()),
&response_page_id, &response_data);
// The credit card name, type and number should be filled.
ExpectFilledField("Name on Card", "nameoncard", "Homer Simpson", "text",
response_data.fields[0]);
ExpectFilledField("Card Type", "cardtype", "Visa", "select-one",
response_data.fields[1]);
ExpectFilledField("Card Number", "cardnumber", "4234567890654321", "text",
response_data.fields[2]);
// The expiration month and year should not be filled.
ExpectFilledField("Expiration Month", "ccmonth", "", "text",
response_data.fields[3]);
ExpectFilledField("Expiration Year", "ccyear", "", "text",
response_data.fields[4]);
}
// Test that non-focusable field is ignored while inferring boundaries between
// sections, but not filled.
TEST_P(AutofillManagerStructuredProfileTest, FillFormWithNonFocusableFields) {
// Create a form with both focusable and non-focusable fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("", "lastname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("", "email", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
test::CreateTestFormField("", "email_", "", "text", &field);
field.is_focusable = false;
form.fields.push_back(field);
test::CreateTestFormField("Country", "country", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Fill the form
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
// All the visible fields should be filled as all the fields belong to the
// same logical section.
ASSERT_EQ(6U, response_data.fields.size());
ExpectFilledField("First Name", "firstname", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("", "lastname", "Presley", "text", response_data.fields[1]);
ExpectFilledField("", "email", "theking@gmail.com", "text",
response_data.fields[2]);
ExpectFilledField("Phone Number", "phonenumber", "12345678901", "tel",
response_data.fields[3]);
ExpectFilledField("", "email_", "", "text", response_data.fields[4]);
ExpectFilledField("Country", "country", "United States", "text",
response_data.fields[5]);
}
// Test that we correctly fill a form that has multiple logical sections, e.g.
// both a billing and a shipping address.
TEST_P(AutofillManagerStructuredProfileTest, FillFormWithMultipleSections) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
const size_t kAddressFormSize = form.fields.size();
test::CreateTestAddressFormData(&form);
for (size_t i = kAddressFormSize; i < form.fields.size(); ++i) {
// Make sure the fields have distinct names.
form.fields[i].name = form.fields[i].name + ASCIIToUTF16("_");
}
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Fill the first section.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
{
SCOPED_TRACE("Address 1");
// The second address section should be empty.
ASSERT_EQ(response_data.fields.size(), 2 * kAddressFormSize);
for (size_t i = kAddressFormSize; i < form.fields.size(); ++i) {
EXPECT_EQ(base::string16(), response_data.fields[i].value);
}
// The first address section should be filled with Elvis's data.
response_data.fields.resize(kAddressFormSize);
ExpectFilledAddressFormElvis(response_page_id, response_data,
kDefaultPageID, false);
}
// Fill the second section, with the initiating field somewhere in the middle
// of the section.
const int kPageID2 = 2;
const char guid2[] = "00000000-0000-0000-0000-000000000001";
ASSERT_LT(9U, kAddressFormSize);
response_page_id = 0;
FillAutofillFormDataAndSaveResults(
kPageID2, form, form.fields[kAddressFormSize + 9],
MakeFrontendID(std::string(), guid2), &response_page_id, &response_data);
{
SCOPED_TRACE("Address 2");
ASSERT_EQ(response_data.fields.size(), form.fields.size());
// The first address section should be empty.
ASSERT_EQ(response_data.fields.size(), 2 * kAddressFormSize);
for (size_t i = 0; i < kAddressFormSize; ++i) {
EXPECT_EQ(base::string16(), response_data.fields[i].value);
}
// The second address section should be filled with Elvis's data.
FormData secondSection = response_data;
secondSection.fields.erase(secondSection.fields.begin(),
secondSection.fields.begin() + kAddressFormSize);
for (size_t i = 0; i < kAddressFormSize; ++i) {
// Restore the expected field names.
base::string16 name = secondSection.fields[i].name;
base::string16 original_name = name.substr(0, name.size() - 1);
secondSection.fields[i].name = original_name;
}
ExpectFilledAddressFormElvis(response_page_id, secondSection, kPageID2,
false);
}
}
// Test that we correctly fill a form that has author-specified sections, which
// might not match our expected section breakdown.
TEST_P(AutofillManagerStructuredProfileTest,
FillFormWithAuthorSpecifiedSections) {
// Create a form with a billing section and an unnamed section, interleaved.
// The billing section includes both address and credit card fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("", "country", "", "text", &field);
field.autocomplete_attribute = "section-billing country";
form.fields.push_back(field);
test::CreateTestFormField("", "firstname", "", "text", &field);
field.autocomplete_attribute = "given-name";
form.fields.push_back(field);
test::CreateTestFormField("", "lastname", "", "text", &field);
field.autocomplete_attribute = "family-name";
form.fields.push_back(field);
test::CreateTestFormField("", "address", "", "text", &field);
field.autocomplete_attribute = "section-billing address-line1";
form.fields.push_back(field);
test::CreateTestFormField("", "city", "", "text", &field);
field.autocomplete_attribute = "section-billing locality";
form.fields.push_back(field);
test::CreateTestFormField("", "state", "", "text", &field);
field.autocomplete_attribute = "section-billing region";
form.fields.push_back(field);
test::CreateTestFormField("", "zip", "", "text", &field);
field.autocomplete_attribute = "section-billing postal-code";
form.fields.push_back(field);
test::CreateTestFormField("", "ccname", "", "text", &field);
field.autocomplete_attribute = "section-billing cc-name";
form.fields.push_back(field);
test::CreateTestFormField("", "ccnumber", "", "text", &field);
field.autocomplete_attribute = "section-billing cc-number";
form.fields.push_back(field);
test::CreateTestFormField("", "ccexp", "", "text", &field);
field.autocomplete_attribute = "section-billing cc-exp";
form.fields.push_back(field);
test::CreateTestFormField("", "email", "", "text", &field);
field.autocomplete_attribute = "email";
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Fill the unnamed section.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[1],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
{
SCOPED_TRACE("Unnamed section");
EXPECT_EQ(kDefaultPageID, response_page_id);
EXPECT_EQ(ASCIIToUTF16("MyForm"), response_data.name);
EXPECT_EQ(GURL("https://myform.com/form.html"), response_data.url);
EXPECT_EQ(GURL("https://myform.com/submit.html"), response_data.action);
ASSERT_EQ(11U, response_data.fields.size());
ExpectFilledField("", "country", "", "text", response_data.fields[0]);
ExpectFilledField("", "firstname", "Elvis", "text",
response_data.fields[1]);
ExpectFilledField("", "lastname", "Presley", "text",
response_data.fields[2]);
ExpectFilledField("", "address", "", "text", response_data.fields[3]);
ExpectFilledField("", "city", "", "text", response_data.fields[4]);
ExpectFilledField("", "state", "", "text", response_data.fields[5]);
ExpectFilledField("", "zip", "", "text", response_data.fields[6]);
ExpectFilledField("", "ccname", "", "text", response_data.fields[7]);
ExpectFilledField("", "ccnumber", "", "text", response_data.fields[8]);
ExpectFilledField("", "ccexp", "", "text", response_data.fields[9]);
ExpectFilledField("", "email", "theking@gmail.com", "text",
response_data.fields[10]);
}
// Fill the address portion of the billing section.
const int kPageID2 = 2;
const char guid2[] = "00000000-0000-0000-0000-000000000001";
response_page_id = 0;
FillAutofillFormDataAndSaveResults(kPageID2, form, form.fields[0],
MakeFrontendID(std::string(), guid2),
&response_page_id, &response_data);
{
SCOPED_TRACE("Billing address");
EXPECT_EQ(kPageID2, response_page_id);
EXPECT_EQ(ASCIIToUTF16("MyForm"), response_data.name);
EXPECT_EQ(GURL("https://myform.com/form.html"), response_data.url);
EXPECT_EQ(GURL("https://myform.com/submit.html"), response_data.action);
ASSERT_EQ(11U, response_data.fields.size());
ExpectFilledField("", "country", "US", "text", response_data.fields[0]);
ExpectFilledField("", "firstname", "", "text", response_data.fields[1]);
ExpectFilledField("", "lastname", "", "text", response_data.fields[2]);
ExpectFilledField("", "address", "3734 Elvis Presley Blvd.", "text",
response_data.fields[3]);
ExpectFilledField("", "city", "Memphis", "text", response_data.fields[4]);
ExpectFilledField("", "state", "Tennessee", "text",
response_data.fields[5]);
ExpectFilledField("", "zip", "38116", "text", response_data.fields[6]);
ExpectFilledField("", "ccname", "", "text", response_data.fields[7]);
ExpectFilledField("", "ccnumber", "", "text", response_data.fields[8]);
ExpectFilledField("", "ccexp", "", "text", response_data.fields[9]);
ExpectFilledField("", "email", "", "text", response_data.fields[10]);
}
// Fill the credit card portion of the billing section.
const int kPageID3 = 3;
const char guid3[] = "00000000-0000-0000-0000-000000000004";
response_page_id = 0;
FillAutofillFormDataAndSaveResults(
kPageID3, form, form.fields[form.fields.size() - 2],
MakeFrontendID(guid3, std::string()), &response_page_id, &response_data);
{
SCOPED_TRACE("Credit card");
EXPECT_EQ(kPageID3, response_page_id);
EXPECT_EQ(ASCIIToUTF16("MyForm"), response_data.name);
EXPECT_EQ(GURL("https://myform.com/form.html"), response_data.url);
EXPECT_EQ(GURL("https://myform.com/submit.html"), response_data.action);
ASSERT_EQ(11U, response_data.fields.size());
ExpectFilledField("", "country", "", "text", response_data.fields[0]);
ExpectFilledField("", "firstname", "", "text", response_data.fields[1]);
ExpectFilledField("", "lastname", "", "text", response_data.fields[2]);
ExpectFilledField("", "address", "", "text", response_data.fields[3]);
ExpectFilledField("", "city", "", "text", response_data.fields[4]);
ExpectFilledField("", "state", "", "text", response_data.fields[5]);
ExpectFilledField("", "zip", "", "text", response_data.fields[6]);
ExpectFilledField("", "ccname", "Elvis Presley", "text",
response_data.fields[7]);
ExpectFilledField("", "ccnumber", "4234567890123456", "text",
response_data.fields[8]);
ExpectFilledField("", "ccexp", "04/2999", "text", response_data.fields[9]);
ExpectFilledField("", "email", "", "text", response_data.fields[10]);
}
}
// Test that we correctly fill a form that has a single logical section with
// multiple email address fields.
TEST_P(AutofillManagerStructuredProfileTest, FillFormWithMultipleEmails) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
FormFieldData field;
test::CreateTestFormField("Confirm email", "email2", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Fill the form.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
// The second email address should be filled.
EXPECT_EQ(ASCIIToUTF16("theking@gmail.com"),
response_data.fields.back().value);
// The remainder of the form should be filled as usual.
response_data.fields.pop_back();
ExpectFilledAddressFormElvis(response_page_id, response_data, kDefaultPageID,
false);
}
// Test that we correctly fill a previously auto-filled form.
TEST_P(AutofillManagerStructuredProfileTest, FillAutofilledForm) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
// Mark the address fields as autofilled.
for (auto iter = form.fields.begin(); iter != form.fields.end(); ++iter) {
iter->is_autofilled = true;
}
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// First fill the address data.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
{
SCOPED_TRACE("Address");
ExpectFilledForm(response_page_id, response_data, kDefaultPageID, "Elvis",
"", "", "", "", "", "", "", "", "", "", "", "", "", "",
true, true, false);
}
// Now fill the credit card data.
const int kPageID2 = 2;
const char guid2[] = "00000000-0000-0000-0000-000000000004";
response_page_id = 0;
FillAutofillFormDataAndSaveResults(kPageID2, form, form.fields.back(),
MakeFrontendID(guid2, std::string()),
&response_page_id, &response_data);
{
SCOPED_TRACE("Credit card 1");
ExpectFilledCreditCardFormElvis(response_page_id, response_data, kPageID2,
true);
}
// Now set the credit card fields to also be auto-filled, and try again to
// fill the credit card data
for (auto iter = form.fields.begin(); iter != form.fields.end(); ++iter) {
iter->is_autofilled = true;
}
const int kPageID3 = 3;
response_page_id = 0;
FillAutofillFormDataAndSaveResults(
kPageID3, form, form.fields[form.fields.size() - 2],
MakeFrontendID(guid2, std::string()), &response_page_id, &response_data);
{
SCOPED_TRACE("Credit card 2");
ExpectFilledForm(response_page_id, response_data, kPageID3, "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "2999", true, true,
false);
}
}
// Test that we correctly fill a previously partly auto-filled form.
TEST_P(AutofillManagerStructuredProfileTest, FillPartlyAutofilledForm) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
// Mark couple of the address fields as autofilled.
form.fields[3].is_autofilled = true;
form.fields[4].is_autofilled = true;
form.fields[5].is_autofilled = true;
form.fields[6].is_autofilled = true;
form.fields[10].is_autofilled = true;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// First fill the address data.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
{
SCOPED_TRACE("Address");
ExpectFilledForm(response_page_id, response_data, kDefaultPageID, "Elvis",
"Aaron", "Presley", "", "", "", "", "38116",
"United States", "12345678901", "", "", "", "", "", true,
true, false);
}
// Now fill the credit card data.
const int kPageID2 = 2;
const char guid2[] = "00000000-0000-0000-0000-000000000004";
response_page_id = 0;
FillAutofillFormDataAndSaveResults(kPageID2, form, form.fields.back(),
MakeFrontendID(guid2, std::string()),
&response_page_id, &response_data);
{
SCOPED_TRACE("Credit card 1");
ExpectFilledCreditCardFormElvis(response_page_id, response_data, kPageID2,
true);
}
}
// Test that we correctly fill a previously partly auto-filled form.
TEST_P(AutofillManagerStructuredProfileTest, FillPartlyManuallyFilledForm) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
CreateTestCreditCardFormData(&form, true, false);
FormsSeen({form});
// Michael will be overridden with Elvis because Autofill is triggered from
// the first field.
form.fields[0].value = base::ASCIIToUTF16("Michael");
form.fields[0].properties_mask |= kUserTyped;
// Jackson will be preserved.
form.fields[2].value = base::ASCIIToUTF16("Jackson");
form.fields[2].properties_mask |= kUserTyped;
FormsSeen({form});
// First fill the address data.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
{
SCOPED_TRACE("Address");
ExpectFilledForm(response_page_id, response_data, kDefaultPageID, "Elvis",
"Aaron", "Jackson", "3734 Elvis Presley Blvd.", "Apt. 10",
"Memphis", "Tennessee", "38116", "United States",
"12345678901", "theking@gmail.com", "", "", "", "", true,
true, false);
}
// Now fill the credit card data.
const int kPageID2 = 2;
const char guid2[] = "00000000-0000-0000-0000-000000000004";
response_page_id = 0;
FillAutofillFormDataAndSaveResults(kPageID2, form, form.fields.back(),
MakeFrontendID(guid2, std::string()),
&response_page_id, &response_data);
{
SCOPED_TRACE("Credit card 1");
ExpectFilledForm(response_page_id, response_data, kPageID2, "Michael", "",
"Jackson", "", "", "", "", "", "", "", "", "Elvis Presley",
"4234567890123456", "04", "2999", true, true, false);
}
}
// Test that we correctly fill a phone number split across multiple fields.
TEST_P(AutofillManagerStructuredProfileTest, FillPhoneNumber) {
// In one form, rely on the max length attribute to imply US phone number
// parts. In the other form, rely on the autocomplete type attribute.
FormData form_with_us_number_max_length;
form_with_us_number_max_length.name = ASCIIToUTF16("MyMaxlengthPhoneForm");
form_with_us_number_max_length.url =
GURL("https://myform.com/phone_form.html");
form_with_us_number_max_length.action =
GURL("https://myform.com/phone_submit.html");
FormData form_with_autocompletetype = form_with_us_number_max_length;
form_with_autocompletetype.name = ASCIIToUTF16("MyAutocompletetypePhoneForm");
struct {
const char* label;
const char* name;
size_t max_length;
const char* autocomplete_attribute;
} test_fields[] = {{"country code", "country_code", 1, "tel-country-code"},
{"area code", "area_code", 3, "tel-area-code"},
{"phone", "phone_prefix", 3, "tel-local-prefix"},
{"-", "phone_suffix", 4, "tel-local-suffix"},
{"Phone Extension", "ext", 3, "tel-extension"}};
FormFieldData field;
const size_t default_max_length = field.max_length;
for (const auto& test_field : test_fields) {
test::CreateTestFormField(test_field.label, test_field.name, "", "text",
&field);
field.max_length = test_field.max_length;
field.autocomplete_attribute = std::string();
form_with_us_number_max_length.fields.push_back(field);
field.max_length = default_max_length;
field.autocomplete_attribute = test_field.autocomplete_attribute;
form_with_autocompletetype.fields.push_back(field);
}
std::vector<FormData> forms;
forms.push_back(form_with_us_number_max_length);
forms.push_back(form_with_autocompletetype);
FormsSeen(forms);
// We should be able to fill prefix and suffix fields for US numbers.
AutofillProfile* work_profile =
personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
ASSERT_TRUE(work_profile != nullptr);
work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
ASCIIToUTF16("16505554567"));
std::string guid(work_profile->guid());
int page_id = 1;
int response_page_id = 0;
FormData response_data1;
FillAutofillFormDataAndSaveResults(
page_id, form_with_us_number_max_length,
*form_with_us_number_max_length.fields.begin(),
MakeFrontendID(std::string(), guid), &response_page_id, &response_data1);
EXPECT_EQ(1, response_page_id);
ASSERT_EQ(5U, response_data1.fields.size());
EXPECT_EQ(ASCIIToUTF16("1"), response_data1.fields[0].value);
EXPECT_EQ(ASCIIToUTF16("650"), response_data1.fields[1].value);
EXPECT_EQ(ASCIIToUTF16("555"), response_data1.fields[2].value);
EXPECT_EQ(ASCIIToUTF16("4567"), response_data1.fields[3].value);
EXPECT_EQ(base::string16(), response_data1.fields[4].value);
page_id = 2;
response_page_id = 0;
FormData response_data2;
FillAutofillFormDataAndSaveResults(page_id, form_with_autocompletetype,
*form_with_autocompletetype.fields.begin(),
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data2);
EXPECT_EQ(2, response_page_id);
ASSERT_EQ(5U, response_data2.fields.size());
EXPECT_EQ(ASCIIToUTF16("1"), response_data2.fields[0].value);
EXPECT_EQ(ASCIIToUTF16("650"), response_data2.fields[1].value);
EXPECT_EQ(ASCIIToUTF16("555"), response_data2.fields[2].value);
EXPECT_EQ(ASCIIToUTF16("4567"), response_data2.fields[3].value);
EXPECT_EQ(base::string16(), response_data2.fields[4].value);
// We should not be able to fill international numbers correctly in a form
// containing fields with US max_length. However, the field should fill with
// the number of digits equal to the max length specified, starting from the
// right.
work_profile->SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("GB"));
work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
ASCIIToUTF16("447700954321"));
page_id = 3;
response_page_id = 0;
FormData response_data3;
FillAutofillFormDataAndSaveResults(
page_id, form_with_us_number_max_length,
*form_with_us_number_max_length.fields.begin(),
MakeFrontendID(std::string(), guid), &response_page_id, &response_data3);
EXPECT_EQ(3, response_page_id);
ASSERT_EQ(5U, response_data3.fields.size());
EXPECT_EQ(ASCIIToUTF16("4"), response_data3.fields[0].value);
EXPECT_EQ(ASCIIToUTF16("700"), response_data3.fields[1].value);
EXPECT_EQ(ASCIIToUTF16("321"), response_data3.fields[2].value);
EXPECT_EQ(ASCIIToUTF16("4321"), response_data3.fields[3].value);
EXPECT_EQ(base::string16(), response_data3.fields[4].value);
page_id = 4;
response_page_id = 0;
FormData response_data4;
FillAutofillFormDataAndSaveResults(page_id, form_with_autocompletetype,
*form_with_autocompletetype.fields.begin(),
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data4);
EXPECT_EQ(4, response_page_id);
ASSERT_EQ(5U, response_data4.fields.size());
EXPECT_EQ(ASCIIToUTF16("44"), response_data4.fields[0].value);
EXPECT_EQ(ASCIIToUTF16("7700"), response_data4.fields[1].value);
EXPECT_EQ(ASCIIToUTF16("954321"), response_data4.fields[2].value);
EXPECT_EQ(ASCIIToUTF16("954321"), response_data4.fields[3].value);
EXPECT_EQ(base::string16(), response_data4.fields[4].value);
}
TEST_P(AutofillManagerStructuredProfileTest,
FillFirstPhoneNumber_ComponentizedNumbers) {
AutofillProfile* work_profile =
personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
ASSERT_TRUE(work_profile != nullptr);
work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
ASCIIToUTF16("16505554567"));
std::string guid(work_profile->guid());
// Verify only the first complete number is filled when there are multiple
// componentized number fields.
FormData form_with_multiple_componentized_phone_fields;
form_with_multiple_componentized_phone_fields.url =
GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
field.max_length = 10;
form_with_multiple_componentized_phone_fields.name =
ASCIIToUTF16("multiple_componentized_number_fields");
test::CreateTestFormField("Full Name", "full_name", "", "text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("country code", "country_code", "", "text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("area code", "area_code", "", "text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("number", "phone_number", "", "text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("extension", "extension", "", "text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("shipping country code", "shipping_country_code",
"", "text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("shipping area code", "shipping_area_code", "",
"text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("shipping number", "shipping_phone_number", "",
"text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
std::vector<FormData> forms;
forms.push_back(form_with_multiple_componentized_phone_fields);
FormData form_data_copy(form_with_multiple_componentized_phone_fields);
std::vector<FormData> forms_copy;
forms_copy.push_back(form_data_copy);
FormsSeen(forms);
int page_id = 1;
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(
page_id, form_with_multiple_componentized_phone_fields,
*form_with_multiple_componentized_phone_fields.fields.begin(),
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
EXPECT_EQ(1, response_page_id);
// Verify only the first complete set of phone number fields are filled.
ASSERT_EQ(8U, response_data.fields.size());
EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"),
response_data.fields[0].value);
EXPECT_EQ(ASCIIToUTF16("1"), response_data.fields[1].value);
EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value);
EXPECT_EQ(ASCIIToUTF16("5554567"), response_data.fields[3].value);
EXPECT_EQ(base::string16(), response_data.fields[4].value);
EXPECT_EQ(base::string16(), response_data.fields[5].value);
EXPECT_EQ(base::string16(), response_data.fields[6].value);
EXPECT_EQ(base::string16(), response_data.fields[7].value);
}
TEST_P(AutofillManagerStructuredProfileTest,
FillFirstPhoneNumber_WholeNumbers) {
AutofillProfile* work_profile =
personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
ASSERT_TRUE(work_profile != nullptr);
work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
ASCIIToUTF16("16505554567"));
std::string guid(work_profile->guid());
FormData form_with_multiple_whole_number_fields;
form_with_multiple_whole_number_fields.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
field.max_length = 10;
form_with_multiple_whole_number_fields.name =
ASCIIToUTF16("multiple_whole_number_fields");
test::CreateTestFormField("Full Name", "full_name", "", "text", &field);
form_with_multiple_whole_number_fields.fields.push_back(field);
test::CreateTestFormField("number", "phone_number", "", "text", &field);
form_with_multiple_whole_number_fields.fields.push_back(field);
test::CreateTestFormField("extension", "extension", "", "text", &field);
form_with_multiple_whole_number_fields.fields.push_back(field);
test::CreateTestFormField("shipping number", "shipping_phone_number", "",
"text", &field);
form_with_multiple_whole_number_fields.fields.push_back(field);
std::vector<FormData> forms;
forms.push_back(form_with_multiple_whole_number_fields);
FormData form_data_copy(form_with_multiple_whole_number_fields);
std::vector<FormData> forms_copy;
forms_copy.push_back(form_data_copy);
FormsSeen(forms);
int page_id = 1;
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(
page_id, form_with_multiple_whole_number_fields,
*form_with_multiple_whole_number_fields.fields.begin(),
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
EXPECT_EQ(1, response_page_id);
// Verify only the first complete set of phone number fields are filled.
ASSERT_EQ(4U, response_data.fields.size());
EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"),
response_data.fields[0].value);
EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[1].value);
EXPECT_EQ(base::string16(), response_data.fields[2].value);
EXPECT_EQ(base::string16(), response_data.fields[3].value);
}
TEST_P(AutofillManagerStructuredProfileTest,
FillFirstPhoneNumber_FillPartsOnceOnly) {
AutofillProfile* work_profile =
personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
ASSERT_TRUE(work_profile != nullptr);
work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
ASCIIToUTF16("16505554567"));
std::string guid(work_profile->guid());
// Verify only the first complete number is filled when there are multiple
// componentized number fields.
FormData form_with_multiple_componentized_phone_fields;
form_with_multiple_componentized_phone_fields.url =
GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
field.max_length = 10;
form_with_multiple_componentized_phone_fields.name =
ASCIIToUTF16("multiple_componentized_number_fields");
test::CreateTestFormField("Full Name", "full_name", "", "text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("country code", "country_code", "", "text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("area code", "area_code", "", "text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("number", "phone_number", "", "text", &field);
field.autocomplete_attribute = "tel-national";
form_with_multiple_componentized_phone_fields.fields.push_back(field);
field.autocomplete_attribute = "";
test::CreateTestFormField("extension", "extension", "", "text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("shipping country code", "shipping_country_code",
"", "text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("shipping area code", "shipping_area_code", "",
"text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
test::CreateTestFormField("shipping number", "shipping_phone_number", "",
"text", &field);
form_with_multiple_componentized_phone_fields.fields.push_back(field);
std::vector<FormData> forms;
forms.push_back(form_with_multiple_componentized_phone_fields);
FormData form_data_copy(form_with_multiple_componentized_phone_fields);
std::vector<FormData> forms_copy;
forms_copy.push_back(form_data_copy);
FormsSeen(forms);
int page_id = 1;
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(
page_id, form_with_multiple_componentized_phone_fields,
*form_with_multiple_componentized_phone_fields.fields.begin(),
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
EXPECT_EQ(1, response_page_id);
// Verify only the first complete set of phone number fields are filled,
// and phone components are not filled more than once.
ASSERT_EQ(8U, response_data.fields.size());
EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"),
response_data.fields[0].value);
EXPECT_EQ(ASCIIToUTF16("1"), response_data.fields[1].value);
EXPECT_EQ(base::string16(), response_data.fields[2].value);
EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value);
EXPECT_EQ(base::string16(), response_data.fields[4].value);
EXPECT_EQ(base::string16(), response_data.fields[5].value);
EXPECT_EQ(base::string16(), response_data.fields[6].value);
EXPECT_EQ(base::string16(), response_data.fields[7].value);
}
// Verify when extension is misclassified, and there is a complete
// phone field, we do not fill anything to extension field.
TEST_P(AutofillManagerStructuredProfileTest,
FillFirstPhoneNumber_NotFillMisclassifiedExtention) {
AutofillProfile* work_profile =
personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
ASSERT_TRUE(work_profile != nullptr);
work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
ASCIIToUTF16("16505554567"));
std::string guid(work_profile->guid());
FormData form_with_misclassified_extension;
form_with_misclassified_extension.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
field.max_length = 10;
form_with_misclassified_extension.name =
ASCIIToUTF16("complete_phone_form_with_extension");
test::CreateTestFormField("Full Name", "full_name", "", "text", &field);
field.autocomplete_attribute = "name";
form_with_misclassified_extension.fields.push_back(field);
test::CreateTestFormField("address", "address", "", "text", &field);
field.autocomplete_attribute = "addresses";
form_with_misclassified_extension.fields.push_back(field);
test::CreateTestFormField("area code", "area_code", "", "text", &field);
field.autocomplete_attribute = "tel-area-code";
form_with_misclassified_extension.fields.push_back(field);
test::CreateTestFormField("number", "phone_number", "", "text", &field);
field.autocomplete_attribute = "tel-local";
form_with_misclassified_extension.fields.push_back(field);
test::CreateTestFormField("extension", "extension", "", "text", &field);
field.autocomplete_attribute = "tel-local";
form_with_misclassified_extension.fields.push_back(field);
std::vector<FormData> forms;
forms.push_back(form_with_misclassified_extension);
FormData form_data_copy(form_with_misclassified_extension);
std::vector<FormData> forms_copy;
forms_copy.push_back(form_data_copy);
FormsSeen(forms);
int page_id = 1;
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(
page_id, form_with_misclassified_extension,
*form_with_misclassified_extension.fields.begin(),
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
EXPECT_EQ(1, response_page_id);
// Verify the misclassified extension field is not filled.
ASSERT_EQ(5U, response_data.fields.size());
EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"),
response_data.fields[0].value);
EXPECT_EQ(base::string16(), response_data.fields[1].value);
EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value);
EXPECT_EQ(ASCIIToUTF16("5554567"), response_data.fields[3].value);
EXPECT_EQ(base::string16(), response_data.fields[4].value);
}
// Verify when no complete number can be found, we do best-effort filling.
TEST_P(AutofillManagerStructuredProfileTest,
FillFirstPhoneNumber_BestEfforFilling) {
AutofillProfile* work_profile =
personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
ASSERT_TRUE(work_profile != nullptr);
work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
ASCIIToUTF16("16505554567"));
std::string guid(work_profile->guid());
FormData form_with_no_complete_number;
form_with_no_complete_number.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
field.max_length = 10;
form_with_no_complete_number.name = ASCIIToUTF16("no_complete_phone_form");
test::CreateTestFormField("Full Name", "full_name", "", "text", &field);
field.autocomplete_attribute = "name";
form_with_no_complete_number.fields.push_back(field);
test::CreateTestFormField("address", "address", "", "text", &field);
field.autocomplete_attribute = "address"; // not standard, but covered.
form_with_no_complete_number.fields.push_back(field);
test::CreateTestFormField("area code", "area_code", "", "text", &field);
field.autocomplete_attribute = "tel-area-code";
form_with_no_complete_number.fields.push_back(field);
test::CreateTestFormField("extension", "extension", "", "text", &field);
field.autocomplete_attribute = "extension";
form_with_no_complete_number.fields.push_back(field);
std::vector<FormData> forms;
forms.push_back(form_with_no_complete_number);
FormData form_data_copy(form_with_no_complete_number);
std::vector<FormData> forms_copy;
forms_copy.push_back(form_data_copy);
FormsSeen(forms);
int page_id = 1;
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(
page_id, form_with_no_complete_number,
*form_with_no_complete_number.fields.begin(),
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
EXPECT_EQ(1, response_page_id);
// Verify when there is no complete phone number fields, we do best effort
// filling.
ASSERT_EQ(4U, response_data.fields.size());
EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"),
response_data.fields[0].value);
EXPECT_EQ(ASCIIToUTF16("123 Apple St., unit 6"),
response_data.fields[1].value);
EXPECT_EQ(ASCIIToUTF16("650"), response_data.fields[2].value);
EXPECT_EQ(base::string16(), response_data.fields[3].value);
}
// When the focus is on second phone field explicitly, we will fill the
// entire form, both first phone field and second phone field included.
TEST_P(AutofillManagerStructuredProfileTest,
FillFirstPhoneNumber_FocusOnSecondPhoneNumber) {
AutofillProfile* work_profile =
personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
ASSERT_TRUE(work_profile != nullptr);
work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
ASCIIToUTF16("16505554567"));
std::string guid(work_profile->guid());
FormData form_with_multiple_whole_number_fields;
form_with_multiple_whole_number_fields.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
field.max_length = 10;
form_with_multiple_whole_number_fields.name =
ASCIIToUTF16("multiple_whole_number_fields");
test::CreateTestFormField("Full Name", "full_name", "", "text", &field);
form_with_multiple_whole_number_fields.fields.push_back(field);
test::CreateTestFormField("number", "phone_number", "", "text", &field);
form_with_multiple_whole_number_fields.fields.push_back(field);
test::CreateTestFormField("extension", "extension", "", "text", &field);
form_with_multiple_whole_number_fields.fields.push_back(field);
test::CreateTestFormField("shipping number", "shipping_phone_number", "",
"text", &field);
form_with_multiple_whole_number_fields.fields.push_back(field);
std::vector<FormData> forms;
forms.push_back(form_with_multiple_whole_number_fields);
FormData form_data_copy(form_with_multiple_whole_number_fields);
std::vector<FormData> forms_copy;
forms_copy.push_back(form_data_copy);
FormsSeen(forms);
int page_id = 1;
int response_page_id = 0;
FormData response_data;
auto it = form_with_multiple_whole_number_fields.fields.begin();
// Move it to point to "shipping number".
std::advance(it, 3);
FillAutofillFormDataAndSaveResults(
page_id, form_with_multiple_whole_number_fields, *it,
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
EXPECT_EQ(1, response_page_id);
// Verify when the second phone number field is being focused, we fill
// that field *AND* the first phone number field.
ASSERT_EQ(4U, response_data.fields.size());
EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"),
response_data.fields[0].value);
EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[1].value);
EXPECT_EQ(base::string16(), response_data.fields[2].value);
EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value);
}
TEST_P(AutofillManagerStructuredProfileTest,
FillFirstPhoneNumber_HiddenFieldShouldNotCount) {
AutofillProfile* work_profile =
personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
ASSERT_TRUE(work_profile != nullptr);
work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
ASCIIToUTF16("16505554567"));
std::string guid(work_profile->guid());
FormData form_with_multiple_whole_number_fields;
form_with_multiple_whole_number_fields.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
field.max_length = 10;
form_with_multiple_whole_number_fields.name =
ASCIIToUTF16("multiple_whole_number_fields");
test::CreateTestFormField("Full Name", "full_name", "", "text", &field);
form_with_multiple_whole_number_fields.fields.push_back(field);
test::CreateTestFormField("number", "phone_number", "", "text", &field);
field.is_focusable = false;
form_with_multiple_whole_number_fields.fields.push_back(field);
field.is_focusable = true;
test::CreateTestFormField("extension", "extension", "", "text", &field);
form_with_multiple_whole_number_fields.fields.push_back(field);
test::CreateTestFormField("shipping number", "shipping_phone_number", "",
"text", &field);
form_with_multiple_whole_number_fields.fields.push_back(field);
std::vector<FormData> forms;
forms.push_back(form_with_multiple_whole_number_fields);
FormData form_data_copy(form_with_multiple_whole_number_fields);
std::vector<FormData> forms_copy;
forms_copy.push_back(form_data_copy);
FormsSeen(forms);
int page_id = 1;
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(
page_id, form_with_multiple_whole_number_fields,
*form_with_multiple_whole_number_fields.fields.begin(),
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
EXPECT_EQ(1, response_page_id);
// Verify hidden/non-focusable phone field is set to only_fill_when_focused.
ASSERT_EQ(4U, response_data.fields.size());
EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"),
response_data.fields[0].value);
EXPECT_EQ(base::string16(), response_data.fields[1].value);
EXPECT_EQ(base::string16(), response_data.fields[2].value);
EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[3].value);
}
// The hidden and the presentational fields should be filled, only if their
// control type is 'select-one'. This exception is made to support synthetic
// fields.
TEST_P(AutofillManagerStructuredProfileTest,
FormWithHiddenOrPresentationalSelects) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last name", "lastname", "", "text", &field);
form.fields.push_back(field);
{
const std::vector<const char*> values{"CA", "US", "BR"};
const std::vector<const char*> contents{"Canada", "United States",
"Banana Republic"};
test::CreateTestSelectField("Country", "country", "", values, contents,
values.size(), &field);
field.is_focusable = false;
form.fields.push_back(field);
}
{
const std::vector<const char*> values{"NY", "CA", "TN"};
const std::vector<const char*> contents{"New York", "California",
"Tennessee"};
test::CreateTestSelectField("State", "state", "", values, contents,
values.size(), &field);
field.role = FormFieldData::RoleAttribute::kPresentation;
form.fields.push_back(field);
}
test::CreateTestFormField("City", "city", "", "text", &field);
field.is_focusable = false;
form.fields.push_back(field);
test::CreateTestFormField("Street Address", "address", "", "text", &field);
field.role = FormFieldData::RoleAttribute::kPresentation;
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
base::HistogramTester histogram_tester;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
histogram_tester.ExpectTotalCount(
"Autofill.HiddenOrPresentationalSelectFieldsFilled", 2);
ExpectFilledField("First name", "firstname", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("Last name", "lastname", "Presley", "text",
response_data.fields[1]);
ExpectFilledField("Country", "country", "US", "select-one",
response_data.fields[2]);
ExpectFilledField("State", "state", "TN", "select-one",
response_data.fields[3]);
ExpectFilledField("City", "city", "", "text", response_data.fields[4]);
ExpectFilledField("Street Address", "address", "", "text",
response_data.fields[5]);
}
TEST_P(AutofillManagerStructuredProfileTest,
FillFirstPhoneNumber_MultipleSectionFilledCorrectly) {
AutofillProfile* work_profile =
personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
ASSERT_TRUE(work_profile != nullptr);
work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
ASCIIToUTF16("16505554567"));
std::string guid(work_profile->guid());
FormData form_with_multiple_sections;
form_with_multiple_sections.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
field.max_length = 10;
form_with_multiple_sections.name = ASCIIToUTF16("multiple_section_fields");
test::CreateTestFormField("Full Name", "full_name", "", "text", &field);
form_with_multiple_sections.fields.push_back(field);
test::CreateTestFormField("Address", "address", "", "text", &field);
form_with_multiple_sections.fields.push_back(field);
test::CreateTestFormField("number", "phone_number", "", "text", &field);
form_with_multiple_sections.fields.push_back(field);
test::CreateTestFormField("other number", "other_phone_number", "", "text",
&field);
form_with_multiple_sections.fields.push_back(field);
test::CreateTestFormField("extension", "extension", "", "text", &field);
form_with_multiple_sections.fields.push_back(field);
test::CreateTestFormField("Full Name", "full_name", "", "text", &field);
form_with_multiple_sections.fields.push_back(field);
test::CreateTestFormField("Shipping Address", "shipping_address", "", "text",
&field);
form_with_multiple_sections.fields.push_back(field);
test::CreateTestFormField("shipping number", "shipping_phone_number", "",
"text", &field);
form_with_multiple_sections.fields.push_back(field);
test::CreateTestFormField("other shipping number",
"other_shipping_phone_number", "", "text", &field);
form_with_multiple_sections.fields.push_back(field);
std::vector<FormData> forms;
forms.push_back(form_with_multiple_sections);
FormData form_data_copy(form_with_multiple_sections);
std::vector<FormData> forms_copy;
forms_copy.push_back(form_data_copy);
FormsSeen(forms);
int page_id = 1;
int response_page_id = 0;
FormData response_data;
// Fill first sections.
FillAutofillFormDataAndSaveResults(
page_id, form_with_multiple_sections,
*form_with_multiple_sections.fields.begin(),
MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
EXPECT_EQ(1, response_page_id);
// Verify first section is filled with rationalization.
ASSERT_EQ(9U, response_data.fields.size());
EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"),
response_data.fields[0].value);
EXPECT_EQ(ASCIIToUTF16("123 Apple St."), response_data.fields[1].value);
EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[2].value);
EXPECT_EQ(base::string16(), response_data.fields[3].value);
EXPECT_EQ(base::string16(), response_data.fields[4].value);
EXPECT_EQ(base::string16(), response_data.fields[5].value);
EXPECT_EQ(base::string16(), response_data.fields[6].value);
EXPECT_EQ(base::string16(), response_data.fields[7].value);
EXPECT_EQ(base::string16(), response_data.fields[8].value);
// Fill second section.
auto it = form_with_multiple_sections.fields.begin();
std::advance(it, 6); // Pointing to second section.
FillAutofillFormDataAndSaveResults(page_id, form_with_multiple_sections, *it,
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
EXPECT_EQ(1, response_page_id);
// Verify second section is filled with rationalization.
ASSERT_EQ(9U, response_data.fields.size());
EXPECT_EQ(base::string16(), response_data.fields[0].value);
EXPECT_EQ(base::string16(), response_data.fields[1].value);
EXPECT_EQ(base::string16(), response_data.fields[2].value);
EXPECT_EQ(base::string16(), response_data.fields[3].value);
EXPECT_EQ(base::string16(), response_data.fields[4].value);
EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley"),
response_data.fields[5].value);
EXPECT_EQ(ASCIIToUTF16("123 Apple St."), response_data.fields[6].value);
EXPECT_EQ(ASCIIToUTF16("6505554567"), response_data.fields[7].value);
EXPECT_EQ(base::string16(), response_data.fields[8].value);
}
// Test that we can still fill a form when a field has been removed from it.
TEST_P(AutofillManagerStructuredProfileTest, FormChangesRemoveField) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
// Add a field -- we'll remove it again later.
FormFieldData field;
test::CreateTestFormField("Some", "field", "", "text", &field);
form.fields.insert(form.fields.begin() + 3, field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Now, after the call to |FormsSeen|, we remove the field before filling.
form.fields.erase(form.fields.begin() + 3);
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
ExpectFilledAddressFormElvis(response_page_id, response_data, kDefaultPageID,
false);
}
// Test that we can still fill a form when a field has been added to it.
TEST_P(AutofillManagerStructuredProfileTest, FormChangesAddField) {
// The offset of the phone field in the address form.
const int kPhoneFieldOffset = 9;
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
// Remove the phone field -- we'll add it back later.
auto pos = form.fields.begin() + kPhoneFieldOffset;
FormFieldData field = *pos;
pos = form.fields.erase(pos);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Now, after the call to |FormsSeen|, we restore the field before filling.
form.fields.insert(pos, field);
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
ExpectFilledAddressFormElvis(response_page_id, response_data, kDefaultPageID,
false);
}
// Test that we can still fill a form when the visibility of some fields
// changes.
TEST_P(AutofillManagerStructuredProfileTest, FormChangesVisibilityOfFields) {
// Set up our form data.
FormData form;
form.url = GURL("https://www.foo.com/");
FormFieldData field;
// Default is zero, have to set to a number autofill can process.
field.max_length = 10;
form.name = ASCIIToUTF16("multiple_groups_fields");
test::CreateTestFormField("First Name", "first_name", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "last_name", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Address", "address", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Postal Code", "postal_code", "", "text", &field);
field.is_focusable = false;
form.fields.push_back(field);
test::CreateTestFormField("Country", "country", "", "text", &field);
field.is_focusable = false;
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Fill the form with the first profile. The hidden fields will not get
// filled.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
ASSERT_EQ(5U, response_data.fields.size());
ExpectFilledField("First Name", "first_name", "Elvis", "text",
response_data.fields[0]);
ExpectFilledField("Last Name", "last_name", "Presley", "text",
response_data.fields[1]);
ExpectFilledField("Address", "address", "3734 Elvis Presley Blvd.", "text",
response_data.fields[2]);
ExpectFilledField("Postal Code", "postal_code", "", "text",
response_data.fields[3]);
ExpectFilledField("Country", "country", "", "text", response_data.fields[4]);
// Two other fields will show up. Select the second profile. The fields that
// were already filled, would be left unchanged, and the rest would be filled
// with the second profile. (Two different profiles are selected, to make sure
// the right fields are getting filled.)
response_data.fields[3].is_focusable = true;
response_data.fields[4].is_focusable = true;
FormData later_response_data;
const char guid2[] = "00000000-0000-0000-0000-000000000002";
FillAutofillFormDataAndSaveResults(kDefaultPageID, response_data,
response_data.fields[4],
MakeFrontendID(std::string(), guid2),
&response_page_id, &later_response_data);
ASSERT_EQ(5U, later_response_data.fields.size());
ExpectFilledField("First Name", "first_name", "Elvis", "text",
later_response_data.fields[0]);
ExpectFilledField("Last Name", "last_name", "Presley", "text",
later_response_data.fields[1]);
ExpectFilledField("Address", "address", "3734 Elvis Presley Blvd.", "text",
later_response_data.fields[2]);
ExpectFilledField("Postal Code", "postal_code", "79401", "text",
later_response_data.fields[3]);
ExpectFilledField("Country", "country", "United States", "text",
later_response_data.fields[4]);
}
// Test that we are able to save form data when forms are submitted.
TEST_P(AutofillManagerStructuredProfileTest, FormSubmitted) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Fill the form.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
ExpectFilledAddressFormElvis(response_page_id, response_data, kDefaultPageID,
false);
// Simulate form submission. We should call into the PDM to try to save the
// filled data.
FormSubmitted(response_data);
EXPECT_EQ(1, personal_data_.num_times_save_imported_profile_called());
}
// Test that we are saving form data when the FormSubmitted event is sent.
TEST_P(AutofillManagerStructuredProfileTest, FormSubmittedSaveData) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Fill the form.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
ExpectFilledAddressFormElvis(response_page_id, response_data, kDefaultPageID,
false);
autofill_manager_->OnFormSubmitted(response_data, false,
SubmissionSource::FORM_SUBMISSION);
EXPECT_EQ(1, personal_data_.num_times_save_imported_profile_called());
}
// Test that when Autocomplete is enabled and Autofill is disabled, form
// submissions are still received by AutocompleteHistoryManager.
TEST_P(AutofillManagerStructuredProfileTest, FormSubmittedAutocompleteEnabled) {
TestAutofillClient client;
autofill_manager_.reset(
new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnWillSubmitForm(_, true));
FormSubmitted(form);
}
// Test that the value patterns metric is reported.
TEST_P(AutofillManagerStructuredProfileTest, ValuePatternsMetric) {
struct ValuePatternTestCase {
const char* value;
autofill::ValuePatternsMetric pattern;
} kTestCases[] = {
{"user@okaxis", autofill::ValuePatternsMetric::kUpiVpa},
{"IT60X0542811101000000123456", autofill::ValuePatternsMetric::kIban}};
for (const ValuePatternTestCase test_case : kTestCases) {
// Set up our form data.
FormData form;
FormFieldData field;
test::CreateTestFormField("Some label", "my-field", test_case.value, "text",
&field);
field.is_focusable = true; // The metric skips hidden fields.
form.name = ASCIIToUTF16("my-form");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
base::HistogramTester histogram_tester;
FormSubmitted(form);
histogram_tester.ExpectUniqueSample("Autofill.SubmittedValuePatterns",
test_case.pattern, 1);
}
}
// Test that when Autofill is disabled, Autocomplete suggestions are still
// queried.
TEST_P(AutofillManagerStructuredProfileTest,
AutocompleteSuggestions_SomeWhenAutofillDisabled) {
TestAutofillClient client;
autofill_manager_.reset(
new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
external_delegate_ = external_delegate.get();
autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const FormFieldData& field = form.fields[0];
// Expect Autocomplete manager to be called for suggestions.
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions);
GetAutofillSuggestions(form, field);
}
// Test that when Autofill is disabled and the field should not autocomplete,
// autocomplete is not queried for suggestions.
TEST_P(AutofillManagerStructuredProfileTest,
AutocompleteSuggestions_AutofillDisabledAndFieldShouldNotAutocomplete) {
TestAutofillClient client;
autofill_manager_.reset(
new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
external_delegate_ = external_delegate.get();
autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[0];
field.should_autocomplete = false;
// Autocomplete manager is not called for suggestions.
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions)
.Times(0);
GetAutofillSuggestions(form, field);
}
// Test that we do not query for Autocomplete suggestions when there are
// Autofill suggestions available.
TEST_P(AutofillManagerStructuredProfileTest,
AutocompleteSuggestions_NoneWhenAutofillPresent) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const FormFieldData& field = form.fields[0];
// AutocompleteManager is not called for suggestions.
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions)
.Times(0);
GetAutofillSuggestions(form, field);
// Verify that suggestions are returned.
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
// Test that we query for Autocomplete suggestions when there are no Autofill
// suggestions available.
TEST_P(AutofillManagerStructuredProfileTest,
AutocompleteSuggestions_SomeWhenAutofillEmpty) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// No suggestions matching "donkey".
FormFieldData field;
test::CreateTestFormField("Email", "email", "donkey", "email", &field);
// Autocomplete manager is called for suggestions because Autofill is empty.
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions);
GetAutofillSuggestions(form, field);
}
// Test that when Autofill is disabled and the field is a credit card name
// field,
// autocomplete is queried for suggestions.
TEST_P(AutofillManagerStructuredProfileTest,
AutocompleteSuggestions_CreditCardNameFieldShouldAutocomplete) {
TestAutofillClient client;
// Since we are testing a form that submits over HTTP, we also need to set
// the main frame to HTTP in the client, otherwise mixed form warnings will
// trigger and autofill will be disabled.
GURL::Replacements replacements;
replacements.SetScheme(url::kHttpScheme,
url::Component(0, strlen(url::kHttpScheme)));
client.set_form_origin(client.form_origin().ReplaceComponents(replacements));
autofill_manager_.reset(
new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
external_delegate_ = external_delegate.get();
autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, false, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// The first field is "Name on card", which should autocomplete.
FormFieldData field = form.fields[0];
field.should_autocomplete = true;
// Autocomplete manager is not called for suggestions.
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions);
GetAutofillSuggestions(form, field);
}
// Test that when Autofill is disabled and the field is a credit card number
// field, autocomplete is not queried for suggestions.
TEST_P(AutofillManagerStructuredProfileTest,
AutocompleteSuggestions_CreditCardNumberShouldNotAutocomplete) {
TestAutofillClient client;
// Since we are testing a form that submits over HTTP, we also need to set
// the main frame to HTTP in the client, otherwise mixed form warnings will
// trigger and autofill will be disabled.
GURL::Replacements replacements;
replacements.SetScheme(url::kHttpScheme,
url::Component(0, strlen(url::kHttpScheme)));
client.set_form_origin(client.form_origin().ReplaceComponents(replacements));
autofill_manager_.reset(
new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
external_delegate_ = external_delegate.get();
autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, false, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// The second field is "Card Number", which should not autocomplete.
FormFieldData field = form.fields[1];
field.should_autocomplete = true;
// Autocomplete manager is not called for suggestions.
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions)
.Times(0);
GetAutofillSuggestions(form, field);
}
// Test that we do not query for Autocomplete suggestions when there are no
// Autofill suggestions available, and that the field should not autocomplete.
TEST_F(
AutofillManagerTest,
AutocompleteSuggestions_NoneWhenAutofillEmptyFieldShouldNotAutocomplete) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// No suggestions matching "donkey".
FormFieldData field;
field.should_autocomplete = false;
test::CreateTestFormField("Email", "email", "donkey", "email", &field);
// Autocomplete manager is not called for suggestions.
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions)
.Times(0);
GetAutofillSuggestions(form, field);
}
TEST_P(AutofillManagerStructuredProfileTest,
AutocompleteOffRespectedForAutocomplete) {
TestAutofillClient client;
autofill_manager_.reset(
new TestAutofillManager(autofill_driver_.get(), &client, &personal_data_,
autocomplete_history_manager_.get()));
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
auto external_delegate = std::make_unique<TestAutofillExternalDelegate>(
autofill_manager_.get(), autofill_driver_.get(),
/*call_parent_methods=*/false);
external_delegate_ = external_delegate.get();
autofill_manager_->SetExternalDelegateForTest(std::move(external_delegate));
EXPECT_CALL(*(autocomplete_history_manager_.get()),
OnGetAutocompleteSuggestions)
.Times(0);
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData* field = &form.fields[0];
field->should_autocomplete = false;
GetAutofillSuggestions(form, *field);
}
TEST_P(AutofillManagerStructuredProfileTest,
DestructorCancelsAutocompleteQueries) {
EXPECT_CALL(*(autocomplete_history_manager_.get()), CancelPendingQueries)
.Times(1);
autofill_manager_.reset();
}
// Make sure that we don't error out when AutocompleteHistoryManager was
// destroyed before AutofillManager.
TEST_P(AutofillManagerStructuredProfileTest,
Destructor_DeletedAutocomplete_Works) {
// The assertion here is that no exceptions will be thrown.
autocomplete_history_manager_.reset();
autofill_manager_.reset();
}
// Test that OnLoadedServerPredictions can obtain the FormStructure with the
// signature of the queried form from the API and apply type predictions.
// What we test here:
// * The API response parser is used.
// * The query can be processed with a response from the API.
TEST_P(AutofillManagerStructuredProfileTest, OnLoadedServerPredictionsFromApi) {
// First form on the page.
FormData form;
form.unique_renderer_id.value() = 1;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField(/*label=*/"City", /*name=*/"city",
/*value=*/"", /*type=*/"text", /*field=*/&field);
form.fields.push_back(field);
test::CreateTestFormField(/*label=*/"State", /*name=*/"state",
/*value=*/"", /*type=*/"text", /*field=*/&field);
form.fields.push_back(field);
test::CreateTestFormField(/*label=*/"Postal Code", /*name=*/"zipcode",
/*value=*/"", /*type=*/"text", /*field=*/&field);
form.fields.push_back(field);
// Simulate having seen this form on page load.
// |form_structure_instance| will be owned by |autofill_manager_|.
auto form_structure_instance = std::make_unique<TestFormStructure>(form);
// This pointer is valid as long as autofill manager lives.
TestFormStructure* form_structure = form_structure_instance.get();
form_structure->DetermineHeuristicTypes();
autofill_manager_->AddSeenFormStructure(std::move(form_structure_instance));
// Second form on the page.
FormData form2;
form2.unique_renderer_id.value() = 2;
form2.name = ASCIIToUTF16("MyForm2");
form2.url = GURL("https://myform.com/form.html");
form2.action = GURL("https://myform.com/submit.html");
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form2.fields.push_back(field);
test::CreateTestFormField("Middle Name", "middlename", "", "text", &field);
form2.fields.push_back(field);
test::CreateTestFormField("Postal Code", "zipcode", "", "text", &field);
form2.fields.push_back(field);
auto form_structure_instance2 = std::make_unique<TestFormStructure>(form2);
// This pointer is valid as long as autofill manager lives.
TestFormStructure* form_structure2 = form_structure_instance2.get();
form_structure2->DetermineHeuristicTypes();
autofill_manager_->AddSeenFormStructure(std::move(form_structure_instance2));
// Make API response with suggestions.
AutofillQueryResponse response;
AutofillQueryResponse::FormSuggestion* form_suggestion;
// Set suggestions for form 1.
form_suggestion = response.add_form_suggestions();
autofill::test::AddFieldSuggestionToForm(form.fields[0], ADDRESS_HOME_CITY,
form_suggestion);
autofill::test::AddFieldSuggestionToForm(form.fields[1], ADDRESS_HOME_STATE,
form_suggestion);
autofill::test::AddFieldSuggestionToForm(form.fields[2], ADDRESS_HOME_ZIP,
form_suggestion);
// Set suggestions for form 2.
form_suggestion = response.add_form_suggestions();
autofill::test::AddFieldSuggestionToForm(form2.fields[0], NAME_LAST,
form_suggestion);
autofill::test::AddFieldSuggestionToForm(form2.fields[1], NAME_MIDDLE,
form_suggestion);
autofill::test::AddFieldSuggestionToForm(form2.fields[2], ADDRESS_HOME_ZIP,
form_suggestion);
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
std::string encoded_response_string;
base::Base64Encode(response_string, &encoded_response_string);
std::vector<FormSignature> signatures =
test::GetEncodedSignatures({form_structure, form_structure2});
// Run method under test.
base::HistogramTester histogram_tester;
autofill_manager_->OnLoadedServerPredictionsForTest(encoded_response_string,
signatures);
// Verify whether the relevant histograms were updated.
histogram_tester.ExpectBucketCount("Autofill.ServerQueryResponse",
AutofillMetrics::QUERY_RESPONSE_RECEIVED,
1);
histogram_tester.ExpectBucketCount("Autofill.ServerQueryResponse",
AutofillMetrics::QUERY_RESPONSE_PARSED, 1);
// We expect the server suggestions to have been applied to the first field of
// the first form.
EXPECT_EQ(ADDRESS_HOME_CITY,
form_structure->field(0)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_HOME_STATE,
form_structure->field(1)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_HOME_ZIP,
form_structure->field(2)->Type().GetStorableType());
// We expect the server suggestions to have been applied to the second form as
// well.
EXPECT_EQ(NAME_LAST, form_structure2->field(0)->Type().GetStorableType());
EXPECT_EQ(NAME_MIDDLE, form_structure2->field(1)->Type().GetStorableType());
EXPECT_EQ(ADDRESS_HOME_ZIP,
form_structure2->field(2)->Type().GetStorableType());
}
// Test that OnLoadedServerPredictions does not call ParseQueryResponse if the
// AutofillManager has been reset between the time the query was sent and the
// response received.
TEST_P(AutofillManagerStructuredProfileTest,
OnLoadedServerPredictions_ResetManager) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
form_structure->DetermineHeuristicTypes();
std::vector<FormSignature> signatures =
test::GetEncodedSignatures(*form_structure);
autofill_manager_->AddSeenFormStructure(
std::unique_ptr<TestFormStructure>(form_structure));
AutofillQueryResponse response;
auto* form_suggestion = response.add_form_suggestions();
form_suggestion->add_field_suggestions()->set_primary_type_prediction(3);
for (int i = 0; i < 7; ++i) {
form_suggestion->add_field_suggestions()->set_primary_type_prediction(0);
}
form_suggestion->add_field_suggestions()->set_primary_type_prediction(3);
form_suggestion->add_field_suggestions()->set_primary_type_prediction(2);
form_suggestion->add_field_suggestions()->set_primary_type_prediction(61);
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
std::string response_string_base64;
base::Base64Encode(response_string, &response_string_base64);
// Reset the manager (such as during a navigation).
autofill_manager_->Reset();
base::HistogramTester histogram_tester;
autofill_manager_->OnLoadedServerPredictionsForTest(response_string_base64,
signatures);
// Verify that FormStructure::ParseQueryResponse was NOT called.
histogram_tester.ExpectTotalCount("Autofill.ServerQueryResponse", 0);
}
// Test that when server predictions disagree with the heuristic ones, the
// overall types and sections would be set based on the server one.
TEST_P(AutofillManagerStructuredProfileTest,
DetermineHeuristicsWithOverallPrediction) {
// Set up our form data.
FormData form;
form.url = GURL("https://www.myform.com");
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Expiration Year", "exp_year", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Expiration Month", "exp_month", "", "text",
&field);
form.fields.push_back(field);
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
form_structure->DetermineHeuristicTypes();
autofill_manager_->AddSeenFormStructure(
std::unique_ptr<TestFormStructure>(form_structure));
AutofillQueryResponse response;
auto* form_suggestion = response.add_form_suggestions();
autofill::test::AddFieldSuggestionToForm(
form.fields[0], CREDIT_CARD_NAME_FIRST, form_suggestion);
autofill::test::AddFieldSuggestionToForm(
form.fields[1], CREDIT_CARD_NAME_LAST, form_suggestion);
autofill::test::AddFieldSuggestionToForm(form.fields[2], CREDIT_CARD_NUMBER,
form_suggestion);
autofill::test::AddFieldSuggestionToForm(
form.fields[3], CREDIT_CARD_EXP_MONTH, form_suggestion);
autofill::test::AddFieldSuggestionToForm(
form.fields[4], CREDIT_CARD_EXP_4_DIGIT_YEAR, form_suggestion);
std::string response_string;
ASSERT_TRUE(response.SerializeToString(&response_string));
std::string response_string_base64;
base::Base64Encode(response_string, &response_string_base64);
base::HistogramTester histogram_tester;
autofill_manager_->OnLoadedServerPredictionsForTest(
response_string_base64, test::GetEncodedSignatures(*form_structure));
// Verify that FormStructure::ParseQueryResponse was called (here and below).
histogram_tester.ExpectBucketCount("Autofill.ServerQueryResponse",
AutofillMetrics::QUERY_RESPONSE_RECEIVED,
1);
histogram_tester.ExpectBucketCount("Autofill.ServerQueryResponse",
AutofillMetrics::QUERY_RESPONSE_PARSED, 1);
// Since the card holder name appears as the first name + last name (rather
// than the full name), and since they appears as the first fields of the
// section, the heuristics detect them as the address first/last name.
EXPECT_EQ(NAME_FIRST, form_structure->field(0)->heuristic_type());
EXPECT_EQ(NAME_LAST, form_structure->field(1)->heuristic_type());
EXPECT_EQ(CREDIT_CARD_NUMBER, form_structure->field(2)->heuristic_type());
EXPECT_EQ(CREDIT_CARD_EXP_MONTH, form_structure->field(3)->heuristic_type());
EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
form_structure->field(4)->heuristic_type());
// We expect to see the server type as the overall type.
EXPECT_EQ(CREDIT_CARD_NAME_FIRST,
form_structure->field(0)->Type().GetStorableType());
EXPECT_EQ(CREDIT_CARD_NAME_LAST,
form_structure->field(1)->Type().GetStorableType());
EXPECT_EQ(CREDIT_CARD_NUMBER, form_structure->field(2)->heuristic_type());
EXPECT_EQ(CREDIT_CARD_EXP_MONTH, form_structure->field(3)->heuristic_type());
EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
form_structure->field(4)->heuristic_type());
// Although the heuristic types of the first two fields belongs to the address
// section, the final fields' section should be based on the overall
// prediction, therefore they should be grouped in one section.
const auto section = form_structure->field(0)->section;
EXPECT_EQ(section, form_structure->field(1)->section);
EXPECT_EQ(section, form_structure->field(2)->section);
EXPECT_EQ(section, form_structure->field(3)->section);
EXPECT_EQ(section, form_structure->field(4)->section);
}
// Test that we are able to save form data when forms are submitted and we only
// have server data for the field types.
TEST_P(AutofillManagerStructuredProfileTest, FormSubmittedServerTypes) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
FormsSeen(std::vector<FormData>(1, form));
// Simulate having seen this form on page load.
// |form_structure| will be owned by |autofill_manager_|.
TestFormStructure* form_structure = new TestFormStructure(form);
form_structure->DetermineHeuristicTypes();
// Clear the heuristic types, and instead set the appropriate server types.
std::vector<ServerFieldType> heuristic_types, server_types;
for (size_t i = 0; i < form.fields.size(); ++i) {
heuristic_types.push_back(UNKNOWN_TYPE);
server_types.push_back(form_structure->field(i)->heuristic_type());
}
form_structure->SetFieldTypes(heuristic_types, server_types);
autofill_manager_->AddSeenFormStructure(
std::unique_ptr<TestFormStructure>(form_structure));
// Fill the form.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
ExpectFilledAddressFormElvis(response_page_id, response_data, kDefaultPageID,
false);
// Simulate form submission. We should call into the PDM to try to save the
// filled data.
FormSubmitted(response_data);
EXPECT_EQ(1, personal_data_.num_times_save_imported_profile_called());
}
// Test that we are able to save form data after the possible types have been
// determined. We do two submissions and verify that only at the second
// submission are the possible types able to be inferred.
TEST_P(AutofillManagerStructuredProfileTest,
FormSubmittedPossibleTypesTwoSubmissions) {
// Set up our form data.
FormData form;
std::vector<ServerFieldTypeSet> expected_types;
test::CreateTestAddressFormData(&form, &expected_types);
FormsSeen(std::vector<FormData>(1, form));
// Fill the form.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
ExpectFilledAddressFormElvis(response_page_id, response_data, kDefaultPageID,
false);
personal_data_.ClearProfiles();
// The default credit card is a Elvis card. It must be removed because name
// fields would be detected. However at least one profile or card is needed to
// start the upload process, which is why this other card is created.
personal_data_.ClearCreditCards();
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
"4234567890654321", // Visa
"04", "2999", "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000007");
personal_data_.AddCreditCard(credit_card);
ASSERT_EQ(0u, personal_data_.GetProfiles().size());
// Simulate form submission. The first submission should not count the data
// towards possible types. Therefore we expect all UNKNOWN_TYPE entries.
ServerFieldTypeSet type_set;
type_set.insert(UNKNOWN_TYPE);
std::vector<ServerFieldTypeSet> unknown_types(expected_types.size(),
type_set);
autofill_manager_->SetExpectedSubmittedFieldTypes(unknown_types);
FormSubmitted(response_data);
ASSERT_EQ(1u, personal_data_.GetProfiles().size());
// The second submission should now have data by which to infer types.
autofill_manager_->SetExpectedSubmittedFieldTypes(expected_types);
FormSubmitted(response_data);
ASSERT_EQ(1u, personal_data_.GetProfiles().size());
}
// Test that the form signature for an uploaded form always matches the form
// signature from the query.
TEST_P(AutofillManagerStructuredProfileTest, FormSubmittedWithDifferentFields) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Cache the expected form signature.
std::string signature = FormStructure(form).FormSignatureAsStr();
// Change the structure of the form prior to submission.
// Websites would typically invoke JavaScript either on page load or on form
// submit to achieve this.
form.fields.pop_back();
FormFieldData field = form.fields[3];
form.fields[3] = form.fields[7];
form.fields[7] = field;
// Simulate form submission.
FormSubmitted(form);
EXPECT_EQ(signature, autofill_manager_->GetSubmittedFormSignature());
}
// Test that we do not save form data when submitted fields contain default
// values.
TEST_P(AutofillManagerStructuredProfileTest, FormSubmittedWithDefaultValues) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
form.fields[3].value = ASCIIToUTF16("Enter your address");
// Convert the state field to a <select> popup, to make sure that we only
// reject default values for text fields.
ASSERT_TRUE(form.fields[6].name == ASCIIToUTF16("state"));
form.fields[6].form_control_type = "select-one";
form.fields[6].value = ASCIIToUTF16("Tennessee");
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Fill the form.
const char guid[] = "00000000-0000-0000-0000-000000000001";
int response_page_id = 0;
FormData response_data;
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[3],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
// Simulate form submission. We should call into the PDM to try to save the
// filled data.
FormSubmitted(response_data);
EXPECT_EQ(1, personal_data_.num_times_save_imported_profile_called());
// Set the address field's value back to the default value.
response_data.fields[3].value = ASCIIToUTF16("Enter your address");
// Simulate form submission. We should not call into the PDM to try to save
// the filled data, since the filled form is effectively missing an address.
FormSubmitted(response_data);
EXPECT_EQ(1, personal_data_.num_times_save_imported_profile_called());
}
struct ProfileMatchingTypesTestCase {
const char* input_value; // The value to input in the field.
std::set<ServerFieldType>
field_types; // The expected field types to be determined.
std::set<ServerFieldType>
structured_field_types; // The expected field types to be determined.
};
class ProfileMatchingTypesTest
: public AutofillManagerTest,
public ::testing::WithParamInterface<
std::tuple<ProfileMatchingTypesTestCase,
int, // AutofillDataModel::ValidityState
bool, // AutofillDataModel::ValidationSource
bool>> { // kAutofillEnableSupportForMoreStructureInNames
protected:
void SetUp() override {
AutofillManagerTest::SetUp();
InitializeFeatures();
}
bool StructuredNames() const { return structured_names_enabled_; }
void InitializeFeatures();
private:
bool structured_names_enabled_;
base::test::ScopedFeatureList scoped_features_;
};
void ProfileMatchingTypesTest::InitializeFeatures() {
structured_names_enabled_ = std::get<2>(GetParam());
if (structured_names_enabled_) {
scoped_features_.InitAndEnableFeature(
features::kAutofillEnableSupportForMoreStructureInNames);
} else {
scoped_features_.InitAndDisableFeature(
features::kAutofillEnableSupportForMoreStructureInNames);
}
}
const ProfileMatchingTypesTestCase kProfileMatchingTypesTestCases[] = {
// Profile fields matches.
{"Elvis", {NAME_FIRST}, {NAME_FIRST}},
{"Aaron", {NAME_MIDDLE}, {NAME_MIDDLE}},
{"A", {NAME_MIDDLE_INITIAL}, {NAME_MIDDLE_INITIAL}},
{"Presley", {NAME_LAST}, {NAME_LAST, NAME_LAST_SECOND}},
{"Elvis Aaron Presley", {NAME_FULL}, {NAME_FULL}},
{"theking@gmail.com", {EMAIL_ADDRESS}, {EMAIL_ADDRESS}},
{"RCA", {COMPANY_NAME}, {COMPANY_NAME}},
{"3734 Elvis Presley Blvd.", {ADDRESS_HOME_LINE1}, {ADDRESS_HOME_LINE1}},
{"Apt. 10", {ADDRESS_HOME_LINE2}, {ADDRESS_HOME_LINE2}},
{"Memphis", {ADDRESS_HOME_CITY}, {ADDRESS_HOME_CITY}},
{"Tennessee", {ADDRESS_HOME_STATE}, {ADDRESS_HOME_STATE}},
{"38116", {ADDRESS_HOME_ZIP}, {ADDRESS_HOME_ZIP}},
{"USA", {ADDRESS_HOME_COUNTRY}, {ADDRESS_HOME_COUNTRY}},
{"United States", {ADDRESS_HOME_COUNTRY}, {ADDRESS_HOME_COUNTRY}},
{"12345678901", {PHONE_HOME_WHOLE_NUMBER}, {PHONE_HOME_WHOLE_NUMBER}},
{"+1 (234) 567-8901", {PHONE_HOME_WHOLE_NUMBER}, {PHONE_HOME_WHOLE_NUMBER}},
{"(234)567-8901",
{PHONE_HOME_CITY_AND_NUMBER},
{PHONE_HOME_CITY_AND_NUMBER}},
{"2345678901", {PHONE_HOME_CITY_AND_NUMBER}, {PHONE_HOME_CITY_AND_NUMBER}},
{"1", {PHONE_HOME_COUNTRY_CODE}, {PHONE_HOME_COUNTRY_CODE}},
{"234", {PHONE_HOME_CITY_CODE}, {PHONE_HOME_CITY_CODE}},
{"5678901", {PHONE_HOME_NUMBER}, {PHONE_HOME_NUMBER}},
{"567", {PHONE_HOME_NUMBER}, {PHONE_HOME_NUMBER}},
{"8901", {PHONE_HOME_NUMBER}, {PHONE_HOME_NUMBER}},
// Test a European profile.
{"Paris", {ADDRESS_HOME_CITY}, {ADDRESS_HOME_CITY}},
{"ÃŽle de France",
{ADDRESS_HOME_STATE},
{ADDRESS_HOME_STATE}}, // Exact match
{"Ile de France",
{ADDRESS_HOME_STATE},
{ADDRESS_HOME_STATE}}, // Missing accent.
{"-Ile-de-France-",
{ADDRESS_HOME_STATE},
{ADDRESS_HOME_STATE}}, // Extra punctuation.
{"île dÉ FrÃÑÇË",
{ADDRESS_HOME_STATE},
{ADDRESS_HOME_STATE}}, // Other accents & case mismatch.
{"75008", {ADDRESS_HOME_ZIP}, {ADDRESS_HOME_ZIP}},
{"FR", {ADDRESS_HOME_COUNTRY}, {ADDRESS_HOME_COUNTRY}},
{"France", {ADDRESS_HOME_COUNTRY}, {ADDRESS_HOME_COUNTRY}},
{"33249197070", {PHONE_HOME_WHOLE_NUMBER}, {PHONE_HOME_WHOLE_NUMBER}},
{"+33 2 49 19 70 70", {PHONE_HOME_WHOLE_NUMBER}, {PHONE_HOME_WHOLE_NUMBER}},
{"02 49 19 70 70",
{PHONE_HOME_CITY_AND_NUMBER},
{PHONE_HOME_CITY_AND_NUMBER}},
{"0249197070", {PHONE_HOME_CITY_AND_NUMBER}, {PHONE_HOME_CITY_AND_NUMBER}},
{"33", {PHONE_HOME_COUNTRY_CODE}, {PHONE_HOME_COUNTRY_CODE}},
{"2", {PHONE_HOME_CITY_CODE}, {PHONE_HOME_CITY_CODE}},
// Credit card fields matches.
{"John Doe", {CREDIT_CARD_NAME_FULL}, {CREDIT_CARD_NAME_FULL}},
{"John", {CREDIT_CARD_NAME_FIRST}, {CREDIT_CARD_NAME_FIRST}},
{"Doe", {CREDIT_CARD_NAME_LAST}, {CREDIT_CARD_NAME_LAST}},
{"4234-5678-9012-3456", {CREDIT_CARD_NUMBER}, {CREDIT_CARD_NUMBER}},
{"04", {CREDIT_CARD_EXP_MONTH}, {CREDIT_CARD_EXP_MONTH}},
{"April", {CREDIT_CARD_EXP_MONTH}, {CREDIT_CARD_EXP_MONTH}},
{"2999", {CREDIT_CARD_EXP_4_DIGIT_YEAR}, {CREDIT_CARD_EXP_4_DIGIT_YEAR}},
{"99", {CREDIT_CARD_EXP_2_DIGIT_YEAR}, {CREDIT_CARD_EXP_2_DIGIT_YEAR}},
{"04/2999",
{CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
{CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
// Make sure whitespace and invalid characters are handled properly.
{"", {EMPTY_TYPE}, {EMPTY_TYPE}},
{" ", {EMPTY_TYPE}, {EMPTY_TYPE}},
{"***", {UNKNOWN_TYPE}, {UNKNOWN_TYPE}},
{" Elvis", {NAME_FIRST}, {NAME_FIRST}},
{"Elvis ", {NAME_FIRST}, {NAME_FIRST}},
// Make sure fields that differ by case match.
{"elvis ", {NAME_FIRST}, {NAME_FIRST}},
{"UnItEd StAtEs", {ADDRESS_HOME_COUNTRY}, {ADDRESS_HOME_COUNTRY}},
// Make sure fields that differ by punctuation match.
{"3734 Elvis Presley Blvd", {ADDRESS_HOME_LINE1}, {ADDRESS_HOME_LINE1}},
{"3734, Elvis Presley Blvd.",
{ADDRESS_HOME_LINE1},
{ADDRESS_HOME_LINE1}},
// Make sure that a state's full name and abbreviation match.
{"TN",
{ADDRESS_HOME_STATE},
{ADDRESS_HOME_STATE}}, // Saved as "Tennessee" in profile.
{"Texas",
{ADDRESS_HOME_STATE},
{ADDRESS_HOME_STATE}}, // Saved as "TX" in profile.
// Special phone number case. A profile with no country code should
// only match PHONE_HOME_CITY_AND_NUMBER.
{"5142821292", {PHONE_HOME_CITY_AND_NUMBER}, {PHONE_HOME_CITY_AND_NUMBER}},
// Make sure unsupported variants do not match.
{"Elvis Aaron", {UNKNOWN_TYPE}, {UNKNOWN_TYPE}},
{"Mr. Presley", {UNKNOWN_TYPE}, {UNKNOWN_TYPE}},
{"3734 Elvis Presley", {UNKNOWN_TYPE}, {UNKNOWN_TYPE}},
{"38116-1023", {UNKNOWN_TYPE}, {UNKNOWN_TYPE}},
{"5", {UNKNOWN_TYPE}, {UNKNOWN_TYPE}},
{"56", {UNKNOWN_TYPE}, {UNKNOWN_TYPE}},
{"901", {UNKNOWN_TYPE}, {UNKNOWN_TYPE}},
};
// Tests that DeterminePossibleFieldTypesForUpload finds accurate possible
// types and validities.
TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
// Unpack the test parameters
const auto& test_case = std::get<0>(GetParam());
auto validity_state =
static_cast<AutofillDataModel::ValidityState>(std::get<1>(GetParam()));
const auto& validation_source =
static_cast<AutofillDataModel::ValidationSource>(std::get<2>(GetParam()));
SCOPED_TRACE(base::StringPrintf(
"Test: input_value='%s', field_type=%s, validity_state=%d, "
"validation_source=%d "
"structured_names=%s ",
test_case.input_value,
AutofillType(*test_case.field_types.begin()).ToString().c_str(),
validity_state, validation_source, StructuredNames() ? "true" : "false"));
// Take the field types depending on the state of the structured names
// feature.
const std::set<ServerFieldType>& expected_possible_types =
StructuredNames() ? test_case.structured_field_types
: test_case.field_types;
ASSERT_LE(AutofillDataModel::UNVALIDATED, validity_state);
ASSERT_LE(validity_state, AutofillDataModel::UNSUPPORTED);
// Set up the test profiles.
std::vector<AutofillProfile> profiles;
profiles.resize(3);
test::SetProfileInfo(&profiles[0], "Elvis", "Aaron", "Presley",
"theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
"Apt. 10", "Memphis", "Tennessee", "38116", "US",
"+1 (234) 567-8901");
profiles[0].set_guid("00000000-0000-0000-0000-000000000001");
test::SetProfileInfo(&profiles[1], "Charles", "", "Holley", "buddy@gmail.com",
"Decca", "123 Apple St.", "unit 6", "Lubbock", "TX",
"79401", "US", "5142821292");
profiles[1].set_guid("00000000-0000-0000-0000-000000000002");
test::SetProfileInfo(&profiles[2], "Charles", "", "Baudelaire",
"lesfleursdumal@gmail.com", "", "108 Rue Saint-Lazare",
"Apt. 11", "Paris", "ÃŽle de France", "75008", "FR",
"+33 2 49 19 70 70");
profiles[2].set_guid("00000000-0000-0000-0000-000000000001");
// Set the validity state for the matching field type.
for (auto type : expected_possible_types) {
if (GroupTypeOfServerFieldType(type) != CREDIT_CARD) {
for (auto& profile : profiles) {
ASSERT_GT(test_case.field_types.size(), 0U);
if (type == UNKNOWN_TYPE) {
// An UNKNOWN type is always UNVALIDATED
validity_state = AutofillDataModel::UNVALIDATED;
} else if (profile.IsAnInvalidPhoneNumber(type)) {
// A phone field is a compound field, and an invalid part makes
// the phone number invalid.
validity_state = AutofillDataModel::INVALID;
}
profile.SetValidityState(type, validity_state, validation_source);
}
}
}
// Set up the test credit cards.
std::vector<CreditCard> credit_cards;
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "John Doe", "4234-5678-9012-3456", "04",
"2999", "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000003");
credit_cards.push_back(credit_card);
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("", "1", "", "text", &field);
field.value = UTF8ToUTF16(test_case.input_value);
form.fields.push_back(field);
FormStructure form_structure(form);
base::HistogramTester histogram_tester;
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, credit_cards, base::string16(), "en-us", &form_structure);
ASSERT_EQ(1U, form_structure.field_count());
ServerFieldTypeSet possible_types = form_structure.field(0)->possible_types();
EXPECT_EQ(possible_types, expected_possible_types);
for (auto type : expected_possible_types) {
// We don't add validity states for credit card fields.
if (GroupTypeOfServerFieldType(type) != CREDIT_CARD) {
ServerFieldTypeValidityStatesMap possible_types_validities =
form_structure.field(0)->possible_types_validities();
ASSERT_EQ(expected_possible_types.size(),
possible_types_validities.size());
EXPECT_NE(possible_types_validities.end(),
possible_types_validities.find(type));
EXPECT_EQ(possible_types_validities[type][0],
(validation_source == AutofillDataModel::SERVER)
? validity_state
: AutofillDataModel::UNVALIDATED);
}
}
}
// Tests that DeterminePossibleFieldTypesForUpload is called when a form is
// submitted.
TEST_P(AutofillManagerStructuredProfileTest,
DeterminePossibleFieldTypesForUpload_IsTriggered) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
std::vector<ServerFieldTypeSet> expected_types;
std::vector<base::string16> expected_values;
// These fields should all match.
FormFieldData field;
ServerFieldTypeSet types;
test::CreateTestFormField("", "1", "", "text", &field);
expected_values.push_back(ASCIIToUTF16("Elvis"));
types.clear();
types.insert(NAME_FIRST);
form.fields.push_back(field);
expected_types.push_back(types);
test::CreateTestFormField("", "2", "", "text", &field);
expected_values.push_back(ASCIIToUTF16("Aaron"));
types.clear();
types.insert(NAME_MIDDLE);
form.fields.push_back(field);
expected_types.push_back(types);
test::CreateTestFormField("", "3", "", "text", &field);
expected_values.push_back(ASCIIToUTF16("A"));
types.clear();
types.insert(NAME_MIDDLE_INITIAL);
form.fields.push_back(field);
expected_types.push_back(types);
// Make sure the form is in the cache so that it is processed for Autofill
// upload.
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Once the form is cached, fill the values.
EXPECT_EQ(form.fields.size(), expected_values.size());
for (size_t i = 0; i < expected_values.size(); i++) {
form.fields[i].value = expected_values[i];
}
autofill_manager_->SetExpectedSubmittedFieldTypes(expected_types);
FormSubmitted(form);
}
// Test that the possible field types with multiple validities are determined
// correctly.
TEST_P(AutofillManagerStructuredProfileTest,
DeterminePossibleFieldTypesWithMultipleValidities) {
// Set up the user's profiles.
std::vector<AutofillProfile> profiles;
{
AutofillProfile profile;
test::SetProfileInfo(&profile, "Elvis", "Aaron", "Presley",
"theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
"", "Memphis", "Tennessee", "38116", "US",
"(234) 567-8901");
profile.set_guid("00000000-0000-0000-0000-000000000001");
profile.SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::VALID,
AutofillDataModel::SERVER);
profiles.push_back(profile);
}
{
AutofillProfile profile;
test::SetProfileInfo(&profile, "Alice", "", "Munro", "munro@gmail.com", "",
"1331 W Georgia", "", "Vancouver", "Tennessee",
"V4D 4S4", "CA", "(778) 567-8901");
profile.set_guid("00000000-0000-0000-0000-000000000002");
profile.SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::INVALID,
AutofillDataModel::SERVER);
profiles.push_back(profile);
}
// Set up the test cases:
typedef struct {
std::string input_value;
ServerFieldType field_type;
std::vector<AutofillDataModel::ValidityState> expected_validity_states;
} TestFieldData;
std::vector<TestFieldData> test_cases[3];
// Tennessee appears in both of the user's profile as ADDRESS_HOME_STATE. In
// the first one, it's VALID, and for the other, it's INVALID. Therefore, the
// possible_field_types would only include the type ADDRESS_HOME_STATE, and
// the corresponding validity of that type would include both VALID and
// INVALID.
test_cases[0].push_back(
{"Tennessee",
ADDRESS_HOME_STATE,
{AutofillDataModel::VALID, AutofillDataModel::INVALID}});
// Alice appears only in the second profile as a NAME_FIRST, and it's
// UNVALIDATED.
test_cases[1].push_back(
{"Alice", NAME_FIRST, {AutofillDataModel::UNVALIDATED}});
// An UNKNOWN type is always UNVALIDATED.
test_cases[2].push_back({"What a beautiful day!",
UNKNOWN_TYPE,
{AutofillDataModel::UNVALIDATED}});
for (const std::vector<TestFieldData>& test_fields : test_cases) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
// Create the form fields specified in the test case.
FormFieldData field;
ServerFieldTypeSet possible_types;
ServerFieldTypeValidityStatesMap possible_types_validities;
for (const TestFieldData& test_field : test_fields) {
test::CreateTestFormField("", "1", "", "text", &field);
field.value = ASCIIToUTF16(test_field.input_value);
form.fields.push_back(field);
}
// Assign the specified predicted type for each field in the test case.
FormStructure form_structure(form);
for (size_t i = 0; i < test_fields.size(); ++i) {
form_structure.field(i)->set_server_type(test_fields[i].field_type);
}
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, {}, base::string16(), "en-us", &form_structure);
ASSERT_EQ(test_fields.size(), form_structure.field_count());
for (size_t i = 0; i < test_fields.size(); ++i) {
possible_types = form_structure.field(i)->possible_types();
// For both cases we only expect one possible type.
EXPECT_EQ(1U, possible_types.size());
// Expect to see the field_type as the possible type.
EXPECT_NE(possible_types.end(),
possible_types.find(test_fields[i].field_type));
// Expect the same for possible_types_validities.
possible_types_validities =
form_structure.field(i)->possible_types_validities();
EXPECT_EQ(1U, possible_types_validities.size());
EXPECT_NE(possible_types_validities.end(),
possible_types_validities.find(test_fields[i].field_type));
// Check for the expected validity states for the possible type.
EXPECT_EQ(test_fields[i].expected_validity_states.size(),
possible_types_validities[test_fields[i].field_type].size());
for (size_t j = 0; j < test_fields[i].expected_validity_states.size();
++j)
EXPECT_EQ(possible_types_validities[test_fields[i].field_type][j],
test_fields[i].expected_validity_states[j]);
}
}
}
// Tests that DisambiguateUploadTypes makes the correct choices.
TEST_P(AutofillManagerStructuredProfileTest, DisambiguateUploadTypes) {
// Set up the test profile.
std::vector<AutofillProfile> profiles;
AutofillProfile profile;
test::SetProfileInfo(&profile, "Elvis", "Aaron", "Presley",
"theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
"", "Memphis", "Tennessee", "38116", "US",
"(234) 567-8901");
profile.set_guid("00000000-0000-0000-0000-000000000001");
profiles.push_back(profile);
// Set up the test credit card.
std::vector<CreditCard> credit_cards;
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "Elvis Presley", "4234-5678-9012-3456",
"04", "2999", "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000003");
credit_cards.push_back(credit_card);
typedef struct {
std::string input_value;
ServerFieldType predicted_type;
bool expect_disambiguation;
ServerFieldType expected_upload_type;
} TestFieldData;
std::vector<TestFieldData> test_cases[13];
// Address disambiguation.
// An ambiguous address line followed by a field predicted as a line 2 and
// that is empty should be disambiguated as an ADDRESS_HOME_LINE1.
test_cases[0].push_back({"3734 Elvis Presley Blvd.", ADDRESS_HOME_LINE1, true,
ADDRESS_HOME_LINE1});
test_cases[0].push_back({"", ADDRESS_HOME_LINE2, true, EMPTY_TYPE});
// An ambiguous address line followed by a field predicted as a line 2 but
// filled with another know profile value should be disambiguated as an
// ADDRESS_HOME_STREET_ADDRESS.
test_cases[1].push_back({"3734 Elvis Presley Blvd.",
ADDRESS_HOME_STREET_ADDRESS, true,
ADDRESS_HOME_STREET_ADDRESS});
test_cases[1].push_back(
{"38116", ADDRESS_HOME_LINE2, true, ADDRESS_HOME_ZIP});
// An ambiguous address line followed by an empty field predicted as
// something other than a line 2 should be disambiguated as an
// ADDRESS_HOME_STREET_ADDRESS.
test_cases[2].push_back({"3734 Elvis Presley Blvd.",
ADDRESS_HOME_STREET_ADDRESS, true,
ADDRESS_HOME_STREET_ADDRESS});
test_cases[2].push_back({"", ADDRESS_HOME_ZIP, true, EMPTY_TYPE});
// An ambiguous address line followed by no other field should be
// disambiguated as an ADDRESS_HOME_STREET_ADDRESS.
test_cases[3].push_back({"3734 Elvis Presley Blvd.",
ADDRESS_HOME_STREET_ADDRESS, true,
ADDRESS_HOME_STREET_ADDRESS});
// Phone number disambiguation.
// A field with possible types PHONE_HOME_CITY_AND_NUMBER and
// PHONE_HOME_WHOLE_NUMBER should be disambiguated as
// PHONE_HOME_CITY_AND_NUMBER
test_cases[4].push_back({"2345678901", PHONE_HOME_WHOLE_NUMBER, true,
PHONE_HOME_CITY_AND_NUMBER});
// Name disambiguation.
// An ambiguous name field that has no next field and that is preceded by
// a non credit card field should be disambiguated as a non credit card
// name.
test_cases[5].push_back(
{"Memphis", ADDRESS_HOME_CITY, true, ADDRESS_HOME_CITY});
test_cases[5].push_back({"Elvis", CREDIT_CARD_NAME_FIRST, true, NAME_FIRST});
test_cases[5].push_back({"Presley", CREDIT_CARD_NAME_LAST, true, NAME_LAST});
// An ambiguous name field that has no next field and that is preceded by
// a credit card field should be disambiguated as a credit card name.
test_cases[6].push_back(
{"4234-5678-9012-3456", CREDIT_CARD_NUMBER, true, CREDIT_CARD_NUMBER});
test_cases[6].push_back({"Elvis", NAME_FIRST, true, CREDIT_CARD_NAME_FIRST});
test_cases[6].push_back({"Presley", NAME_LAST, true, CREDIT_CARD_NAME_LAST});
// An ambiguous name field that has no previous field and that is
// followed by a non credit card field should be disambiguated as a non
// credit card name.
test_cases[7].push_back({"Elvis", CREDIT_CARD_NAME_FIRST, true, NAME_FIRST});
test_cases[7].push_back({"Presley", CREDIT_CARD_NAME_LAST, true, NAME_LAST});
test_cases[7].push_back(
{"Memphis", ADDRESS_HOME_CITY, true, ADDRESS_HOME_CITY});
// An ambiguous name field that has no previous field and that is followed
// by a credit card field should be disambiguated as a credit card name.
test_cases[8].push_back({"Elvis", NAME_FIRST, true, CREDIT_CARD_NAME_FIRST});
test_cases[8].push_back({"Presley", NAME_LAST, true, CREDIT_CARD_NAME_LAST});
test_cases[8].push_back(
{"4234-5678-9012-3456", CREDIT_CARD_NUMBER, true, CREDIT_CARD_NUMBER});
// An ambiguous name field that is preceded and followed by non credit
// card fields should be disambiguated as a non credit card name.
test_cases[9].push_back(
{"Memphis", ADDRESS_HOME_CITY, true, ADDRESS_HOME_CITY});
test_cases[9].push_back({"Elvis", CREDIT_CARD_NAME_FIRST, true, NAME_FIRST});
test_cases[9].push_back({"Presley", CREDIT_CARD_NAME_LAST, true, NAME_LAST});
test_cases[9].push_back(
{"Tennessee", ADDRESS_HOME_STATE, true, ADDRESS_HOME_STATE});
// An ambiguous name field that is preceded and followed by credit card
// fields should be disambiguated as a credit card name.
test_cases[10].push_back(
{"4234-5678-9012-3456", CREDIT_CARD_NUMBER, true, CREDIT_CARD_NUMBER});
test_cases[10].push_back({"Elvis", NAME_FIRST, true, CREDIT_CARD_NAME_FIRST});
test_cases[10].push_back({"Presley", NAME_LAST, true, CREDIT_CARD_NAME_LAST});
test_cases[10].push_back({"2999", CREDIT_CARD_EXP_4_DIGIT_YEAR, true,
CREDIT_CARD_EXP_4_DIGIT_YEAR});
// An ambiguous name field that is preceded by a non credit card field and
// followed by a credit card field should not be disambiguated.
test_cases[11].push_back(
{"Memphis", ADDRESS_HOME_CITY, true, ADDRESS_HOME_CITY});
test_cases[11].push_back(
{"Elvis", NAME_FIRST, false, CREDIT_CARD_NAME_FIRST});
test_cases[11].push_back(
{"Presley", NAME_LAST, false, CREDIT_CARD_NAME_LAST});
test_cases[11].push_back({"2999", CREDIT_CARD_EXP_4_DIGIT_YEAR, true,
CREDIT_CARD_EXP_4_DIGIT_YEAR});
// An ambiguous name field that is preceded by a credit card field and
// followed by a non credit card field should not be disambiguated.
test_cases[12].push_back({"2999", CREDIT_CARD_EXP_4_DIGIT_YEAR, true,
CREDIT_CARD_EXP_4_DIGIT_YEAR});
test_cases[12].push_back(
{"Elvis", NAME_FIRST, false, CREDIT_CARD_NAME_FIRST});
test_cases[12].push_back(
{"Presley", NAME_LAST, false, CREDIT_CARD_NAME_LAST});
test_cases[12].push_back(
{"Memphis", ADDRESS_HOME_CITY, true, ADDRESS_HOME_CITY});
for (const std::vector<TestFieldData>& test_fields : test_cases) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
// Create the form fields specified in the test case.
FormFieldData field;
for (const TestFieldData& test_field : test_fields) {
test::CreateTestFormField("", "1", "", "text", &field);
field.value = ASCIIToUTF16(test_field.input_value);
form.fields.push_back(field);
}
// Assign the specified predicted type for each field in the test case.
FormStructure form_structure(form);
for (size_t i = 0; i < test_fields.size(); ++i)
form_structure.field(i)->set_server_type(test_fields[i].predicted_type);
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, credit_cards, base::string16(), "en-us", &form_structure);
ASSERT_EQ(test_fields.size(), form_structure.field_count());
// Make sure the disambiguation method selects the expected upload type.
ServerFieldTypeSet possible_types;
for (size_t i = 0; i < test_fields.size(); ++i) {
possible_types = form_structure.field(i)->possible_types();
if (test_fields[i].expect_disambiguation) {
// For structured names it is possible that a field as two out of three
// possible classifications: NAME_FULL, NAME_LAST,
// NAME_LAST_FIRST/SECOND. Note, all cases contain NAME_LAST.
if (StructuredNames() && possible_types.size() == 2) {
EXPECT_TRUE(possible_types.count(NAME_LAST) &&
(possible_types.count(NAME_LAST_SECOND) ||
possible_types.count(NAME_LAST_FIRST) ||
possible_types.count(NAME_FULL)));
} else if (StructuredNames() && possible_types.size() == 3) {
// Or even all three.
EXPECT_TRUE(possible_types.count(NAME_FULL) &&
possible_types.count(NAME_LAST) &&
(possible_types.count(NAME_LAST_SECOND) ||
possible_types.count(NAME_LAST_FIRST)));
} else {
EXPECT_EQ(1U, possible_types.size());
}
EXPECT_NE(possible_types.end(),
possible_types.find(test_fields[i].expected_upload_type));
} else {
// In the context of those tests, it is expected that the type is
// ambiguous.
EXPECT_NE(1U, possible_types.size());
}
}
}
}
// When a field contains fields with UPI ID values, a crowdsourcing vote should
// be uploaded.
TEST_P(AutofillManagerStructuredProfileTest, CrowdsourceUPIVPA) {
std::vector<AutofillProfile> profiles;
std::vector<CreditCard> credit_cards;
FormData form;
FormFieldData field;
test::CreateTestFormField("", "name1", "1234@indianbank", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("", "name2", "not-upi@gmail.com", "text", &field);
form.fields.push_back(field);
FormStructure form_structure(form);
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, credit_cards, base::string16(), "en-us", &form_structure);
EXPECT_THAT(form_structure.field(0)->possible_types(), ElementsAre(UPI_VPA));
EXPECT_THAT(form_structure.field(1)->possible_types(),
Not(Contains(UPI_VPA)));
}
// If a server-side credit card is unmasked by entering the CVC, the
// AutofillManager reuses the CVC value to identify a potentially existing CVC
// form field to cast a |CREDIT_CARD_VERIFICATION_CODE|-type vote.
TEST_P(AutofillManagerStructuredProfileTest, CrowdsourceCVCFieldByValue) {
std::vector<AutofillProfile> profiles;
std::vector<CreditCard> credit_cards;
const char cvc[] = "1234";
const char four_digit_but_not_cvc[] = "6676";
const char credit_card_number[] = "4234-5678-9012-3456";
FormData form;
FormFieldData field1;
test::CreateTestFormField("number", "number", credit_card_number, "text",
&field1);
form.fields.push_back(field1);
// This field would not be detected as CVC heuristically if the CVC value
// wouldn't be known.
FormFieldData field2;
test::CreateTestFormField("not_cvc", "not_cvc", four_digit_but_not_cvc,
"text", &field2);
form.fields.push_back(field2);
// This field has the CVC value used to unlock the card and should be detected
// as the CVC field.
FormFieldData field3;
test::CreateTestFormField("c_v_c", "c_v_c", cvc, "text", &field3);
form.fields.push_back(field3);
FormStructure form_structure(form);
form_structure.field(0)->set_possible_types({CREDIT_CARD_NUMBER});
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, credit_cards, base::ASCIIToUTF16(cvc), "en-us",
&form_structure);
CheckThatOnlyFieldByIndexHasThisPossibleType(
form_structure, 2, CREDIT_CARD_VERIFICATION_CODE,
FieldPropertiesFlags::kKnownValue);
}
// Expiration year field was detected by the server. The other field with a
// 4-digit value should be detected as CVC.
TEST_P(AutofillManagerStructuredProfileTest,
CrowdsourceCVCFieldAfterInvalidExpDateByHeuristics) {
FormData form;
FormFieldData field;
const char credit_card_number[] = "4234-5678-9012-3456";
const char actual_credit_card_exp_year[] = "2030";
const char user_entered_credit_card_exp_year[] = "2031";
const char cvc[] = "1234";
test::CreateTestFormField("number", "number", credit_card_number, "text",
&field);
form.fields.push_back(field);
// Expiration date, but is not the expiration date of the used credit card.
FormFieldData field1;
test::CreateTestFormField("exp_year", "exp_year",
user_entered_credit_card_exp_year, "text", &field1);
form.fields.push_back(field1);
// Must be CVC since expiration date was already identified.
FormFieldData field2;
test::CreateTestFormField("cvc_number", "cvc_number", cvc, "text", &field2);
form.fields.push_back(field2);
FormStructure form_structure(form);
// Set the field types.
form_structure.field(0)->set_possible_types({CREDIT_CARD_NUMBER});
form_structure.field(1)->set_possible_types({CREDIT_CARD_EXP_4_DIGIT_YEAR});
form_structure.field(2)->set_possible_types({UNKNOWN_TYPE});
// Set up the test credit cards.
std::vector<CreditCard> credit_cards;
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "John Doe", credit_card_number, "04",
actual_credit_card_exp_year, "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000003");
credit_cards.push_back(credit_card);
// Set up the test profiles.
std::vector<AutofillProfile> profiles;
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, credit_cards, base::string16(), "en-us", &form_structure);
CheckThatOnlyFieldByIndexHasThisPossibleType(form_structure, 2,
CREDIT_CARD_VERIFICATION_CODE,
FieldPropertiesFlags::kNoFlags);
}
// Tests if the CVC field is heuristically detected if it appears after the
// expiration year field as it was predicted by the server.
// The value in the CVC field would be a valid expiration year value.
TEST_P(AutofillManagerStructuredProfileTest,
CrowdsourceCVCFieldAfterExpDateByHeuristics) {
FormData form;
FormFieldData field;
const char credit_card_number[] = "4234-5678-9012-3456";
const char actual_credit_card_exp_year[] = "2030";
const char cvc[] = "1234";
test::CreateTestFormField("number", "number", credit_card_number, "text",
&field);
form.fields.push_back(field);
// Expiration date, that is the expiration date of the used credit card.
FormFieldData field1;
test::CreateTestFormField("date_or_cvc1", "date_or_cvc1",
actual_credit_card_exp_year, "text", &field1);
form.fields.push_back(field1);
// Must be CVC since expiration date was already identified.
FormFieldData field2;
test::CreateTestFormField("date_or_cvc2", "date_or_cvc2", cvc, "text",
&field2);
form.fields.push_back(field2);
FormStructure form_structure(form);
// Set the field types.
form_structure.field(0)->set_possible_types({CREDIT_CARD_NUMBER});
form_structure.field(1)->set_possible_types({CREDIT_CARD_EXP_4_DIGIT_YEAR});
form_structure.field(2)->set_possible_types({UNKNOWN_TYPE});
// Set up the test credit cards.
std::vector<CreditCard> credit_cards;
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "John Doe", credit_card_number, "04",
actual_credit_card_exp_year, "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000003");
credit_cards.push_back(credit_card);
// Set up the test profiles.
std::vector<AutofillProfile> profiles;
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, credit_cards, base::string16(), "en-us", &form_structure);
CheckThatOnlyFieldByIndexHasThisPossibleType(form_structure, 2,
CREDIT_CARD_VERIFICATION_CODE,
FieldPropertiesFlags::kNoFlags);
}
// Tests if the CVC field is heuristically detected if it contains a value which
// is not a valid expiration year.
TEST_P(AutofillManagerStructuredProfileTest,
CrowdsourceCVCFieldBeforeExpDateByHeuristics) {
FormData form;
FormFieldData field;
const char credit_card_number[] = "4234-5678-9012-3456";
const char actual_credit_card_exp_year[] = "2030";
const char user_entered_credit_card_exp_year[] = "2031";
test::CreateTestFormField("number", "number", credit_card_number, "text",
&field);
form.fields.push_back(field);
// Must be CVC since it is an implausible expiration date.
FormFieldData field2;
test::CreateTestFormField("date_or_cvc2", "date_or_cvc2", "2130", "text",
&field2);
form.fields.push_back(field2);
// A field which is filled with a plausible expiration date which is not the
// date of the credit card.
FormFieldData field1;
test::CreateTestFormField("date_or_cvc1", "date_or_cvc1",
user_entered_credit_card_exp_year, "text", &field1);
form.fields.push_back(field1);
FormStructure form_structure(form);
// Set the field types.
form_structure.field(0)->set_possible_types({CREDIT_CARD_NUMBER});
form_structure.field(1)->set_possible_types({UNKNOWN_TYPE});
form_structure.field(2)->set_possible_types({UNKNOWN_TYPE});
// Set up the test credit cards.
std::vector<CreditCard> credit_cards;
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "John Doe", credit_card_number, "04",
actual_credit_card_exp_year, "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000003");
credit_cards.push_back(credit_card);
// Set up the test profiles.
std::vector<AutofillProfile> profiles;
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, credit_cards, base::string16(), "en-us", &form_structure);
CheckThatOnlyFieldByIndexHasThisPossibleType(form_structure, 1,
CREDIT_CARD_VERIFICATION_CODE,
FieldPropertiesFlags::kNoFlags);
}
// Tests if no CVC field is heuristically detected due to the missing of a
// credit card number field.
TEST_P(AutofillManagerStructuredProfileTest,
CrowdsourceNoCVCFieldDueToMissingCreditCardNumber) {
FormData form;
FormFieldData field;
const char credit_card_number[] = "4234-5678-9012-3456";
const char actual_credit_card_exp_year[] = "2030";
const char user_entered_credit_card_exp_year[] = "2031";
const char cvc[] = "2031";
test::CreateTestFormField("number", "number", credit_card_number, "text",
&field);
form.fields.push_back(field);
// Server predicted as expiration year.
FormFieldData field1;
test::CreateTestFormField("date_or_cvc1", "date_or_cvc1",
user_entered_credit_card_exp_year, "text", &field1);
form.fields.push_back(field1);
// Must be CVC since expiration date was already identified.
FormFieldData field2;
test::CreateTestFormField("date_or_cvc2", "date_or_cvc2", cvc, "text",
&field2);
form.fields.push_back(field2);
FormStructure form_structure(form);
// Set the field types.
form_structure.field(0)->set_possible_types({UNKNOWN_TYPE});
form_structure.field(1)->set_possible_types({CREDIT_CARD_EXP_4_DIGIT_YEAR});
form_structure.field(2)->set_possible_types({UNKNOWN_TYPE});
// Set up the test credit cards.
std::vector<CreditCard> credit_cards;
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "John Doe", credit_card_number, "04",
actual_credit_card_exp_year, "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000003");
credit_cards.push_back(credit_card);
// Set up the test profiles.
std::vector<AutofillProfile> profiles;
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, credit_cards, base::string16(), "en-us", &form_structure);
CheckThatNoFieldHasThisPossibleType(form_structure,
CREDIT_CARD_VERIFICATION_CODE);
}
// Test if no CVC is found because the candidate has no valid CVC value.
TEST_P(AutofillManagerStructuredProfileTest,
CrowdsourceNoCVCDueToInvalidCandidateValue) {
FormData form;
FormFieldData field;
const char credit_card_number[] = "4234-5678-9012-3456";
const char credit_card_exp_year[] = "2030";
const char cvc[] = "12";
test::CreateTestFormField("number", "number", credit_card_number, "text",
&field);
form.fields.push_back(field);
// Server predicted as expiration year.
FormFieldData field1;
test::CreateTestFormField("date_or_cvc1", "date_or_cvc1",
credit_card_exp_year, "text", &field1);
form.fields.push_back(field1);
// Must be CVC since expiration date was already identified.
FormFieldData field2;
test::CreateTestFormField("date_or_cvc2", "date_or_cvc2", cvc, "text",
&field2);
form.fields.push_back(field2);
FormStructure form_structure(form);
// Set the field types.
form_structure.field(0)->set_possible_types(
{CREDIT_CARD_NUMBER, UNKNOWN_TYPE});
form_structure.field(1)->set_possible_types({CREDIT_CARD_EXP_4_DIGIT_YEAR});
form_structure.field(2)->set_possible_types({UNKNOWN_TYPE});
// Set up the test credit cards.
std::vector<CreditCard> credit_cards;
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "John Doe", credit_card_number, "04",
credit_card_exp_year, "1");
credit_card.set_guid("00000000-0000-0000-0000-000000000003");
credit_cards.push_back(credit_card);
// Set up the test profiles.
std::vector<AutofillProfile> profiles;
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, credit_cards, base::string16(), "en-us", &form_structure);
CheckThatNoFieldHasThisPossibleType(form_structure,
CREDIT_CARD_VERIFICATION_CODE);
}
TEST_P(AutofillManagerStructuredProfileTest, RemoveProfile) {
// Add and remove an Autofill profile.
AutofillProfile profile;
const char guid[] = "00000000-0000-0000-0000-000000000102";
profile.set_guid(guid);
personal_data_.AddProfile(profile);
int id = MakeFrontendID(std::string(), guid);
autofill_manager_->RemoveAutofillProfileOrCreditCard(id);
EXPECT_FALSE(personal_data_.GetProfileWithGUID(guid));
}
TEST_P(AutofillManagerStructuredProfileTest, RemoveCreditCard) {
// Add and remove an Autofill credit card.
CreditCard credit_card;
const char guid[] = "00000000-0000-0000-0000-000000100007";
credit_card.set_guid(guid);
personal_data_.AddCreditCard(credit_card);
int id = MakeFrontendID(guid, std::string());
autofill_manager_->RemoveAutofillProfileOrCreditCard(id);
EXPECT_FALSE(personal_data_.GetCreditCardWithGUID(guid));
}
// Test our external delegate is called at the right time.
TEST_P(AutofillManagerStructuredProfileTest, TestExternalDelegate) {
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const FormFieldData& field = form.fields[0];
GetAutofillSuggestions(form, field); // should call the delegate's OnQuery()
EXPECT_TRUE(external_delegate_->on_query_seen());
}
// Test that unfocusing a filled form sends an upload with types matching the
// fields.
TEST_P(AutofillManagerStructuredProfileTest,
OnTextFieldDidChangeAndUnfocus_Upload) {
// Set up our form data (it's already filled out with user data).
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
std::vector<ServerFieldTypeSet> expected_types;
ServerFieldTypeSet types;
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
types.insert(NAME_FIRST);
expected_types.push_back(types);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
types.clear();
types.insert(NAME_LAST);
// For structured names, this type cannot be differentiated from
// NAME_LAST_SECOND.
if (base::FeatureList::IsEnabled(
features::kAutofillEnableSupportForMoreStructureInNames))
types.insert(NAME_LAST_SECOND);
expected_types.push_back(types);
test::CreateTestFormField("Email", "email", "", "text", &field);
form.fields.push_back(field);
types.clear();
types.insert(EMAIL_ADDRESS);
expected_types.push_back(types);
FormsSeen(std::vector<FormData>(1, form));
// We will expect these types in the upload and no observed submission (the
// callback initiated by WaitForAsyncUploadProcess checks these expectations.)
autofill_manager_->SetExpectedSubmittedFieldTypes(expected_types);
autofill_manager_->SetExpectedObservedSubmission(false);
// The fields are edited after calling FormsSeen on them. This is because
// default values are not used for upload comparisons.
form.fields[0].value = ASCIIToUTF16("Elvis");
form.fields[1].value = ASCIIToUTF16("Presley");
form.fields[2].value = ASCIIToUTF16("theking@gmail.com");
// Simulate editing a field.
autofill_manager_->OnTextFieldDidChange(
form, form.fields.front(), gfx::RectF(), AutofillTickClock::NowTicks());
// Simulate lost of focus on the form.
autofill_manager_->OnFocusNoLongerOnForm(true);
}
// Test that navigating with a filled form sends an upload with types matching
// the fields.
TEST_P(AutofillManagerStructuredProfileTest,
OnTextFieldDidChangeAndNavigation_Upload) {
// Set up our form data (it's already filled out with user data).
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
std::vector<ServerFieldTypeSet> expected_types;
ServerFieldTypeSet types;
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
types.insert(NAME_FIRST);
expected_types.push_back(types);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
types.clear();
if (StructuredNames())
types.insert(NAME_LAST_SECOND);
types.insert(NAME_LAST);
expected_types.push_back(types);
test::CreateTestFormField("Email", "email", "", "text", &field);
form.fields.push_back(field);
types.clear();
types.insert(EMAIL_ADDRESS);
expected_types.push_back(types);
FormsSeen(std::vector<FormData>(1, form));
// We will expect these types in the upload and no observed submission. (the
// callback initiated by WaitForAsyncUploadProcess checks these expectations.)
autofill_manager_->SetExpectedSubmittedFieldTypes(expected_types);
autofill_manager_->SetExpectedObservedSubmission(false);
// The fields are edited after calling FormsSeen on them. This is because
// default values are not used for upload comparisons.
form.fields[0].value = ASCIIToUTF16("Elvis");
form.fields[1].value = ASCIIToUTF16("Presley");
form.fields[2].value = ASCIIToUTF16("theking@gmail.com");
// Simulate editing a field.
autofill_manager_->OnTextFieldDidChange(
form, form.fields.front(), gfx::RectF(), AutofillTickClock::NowTicks());
// Simulate a navigation so that the pending form is uploaded.
autofill_manager_->Reset();
}
// Test that unfocusing a filled form sends an upload with types matching the
// fields.
TEST_P(AutofillManagerStructuredProfileTest,
OnDidFillAutofillFormDataAndUnfocus_Upload) {
// Set up our form data (empty).
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
std::vector<ServerFieldTypeSet> expected_types;
// These fields should all match.
ServerFieldTypeSet types;
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
types.insert(NAME_FIRST);
expected_types.push_back(types);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
types.clear();
if (StructuredNames())
types.insert(NAME_LAST_SECOND);
types.insert(NAME_LAST);
expected_types.push_back(types);
test::CreateTestFormField("Email", "email", "", "text", &field);
form.fields.push_back(field);
types.clear();
types.insert(EMAIL_ADDRESS);
expected_types.push_back(types);
FormsSeen(std::vector<FormData>(1, form));
// We will expect these types in the upload and no observed submission. (the
// callback initiated by WaitForAsyncUploadProcess checks these expectations.)
autofill_manager_->SetExpectedSubmittedFieldTypes(expected_types);
autofill_manager_->SetExpectedObservedSubmission(false);
// Form was autofilled with user data.
form.fields[0].value = ASCIIToUTF16("Elvis");
form.fields[1].value = ASCIIToUTF16("Presley");
form.fields[2].value = ASCIIToUTF16("theking@gmail.com");
autofill_manager_->OnDidFillAutofillFormData(form,
AutofillTickClock::NowTicks());
// Simulate lost of focus on the form.
autofill_manager_->OnFocusNoLongerOnForm(true);
}
// Test that suggestions are returned for credit card fields with an
// unrecognized
// autocomplete attribute.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_UnrecognizedAttribute) {
// Set up the form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
// Set a valid autocomplete attribute on the card name.
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
field.autocomplete_attribute = "cc-name";
form.fields.push_back(field);
// Set no autocomplete attribute on the card number.
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
field.autocomplete_attribute = "";
form.fields.push_back(field);
// Set an unrecognized autocomplete attribute on the expiration month.
test::CreateTestFormField("Expiration Date", "ccmonth", "", "text", &field);
field.autocomplete_attribute = "unrecognized";
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Suggestions should be returned for the first two fields
GetAutofillSuggestions(form, form.fields[0]);
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
GetAutofillSuggestions(form, form.fields[1]);
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
// Suggestions should still be returned for the third field because it is a
// credit card field.
GetAutofillSuggestions(form, form.fields[2]);
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
// Test to verify suggestions appears for forms having credit card number split
// across fields.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_ForNumberSplitAcrossFields) {
// Set up our form data with credit card number split across fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData name_field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text",
&name_field);
form.fields.push_back(name_field);
// Add new 4 |card_number_field|s to the |form|.
FormFieldData card_number_field;
card_number_field.max_length = 4;
test::CreateTestFormField("Card Number", "cardnumber_1", "", "text",
&card_number_field);
form.fields.push_back(card_number_field);
test::CreateTestFormField("", "cardnumber_2", "", "text", &card_number_field);
form.fields.push_back(card_number_field);
test::CreateTestFormField("", "cardnumber_3", "", "text", &card_number_field);
form.fields.push_back(card_number_field);
test::CreateTestFormField("", "cardnumber_4", "", "text", &card_number_field);
form.fields.push_back(card_number_field);
FormFieldData exp_field;
test::CreateTestFormField("Expiration Date", "ccmonth", "", "text",
&exp_field);
form.fields.push_back(exp_field);
test::CreateTestFormField("", "ccyear", "", "text", &exp_field);
form.fields.push_back(exp_field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Verify whether suggestions are populated correctly for one of the middle
// credit card number fields when filled partially.
FormFieldData number_field = form.fields[3];
number_field.value = ASCIIToUTF16("901");
// Get the suggestions for already filled credit card |number_field|.
GetAutofillSuggestions(form, number_field);
#if defined(OS_ANDROID) || defined(OS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
const std::string visa_label = std::string("Expires on 04/99");
const std::string master_card_label = std::string("Expires on 10/98");
#endif
CheckSuggestions(
kDefaultPageID,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
visa_label, kVisaCard, autofill_manager_->GetPackedCreditCardID(4)));
}
// Test that inputs detected to be CVC inputs are forced to
// !should_autocomplete for AutocompleteHistoryManager::OnWillSubmitForm.
TEST_P(AutofillManagerStructuredProfileTest, DontSaveCvcInAutocompleteHistory) {
FormData form_seen_by_ahm;
EXPECT_CALL(*(autocomplete_history_manager_.get()), OnWillSubmitForm(_, true))
.WillOnce(SaveArg<0>(&form_seen_by_ahm));
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
struct {
const char* label;
const char* name;
const char* value;
ServerFieldType expected_field_type;
} test_fields[] = {
{"Card number", "1", "4234-5678-9012-3456", CREDIT_CARD_NUMBER},
{"Card verification code", "2", "123", CREDIT_CARD_VERIFICATION_CODE},
{"expiration date", "3", "04/2020", CREDIT_CARD_EXP_4_DIGIT_YEAR},
};
for (const auto& test_field : test_fields) {
FormFieldData field;
test::CreateTestFormField(test_field.label, test_field.name,
test_field.value, "text", &field);
form.fields.push_back(field);
}
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormSubmitted(form);
EXPECT_EQ(form.fields.size(), form_seen_by_ahm.fields.size());
ASSERT_EQ(base::size(test_fields), form_seen_by_ahm.fields.size());
for (size_t i = 0; i < base::size(test_fields); ++i) {
EXPECT_EQ(
form_seen_by_ahm.fields[i].should_autocomplete,
test_fields[i].expected_field_type != CREDIT_CARD_VERIFICATION_CODE);
}
}
TEST_P(AutofillManagerStructuredProfileTest, DontOfferToSavePaymentsCard) {
FormData form;
CreditCard card;
PrepareForRealPanResponse(&form, &card);
// Manually fill out |form| so we can use it in OnFormSubmitted.
for (size_t i = 0; i < form.fields.size(); ++i) {
if (form.fields[i].name == ASCIIToUTF16("cardnumber"))
form.fields[i].value = ASCIIToUTF16("4012888888881881");
else if (form.fields[i].name == ASCIIToUTF16("nameoncard"))
form.fields[i].value = ASCIIToUTF16("John H Dillinger");
else if (form.fields[i].name == ASCIIToUTF16("ccmonth"))
form.fields[i].value = ASCIIToUTF16("01");
else if (form.fields[i].name == ASCIIToUTF16("ccyear"))
form.fields[i].value = ASCIIToUTF16("2017");
}
CardUnmaskDelegate::UserProvidedUnmaskDetails details;
details.should_store_pan = false;
details.cvc = ASCIIToUTF16("123");
full_card_unmask_delegate()->OnUnmaskPromptAccepted(details);
OnDidGetRealPan(AutofillClient::SUCCESS, "4012888888881881");
autofill_manager_->OnFormSubmitted(form, false,
SubmissionSource::FORM_SUBMISSION);
}
TEST_P(AutofillManagerStructuredProfileTest, FillInUpdatedExpirationDate) {
FormData form;
CreditCard card;
PrepareForRealPanResponse(&form, &card);
CardUnmaskDelegate::UserProvidedUnmaskDetails details;
details.should_store_pan = false;
details.cvc = ASCIIToUTF16("123");
details.exp_month = ASCIIToUTF16("02");
details.exp_year = ASCIIToUTF16("2018");
full_card_unmask_delegate()->OnUnmaskPromptAccepted(details);
OnDidGetRealPan(AutofillClient::SUCCESS, "4012888888881881");
}
TEST_P(AutofillManagerStructuredProfileTest,
ProfileDisabledDoesNotFillFormData) {
autofill_manager_->SetAutofillProfileEnabled(false);
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000001";
// Expect no fields filled, no form data sent to renderer.
EXPECT_CALL(*autofill_driver_, SendFormDataToRenderer(_, _, _)).Times(0);
FillAutofillFormData(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(std::string(), guid));
}
TEST_P(AutofillManagerStructuredProfileTest, ProfileDisabledDoesNotSuggest) {
autofill_manager_->SetAutofillProfileEnabled(false);
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Email", "email", "", "email", &field);
GetAutofillSuggestions(form, field);
// Expect no suggestions as autofill and autocomplete are disabled for
// addresses.
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
TEST_P(AutofillManagerStructuredProfileTest,
CreditCardDisabledDoesNotFillFormData) {
autofill_manager_->SetAutofillCreditCardEnabled(false);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const char guid[] = "00000000-0000-0000-0000-000000000004";
// Expect no fields filled, no form data sent to renderer.
EXPECT_CALL(*autofill_driver_, SendFormDataToRenderer(_, _, _)).Times(0);
FillAutofillFormData(kDefaultPageID, form, *form.fields.begin(),
MakeFrontendID(guid, std::string()));
}
TEST_P(AutofillManagerStructuredProfileTest, CreditCardDisabledDoesNotSuggest) {
autofill_manager_->SetAutofillCreditCardEnabled(false);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
EXPECT_CALL(autofill_client_, ShouldShowSigninPromo());
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
GetAutofillSuggestions(form, field);
// Expect no suggestions as autofill and autocomplete are disabled for credit
// cards.
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
// Verify that typing "gmail" matches "theking@gmail.com" and "buddy@gmail.com"
// when substring matching is enabled.
TEST_P(SuggestionMatchingTest, DisplaySuggestionsWithMatchingTokens) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(features::kAutofillTokenPrefixMatching);
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Email", "email", "gmail", "email", &field);
GetAutofillSuggestions(form, field);
std::string label1;
std::string label2;
switch (enabled_feature_) {
// 23456789012 is not formatted because it is invalid for the app locale.
// It has an extra digit.
case EnabledFeature::kDesktop:
label1 =
MakeLabel({"Charles Holley", "123 Apple St., unit 6", "23456789012"});
label2 = MakeLabel({"Elvis Presley", "3734 Elvis Presley Blvd., Apt. 10",
"(234) 567-8901"});
break;
case EnabledFeature::kMobileShowAll:
// 23456789012 is not formatted because it is invalid for the app locale.
// It
// has an extra digit.
label1 =
MakeMobileLabel({"Charles", "123 Apple St., unit 6", "23456789012"});
label2 = MakeMobileLabel(
{"Elvis", "3734 Elvis Presley Blvd., Apt. 10", "(234) 567-8901"});
break;
case EnabledFeature::kMobileShowOne:
label1 = "123 Apple St., unit 6";
label2 = "3734 Elvis Presley Blvd., Apt. 10";
break;
case EnabledFeature::kNone:
label1 = "123 Apple St.";
label2 = "3734 Elvis Presley Blvd.";
}
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID, Suggestion("buddy@gmail.com", label1, "", 1),
Suggestion("theking@gmail.com", label2, "", 2));
}
// Verify that typing "apple" will match "123 Apple St." when substring matching
// is enabled.
TEST_P(SuggestionMatchingTest,
DisplaySuggestionsWithMatchingTokens_CaseIgnored) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(features::kAutofillTokenPrefixMatching);
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Address Line 2", "addr2", "apple", "text", &field);
GetAutofillSuggestions(form, field);
std::string label;
switch (enabled_feature_) {
case EnabledFeature::kDesktop:
label = "Charles Holley";
break;
case EnabledFeature::kMobileShowAll:
case EnabledFeature::kMobileShowOne:
// 23456789012 is not formatted because it is invalid for the app locale.
// It has an extra digit.
label = "23456789012";
break;
case EnabledFeature::kNone:
label = "123 Apple St.";
}
// Test that we sent the right values to the external delegate.
CheckSuggestions(kDefaultPageID,
Suggestion("123 Apple St., unit 6", label, "", 1));
}
// Verify that typing "mail" will not match any of the "@gmail.com" email
// addresses when substring matching is enabled.
TEST_P(AutofillManagerStructuredProfileTest,
NoSuggestionForNonPrefixTokenMatch) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(features::kAutofillTokenPrefixMatching);
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Email", "email", "mail", "email", &field);
GetAutofillSuggestions(form, field);
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
// Verify that typing "dre" matches "Nancy Drew" when substring matching is
// enabled.
TEST_P(CreditCardSuggestionTest,
DisplayCreditCardSuggestionsWithMatchingTokens) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(features::kAutofillTokenPrefixMatching);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "dre", "text",
&field);
const char guid[] = "00000000-0000-0000-0000-000000000030";
CreditCard credit_card;
test::SetCreditCardInfo(&credit_card, "Nancy Drew",
"4444555566667777", // Visa
"01", "2030", "1");
credit_card.set_guid(guid);
credit_card.SetNickname(ASCIIToUTF16(kArbitraryNickname));
personal_data_.AddCreditCard(credit_card);
#if defined(OS_ANDROID)
// When keyboard accessary is enabled, always show "7777".
// When keyboard accessary is disabled, if nickname is valid, show "Nickname
// ****7777", otherwise, show "Visa ****7777".
const std::string visa_label =
IsKeyboardAccessoryEnabled()
? test::ObfuscatedCardDigitsAsUTF8("7777")
: kArbitraryNickname + " " +
test::ObfuscatedCardDigitsAsUTF8("7777");
#elif defined(OS_IOS)
const std::string visa_label = test::ObfuscatedCardDigitsAsUTF8("7777");
#else
const std::string visa_label = base::JoinString(
{kArbitraryNickname + " ", test::ObfuscatedCardDigitsAsUTF8("7777"),
", expires on 01/30"},
"");
#endif
GetAutofillSuggestions(form, field);
CheckSuggestions(kDefaultPageID,
Suggestion("Nancy Drew", visa_label, kVisaCard,
MakeFrontendID(guid, std::string())));
}
// Verify that typing "lvis" will not match any of the credit card name when
// substring matching is enabled.
TEST_P(AutofillManagerStructuredProfileTest,
NoCreditCardSuggestionsForNonPrefixTokenMatch) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(features::kAutofillTokenPrefixMatching);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "lvis", "text",
&field);
GetAutofillSuggestions(form, field);
// Autocomplete suggestions are queried, but not Autofill.
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
TEST_P(AutofillManagerStructuredProfileTest, GetPopupType_CreditCardForm) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
for (const FormFieldData& field : form.fields) {
EXPECT_EQ(PopupType::kCreditCards,
autofill_manager_->GetPopupType(form, field));
}
}
TEST_P(AutofillManagerStructuredProfileTest, GetPopupType_AddressForm) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
for (const FormFieldData& field : form.fields) {
EXPECT_EQ(PopupType::kAddresses,
autofill_manager_->GetPopupType(form, field));
}
}
TEST_P(AutofillManagerStructuredProfileTest,
GetPopupType_PersonalInformationForm) {
// Set up our form data.
FormData form;
test::CreateTestPersonalInformationFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
for (const FormFieldData& field : form.fields) {
EXPECT_EQ(PopupType::kPersonalInformation,
autofill_manager_->GetPopupType(form, field));
}
}
// Test that ShouldShowCreditCardSigninPromo behaves as expected for a credit
// card form with an impression limit of three and no impressions yet.
TEST_P(AutofillManagerStructuredProfileTest,
ShouldShowCreditCardSigninPromo_CreditCardField_UnmetLimit) {
// No impressions yet.
ASSERT_EQ(0, autofill_client_.GetPrefs()->GetInteger(
prefs::kAutofillCreditCardSigninPromoImpressionCount));
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
// The mock implementation of ShouldShowSigninPromo() will return true here,
// creating an impression, and false below, preventing an impression.
EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
.WillOnce(testing::Return(true));
EXPECT_TRUE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
// Expect to now have an impression.
EXPECT_EQ(1, autofill_client_.GetPrefs()->GetInteger(
prefs::kAutofillCreditCardSigninPromoImpressionCount));
EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
.WillOnce(testing::Return(false));
EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
// No additional impression.
EXPECT_EQ(1, autofill_client_.GetPrefs()->GetInteger(
prefs::kAutofillCreditCardSigninPromoImpressionCount));
}
// Test that ShouldShowCreditCardSigninPromo behaves as expected for a credit
// card form with an impression limit that has been attained already.
TEST_P(AutofillManagerStructuredProfileTest,
ShouldShowCreditCardSigninPromo_CreditCardField_WithAttainedLimit) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
// Set the impression count to the same value as the limit.
autofill_client_.GetPrefs()->SetInteger(
prefs::kAutofillCreditCardSigninPromoImpressionCount,
kCreditCardSigninPromoImpressionLimit);
// Both calls will now return false, regardless of the mock implementation of
// ShouldShowSigninPromo().
EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
.WillOnce(testing::Return(true));
EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
.WillOnce(testing::Return(false));
EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
// Number of impressions stay the same.
EXPECT_EQ(kCreditCardSigninPromoImpressionLimit,
autofill_client_.GetPrefs()->GetInteger(
prefs::kAutofillCreditCardSigninPromoImpressionCount));
}
// Test that ShouldShowCreditCardSigninPromo behaves as expected for a credit
// card form on a non-secure page.
TEST_P(AutofillManagerStructuredProfileTest,
ShouldShowCreditCardSigninPromo_CreditCardField_NonSecureContext) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, false, false);
form.url = GURL("http://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
autofill_client_.set_form_origin(form.url);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
// Both calls will now return false, regardless of the mock implementation of
// ShouldShowSigninPromo().
EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
.WillOnce(testing::Return(true));
EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
.WillOnce(testing::Return(false));
EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
// Number of impressions should remain at zero.
EXPECT_EQ(0, autofill_client_.GetPrefs()->GetInteger(
prefs::kAutofillCreditCardSigninPromoImpressionCount));
}
// Test that ShouldShowCreditCardSigninPromo behaves as expected for a credit
// card form targeting a non-secure page.
TEST_P(AutofillManagerStructuredProfileTest,
ShouldShowCreditCardSigninPromo_CreditCardField_NonSecureAction) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, false, false);
form.url = GURL("https://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
// Both calls will now return false, regardless of the mock implementation of
// ShouldShowSigninPromo().
EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
.WillOnce(testing::Return(true));
EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
EXPECT_CALL(autofill_client_, ShouldShowSigninPromo())
.WillOnce(testing::Return(false));
EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
// Number of impressions should remain at zero.
EXPECT_EQ(0, autofill_client_.GetPrefs()->GetInteger(
prefs::kAutofillCreditCardSigninPromoImpressionCount));
}
// Test that ShouldShowCreditCardSigninPromo behaves as expected for an address
// form.
TEST_P(AutofillManagerStructuredProfileTest,
ShouldShowCreditCardSigninPromo_AddressField) {
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
// Call will now return false, because it is initiated from an address field.
EXPECT_CALL(autofill_client_, ShouldShowSigninPromo()).Times(0);
EXPECT_FALSE(autofill_manager_->ShouldShowCreditCardSigninPromo(form, field));
}
// Verify that typing "S" into the middle name field will match and order middle
// names "Shawn Smith" followed by "Adam Smith" i.e. prefix matched followed by
// substring matched.
TEST_P(SuggestionMatchingTest,
DisplaySuggestionsWithPrefixesPrecedeSubstringMatched) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(features::kAutofillTokenPrefixMatching);
// Set up our form data.
FormData form;
test::CreateTestAddressFormData(&form);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
AutofillProfile profile1;
profile1.set_guid("00000000-0000-0000-0000-000000000103");
profile1.SetInfo(NAME_FIRST, ASCIIToUTF16("Robin"), "en-US");
profile1.SetInfo(NAME_MIDDLE, ASCIIToUTF16("Adam Smith"), "en-US");
profile1.SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
profile1.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
"en-US");
personal_data_.AddProfile(profile1);
AutofillProfile profile2;
profile2.set_guid("00000000-0000-0000-0000-000000000124");
profile2.SetInfo(NAME_FIRST, ASCIIToUTF16("Carl"), "en-US");
profile2.SetInfo(NAME_MIDDLE, ASCIIToUTF16("Shawn Smith"), "en-US");
profile2.SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
profile2.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
"en-US");
personal_data_.AddProfile(profile2);
FormFieldData field;
test::CreateTestFormField("Middle Name", "middlename", "S", "text", &field);
GetAutofillSuggestions(form, field);
std::string label1;
std::string label2;
switch (enabled_feature_) {
case EnabledFeature::kDesktop:
case EnabledFeature::kMobileShowAll:
case EnabledFeature::kMobileShowOne:
label1 = "1234 Smith Blvd.";
label2 = "1234 Smith Blvd.";
break;
case EnabledFeature::kNone:
label1 = "1234 Smith Blvd., Carl Shawn Smith Grimes";
label2 = "1234 Smith Blvd., Robin Adam Smith Grimes";
}
CheckSuggestions(kDefaultPageID, Suggestion("Shawn Smith", label1, "", 1),
Suggestion("Adam Smith", label2, "", 2));
}
TEST_P(AutofillManagerStructuredProfileTest, ShouldUploadForm) {
// Note: The enforcement of a minimum number of required fields for upload
// is disabled by default. This tests validates both the disabled and enabled
// scenarios.
FormData form;
form.name = ASCIIToUTF16("TestForm");
form.url = GURL("https://example.com/form.html");
form.action = GURL("https://example.com/submit.html");
// Empty Form.
EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Add a field to the form.
FormFieldData field;
test::CreateTestFormField("Name", "name", "", "text", &field);
form.fields.push_back(field);
EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Add a second field to the form.
test::CreateTestFormField("Email", "email", "", "text", &field);
form.fields.push_back(field);
EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Has less than 3 fields but has autocomplete attribute.
form.fields[0].autocomplete_attribute = "given-name";
EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Has more than 3 fields, no autocomplete attribute.
form.fields[0].autocomplete_attribute = "";
test::CreateTestFormField("Country", "country", "", "text", &field);
form.fields.push_back(field);
FormStructure form_structure_3(form);
EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Has more than 3 fields and at least one autocomplete attribute.
form.fields[0].autocomplete_attribute = "given-name";
EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Is off the record.
autofill_driver_->SetIsIncognito(true);
EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Make sure it's reset for the next test case.
autofill_driver_->SetIsIncognito(false);
EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Has one field which is appears to be a password field.
form.fields.clear();
test::CreateTestFormField("Password", "password", "", "password", &field);
form.fields.push_back(field);
// With min required fields disabled.
EXPECT_TRUE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
// Autofill disabled.
autofill_manager_->SetAutofillProfileEnabled(false);
autofill_manager_->SetAutofillCreditCardEnabled(false);
EXPECT_FALSE(autofill_manager_->ShouldUploadForm(FormStructure(form)));
}
// Verify that no suggestions are shown on desktop for non credit card related
// fields if the initiating field has the "autocomplete" attribute set to off.
TEST_P(AutofillManagerStructuredProfileTest,
DisplaySuggestions_AutocompleteOffNotRespected_AddressField) {
// Set up an address form.
FormData mixed_form;
mixed_form.name = ASCIIToUTF16("MyForm");
mixed_form.url = GURL("https://myform.com/form.html");
mixed_form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First name", "firstname", "", "text", &field);
field.should_autocomplete = false;
mixed_form.fields.push_back(field);
test::CreateTestFormField("Last name", "lastname", "", "text", &field);
field.should_autocomplete = true;
mixed_form.fields.push_back(field);
test::CreateTestFormField("Address", "address", "", "text", &field);
field.should_autocomplete = true;
mixed_form.fields.push_back(field);
std::vector<FormData> mixed_forms(1, mixed_form);
FormsSeen(mixed_forms);
// Suggestions should be displayed on desktop for this field in all
// circumstances.
GetAutofillSuggestions(mixed_form, mixed_form.fields[0]);
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
// Suggestions should always be displayed for all the other fields.
for (size_t i = 1U; i < mixed_form.fields.size(); ++i) {
GetAutofillSuggestions(mixed_form, mixed_form.fields[i]);
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
}
// Verify that suggestions are shown on desktop for credit card related fields
// even if the initiating field field has the "autocomplete" attribute set to
// off.
TEST_P(AutofillManagerStructuredProfileTest,
DisplaySuggestions_AutocompleteOff_CreditCardField) {
// Set up a credit card form.
FormData mixed_form;
mixed_form.name = ASCIIToUTF16("MyForm");
mixed_form.url = GURL("https://myform.com/form.html");
mixed_form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
field.should_autocomplete = false;
mixed_form.fields.push_back(field);
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
field.should_autocomplete = true;
mixed_form.fields.push_back(field);
test::CreateTestFormField("Expiration Month", "ccexpiresmonth", "", "text",
&field);
field.should_autocomplete = false;
mixed_form.fields.push_back(field);
mixed_form.fields.push_back(field);
std::vector<FormData> mixed_forms(1, mixed_form);
FormsSeen(mixed_forms);
// Suggestions should always be displayed.
for (const FormFieldData& field : mixed_form.fields) {
GetAutofillSuggestions(mixed_form, field);
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
}
// Tests that a form with server only types is still autofillable if the form
// gets updated in cache.
TEST_P(AutofillManagerStructuredProfileTest,
DisplaySuggestionsForUpdatedServerTypedForm) {
// Create a form with unknown heuristic fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Field 1", "field1", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Field 2", "field2", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Field 3", "field3", "", "text", &field);
form.fields.push_back(field);
auto form_structure = std::make_unique<TestFormStructure>(form);
form_structure->DetermineHeuristicTypes();
// Make sure the form can not be autofilled now.
ASSERT_EQ(0u, form_structure->autofill_count());
for (size_t idx = 0; idx < form_structure->field_count(); ++idx) {
ASSERT_EQ(UNKNOWN_TYPE, form_structure->field(idx)->heuristic_type());
}
// Prepare and set known server fields.
const std::vector<ServerFieldType> heuristic_types(form.fields.size(),
UNKNOWN_TYPE);
const std::vector<ServerFieldType> server_types{NAME_FIRST, NAME_MIDDLE,
NAME_LAST};
form_structure->SetFieldTypes(heuristic_types, server_types);
autofill_manager_->AddSeenFormStructure(std::move(form_structure));
// Make sure the form can be autofilled.
for (const FormFieldData& field : form.fields) {
GetAutofillSuggestions(form, field);
ASSERT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
// Modify one of the fields in the original form.
form.fields[0].css_classes += ASCIIToUTF16("a");
// Expect the form still can be autofilled.
for (const FormFieldData& field : form.fields) {
GetAutofillSuggestions(form, field);
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
// Modify form action URL. This can happen on in-page navitaion if the form
// doesn't have an actual action (attribute is empty).
form.action = net::AppendQueryParameter(form.action, "arg", "value");
// Expect the form still can be autofilled.
for (const FormFieldData& field : form.fields) {
GetAutofillSuggestions(form, field);
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
}
// Tests that a form with <select> field is accepted if <option> value (not
// content) is quite long. Some websites use value to propagate long JSON to
// JS-backed logic.
TEST_P(AutofillManagerStructuredProfileTest,
FormWithLongOptionValuesIsAcceptable) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("First name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last name", "lastname", "", "text", &field);
form.fields.push_back(field);
// Prepare <select> field with long <option> values.
const size_t kOptionValueLength = 10240;
const std::string long_string(kOptionValueLength, 'a');
const std::vector<const char*> values(3, long_string.c_str());
const std::vector<const char*> contents{"A", "B", "C"};
test::CreateTestSelectField("Country", "country", "", values, contents,
values.size(), &field);
form.fields.push_back(field);
FormsSeen({form});
// Suggestions should be displayed.
for (const FormFieldData& field : form.fields) {
GetAutofillSuggestions(form, field);
EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
}
}
// Test that is_all_server_suggestions is true if there are only
// full_server_card and masked_server_card on file.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_IsAllServerSuggestionsTrue) {
// Create server credit cards.
CreateTestServerCreditCards();
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
// Test that we sent the right values to the external delegate.
ASSERT_TRUE(external_delegate_->is_all_server_suggestions());
}
// Test that is_all_server_suggestions is false if there is at least one
// local_card on file.
TEST_P(AutofillManagerStructuredProfileTest,
GetCreditCardSuggestions_IsAllServerSuggestionsFalse) {
// Create server and local credit cards.
CreateTestServerAndLocalCreditCards();
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
// Test that we sent the right values to the external delegate.
ASSERT_FALSE(external_delegate_->is_all_server_suggestions());
}
// If the rich query feature is enabled, the IsRichQueryEnabled methods only
// returns true if the channel is neither STABLE not BETA.
TEST_P(AutofillManagerStructuredProfileTest,
IsRichQueryEnabled_FeatureEnabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
features::kAutofillRichMetadataQueries);
for (auto channel :
{version_info::Channel::STABLE, version_info::Channel::BETA,
version_info::Channel::CANARY, version_info::Channel::DEV,
version_info::Channel::UNKNOWN}) {
SCOPED_TRACE(::testing::Message()
<< "Channel " << static_cast<int>(channel));
// One more call is from TestAutofillManager constructor.
EXPECT_CALL(autofill_client_, GetChannel()).WillRepeatedly(Return(channel));
TestAutofillManager test_instance(autofill_driver_.get(), &autofill_client_,
&personal_data_,
autocomplete_history_manager_.get());
switch (channel) {
case version_info::Channel::STABLE:
case version_info::Channel::BETA:
EXPECT_FALSE(AutofillManager::IsRichQueryEnabled(channel));
EXPECT_FALSE(test_instance.is_rich_query_enabled());
break;
case version_info::Channel::CANARY:
case version_info::Channel::DEV:
case version_info::Channel::UNKNOWN:
EXPECT_TRUE(AutofillManager::IsRichQueryEnabled(channel));
EXPECT_TRUE(test_instance.is_rich_query_enabled());
break;
}
}
}
// No matter what the channel, IsRichQueryEnabled returns false if the feature
// is disabled.
TEST_P(AutofillManagerStructuredProfileTest,
IsRichQueryEnabled_FeatureDisabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(
features::kAutofillRichMetadataQueries);
for (auto channel :
{version_info::Channel::STABLE, version_info::Channel::BETA,
version_info::Channel::CANARY, version_info::Channel::DEV,
version_info::Channel::UNKNOWN}) {
SCOPED_TRACE(::testing::Message()
<< "Channel " << static_cast<int>(channel));
EXPECT_FALSE(AutofillManager::IsRichQueryEnabled(channel));
// One more call is from TestAutofillManager constructor.
EXPECT_CALL(autofill_client_, GetChannel()).WillRepeatedly(Return(channel));
TestAutofillManager test_instance(autofill_driver_.get(), &autofill_client_,
&personal_data_,
autocomplete_history_manager_.get());
EXPECT_FALSE(test_instance.is_rich_query_enabled());
}
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogAutocompleteShownMetric) {
FormData form;
form.name = ASCIIToUTF16("NothingSpecial");
FormFieldData field;
test::CreateTestFormField("Something", "something", "", "text", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/false,
form, field);
histogram_tester.ExpectBucketCount(
"Autocomplete.Events", AutofillMetrics::AUTOCOMPLETE_SUGGESTIONS_SHOWN,
1);
// No Autofill logs.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(histograms,
Not(AnyOf(HasSubstr("Autofill.UserHappiness"),
HasSubstr("Autofill.FormEvents.Address"),
HasSubstr("Autofill.FormEvents.CreditCard"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogAutofillAddressShownMetric) {
FormData form;
test::CreateTestAddressFormData(&form);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness",
AutofillMetrics::SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address",
AutofillMetrics::SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.UserHappiness", AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, 1);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address",
AutofillMetrics::SUGGESTIONS_SHOWN_ONCE,
1);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// No Autocomplete or credit cards logs.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(histograms,
Not(AnyOf(HasSubstr("Autocomplete.Events"),
HasSubstr("Autofill.FormEvents.CreditCard"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_AddressOnly) {
// Create a form with name and address fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.AddressOnly",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.AddressOnly",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(
HasSubstr("Autofill.FormEvents.Address.AddressPlusContact"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmail "),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.ContactOnly"),
HasSubstr("Autofill.FormEvents.Address.PhoneOnly"),
HasSubstr("Autofill.FormEvents.Address.Other"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_AddressOnlyWithoutName) {
// Create a form with address fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Address Line 2", "addr2", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Postal Code", "zipcode", "", "text", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.AddressOnly",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.AddressOnly",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(
HasSubstr("Autofill.FormEvents.Address.AddressPlusContact"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmail "),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.ContactOnly"),
HasSubstr("Autofill.FormEvents.Address.PhoneOnly"),
HasSubstr("Autofill.FormEvents.Address.Other"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_ContactOnly) {
// Create a form with name and contact fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.ContactOnly",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.ContactOnly",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(
HasSubstr("Autofill.FormEvents.Address.AddressPlusContact"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmail "),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressOnly"),
HasSubstr("Autofill.FormEvents.Address.PhoneOnly"),
HasSubstr("Autofill.FormEvents.Address.Other"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_ContactOnlyWithoutName) {
// Create a form with contact fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.ContactOnly",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.ContactOnly",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(
HasSubstr("Autofill.FormEvents.Address.AddressPlusContact"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmail "),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressOnly"),
HasSubstr("Autofill.FormEvents.Address.PhoneOnly"),
HasSubstr("Autofill.FormEvents.Address.Other"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_PhoneOnly) {
// Create a form with phone field.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.PhoneOnly",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.PhoneOnly",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmail"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusContact"),
HasSubstr("Autofill.FormEvents.Address.AddressOnly"),
HasSubstr("Autofill.FormEvents.Address.ContactOnly"),
HasSubstr("Autofill.FormEvents.Address.Other"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_Other) {
// Create a form with name fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Middle Name", "middlename", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.Other",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address.Other",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(
HasSubstr("Autofill.FormEvents.Address.AddressPlusContact"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmail "),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressOnly"),
HasSubstr("Autofill.FormEvents.Address.PhoneOnly"),
HasSubstr("Autofill.FormEvents.Address.ContactOnly"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_AddressPlusEmail) {
// Create a form with name, address, and email fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusEmail",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusEmail",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressOnly"),
HasSubstr("Autofill.FormEvents.Address.ContactOnly"),
HasSubstr("Autofill.FormEvents.Address.PhoneOnly"),
HasSubstr("Autofill.FormEvents.Address.Other"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_AddressPlusEmailWithoutName) {
// Create a form with address and email fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Address Line 2", "addr2", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusEmail",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusEmail",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressOnly"),
HasSubstr("Autofill.FormEvents.Address.ContactOnly"),
HasSubstr("Autofill.FormEvents.Address.PhoneOnly"),
HasSubstr("Autofill.FormEvents.Address.Other"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_AddressPlusPhone) {
// Create a form with name fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusPhone",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusPhone",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmail "),
HasSubstr("Autofill.FormEvents.Address.AddressOnly"),
HasSubstr("Autofill.FormEvents.Address.ContactOnly"),
HasSubstr("Autofill.FormEvents.Address.PhoneOnly"),
HasSubstr("Autofill.FormEvents.Address.Other"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_AddressPlusPhoneWithoutName) {
// Create a form with name, address, and phone fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Address Line 2", "addr2", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusPhone",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusPhone",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmailPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmail "),
HasSubstr("Autofill.FormEvents.Address.AddressOnly"),
HasSubstr("Autofill.FormEvents.Address.ContactOnly"),
HasSubstr("Autofill.FormEvents.Address.PhoneOnly"),
HasSubstr("Autofill.FormEvents.Address.Other"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_AddressPlusEmailPlusPhone) {
// Create a form with name, address, phone, and email fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("First Name", "firstname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusEmailPlusPhone",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusEmailPlusPhone",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(HasSubstr("Autofill.FormEvents.Address.AddressPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmail "),
HasSubstr("Autofill.FormEvents.Address.AddressOnly"),
HasSubstr("Autofill.FormEvents.Address.ContactOnly"),
HasSubstr("Autofill.FormEvents.Address.PhoneOnly"),
HasSubstr("Autofill.FormEvents.Address.Other"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogByType_AddressPlusEmailPlusPhoneWithoutName) {
// Create a form with address, phone, and email fields.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.button_titles = {
std::make_pair(ASCIIToUTF16("Submit"),
mojom::ButtonTitleType::BUTTON_ELEMENT_SUBMIT_TYPE)};
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
form.submission_event = SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
FormFieldData field;
test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Phone Number", "phonenumber", "", "tel", &field);
form.fields.push_back(field);
test::CreateTestFormField("Email", "email", "", "email", &field);
form.fields.push_back(field);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusEmailPlusPhone",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusEmailPlusPhone",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address.AddressPlusContact",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// Logging is not done for other types of address forms.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(
histograms,
Not(AnyOf(HasSubstr("Autofill.FormEvents.Address.AddressPlusPhone"),
HasSubstr("Autofill.FormEvents.Address.AddressPlusEmail "),
HasSubstr("Autofill.FormEvents.Address.AddressOnly"),
HasSubstr("Autofill.FormEvents.Address.ContactOnly"),
HasSubstr("Autofill.FormEvents.Address.PhoneOnly"),
HasSubstr("Autofill.FormEvents.Address.Other"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidShowSuggestions_LogAutofillCreditCardShownMetric) {
FormData form;
CreateTestCreditCardFormData(&form, true, false);
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(/*has_autofill_suggestions=*/true, form,
form.fields[0]);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness",
AutofillMetrics::SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness.CreditCard",
AutofillMetrics::SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount(
"Autofill.UserHappiness", AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, 1);
histogram_tester.ExpectBucketCount("Autofill.UserHappiness.CreditCard",
AutofillMetrics::SUGGESTIONS_SHOWN_ONCE,
1);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
FORM_EVENT_SUGGESTIONS_SHOWN, 1);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
FORM_EVENT_SUGGESTIONS_SHOWN_ONCE, 1);
// No Autocomplete or address logs.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(histograms, Not(AnyOf(HasSubstr("Autocomplete.Events"),
HasSubstr("Autofill.FormEvents.Address"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidSuppressPopup_LogAutofillAddressPopupSuppressed) {
FormData form;
test::CreateTestAddressFormData(&form);
base::HistogramTester histogram_tester;
autofill_manager_->DidSuppressPopup(form, form.fields[0]);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.Address",
FORM_EVENT_POPUP_SUPPRESSED, 1);
// No Autocomplete or credit cards logs.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(histograms,
Not(AnyOf(HasSubstr("Autofill.UserHappiness"),
HasSubstr("Autocomplete.Events"),
HasSubstr("Autofill.FormEvents.CreditCard"))));
}
TEST_P(AutofillManagerStructuredProfileTest,
DidSuppressPopup_LogAutofillCreditCardPopupSuppressed) {
FormData form;
CreateTestCreditCardFormData(&form, true, false);
base::HistogramTester histogram_tester;
autofill_manager_->DidSuppressPopup(form, form.fields[0]);
histogram_tester.ExpectBucketCount("Autofill.FormEvents.CreditCard",
FORM_EVENT_POPUP_SUPPRESSED, 1);
// No Autocomplete or address logs.
const std::string histograms = histogram_tester.GetAllHistogramsRecorded();
EXPECT_THAT(histograms, Not(AnyOf(HasSubstr("Autofill.UserHappiness"),
HasSubstr("Autocomplete.Events"),
HasSubstr("Autofill.FormEvents.Address"))));
}
// Test that we import data when the field type is determined by the value and
// without any heuristics on the attributes.
TEST_P(AutofillManagerStructuredProfileTest, ImportDataWhenValueDetected) {
const std::string test_upi_id_value = "user@indianbank";
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kAutofillSaveAndFillVPA);
#if !defined(OS_ANDROID) && !defined(OS_IOS)
EXPECT_CALL(autofill_client_, ConfirmSaveUpiIdLocally(test_upi_id_value, _))
.WillOnce([](std::string upi_id,
base::OnceCallback<void(bool user_decision)> callback) {
std::move(callback).Run(true);
});
#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
FormData form;
form.url = GURL("https://wwww.foo.com");
FormFieldData field;
test::CreateTestFormField("UPI ID:", "upi_id", "", "text", &field);
form.fields.push_back(field);
FormsSeen({form});
autofill_manager_->SetExpectedSubmittedFieldTypes({{UPI_VPA}});
autofill_manager_->SetExpectedObservedSubmission(true);
autofill_manager_->SetCallParentUploadFormData(true);
form.submission_event =
mojom::SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
form.fields[0].value = base::UTF8ToUTF16(test_upi_id_value);
FormSubmitted(form);
#if defined(OS_ANDROID) || defined(OS_IOS)
// The feature is not implemented for mobile.
EXPECT_EQ(0, personal_data_.num_times_save_upi_id_called());
#else
EXPECT_EQ(1, personal_data_.num_times_save_upi_id_called());
#endif
}
// Test that we do not import UPI data when in incognito.
TEST_F(AutofillManagerTest, DontImportUpiIdWhenIncognito) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kAutofillSaveAndFillVPA);
autofill_driver_->SetIsIncognito(true);
EXPECT_CALL(autofill_client_, ConfirmSaveUpiIdLocally(_, _)).Times(0);
FormData form;
form.url = GURL("https://wwww.foo.com");
FormFieldData field;
test::CreateTestFormField("UPI ID:", "upi_id", "", "text", &field);
form.fields.push_back(field);
FormsSeen({form});
autofill_manager_->SetExpectedSubmittedFieldTypes({{UPI_VPA}});
autofill_manager_->SetExpectedObservedSubmission(true);
autofill_manager_->SetCallParentUploadFormData(true);
form.submission_event =
mojom::SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
form.fields[0].value = ASCIIToUTF16("user@indianbank");
FormSubmitted(form);
EXPECT_EQ(0, personal_data_.num_times_save_upi_id_called());
}
// Tests the vote generation for the address enhancement types.
TEST_F(AutofillManagerTest, PossibleFieldTypesForEnhancementVotes) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
features::kAutofillAddressEnhancementVotes);
std::vector<AutofillProfile> profiles = {AutofillProfile()};
profiles[0].SetRawInfo(ADDRESS_HOME_STREET_NAME,
base::ASCIIToUTF16("StreetName"));
profiles[0].SetRawInfo(ADDRESS_HOME_HOUSE_NUMBER,
base::ASCIIToUTF16("HouseNumber"));
profiles[0].SetRawInfo(ADDRESS_HOME_PREMISE_NAME,
base::ASCIIToUTF16("Premise"));
profiles[0].SetRawInfo(ADDRESS_HOME_SUBPREMISE,
base::ASCIIToUTF16("Subpremise"));
FormData form;
FormFieldData field1;
test::CreateTestFormField("somelabel", "someid", "StreetName", "text",
&field1);
form.fields.push_back(field1);
test::CreateTestFormField("somelabel", "someid", "HouseNumber", "text",
&field1);
form.fields.push_back(field1);
test::CreateTestFormField("somelabel", "someid", "Premise", "text", &field1);
form.fields.push_back(field1);
test::CreateTestFormField("somelabel", "someid", "Subpremise", "text",
&field1);
form.fields.push_back(field1);
FormStructure form_structure(form);
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, {}, base::string16(), "en-us", &form_structure);
ASSERT_EQ(4U, form_structure.field_count());
EXPECT_EQ(form_structure.field(0)->possible_types(),
ServerFieldTypeSet({ADDRESS_HOME_STREET_NAME}));
EXPECT_EQ(form_structure.field(1)->possible_types(),
ServerFieldTypeSet({ADDRESS_HOME_HOUSE_NUMBER}));
EXPECT_EQ(form_structure.field(2)->possible_types(),
ServerFieldTypeSet({ADDRESS_HOME_PREMISE_NAME}));
EXPECT_EQ(form_structure.field(3)->possible_types(),
ServerFieldTypeSet({ADDRESS_HOME_SUBPREMISE}));
// Disable the feature and verify that no possible types are detected.
scoped_feature_list.Reset();
scoped_feature_list.InitAndDisableFeature(
features::kAutofillAddressEnhancementVotes);
AutofillManager::DeterminePossibleFieldTypesForUploadForTest(
profiles, {}, base::string16(), "en-us", &form_structure);
ASSERT_EQ(4U, form_structure.field_count());
EXPECT_EQ(form_structure.field(0)->possible_types(),
ServerFieldTypeSet({UNKNOWN_TYPE}));
EXPECT_EQ(form_structure.field(1)->possible_types(),
ServerFieldTypeSet({UNKNOWN_TYPE}));
EXPECT_EQ(form_structure.field(2)->possible_types(),
ServerFieldTypeSet({UNKNOWN_TYPE}));
EXPECT_EQ(form_structure.field(3)->possible_types(),
ServerFieldTypeSet({UNKNOWN_TYPE}));
}
TEST_F(AutofillManagerTest, PageLanguageGetsCorrectlySet) {
FormData form;
test::CreateTestAddressFormData(&form);
autofill_client_.GetLanguageState()->SetCurrentLanguage("und");
autofill_manager_->OnFormsSeen({form});
FormStructure* parsed_form =
autofill_manager_->FindCachedFormByRendererId(form.unique_renderer_id);
ASSERT_TRUE(parsed_form);
ASSERT_EQ(LanguageCode("und"), parsed_form->current_page_language());
autofill_client_.GetLanguageState()->SetCurrentLanguage("zh");
autofill_manager_->OnFormsSeen({form});
parsed_form =
autofill_manager_->FindCachedFormByRendererId(form.unique_renderer_id);
ASSERT_EQ(LanguageCode("zh"), parsed_form->current_page_language());
}
// AutofillManagerTest with kAutofillDisabledMixedForms feature enabled.
class AutofillManagerTestWithMixedForms : public AutofillManagerTest {
protected:
AutofillManagerTestWithMixedForms() = default;
~AutofillManagerTestWithMixedForms() override = default;
void SetUp() override {
AutofillManagerTest::SetUp();
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillPreventMixedFormsFilling);
}
};
// Test that if a form is mixed content we show a warning instead of any
// suggestions.
TEST_F(AutofillManagerTestWithMixedForms, GetSuggestions_MixedForm) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
form.fields.push_back(field);
GetAutofillSuggestions(form, form.fields[0]);
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
Suggestion(l10n_util::GetStringUTF8(IDS_AUTOFILL_WARNING_MIXED_FORM), "",
"", POPUP_ITEM_ID_MIXED_FORM_MESSAGE));
}
// Test that if a form is mixed content we do not show a warning if the opt out
// polcy is set.
TEST_F(AutofillManagerTestWithMixedForms,
GetSuggestions_MixedFormOptoutPolicy) {
// Set pref to disabled.
autofill_client_.GetPrefs()->SetBoolean(::prefs::kMixedFormsWarningsEnabled,
false);
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
form.fields.push_back(field);
GetAutofillSuggestions(form, form.fields[0]);
// Check there is no warning.
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
// Test that we dismiss the mixed form warning if user starts typing.
TEST_F(AutofillManagerTestWithMixedForms, GetSuggestions_MixedFormUserTyped) {
// Set up our form data.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
form.fields.push_back(field);
GetAutofillSuggestions(form, form.fields[0]);
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
Suggestion(l10n_util::GetStringUTF8(IDS_AUTOFILL_WARNING_MIXED_FORM), "",
"", POPUP_ITEM_ID_MIXED_FORM_MESSAGE));
// Pretend user started typing and make sure we no longer set suggestions.
form.fields[0].value = base::ASCIIToUTF16("Michael");
form.fields[0].properties_mask |= kUserTyped;
GetAutofillSuggestions(form, form.fields[0]);
external_delegate_->CheckNoSuggestions(kDefaultPageID);
}
// Test that we don't treat javascript scheme target URLs as mixed forms.
// Regression test for crbug.com/1135173
TEST_F(AutofillManagerTestWithMixedForms, GetSuggestions_JavascriptUrlTarget) {
// Set up our form data, using a javascript scheme target URL.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("javascript:alert('hello');");
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
form.fields.push_back(field);
GetAutofillSuggestions(form, form.fields[0]);
// Check there is no warning.
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
// Test that we don't treat about:blank target URLs as mixed forms.
TEST_F(AutofillManagerTestWithMixedForms, GetSuggestions_AboutBlankTarget) {
// Set up our form data, using a javascript scheme target URL.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("about:blank");
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
form.fields.push_back(field);
GetAutofillSuggestions(form, form.fields[0]);
// Check there is no warning.
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
// Desktop only tests.
#if !defined(OS_ANDROID) && !defined(OS_IOS)
class AutofillManagerTestForVirtualCardOption : public AutofillManagerTest {
protected:
AutofillManagerTestForVirtualCardOption() = default;
~AutofillManagerTestForVirtualCardOption() override = default;
void SetUp() override {
AutofillManagerTest::SetUp();
// The URL should always matche the form URL in
// CreateTestCreditCardFormData() to have the allowlist work correctly.
autofill_client_.set_allowed_merchants({"https://myform.com/form.html"});
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillEnableVirtualCard);
// Add only one server card so the second suggestion (if any) must be the
// "Use a virtual card number" option.
personal_data_.ClearCreditCards();
CreditCard masked_server_card(CreditCard::MASKED_SERVER_CARD,
/*server_id=*/"a123");
// TODO(crbug.com/1020740): Replace all the hard-coded expiration year in
// this file with NextYear().
test::SetCreditCardInfo(&masked_server_card, "Elvis Presley",
"4234567890123456", // Visa
"04", "2999", "1");
masked_server_card.SetNetworkForMaskedCard(kVisaCard);
masked_server_card.set_guid("00000000-0000-0000-0000-000000000007");
personal_data_.AddServerCreditCard(masked_server_card);
}
void CreateCompleteFormAndGetSuggestions() {
FormData form;
CreateTestCreditCardFormData(&form, /*is_https=*/true,
/*use_month_type=*/false);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
const FormFieldData& field = form.fields[1]; // card number field.
GetAutofillSuggestions(form, field);
}
// Adds a CreditCardCloudTokenData to PersonalDataManager. This needs to be
// called before suggestions are fetched.
void CreateCloudTokenDataForDefaultCard() {
personal_data_.ClearCloudTokenData();
CreditCardCloudTokenData data1 = test::GetCreditCardCloudTokenData1();
data1.masked_card_id = "a123";
personal_data_.AddCloudTokenData(data1);
}
void VerifyNoVirtualCardSuggestions() {
external_delegate_->CheckSuggestionCount(kDefaultPageID, 1);
// Suggestion details need to match the credit card added in the SetUp()
// above.
CheckSuggestions(kDefaultPageID,
Suggestion(std::string("Visa ") +
test::ObfuscatedCardDigitsAsUTF8("3456"),
"Expires on 04/99", kVisaCard,
autofill_manager_->GetPackedCreditCardID(7)));
}
};
// Ensures the "Use a virtual card number" option should not be shown when
// experiment is disabled.
TEST_F(AutofillManagerTestForVirtualCardOption,
ShouldNotShowDueToExperimentDisabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(
features::kAutofillEnableVirtualCard);
CreateCompleteFormAndGetSuggestions();
VerifyNoVirtualCardSuggestions();
}
// Ensures the "Use a virtual card number" option should not be shown when the
// preference for credit card upload is set to disabled.
TEST_F(AutofillManagerTestForVirtualCardOption,
ShouldNotShowDueToCreditCardUploadPrefDisabled) {
autofill_manager_->SetAutofillCreditCardEnabled(false);
CreateCompleteFormAndGetSuggestions();
external_delegate_->CheckSuggestionCount(kDefaultPageID, 0);
}
// Ensures the "Use a virtual card number" option should not be shown when
// merchant is not allowlisted.
TEST_F(AutofillManagerTestForVirtualCardOption,
ShouldNotShowDueToMerchantNotAllowlisted) {
// Adds a different URL in the allowlist.
autofill_client_.set_allowed_merchants(
{"https://myform.anotherallowlist.com/form.html"});
CreateCompleteFormAndGetSuggestions();
VerifyNoVirtualCardSuggestions();
}
// Ensures the "Use a virtual card number" option should not be shown when card
// number field is not detected.
TEST_F(AutofillManagerTestForVirtualCardOption,
ShouldNotShowDueToFormNotHavingCardNumberField) {
// Creates an incomplete form without card number field.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Expiration Date", "ccmonth", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("", "ccyear", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("CVC", "cvc", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
field = form.fields[0]; // cardholder name field.
GetAutofillSuggestions(form, field);
external_delegate_->CheckSuggestionCount(kDefaultPageID, 1);
const std::string visa_label =
base::JoinString({"Visa ", test::ObfuscatedCardDigitsAsUTF8("3456"),
", expires on 04/99"},
"");
CheckSuggestions(kDefaultPageID,
Suggestion("Elvis Presley", visa_label, kVisaCard,
autofill_manager_->GetPackedCreditCardID(7)));
}
// Ensures the "Use a virtual card number" option should not be shown when there
// is no cloud token data for the card.
TEST_F(AutofillManagerTestForVirtualCardOption,
ShouldNotShowDueToNoCloudTokenData) {
CreateCompleteFormAndGetSuggestions();
VerifyNoVirtualCardSuggestions();
}
// Ensures the "Use a virtual card number" option should not be shown when there
// is multiple cloud token data for the card.
TEST_F(AutofillManagerTestForVirtualCardOption,
ShouldNotShowDueToMultipleCloudTokenData) {
CreateCloudTokenDataForDefaultCard();
CreditCardCloudTokenData data2 = test::GetCreditCardCloudTokenData2();
data2.masked_card_id = "a123";
personal_data_.AddCloudTokenData(data2);
CreateCompleteFormAndGetSuggestions();
VerifyNoVirtualCardSuggestions();
}
// Ensures the "Use a virtual card number" option should not be shown when card
// expiration date field is not detected.
TEST_F(AutofillManagerTestForVirtualCardOption,
ShouldNotShowDueToFormNotHavingExpirationDateField) {
// Creates an incomplete form without expiration date field.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("CVC", "cvc", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
field = form.fields[1]; // card number field.
GetAutofillSuggestions(form, field);
VerifyNoVirtualCardSuggestions();
}
// Ensures the "Use a virtual card number" option should not be shown when card
// cvc field is not detected.
TEST_F(AutofillManagerTestForVirtualCardOption,
ShouldNotShowDueToFormNotHavingCvcField) {
// Creates an incomplete form without cvc field.
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
form.main_frame_origin =
url::Origin::Create(GURL("https://myform_root.com/form.html"));
FormFieldData field;
test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("Expiration Date", "ccmonth", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("", "ccyear", "", "text", &field);
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
field = form.fields[1]; // card number field.
GetAutofillSuggestions(form, field);
VerifyNoVirtualCardSuggestions();
}
// Ensures the "Use a virtual card number" option should be shown when all
// requirements are met.
TEST_F(AutofillManagerTestForVirtualCardOption,
ShouldShowVirtualCardOption_OneCard) {
CreateCloudTokenDataForDefaultCard();
CreateCompleteFormAndGetSuggestions();
// Ensures the card suggestion and the virtual card suggestion are shown.
external_delegate_->CheckSuggestionCount(kDefaultPageID, 2);
CheckSuggestions(
kDefaultPageID,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
"Expires on 04/99", kVisaCard,
autofill_manager_->GetPackedCreditCardID(7)),
Suggestion(l10n_util::GetStringUTF8(
IDS_AUTOFILL_CLOUD_TOKEN_DROPDOWN_OPTION_LABEL),
"", "", PopupItemId::POPUP_ITEM_ID_USE_VIRTUAL_CARD));
}
// Ensures the "Use a virtual card number" option should be shown when there are
// multiple cards and at least one card meets requirements.
TEST_F(AutofillManagerTestForVirtualCardOption,
ShouldShowVirtualCardOption_MultipleCards) {
CreateCloudTokenDataForDefaultCard();
// Adds another card which does not meet the requirements (has two cloud
// tokens).
CreditCard masked_server_card(CreditCard::MASKED_SERVER_CARD,
/*server_id=*/"a456");
// TODO(crbug.com/1020740): Replace all the hard-coded expiration year in
// this file with NextYear().
test::SetCreditCardInfo(&masked_server_card, "Elvis Presley",
"4111111111111111", // Visa
"04", "2999", "1");
masked_server_card.SetNetworkForMaskedCard(kVisaCard);
masked_server_card.set_guid("00000000-0000-0000-0000-000000000008");
personal_data_.AddServerCreditCard(masked_server_card);
CreditCardCloudTokenData data1 = test::GetCreditCardCloudTokenData1();
data1.masked_card_id = "a456";
personal_data_.AddCloudTokenData(data1);
CreditCardCloudTokenData data2 = test::GetCreditCardCloudTokenData2();
data2.masked_card_id = "a456";
personal_data_.AddCloudTokenData(data2);
CreateCompleteFormAndGetSuggestions();
// Ensures the card suggestion and the virtual card suggestion are shown.
external_delegate_->CheckSuggestionCount(kDefaultPageID, 3);
CheckSuggestions(
kDefaultPageID,
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("1111"),
"Expires on 04/99", kVisaCard,
autofill_manager_->GetPackedCreditCardID(8)),
Suggestion(
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
"Expires on 04/99", kVisaCard,
autofill_manager_->GetPackedCreditCardID(7)),
Suggestion(l10n_util::GetStringUTF8(
IDS_AUTOFILL_CLOUD_TOKEN_DROPDOWN_OPTION_LABEL),
"", "", PopupItemId::POPUP_ITEM_ID_USE_VIRTUAL_CARD));
}
#endif
// Test param indicates if there is an active screen reader.
class OnFocusOnFormFieldTest : public AutofillManagerTest,
public testing::WithParamInterface<bool> {
protected:
OnFocusOnFormFieldTest() = default;
~OnFocusOnFormFieldTest() override = default;
void SetUp() override {
AutofillManagerTest::SetUp();
has_active_screen_reader_ = GetParam();
external_delegate_->set_has_active_screen_reader(has_active_screen_reader_);
scoped_feature_list_.InitWithFeatures(
// Enabled
{},
// Disabled
{kAutofillRestrictUnownedFieldsToFormlessCheckout});
}
void TearDown() override {
external_delegate_->set_has_active_screen_reader(false);
AutofillManagerTest::TearDown();
}
void CheckSuggestionsAvailableIfScreenReaderRunning() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
// The only existing functions for determining whether ChromeVox is in use
// are in the src/chrome directory, which cannot be included in components.
// Thus, if the platform is ChromeOS, we assume that ChromeVox is in use at
// this point in the code.
EXPECT_EQ(true,
external_delegate_->has_suggestions_available_on_field_focus());
#else
EXPECT_EQ(has_active_screen_reader_,
external_delegate_->has_suggestions_available_on_field_focus());
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
void CheckNoSuggestionsAvailableOnFieldFocus() {
EXPECT_FALSE(
external_delegate_->has_suggestions_available_on_field_focus());
}
bool has_active_screen_reader_;
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_P(OnFocusOnFormFieldTest, AddressSuggestions) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
// Set a valid autocomplete attribute for the first name.
test::CreateTestFormField("First name", "firstname", "", "text", &field);
field.autocomplete_attribute = "given-name";
form.fields.push_back(field);
// Set an unrecognized autocomplete attribute for the last name.
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
field.autocomplete_attribute = "unrecognized";
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
// Suggestions should be returned for the first field.
autofill_manager_->OnFocusOnFormFieldImpl(form, form.fields[0], gfx::RectF());
CheckSuggestionsAvailableIfScreenReaderRunning();
// No suggestions should be provided for the second field because of its
// unrecognized autocomplete attribute.
autofill_manager_->OnFocusOnFormFieldImpl(form, form.fields[1], gfx::RectF());
CheckNoSuggestionsAvailableOnFieldFocus();
}
TEST_P(OnFocusOnFormFieldTest, AddressSuggestions_AutocompleteOffNotRespected) {
FormData form;
form.name = ASCIIToUTF16("MyForm");
form.url = GURL("https://myform.com/form.html");
form.action = GURL("https://myform.com/submit.html");
FormFieldData field;
// Set a valid autocomplete attribute for the first name.
test::CreateTestFormField("First name", "firstname", "", "text", &field);
field.autocomplete_attribute = "given-name";
form.fields.push_back(field);
// Set an autocomplete=off attribute for the last name.
test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
field.should_autocomplete = false;
form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
autofill_manager_->OnFocusOnFormFieldImpl(form, form.fields[1], gfx::RectF());
CheckSuggestionsAvailableIfScreenReaderRunning();
}
TEST_P(OnFocusOnFormFieldTest, CreditCardSuggestions_SecureContext) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
// Clear the form action.
form.action = GURL();
std::vector<FormData> forms(1, form);
FormsSeen(forms);
autofill_manager_->OnFocusOnFormFieldImpl(form, form.fields[1], gfx::RectF());
CheckSuggestionsAvailableIfScreenReaderRunning();
}
TEST_P(OnFocusOnFormFieldTest, CreditCardSuggestions_NonSecureContext) {
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, false, false);
// Clear the form action.
form.action = GURL();
std::vector<FormData> forms(1, form);
FormsSeen(forms);
autofill_manager_->OnFocusOnFormFieldImpl(form, form.fields[1], gfx::RectF());
// In a non-HTTPS context, there will be a warning indicating the page is
// insecure.
CheckSuggestionsAvailableIfScreenReaderRunning();
}
TEST_P(OnFocusOnFormFieldTest, CreditCardSuggestions_Ablation) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
features::kAutofillCreditCardAblationExperiment);
// Set up our form data.
FormData form;
CreateTestCreditCardFormData(&form, true, false);
// Clear the form action.
form.action = GURL();
std::vector<FormData> forms(1, form);
FormsSeen(forms);
autofill_manager_->OnFocusOnFormFieldImpl(form, form.fields[1], gfx::RectF());
CheckNoSuggestionsAvailableOnFieldFocus();
}
INSTANTIATE_TEST_SUITE_P(
AutofillManagerTest,
ProfileMatchingTypesTest,
testing::Combine(
testing::ValuesIn(kProfileMatchingTypesTestCases),
testing::Range(static_cast<int>(AutofillDataModel::UNVALIDATED),
static_cast<int>(AutofillDataModel::UNSUPPORTED) + 1),
testing::Bool(),
testing::Bool()));
INSTANTIATE_TEST_SUITE_P(All, OnFocusOnFormFieldTest, testing::Bool());
// Runs the suite with the feature |kAutofillSupportForMoreStructuredNames|
// enabled and disabled.
INSTANTIATE_TEST_SUITE_P(,
AutofillManagerStructuredProfileTest,
testing::Bool());
#if defined(OS_IOS) || defined(OS_ANDROID)
INSTANTIATE_TEST_SUITE_P(,
SuggestionMatchingTest,
testing::Values(std::make_tuple(0, ""),
std::make_tuple(1, "show-all"),
std::make_tuple(1, "show-one")));
#else
INSTANTIATE_TEST_SUITE_P(All,
SuggestionMatchingTest,
testing::Values(std::make_tuple(0, ""),
std::make_tuple(1, "")));
#endif // defined(OS_IOS) || defined(OS_ANDROID)
// The parameter indicates whether the AutofillKeyboardAccessory feature is
// enabled or disabled.
INSTANTIATE_TEST_SUITE_P(All, CreditCardSuggestionTest, testing::Bool());
} // namespace autofill