password_store_default_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 {
32
33class MockPasswordStoreConsumer : public PasswordStoreConsumer {
34 public:
35  MOCK_METHOD1(OnGetPasswordStoreResults,
36               void(const std::vector<PasswordForm*>&));
37};
38
39class MockPasswordStoreObserver : public PasswordStore::Observer {
40 public:
41  MOCK_METHOD1(OnLoginsChanged,
42               void(const PasswordStoreChangeList& changes));
43};
44
45}  // anonymous namespace
46
47class PasswordStoreDefaultTest : public testing::Test {
48 protected:
49  virtual void SetUp() OVERRIDE {
50    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
51    login_db_.reset(new LoginDatabase());
52    ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append(
53        FILE_PATH_LITERAL("login_test"))));
54  }
55
56  virtual void TearDown() OVERRIDE {
57    ASSERT_TRUE(temp_dir_.Delete());
58  }
59
60  base::MessageLoopForUI message_loop_;
61  scoped_ptr<LoginDatabase> login_db_;
62  base::ScopedTempDir temp_dir_;
63};
64
65ACTION(STLDeleteElements0) {
66  STLDeleteContainerPointers(arg0.begin(), arg0.end());
67}
68
69TEST_F(PasswordStoreDefaultTest, NonASCIIData) {
70  scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
71      base::MessageLoopProxy::current(),
72      base::MessageLoopProxy::current(),
73      login_db_.release()));
74  store->Init(syncer::SyncableService::StartSyncFlare());
75
76  // Some non-ASCII password form data.
77  static const PasswordFormData form_data[] = {
78    { PasswordForm::SCHEME_HTML,
79      "http://foo.example.com",
80      "http://foo.example.com/origin",
81      "http://foo.example.com/action",
82      L"มีสีสัน",
83      L"お元気ですか?",
84      L"盆栽",
85      L"أحب كرة",
86      L"£éä국수çà",
87      true, false, 1 },
88  };
89
90  // Build the expected forms vector and add the forms to the store.
91  std::vector<PasswordForm*> expected_forms;
92  for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(form_data); ++i) {
93    PasswordForm* form = CreatePasswordFormFromData(form_data[i]);
94    expected_forms.push_back(form);
95    store->AddLogin(*form);
96  }
97
98  base::MessageLoop::current()->RunUntilIdle();
99
100  MockPasswordStoreConsumer consumer;
101
102  // We expect to get the same data back, even though it's not all ASCII.
103  EXPECT_CALL(consumer,
104      OnGetPasswordStoreResults(ContainsAllPasswordForms(expected_forms)))
105      .WillOnce(WithArg<0>(STLDeleteElements0()));
106  store->GetAutofillableLogins(&consumer);
107
108  base::MessageLoop::current()->RunUntilIdle();
109
110  STLDeleteElements(&expected_forms);
111  store->Shutdown();
112  base::MessageLoop::current()->RunUntilIdle();
113}
114
115TEST_F(PasswordStoreDefaultTest, Notifications) {
116  scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
117      base::MessageLoopProxy::current(),
118      base::MessageLoopProxy::current(),
119      login_db_.release()));
120  store->Init(syncer::SyncableService::StartSyncFlare());
121
122  PasswordFormData form_data =
123  { PasswordForm::SCHEME_HTML,
124    "http://bar.example.com",
125    "http://bar.example.com/origin",
126    "http://bar.example.com/action",
127    L"submit_element",
128    L"username_element",
129    L"password_element",
130    L"username_value",
131    L"password_value",
132    true, false, 1 };
133  scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
134
135  MockPasswordStoreObserver observer;
136  store->AddObserver(&observer);
137
138  const PasswordStoreChange expected_add_changes[] = {
139    PasswordStoreChange(PasswordStoreChange::ADD, *form),
140  };
141
142  EXPECT_CALL(
143      observer,
144      OnLoginsChanged(ElementsAreArray(expected_add_changes)));
145
146  // Adding a login should trigger a notification.
147  store->AddLogin(*form);
148  base::MessageLoop::current()->RunUntilIdle();
149
150  // Change the password.
151  form->password_value = base::ASCIIToUTF16("a different password");
152
153  const PasswordStoreChange expected_update_changes[] = {
154    PasswordStoreChange(PasswordStoreChange::UPDATE, *form),
155  };
156
157  EXPECT_CALL(
158      observer,
159      OnLoginsChanged(ElementsAreArray(expected_update_changes)));
160
161  // Updating the login with the new password should trigger a notification.
162  store->UpdateLogin(*form);
163  base::MessageLoop::current()->RunUntilIdle();
164
165  const PasswordStoreChange expected_delete_changes[] = {
166    PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
167  };
168
169  EXPECT_CALL(
170      observer,
171      OnLoginsChanged(ElementsAreArray(expected_delete_changes)));
172
173  // Deleting the login should trigger a notification.
174  store->RemoveLogin(*form);
175  base::MessageLoop::current()->RunUntilIdle();
176
177  store->RemoveObserver(&observer);
178  store->Shutdown();
179  base::MessageLoop::current()->RunUntilIdle();
180}
181