• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
SetUp()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 
TearDown()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 
ACTION(STLDeleteElements0)67 ACTION(STLDeleteElements0) {
68   STLDeleteContainerPointers(arg0.begin(), arg0.end());
69 }
70 
TEST_F(PasswordStoreDefaultTest,NonASCIIData)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 
TEST_F(PasswordStoreDefaultTest,Notifications)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