blob: 09a0a05a33be1ef97e36f2c4f59902071c8accc0 [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 <memory>
#include <vector>
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/common/autofill_features.h"
#include "testing/gtest/include/gtest/gtest.h"
using autofill::features::kAutofillEnforceMinRequiredFieldsForHeuristics;
using autofill::features::kAutofillFixFillableFieldTypes;
using base::ASCIIToUTF16;
namespace autofill {
TEST(FormFieldTest, Match) {
AutofillField field;
// Empty strings match.
EXPECT_TRUE(
FormField::Match(&field, base::string16(), FormField::MATCH_LABEL));
// Empty pattern matches non-empty string.
field.label = ASCIIToUTF16("a");
EXPECT_TRUE(
FormField::Match(&field, base::string16(), FormField::MATCH_LABEL));
// Strictly empty pattern matches empty string.
field.label = base::string16();
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("^$"), FormField::MATCH_LABEL));
// Strictly empty pattern does not match non-empty string.
field.label = ASCIIToUTF16("a");
EXPECT_FALSE(
FormField::Match(&field, ASCIIToUTF16("^$"), FormField::MATCH_LABEL));
// Non-empty pattern doesn't match empty string.
field.label = base::string16();
EXPECT_FALSE(
FormField::Match(&field, ASCIIToUTF16("a"), FormField::MATCH_LABEL));
// Beginning of line.
field.label = ASCIIToUTF16("head_tail");
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("^head"), FormField::MATCH_LABEL));
EXPECT_FALSE(
FormField::Match(&field, ASCIIToUTF16("^tail"), FormField::MATCH_LABEL));
// End of line.
field.label = ASCIIToUTF16("head_tail");
EXPECT_FALSE(
FormField::Match(&field, ASCIIToUTF16("head$"), FormField::MATCH_LABEL));
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("tail$"), FormField::MATCH_LABEL));
// Exact.
field.label = ASCIIToUTF16("head_tail");
EXPECT_FALSE(
FormField::Match(&field, ASCIIToUTF16("^head$"), FormField::MATCH_LABEL));
EXPECT_FALSE(
FormField::Match(&field, ASCIIToUTF16("^tail$"), FormField::MATCH_LABEL));
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("^head_tail$"),
FormField::MATCH_LABEL));
// Escaped dots.
field.label = ASCIIToUTF16("m.i.");
// Note: This pattern is misleading as the "." characters are wild cards.
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("m.i."), FormField::MATCH_LABEL));
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("m\\.i\\."),
FormField::MATCH_LABEL));
field.label = ASCIIToUTF16("mXiX");
EXPECT_TRUE(
FormField::Match(&field, ASCIIToUTF16("m.i."), FormField::MATCH_LABEL));
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("m\\.i\\."),
FormField::MATCH_LABEL));
// Repetition.
field.label = ASCIIToUTF16("headtail");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.*tail"),
FormField::MATCH_LABEL));
field.label = ASCIIToUTF16("headXtail");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.*tail"),
FormField::MATCH_LABEL));
field.label = ASCIIToUTF16("headXXXtail");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.*tail"),
FormField::MATCH_LABEL));
field.label = ASCIIToUTF16("headtail");
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("head.+tail"),
FormField::MATCH_LABEL));
field.label = ASCIIToUTF16("headXtail");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.+tail"),
FormField::MATCH_LABEL));
field.label = ASCIIToUTF16("headXXXtail");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.+tail"),
FormField::MATCH_LABEL));
// Alternation.
field.label = ASCIIToUTF16("head_tail");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head|other"),
FormField::MATCH_LABEL));
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("tail|other"),
FormField::MATCH_LABEL));
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("bad|good"),
FormField::MATCH_LABEL));
// Case sensitivity.
field.label = ASCIIToUTF16("xxxHeAd_tAiLxxx");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head_tail"),
FormField::MATCH_LABEL));
// Word boundaries.
field.label = ASCIIToUTF16("contains word:");
EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("\\bword\\b"),
FormField::MATCH_LABEL));
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("\\bcon\\b"),
FormField::MATCH_LABEL));
// Make sure the circumflex in 'crepe' is not treated as a word boundary.
field.label = base::UTF8ToUTF16("cr\xC3\xAApe");
EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("\\bcr\\b"),
FormField::MATCH_LABEL));
}
// Test that we ignore checkable elements.
TEST(FormFieldTest, ParseFormFields) {
std::vector<std::unique_ptr<AutofillField>> fields;
FormFieldData field_data;
field_data.form_control_type = "text";
field_data.check_status = FormFieldData::CheckStatus::kCheckableButUnchecked;
field_data.label = ASCIIToUTF16("Is PO Box");
fields.push_back(
std::make_unique<AutofillField>(field_data, field_data.label));
// Does not parse since there are only field and it's checkable.
EXPECT_TRUE(FormField::ParseFormFields(fields, true).empty());
// reset |is_checkable| to false.
field_data.check_status = FormFieldData::CheckStatus::kNotCheckable;
field_data.label = ASCIIToUTF16("Address line1");
fields.push_back(
std::make_unique<AutofillField>(field_data, field_data.label));
// Parse a single address line 1 field.
{
base::test::ScopedFeatureList enforce_min_fields;
enforce_min_fields.InitAndEnableFeature(
kAutofillEnforceMinRequiredFieldsForHeuristics);
ASSERT_EQ(0u, FormField::ParseFormFields(fields, true).size());
}
{
base::test::ScopedFeatureList do_not_enforce_min_fields;
do_not_enforce_min_fields.InitAndDisableFeature(
kAutofillEnforceMinRequiredFieldsForHeuristics);
const FieldCandidatesMap field_candidates_map =
FormField::ParseFormFields(fields, true);
ASSERT_EQ(1u, field_candidates_map.size());
EXPECT_EQ(ADDRESS_HOME_LINE1,
field_candidates_map.find(ASCIIToUTF16("Address line1"))
->second.BestHeuristicType());
}
// Parses address line 1 and 2.
field_data.label = ASCIIToUTF16("Address line2");
fields.push_back(
std::make_unique<AutofillField>(field_data, field_data.label));
{
base::test::ScopedFeatureList enforce_min_fields;
enforce_min_fields.InitAndEnableFeature(
kAutofillEnforceMinRequiredFieldsForHeuristics);
ASSERT_EQ(0u, FormField::ParseFormFields(fields, true).size());
}
{
base::test::ScopedFeatureList do_not_enforce_min_fields;
do_not_enforce_min_fields.InitAndDisableFeature(
kAutofillEnforceMinRequiredFieldsForHeuristics);
const FieldCandidatesMap field_candidates_map =
FormField::ParseFormFields(fields, true);
ASSERT_EQ(2u, field_candidates_map.size());
EXPECT_EQ(ADDRESS_HOME_LINE1,
field_candidates_map.find(ASCIIToUTF16("Address line1"))
->second.BestHeuristicType());
EXPECT_EQ(ADDRESS_HOME_LINE2,
field_candidates_map.find(ASCIIToUTF16("Address line2"))
->second.BestHeuristicType());
}
}
// Test that the minimum number of required fields for the heuristics considers
// whether a field is actually fillable.
TEST(FormFieldTest, ParseFormFieldEnforceMinFillableFields) {
std::vector<std::unique_ptr<AutofillField>> fields;
FormFieldData field_data;
field_data.form_control_type = "text";
field_data.label = ASCIIToUTF16("Address line 1");
fields.push_back(
std::make_unique<AutofillField>(field_data, field_data.label));
field_data.label = ASCIIToUTF16("Address line 2");
fields.push_back(
std::make_unique<AutofillField>(field_data, field_data.label));
// Don't parse forms with 2 fields.
{
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
kAutofillEnforceMinRequiredFieldsForHeuristics);
EXPECT_EQ(0u, FormField::ParseFormFields(fields, true).size());
}
field_data.label = ASCIIToUTF16("Search");
fields.push_back(
std::make_unique<AutofillField>(field_data, field_data.label));
// Before the fix in kAutofillFixFillableFieldTypes, we would parse the form
// now, although a search field is not fillable.
{
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
/*enabled_features=*/
{kAutofillEnforceMinRequiredFieldsForHeuristics},
/*disabled_features=*/{kAutofillFixFillableFieldTypes});
EXPECT_EQ(3u, FormField::ParseFormFields(fields, true).size());
}
// With the fix, we don't parse the form because search fields are not
// fillable (therefore, the form has only 2 fillable fields).
{
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
/*enabled_features=*/
{kAutofillEnforceMinRequiredFieldsForHeuristics,
kAutofillFixFillableFieldTypes},
/*disabled_features=*/{});
const FieldCandidatesMap field_candidates_map =
FormField::ParseFormFields(fields, true);
EXPECT_EQ(0u, FormField::ParseFormFields(fields, true).size());
}
}
} // namespace autofill