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