Home | History | Annotate | Download | only in password_manager
      1 // Copyright (c) 2012 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 "testing/gtest/include/gtest/gtest.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/strings/string_util.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "chrome/browser/password_manager/password_form_manager.h"
     12 #include "chrome/browser/password_manager/password_manager.h"
     13 #include "chrome/browser/password_manager/password_manager_delegate.h"
     14 #include "chrome/browser/password_manager/password_store.h"
     15 #include "chrome/browser/password_manager/password_store_factory.h"
     16 #include "chrome/browser/password_manager/test_password_store.h"
     17 #include "chrome/browser/profiles/profile_manager.h"
     18 #include "chrome/test/base/testing_profile.h"
     19 #include "content/public/common/password_form.h"
     20 #include "content/public/test/test_utils.h"
     21 #include "testing/gmock/include/gmock/gmock.h"
     22 
     23 using content::PasswordForm;
     24 
     25 using ::testing::Eq;
     26 
     27 class TestPasswordManagerDelegate : public PasswordManagerDelegate {
     28  public:
     29   explicit TestPasswordManagerDelegate(Profile* profile) : profile_(profile) {}
     30 
     31   virtual void FillPasswordForm(
     32       const autofill::PasswordFormFillData& form_data) OVERRIDE {}
     33   virtual void AddSavePasswordInfoBarIfPermitted(
     34       PasswordFormManager* form_to_save) OVERRIDE {}
     35   virtual Profile* GetProfile() OVERRIDE { return profile_; }
     36   virtual bool DidLastPageLoadEncounterSSLErrors() OVERRIDE { return false; }
     37 
     38  private:
     39   Profile* profile_;
     40 };
     41 
     42 class TestPasswordManager : public PasswordManager {
     43  public:
     44   explicit TestPasswordManager(PasswordManagerDelegate* delegate)
     45       : PasswordManager(NULL, delegate) {}
     46 
     47   virtual void Autofill(
     48       const content::PasswordForm& form_for_autofill,
     49       const content::PasswordFormMap& best_matches,
     50       const content::PasswordForm& preferred_match,
     51       bool wait_for_username) const OVERRIDE {}
     52 };
     53 
     54 class TestPasswordFormManager : public PasswordFormManager {
     55  public:
     56   TestPasswordFormManager(Profile* profile,
     57                           PasswordManager* manager,
     58                           const content::PasswordForm& observed_form,
     59                           bool ssl_valid)
     60     : PasswordFormManager(profile, manager, NULL, observed_form, ssl_valid),
     61       num_sent_messages_(0) {}
     62 
     63   virtual void SendNotBlacklistedToRenderer() OVERRIDE {
     64     ++num_sent_messages_;
     65   }
     66 
     67   size_t num_sent_messages() {
     68     return num_sent_messages_;
     69   }
     70 
     71  private:
     72   size_t num_sent_messages_;
     73 };
     74 
     75 class PasswordFormManagerTest : public testing::Test {
     76  public:
     77   PasswordFormManagerTest() {
     78   }
     79   virtual void SetUp() {
     80     observed_form_.origin = GURL("http://accounts.google.com/a/LoginAuth");
     81     observed_form_.action = GURL("http://accounts.google.com/a/Login");
     82     observed_form_.username_element = ASCIIToUTF16("Email");
     83     observed_form_.password_element = ASCIIToUTF16("Passwd");
     84     observed_form_.submit_element = ASCIIToUTF16("signIn");
     85     observed_form_.signon_realm = "http://accounts.google.com";
     86 
     87     saved_match_ = observed_form_;
     88     saved_match_.origin = GURL("http://accounts.google.com/a/ServiceLoginAuth");
     89     saved_match_.action = GURL("http://accounts.google.com/a/ServiceLogin");
     90     saved_match_.preferred = true;
     91     saved_match_.username_value = ASCIIToUTF16("test (at) gmail.com");
     92     saved_match_.password_value = ASCIIToUTF16("test1");
     93     saved_match_.other_possible_usernames.push_back(
     94         ASCIIToUTF16("test2 (at) gmail.com"));
     95     profile_ = new TestingProfile();
     96   }
     97 
     98   virtual void TearDown() {
     99     delete profile_;
    100   }
    101 
    102   PasswordForm* GetPendingCredentials(PasswordFormManager* p) {
    103     return &p->pending_credentials_;
    104   }
    105 
    106   void SimulateMatchingPhase(PasswordFormManager* p, bool find_match) {
    107     // Roll up the state to mock out the matching phase.
    108     p->state_ = PasswordFormManager::POST_MATCHING_PHASE;
    109     if (!find_match)
    110       return;
    111 
    112     PasswordForm* match = new PasswordForm(saved_match_);
    113     // Heap-allocated form is owned by p.
    114     p->best_matches_[match->username_value] = match;
    115     p->preferred_match_ = match;
    116   }
    117 
    118   void SimulateFetchMatchingLoginsFromPasswordStore(
    119       PasswordFormManager* manager) {
    120     // Just need to update the internal states.
    121     manager->state_ = PasswordFormManager::MATCHING_PHASE;
    122   }
    123 
    124   void SimulateResponseFromPasswordStore(
    125       PasswordFormManager* manager,
    126       const std::vector<PasswordForm*>& result) {
    127     // Simply call the callback method when request done. This will transfer
    128     // the ownership of the objects in |result| to the |manager|.
    129     manager->OnGetPasswordStoreResults(result);
    130   }
    131 
    132   void SanitizePossibleUsernames(PasswordFormManager* p, PasswordForm* form) {
    133     p->SanitizePossibleUsernames(form);
    134   }
    135 
    136   bool IgnoredResult(PasswordFormManager* p, PasswordForm* form) {
    137     return p->IgnoreResult(*form);
    138   }
    139 
    140   Profile* profile() { return profile_; }
    141 
    142   PasswordForm* observed_form() { return &observed_form_; }
    143   PasswordForm* saved_match() { return &saved_match_; }
    144   PasswordForm* CreateSavedMatch(bool blacklisted) {
    145     // Owned by the caller of this method.
    146     PasswordForm* match = new PasswordForm(saved_match_);
    147     match->blacklisted_by_user = blacklisted;
    148     return match;
    149   }
    150 
    151  private:
    152   PasswordForm observed_form_;
    153   PasswordForm saved_match_;
    154   Profile* profile_;
    155 };
    156 
    157 TEST_F(PasswordFormManagerTest, TestNewLogin) {
    158   PasswordFormManager* manager = new PasswordFormManager(
    159       profile(), NULL, NULL, *observed_form(), false);
    160   SimulateMatchingPhase(manager, false);
    161   // User submits credentials for the observed form.
    162   PasswordForm credentials = *observed_form();
    163   credentials.username_value = saved_match()->username_value;
    164   credentials.password_value = saved_match()->password_value;
    165   credentials.preferred = true;
    166   manager->ProvisionallySave(
    167       credentials,
    168       PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
    169 
    170   // Successful login. The PasswordManager would instruct PasswordFormManager
    171   // to save, which should know this is a new login.
    172   EXPECT_TRUE(manager->IsNewLogin());
    173   // Make sure the credentials that would be submitted on successful login
    174   // are going to match the stored entry in the db.
    175   EXPECT_EQ(observed_form()->origin.spec(),
    176             GetPendingCredentials(manager)->origin.spec());
    177   EXPECT_EQ(observed_form()->signon_realm,
    178             GetPendingCredentials(manager)->signon_realm);
    179   EXPECT_EQ(observed_form()->action,
    180               GetPendingCredentials(manager)->action);
    181   EXPECT_TRUE(GetPendingCredentials(manager)->preferred);
    182   EXPECT_EQ(saved_match()->password_value,
    183             GetPendingCredentials(manager)->password_value);
    184   EXPECT_EQ(saved_match()->username_value,
    185             GetPendingCredentials(manager)->username_value);
    186 
    187   // Now, suppose the user re-visits the site and wants to save an additional
    188   // login for the site with a new username. In this case, the matching phase
    189   // will yield the previously saved login.
    190   SimulateMatchingPhase(manager, true);
    191   // Set up the new login.
    192   string16 new_user = ASCIIToUTF16("newuser");
    193   string16 new_pass = ASCIIToUTF16("newpass");
    194   credentials.username_value = new_user;
    195   credentials.password_value = new_pass;
    196   manager->ProvisionallySave(
    197       credentials,
    198       PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
    199 
    200   // Again, the PasswordFormManager should know this is still a new login.
    201   EXPECT_TRUE(manager->IsNewLogin());
    202   // And make sure everything squares up again.
    203   EXPECT_EQ(observed_form()->origin.spec(),
    204             GetPendingCredentials(manager)->origin.spec());
    205   EXPECT_EQ(observed_form()->signon_realm,
    206             GetPendingCredentials(manager)->signon_realm);
    207   EXPECT_TRUE(GetPendingCredentials(manager)->preferred);
    208   EXPECT_EQ(new_pass,
    209             GetPendingCredentials(manager)->password_value);
    210   EXPECT_EQ(new_user,
    211             GetPendingCredentials(manager)->username_value);
    212   // Done.
    213   delete manager;
    214 }
    215 
    216 TEST_F(PasswordFormManagerTest, TestUpdatePassword) {
    217   // Create a PasswordFormManager with observed_form, as if we just
    218   // saw this form and need to find matching logins.
    219   PasswordFormManager* manager = new PasswordFormManager(
    220       profile(), NULL, NULL, *observed_form(), false);
    221   SimulateMatchingPhase(manager, true);
    222 
    223   // User submits credentials for the observed form using a username previously
    224   // stored, but a new password. Note that the observed form may have different
    225   // origin URL (as it does in this case) than the saved_match, but we want to
    226   // make sure the updated password is reflected in saved_match, because that is
    227   // what we autofilled.
    228   string16 new_pass = ASCIIToUTF16("newpassword");
    229   PasswordForm credentials = *observed_form();
    230   credentials.username_value = saved_match()->username_value;
    231   credentials.password_value = new_pass;
    232   credentials.preferred = true;
    233   manager->ProvisionallySave(
    234       credentials,
    235       PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
    236 
    237   // Successful login. The PasswordManager would instruct PasswordFormManager
    238   // to save, and since this is an update, it should know not to save as a new
    239   // login.
    240   EXPECT_FALSE(manager->IsNewLogin());
    241 
    242   // Make sure the credentials that would be submitted on successful login
    243   // are going to match the stored entry in the db. (This verifies correct
    244   // behaviour for bug 1074420).
    245   EXPECT_EQ(GetPendingCredentials(manager)->origin.spec(),
    246             saved_match()->origin.spec());
    247   EXPECT_EQ(GetPendingCredentials(manager)->signon_realm,
    248             saved_match()->signon_realm);
    249   EXPECT_TRUE(GetPendingCredentials(manager)->preferred);
    250   EXPECT_EQ(new_pass,
    251             GetPendingCredentials(manager)->password_value);
    252   // Done.
    253   delete manager;
    254 }
    255 
    256 TEST_F(PasswordFormManagerTest, TestIgnoreResult) {
    257   PasswordFormManager* manager = new PasswordFormManager(
    258       profile(), NULL, NULL, *observed_form(), false);
    259   // Make sure we don't match a PasswordForm if it was originally saved on
    260   // an SSL-valid page and we are now on a page with invalid certificate.
    261   saved_match()->ssl_valid = true;
    262   EXPECT_TRUE(IgnoredResult(manager, saved_match()));
    263 
    264   saved_match()->ssl_valid = false;
    265   // Different paths for action / origin are okay.
    266   saved_match()->action = GURL("http://www.google.com/b/Login");
    267   saved_match()->origin = GURL("http://www.google.com/foo");
    268   EXPECT_FALSE(IgnoredResult(manager, saved_match()));
    269 
    270   // Done.
    271   delete manager;
    272 }
    273 
    274 TEST_F(PasswordFormManagerTest, TestEmptyAction) {
    275   scoped_ptr<PasswordFormManager> manager(new PasswordFormManager(
    276       profile(), NULL, NULL, *observed_form(), false));
    277 
    278   saved_match()->action = GURL();
    279   SimulateMatchingPhase(manager.get(), true);
    280   // User logs in with the autofilled username / password from saved_match.
    281   PasswordForm login = *observed_form();
    282   login.username_value = saved_match()->username_value;
    283   login.password_value = saved_match()->password_value;
    284   manager->ProvisionallySave(
    285       login,
    286       PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
    287   EXPECT_FALSE(manager->IsNewLogin());
    288   // We bless our saved PasswordForm entry with the action URL of the
    289   // observed form.
    290   EXPECT_EQ(observed_form()->action,
    291             GetPendingCredentials(manager.get())->action);
    292 }
    293 
    294 TEST_F(PasswordFormManagerTest, TestUpdateAction) {
    295   scoped_ptr<PasswordFormManager> manager(new PasswordFormManager(
    296       profile(), NULL, NULL, *observed_form(), false));
    297 
    298   SimulateMatchingPhase(manager.get(), true);
    299   // User logs in with the autofilled username / password from saved_match.
    300   PasswordForm login = *observed_form();
    301   login.username_value = saved_match()->username_value;
    302   login.password_value = saved_match()->password_value;
    303 
    304   manager->ProvisionallySave(
    305       login,
    306       PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
    307   EXPECT_FALSE(manager->IsNewLogin());
    308   // The observed action URL is different from the previously saved one, and
    309   // is the same as the one that would be submitted on successful login.
    310   EXPECT_NE(observed_form()->action, saved_match()->action);
    311   EXPECT_EQ(observed_form()->action,
    312             GetPendingCredentials(manager.get())->action);
    313 }
    314 
    315 TEST_F(PasswordFormManagerTest, TestDynamicAction) {
    316   scoped_ptr<PasswordFormManager> manager(new PasswordFormManager(
    317       profile(), NULL, NULL, *observed_form(), false));
    318 
    319   SimulateMatchingPhase(manager.get(), false);
    320   PasswordForm login(*observed_form());
    321   // The submitted action URL is different from the one observed on page load.
    322   GURL new_action = GURL("http://www.google.com/new_action");
    323   login.action = new_action;
    324 
    325   manager->ProvisionallySave(
    326       login,
    327       PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
    328   EXPECT_TRUE(manager->IsNewLogin());
    329   // Check that the provisionally saved action URL is the same as the submitted
    330   // action URL, not the one observed on page load.
    331   EXPECT_EQ(new_action,
    332             GetPendingCredentials(manager.get())->action);
    333 }
    334 
    335 TEST_F(PasswordFormManagerTest, TestAlternateUsername) {
    336   // Need a MessageLoop for callbacks.
    337   base::MessageLoop message_loop;
    338   PasswordStoreFactory::GetInstance()->SetTestingFactory(
    339       profile(), &TestPasswordStore::Create);
    340   scoped_refptr<TestPasswordStore> password_store =
    341       static_cast<TestPasswordStore*>(
    342           PasswordStoreFactory::GetForProfile(profile(),
    343                                               Profile::IMPLICIT_ACCESS).get());
    344   TestPasswordManagerDelegate delegate(profile());
    345   TestPasswordManager password_manager(&delegate);
    346   scoped_ptr<TestPasswordFormManager> manager(new TestPasswordFormManager(
    347       profile(), &password_manager, *observed_form(), false));
    348 
    349   password_store->AddLogin(*saved_match());
    350   manager->FetchMatchingLoginsFromPasswordStore();
    351   content::RunAllPendingInMessageLoop();
    352 
    353   // The saved match has the right username already.
    354   PasswordForm login(*observed_form());
    355   login.username_value = saved_match()->username_value;
    356   login.password_value = saved_match()->password_value;
    357   login.preferred = true;
    358   manager->ProvisionallySave(
    359       login,
    360       PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES);
    361 
    362   EXPECT_FALSE(manager->IsNewLogin());
    363   manager->Save();
    364   content::RunAllPendingInMessageLoop();
    365 
    366   // Should be only one password stored, and should not have
    367   // |other_possible_usernames| set anymore.
    368   TestPasswordStore::PasswordMap passwords = password_store->stored_passwords();
    369   EXPECT_EQ(1U, passwords.size());
    370   ASSERT_EQ(1U, passwords[saved_match()->signon_realm].size());
    371   EXPECT_EQ(saved_match()->username_value,
    372             passwords[saved_match()->signon_realm][0].username_value);
    373   EXPECT_EQ(
    374       0U,
    375       passwords[saved_match()->signon_realm][0].
    376       other_possible_usernames.size());
    377 
    378   // This time use an alternate username
    379   manager.reset(new TestPasswordFormManager(
    380       profile(), &password_manager, *observed_form(), false));
    381   password_store->Clear();
    382   password_store->AddLogin(*saved_match());
    383   manager->FetchMatchingLoginsFromPasswordStore();
    384   content::RunAllPendingInMessageLoop();
    385 
    386   string16 new_username = saved_match()->other_possible_usernames[0];
    387   login.username_value = new_username;
    388   manager->ProvisionallySave(
    389       login,
    390       PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES);
    391 
    392   EXPECT_FALSE(manager->IsNewLogin());
    393   manager->Save();
    394   content::RunAllPendingInMessageLoop();
    395 
    396   // |other_possible_usernames| should also be empty, but username_value should
    397   // be changed to match |new_username|
    398   passwords = password_store->stored_passwords();
    399   EXPECT_EQ(1U, passwords.size());
    400   ASSERT_EQ(1U, passwords[saved_match()->signon_realm].size());
    401   EXPECT_EQ(new_username,
    402             passwords[saved_match()->signon_realm][0].username_value);
    403   EXPECT_EQ(
    404       0U,
    405       passwords[saved_match()->signon_realm][0].
    406       other_possible_usernames.size());
    407 }
    408 
    409 TEST_F(PasswordFormManagerTest, TestValidForms) {
    410   // User submits credentials for the observed form.
    411   PasswordForm credentials = *observed_form();
    412   credentials.scheme = PasswordForm::SCHEME_HTML;
    413   credentials.username_value = saved_match()->username_value;
    414   credentials.password_value = saved_match()->password_value;
    415 
    416   // Form with both username_element and password_element.
    417   PasswordFormManager manager1(profile(), NULL, NULL, credentials, false);
    418   SimulateMatchingPhase(&manager1, false);
    419   EXPECT_TRUE(manager1.HasValidPasswordForm());
    420 
    421   // Form without a username_element but with a password_element.
    422   credentials.username_element.clear();
    423   PasswordFormManager manager2(profile(), NULL, NULL, credentials, false);
    424   SimulateMatchingPhase(&manager2, false);
    425   EXPECT_FALSE(manager2.HasValidPasswordForm());
    426 
    427   // Form without a password_element but with a username_element.
    428   credentials.username_element = saved_match()->username_element;
    429   credentials.password_element.clear();
    430   PasswordFormManager manager3(profile(), NULL, NULL, credentials, false);
    431   SimulateMatchingPhase(&manager3, false);
    432   EXPECT_FALSE(manager3.HasValidPasswordForm());
    433 
    434   // Form with neither a password_element nor a username_element.
    435   credentials.username_element.clear();
    436   credentials.password_element.clear();
    437   PasswordFormManager manager4(profile(), NULL, NULL, credentials, false);
    438   SimulateMatchingPhase(&manager4, false);
    439   EXPECT_FALSE(manager4.HasValidPasswordForm());
    440 }
    441 
    442 TEST_F(PasswordFormManagerTest, TestValidFormsBasic) {
    443   // User submits credentials for the observed form.
    444   PasswordForm credentials = *observed_form();
    445   credentials.scheme = PasswordForm::SCHEME_BASIC;
    446   credentials.username_value = saved_match()->username_value;
    447   credentials.password_value = saved_match()->password_value;
    448 
    449   // Form with both username_element and password_element.
    450   PasswordFormManager manager1(profile(), NULL, NULL, credentials, false);
    451   SimulateMatchingPhase(&manager1, false);
    452   EXPECT_TRUE(manager1.HasValidPasswordForm());
    453 
    454   // Form without a username_element but with a password_element.
    455   credentials.username_element.clear();
    456   PasswordFormManager manager2(profile(), NULL, NULL, credentials, false);
    457   SimulateMatchingPhase(&manager2, false);
    458   EXPECT_TRUE(manager2.HasValidPasswordForm());
    459 
    460   // Form without a password_element but with a username_element.
    461   credentials.username_element = saved_match()->username_element;
    462   credentials.password_element.clear();
    463   PasswordFormManager manager3(profile(), NULL, NULL, credentials, false);
    464   SimulateMatchingPhase(&manager3, false);
    465   EXPECT_TRUE(manager3.HasValidPasswordForm());
    466 
    467   // Form with neither a password_element nor a username_element.
    468   credentials.username_element.clear();
    469   credentials.password_element.clear();
    470   PasswordFormManager manager4(profile(), NULL, NULL, credentials, false);
    471   SimulateMatchingPhase(&manager4, false);
    472   EXPECT_TRUE(manager4.HasValidPasswordForm());
    473 }
    474 
    475 TEST_F(PasswordFormManagerTest, TestSendNotBlacklistedMessage) {
    476   // A dumb password manager.
    477   TestPasswordManagerDelegate delegate(profile());
    478   TestPasswordManager password_manager(&delegate);
    479 
    480   // First time sign up attempt; No login result is found from password store;
    481   // We should send the not blacklisted message.
    482   scoped_ptr<TestPasswordFormManager> manager(new TestPasswordFormManager(
    483       profile(), &password_manager, *observed_form(), false));
    484   SimulateFetchMatchingLoginsFromPasswordStore(manager.get());
    485   std::vector<PasswordForm*> result;
    486   SimulateResponseFromPasswordStore(manager.get(), result);
    487   EXPECT_EQ(1u, manager->num_sent_messages());
    488 
    489   // Sign up attempt to previously visited sites; Login result is found from
    490   // password store, and is not blacklisted; We should send the not blacklisted
    491   // message.
    492   manager.reset(new TestPasswordFormManager(
    493       profile(), &password_manager, *observed_form(), false));
    494   SimulateFetchMatchingLoginsFromPasswordStore(manager.get());
    495   // We need add heap allocated objects to result.
    496   result.push_back(CreateSavedMatch(false));
    497   SimulateResponseFromPasswordStore(manager.get(), result);
    498   EXPECT_EQ(1u, manager->num_sent_messages());
    499 
    500   // Sign up attempt to previously visited sites; Login result is found from
    501   // password store, but is blacklisted; We should not send the not blacklisted
    502   // message.
    503   manager.reset(new TestPasswordFormManager(
    504       profile(), &password_manager, *observed_form(), false));
    505   SimulateFetchMatchingLoginsFromPasswordStore(manager.get());
    506   result.clear();
    507   result.push_back(CreateSavedMatch(true));
    508   SimulateResponseFromPasswordStore(manager.get(), result);
    509   EXPECT_EQ(0u, manager->num_sent_messages());
    510 }
    511 
    512 TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernames) {
    513   scoped_ptr<PasswordFormManager> manager(new PasswordFormManager(
    514       profile(), NULL, NULL, *observed_form(), false));
    515   PasswordForm credentials(*observed_form());
    516   credentials.other_possible_usernames.push_back(ASCIIToUTF16("543-43-1234"));
    517   credentials.other_possible_usernames.push_back(
    518       ASCIIToUTF16("378282246310005"));
    519   credentials.other_possible_usernames.push_back(
    520       ASCIIToUTF16("other username"));
    521   credentials.username_value = ASCIIToUTF16("test (at) gmail.com");
    522 
    523   SanitizePossibleUsernames(manager.get(), &credentials);
    524 
    525   // Possible credit card number and SSN are stripped.
    526   std::vector<string16> expected;
    527   expected.push_back(ASCIIToUTF16("other username"));
    528   EXPECT_THAT(credentials.other_possible_usernames, Eq(expected));
    529 
    530   credentials.other_possible_usernames.clear();
    531   credentials.other_possible_usernames.push_back(ASCIIToUTF16("511-32-9830"));
    532   credentials.other_possible_usernames.push_back(ASCIIToUTF16("duplicate"));
    533   credentials.other_possible_usernames.push_back(ASCIIToUTF16("duplicate"));
    534   credentials.other_possible_usernames.push_back(ASCIIToUTF16("random"));
    535   credentials.other_possible_usernames.push_back(
    536       ASCIIToUTF16("test (at) gmail.com"));
    537 
    538   SanitizePossibleUsernames(manager.get(), &credentials);
    539 
    540   // SSN, duplicate in |other_possible_usernames| and duplicate of
    541   // |username_value| all removed.
    542   expected.clear();
    543   expected.push_back(ASCIIToUTF16("duplicate"));
    544   expected.push_back(ASCIIToUTF16("random"));
    545   EXPECT_THAT(credentials.other_possible_usernames, Eq(expected));
    546 }
    547