Home | History | Annotate | Download | only in browser
      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 "base/basictypes.h"
      6 #include "base/bind.h"
      7 #include "base/bind_helpers.h"
      8 #include "base/files/scoped_temp_dir.h"
      9 #include "base/prefs/pref_service.h"
     10 #include "base/stl_util.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/synchronization/waitable_event.h"
     14 #include "base/time/time.h"
     15 #include "components/password_manager/core/browser/password_form_data.h"
     16 #include "components/password_manager/core/browser/password_store_change.h"
     17 #include "components/password_manager/core/browser/password_store_consumer.h"
     18 #include "components/password_manager/core/browser/password_store_default.h"
     19 #include "testing/gmock/include/gmock/gmock.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 
     22 using autofill::PasswordForm;
     23 using base::WaitableEvent;
     24 using testing::_;
     25 using testing::DoAll;
     26 using testing::ElementsAreArray;
     27 using testing::Pointee;
     28 using testing::Property;
     29 using testing::WithArg;
     30 
     31 namespace password_manager {
     32 
     33 namespace {
     34 
     35 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
     36  public:
     37   MOCK_METHOD1(OnGetPasswordStoreResults,
     38                void(const std::vector<PasswordForm*>&));
     39 };
     40 
     41 class MockPasswordStoreObserver : public PasswordStore::Observer {
     42  public:
     43   MOCK_METHOD1(OnLoginsChanged,
     44                void(const PasswordStoreChangeList& changes));
     45 };
     46 
     47 }  // anonymous namespace
     48 
     49 class PasswordStoreDefaultTest : public testing::Test {
     50  protected:
     51   virtual void SetUp() OVERRIDE {
     52     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     53     login_db_.reset(new LoginDatabase());
     54     ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append(
     55         FILE_PATH_LITERAL("login_test"))));
     56   }
     57 
     58   virtual void TearDown() OVERRIDE {
     59     ASSERT_TRUE(temp_dir_.Delete());
     60   }
     61 
     62   base::MessageLoopForUI message_loop_;
     63   scoped_ptr<LoginDatabase> login_db_;
     64   base::ScopedTempDir temp_dir_;
     65 };
     66 
     67 ACTION(STLDeleteElements0) {
     68   STLDeleteContainerPointers(arg0.begin(), arg0.end());
     69 }
     70 
     71 TEST_F(PasswordStoreDefaultTest, NonASCIIData) {
     72   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
     73       base::MessageLoopProxy::current(),
     74       base::MessageLoopProxy::current(),
     75       login_db_.release()));
     76   store->Init(syncer::SyncableService::StartSyncFlare());
     77 
     78   // Some non-ASCII password form data.
     79   static const PasswordFormData form_data[] = {
     80     { PasswordForm::SCHEME_HTML,
     81       "http://foo.example.com",
     82       "http://foo.example.com/origin",
     83       "http://foo.example.com/action",
     84       L"",
     85       L"?",
     86       L"",
     87       L" ",
     88       L"",
     89       true, false, 1 },
     90   };
     91 
     92   // Build the expected forms vector and add the forms to the store.
     93   std::vector<PasswordForm*> expected_forms;
     94   for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(form_data); ++i) {
     95     PasswordForm* form = CreatePasswordFormFromData(form_data[i]);
     96     expected_forms.push_back(form);
     97     store->AddLogin(*form);
     98   }
     99 
    100   base::MessageLoop::current()->RunUntilIdle();
    101 
    102   MockPasswordStoreConsumer consumer;
    103 
    104   // We expect to get the same data back, even though it's not all ASCII.
    105   EXPECT_CALL(consumer,
    106       OnGetPasswordStoreResults(ContainsAllPasswordForms(expected_forms)))
    107       .WillOnce(WithArg<0>(STLDeleteElements0()));
    108   store->GetAutofillableLogins(&consumer);
    109 
    110   base::MessageLoop::current()->RunUntilIdle();
    111 
    112   STLDeleteElements(&expected_forms);
    113   store->Shutdown();
    114   base::MessageLoop::current()->RunUntilIdle();
    115 }
    116 
    117 TEST_F(PasswordStoreDefaultTest, Notifications) {
    118   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
    119       base::MessageLoopProxy::current(),
    120       base::MessageLoopProxy::current(),
    121       login_db_.release()));
    122   store->Init(syncer::SyncableService::StartSyncFlare());
    123 
    124   PasswordFormData form_data =
    125   { PasswordForm::SCHEME_HTML,
    126     "http://bar.example.com",
    127     "http://bar.example.com/origin",
    128     "http://bar.example.com/action",
    129     L"submit_element",
    130     L"username_element",
    131     L"password_element",
    132     L"username_value",
    133     L"password_value",
    134     true, false, 1 };
    135   scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
    136 
    137   MockPasswordStoreObserver observer;
    138   store->AddObserver(&observer);
    139 
    140   const PasswordStoreChange expected_add_changes[] = {
    141     PasswordStoreChange(PasswordStoreChange::ADD, *form),
    142   };
    143 
    144   EXPECT_CALL(
    145       observer,
    146       OnLoginsChanged(ElementsAreArray(expected_add_changes)));
    147 
    148   // Adding a login should trigger a notification.
    149   store->AddLogin(*form);
    150   base::MessageLoop::current()->RunUntilIdle();
    151 
    152   // Change the password.
    153   form->password_value = base::ASCIIToUTF16("a different password");
    154 
    155   const PasswordStoreChange expected_update_changes[] = {
    156     PasswordStoreChange(PasswordStoreChange::UPDATE, *form),
    157   };
    158 
    159   EXPECT_CALL(
    160       observer,
    161       OnLoginsChanged(ElementsAreArray(expected_update_changes)));
    162 
    163   // Updating the login with the new password should trigger a notification.
    164   store->UpdateLogin(*form);
    165   base::MessageLoop::current()->RunUntilIdle();
    166 
    167   const PasswordStoreChange expected_delete_changes[] = {
    168     PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
    169   };
    170 
    171   EXPECT_CALL(
    172       observer,
    173       OnLoginsChanged(ElementsAreArray(expected_delete_changes)));
    174 
    175   // Deleting the login should trigger a notification.
    176   store->RemoveLogin(*form);
    177   base::MessageLoop::current()->RunUntilIdle();
    178 
    179   store->RemoveObserver(&observer);
    180   store->Shutdown();
    181   base::MessageLoop::current()->RunUntilIdle();
    182 }
    183 
    184 }  // namespace password_manager
    185