1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/password_manager/core/browser/form_parsing/password_field_prediction.h"
6 
7 #include <vector>
8 
9 #include "base/stl_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/test/scoped_feature_list.h"
12 #include "components/autofill/core/browser/form_structure.h"
13 #include "components/autofill/core/common/form_data.h"
14 #include "components/autofill/core/common/renderer_id.h"
15 #include "components/password_manager/core/common/password_manager_features.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 using autofill::ACCOUNT_CREATION_PASSWORD;
20 using autofill::AutofillField;
21 using autofill::CONFIRMATION_PASSWORD;
22 using autofill::CREDIT_CARD_VERIFICATION_CODE;
23 using autofill::EMAIL_ADDRESS;
24 using autofill::FormData;
25 using autofill::FormFieldData;
26 using autofill::FormStructure;
27 using autofill::NEW_PASSWORD;
28 using autofill::NO_SERVER_DATA;
29 using autofill::PASSWORD;
30 using autofill::ServerFieldType;
31 using autofill::SINGLE_USERNAME;
32 using autofill::UNKNOWN_TYPE;
33 using autofill::USERNAME;
34 using autofill::USERNAME_AND_EMAIL_ADDRESS;
35 using base::ASCIIToUTF16;
36 
37 using FieldPrediction = autofill::AutofillQueryResponse::FormSuggestion::
38     FieldSuggestion::FieldPrediction;
39 
40 namespace password_manager {
41 
42 namespace {
43 
44 // The boolean parameter determines the feature state of
45 // `kSecondaryServerFieldPredictions`.
46 class FormPredictionsTest : public ::testing::TestWithParam<bool> {
47  public:
FormPredictionsTest()48   FormPredictionsTest() {
49     feature_list_.InitWithFeatureState(
50         features::kSecondaryServerFieldPredictions,
51         AreSecondaryPredictionsEnabled());
52   }
53 
AreSecondaryPredictionsEnabled() const54   bool AreSecondaryPredictionsEnabled() const { return GetParam(); }
55 
56  private:
57   base::test::ScopedFeatureList feature_list_;
58 };
59 
TEST_P(FormPredictionsTest,ConvertToFormPredictions)60 TEST_P(FormPredictionsTest, ConvertToFormPredictions) {
61   struct TestField {
62     std::string name;
63     std::string form_control_type;
64     ServerFieldType input_type;
65     ServerFieldType expected_type;
66     bool may_use_prefilled_placeholder;
67     std::vector<ServerFieldType> additional_types;
68   } test_fields[] = {
69       {"full_name", "text", UNKNOWN_TYPE, UNKNOWN_TYPE, false},
70       // Password Manager is interested only in credential related types.
71       {"Email", "email", EMAIL_ADDRESS, EMAIL_ADDRESS, false},
72       {"username", "text", USERNAME, USERNAME, true},
73       {"Password", "password", PASSWORD, PASSWORD, false},
74       {"confirm_password", "password", CONFIRMATION_PASSWORD,
75        CONFIRMATION_PASSWORD, true},
76       // username in |additional_types| takes precedence if the feature is
77       // enabled.
78       {"email",
79        "text",
80        EMAIL_ADDRESS,
81        AreSecondaryPredictionsEnabled() ? USERNAME : EMAIL_ADDRESS,
82        false,
83        {USERNAME}},
84       // cvc in |additional_types| takes precedence if the feature is enabled.
85       {"cvc",
86        "password",
87        PASSWORD,
88        AreSecondaryPredictionsEnabled() ? CREDIT_CARD_VERIFICATION_CODE
89                                         : PASSWORD,
90        false,
91        {CREDIT_CARD_VERIFICATION_CODE}},
92       // non-password, non-cvc types in |additional_types| are ignored.
93       {"email", "text", UNKNOWN_TYPE, UNKNOWN_TYPE, false, {EMAIL_ADDRESS}},
94   };
95 
96   FormData form_data;
97   for (size_t i = 0; i < base::size(test_fields); ++i) {
98     FormFieldData field;
99     field.unique_renderer_id = autofill::FieldRendererId(i + 1000);
100     field.name = ASCIIToUTF16(test_fields[i].name);
101     field.form_control_type = test_fields[i].form_control_type;
102     form_data.fields.push_back(field);
103   }
104 
105   FormStructure form_structure(form_data);
106   // Set server predictions and create expected votes.
107   for (size_t i = 0; i < base::size(test_fields); ++i) {
108     AutofillField* field = form_structure.field(i);
109     field->set_server_type(test_fields[i].input_type);
110 
111     std::vector<FieldPrediction> predictions(1);
112 
113     for (ServerFieldType type : test_fields[i].additional_types) {
114       FieldPrediction additional_prediction;
115       additional_prediction.set_type(type);
116       predictions.push_back(additional_prediction);
117     }
118     field->set_server_predictions(predictions);
119     field->set_may_use_prefilled_placeholder(
120         test_fields[i].may_use_prefilled_placeholder);
121   }
122 
123   constexpr int driver_id = 1000;
124   FormPredictions actual_predictions =
125       ConvertToFormPredictions(driver_id, form_structure);
126 
127   // Check whether actual predictions are equal to expected ones.
128   EXPECT_EQ(driver_id, actual_predictions.driver_id);
129   EXPECT_EQ(form_structure.form_signature(), actual_predictions.form_signature);
130   EXPECT_EQ(base::size(test_fields), actual_predictions.fields.size());
131 
132   for (size_t i = 0; i < base::size(test_fields); ++i) {
133     const PasswordFieldPrediction& actual_prediction =
134         actual_predictions.fields[i];
135     EXPECT_EQ(test_fields[i].expected_type, actual_prediction.type);
136     EXPECT_EQ(test_fields[i].may_use_prefilled_placeholder,
137               actual_prediction.may_use_prefilled_placeholder);
138     EXPECT_EQ(form_structure.field(i)->GetFieldSignature(),
139               actual_prediction.signature);
140   }
141 }
142 
TEST(FormPredictionsTest,ConvertToFormPredictions_SynthesiseConfirmation)143 TEST(FormPredictionsTest, ConvertToFormPredictions_SynthesiseConfirmation) {
144   struct TestField {
145     std::string name;
146     std::string form_control_type;
147     ServerFieldType input_type;
148     ServerFieldType expected_type;
149   };
150   const std::vector<TestField> kTestForms[] = {
151       {
152           {"username", "text", USERNAME, USERNAME},
153           {"new password", "password", ACCOUNT_CREATION_PASSWORD,
154            ACCOUNT_CREATION_PASSWORD},
155           // Same name and type means same signature. As a second new-password
156           // field with this signature, the next field should be re-classified
157           // to confirmation password.
158           {"new password", "password", ACCOUNT_CREATION_PASSWORD,
159            CONFIRMATION_PASSWORD},
160       },
161       {
162           {"username", "text", USERNAME, USERNAME},
163           {"new password duplicate", "password", ACCOUNT_CREATION_PASSWORD,
164            ACCOUNT_CREATION_PASSWORD},
165           // An explicit confirmation password above should override the
166           // 2-new-passwords heuristic.
167           {"new password duplicate", "password", ACCOUNT_CREATION_PASSWORD,
168            ACCOUNT_CREATION_PASSWORD},
169           {"confirm_password", "password", CONFIRMATION_PASSWORD,
170            CONFIRMATION_PASSWORD},
171       },
172   };
173 
174   for (const std::vector<TestField>& test_form : kTestForms) {
175     FormData form_data;
176     for (size_t i = 0; i < test_form.size(); ++i) {
177       FormFieldData field;
178       field.unique_renderer_id = autofill::FieldRendererId(i + 1000);
179       field.name = ASCIIToUTF16(test_form[i].name);
180       field.form_control_type = test_form[i].form_control_type;
181       form_data.fields.push_back(field);
182     }
183 
184     FormStructure form_structure(form_data);
185     // Set server predictions and create expected votes.
186     for (size_t i = 0; i < test_form.size(); ++i) {
187       AutofillField* field = form_structure.field(i);
188       field->set_server_type(test_form[i].input_type);
189     }
190 
191     FormPredictions actual_predictions =
192         ConvertToFormPredictions(0 /*driver_id*/, form_structure);
193 
194     for (size_t i = 0; i < form_data.fields.size(); ++i) {
195       SCOPED_TRACE(testing::Message()
196                    << "field description: name=" << test_form[i].name
197                    << ", form control type=" << test_form[i].form_control_type
198                    << ", input type=" << test_form[i].input_type
199                    << ", expected type=" << test_form[i].expected_type
200                    << ", synthesised FormFieldData=" << form_data.fields[i]);
201       EXPECT_EQ(test_form[i].expected_type, actual_predictions.fields[i].type);
202     }
203   }
204 }
205 
TEST(FormPredictionsTest,DeriveFromServerFieldType)206 TEST(FormPredictionsTest, DeriveFromServerFieldType) {
207   struct TestCase {
208     const char* name;
209     // Input.
210     ServerFieldType server_type;
211     CredentialFieldType expected_result;
212   } test_cases[] = {
213       {"No prediction", NO_SERVER_DATA, CredentialFieldType::kNone},
214       {"Irrelevant type", EMAIL_ADDRESS, CredentialFieldType::kNone},
215       {"Username", USERNAME, CredentialFieldType::kUsername},
216       {"Username/Email", USERNAME_AND_EMAIL_ADDRESS,
217        CredentialFieldType::kUsername},
218       {"Single Username", SINGLE_USERNAME,
219        CredentialFieldType::kSingleUsername},
220       {"Password", PASSWORD, CredentialFieldType::kCurrentPassword},
221       {"New password", NEW_PASSWORD, CredentialFieldType::kNewPassword},
222       {"Account creation password", ACCOUNT_CREATION_PASSWORD,
223        CredentialFieldType::kNewPassword},
224       {"Confirmation password", CONFIRMATION_PASSWORD,
225        CredentialFieldType::kConfirmationPassword},
226   };
227 
228   for (const TestCase& test_case : test_cases) {
229     SCOPED_TRACE(test_case.name);
230     EXPECT_EQ(test_case.expected_result,
231               DeriveFromServerFieldType(test_case.server_type));
232   }
233 }
234 INSTANTIATE_TEST_SUITE_P(All, FormPredictionsTest, testing::Bool());
235 }  // namespace
236 
237 }  // namespace password_manager
238