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 22using autofill::PasswordForm; 23using base::WaitableEvent; 24using testing::_; 25using testing::DoAll; 26using testing::ElementsAreArray; 27using testing::Pointee; 28using testing::Property; 29using testing::WithArg; 30 31namespace password_manager { 32 33namespace { 34 35class MockPasswordStoreConsumer : public PasswordStoreConsumer { 36 public: 37 MOCK_METHOD1(OnGetPasswordStoreResults, 38 void(const std::vector<PasswordForm*>&)); 39}; 40 41class MockPasswordStoreObserver : public PasswordStore::Observer { 42 public: 43 MOCK_METHOD1(OnLoginsChanged, 44 void(const PasswordStoreChangeList& changes)); 45}; 46 47} // anonymous namespace 48 49class 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 67ACTION(STLDeleteElements0) { 68 STLDeleteContainerPointers(arg0.begin(), arg0.end()); 69} 70 71TEST_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 117TEST_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