1// Copyright 2013 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/prefs/pref_service.h"
6#include "base/strings/utf_string_conversions.h"
7#include "chrome/browser/ui/autofill/account_chooser_model.h"
8#include "chrome/common/pref_names.h"
9#include "chrome/test/base/testing_profile.h"
10#include "components/autofill/core/browser/autofill_metrics.h"
11#include "testing/gmock/include/gmock/gmock.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14using base::ASCIIToUTF16;
15
16namespace autofill {
17
18namespace {
19
20class TestAccountChooserModel : public AccountChooserModel {
21 public:
22  TestAccountChooserModel(AccountChooserModelDelegate* delegate,
23                          Profile* profile,
24                          bool disable_wallet,
25                          const AutofillMetrics& metric_logger)
26      : AccountChooserModel(delegate, profile, disable_wallet, metric_logger) {}
27  virtual ~TestAccountChooserModel() {}
28
29  using AccountChooserModel::kWalletAccountsStartId;
30  using AccountChooserModel::kWalletAddAccountId;
31  using AccountChooserModel::kAutofillItemId;
32
33 private:
34  DISALLOW_COPY_AND_ASSIGN(TestAccountChooserModel);
35};
36
37class MockAccountChooserModelDelegate : public AccountChooserModelDelegate {
38 public:
39  MockAccountChooserModelDelegate() {}
40  virtual ~MockAccountChooserModelDelegate() {}
41
42  MOCK_METHOD0(AccountChoiceChanged, void());
43  MOCK_METHOD0(AddAccount, void());
44  MOCK_METHOD0(UpdateAccountChooserView, void());
45};
46
47class AccountChooserModelTest : public testing::Test {
48 public:
49  AccountChooserModelTest()
50      : model_(&delegate_, &profile_, false, metric_logger_) {}
51  virtual ~AccountChooserModelTest() {}
52
53  TestingProfile* profile() { return &profile_; }
54  MockAccountChooserModelDelegate* delegate() { return &delegate_; }
55  TestAccountChooserModel* model() { return &model_; }
56  const AutofillMetrics& metric_logger() { return metric_logger_; }
57
58 private:
59  TestingProfile profile_;
60  testing::NiceMock<MockAccountChooserModelDelegate> delegate_;
61  TestAccountChooserModel model_;
62  AutofillMetrics metric_logger_;
63};
64
65}  // namespace
66
67TEST_F(AccountChooserModelTest, ObeysPref) {
68  // When "Pay without wallet" is false, use Wallet by default.
69  {
70    profile()->GetPrefs()->SetBoolean(
71        ::prefs::kAutofillDialogPayWithoutWallet, false);
72    TestAccountChooserModel model(delegate(),
73                                  profile(),
74                                  false,
75                                  metric_logger());
76    EXPECT_TRUE(model.WalletIsSelected());
77  }
78  // When the user chose to "Pay without wallet", use Autofill.
79  {
80    profile()->GetPrefs()->SetBoolean(
81        ::prefs::kAutofillDialogPayWithoutWallet, true);
82    TestAccountChooserModel model(delegate(),
83                                  profile(),
84                                  false,
85                                  metric_logger());
86    EXPECT_FALSE(model.WalletIsSelected());
87  }
88  // When the |disable_wallet| argument is true, use Autofill regardless
89  // of the pref.
90  {
91    profile()->GetPrefs()->SetBoolean(
92        ::prefs::kAutofillDialogPayWithoutWallet, false);
93    TestAccountChooserModel model(delegate(), profile(), true, metric_logger());
94    EXPECT_FALSE(model.WalletIsSelected());
95  }
96  // In incognito, use local data regardless of the pref.
97  {
98    TestingProfile::Builder builder;
99    builder.SetIncognito();
100    scoped_ptr<TestingProfile> incognito = builder.Build();
101    incognito->SetOriginalProfile(profile());
102    profile()->GetPrefs()->SetBoolean(
103        ::prefs::kAutofillDialogPayWithoutWallet, false);
104    incognito->GetPrefs()->SetBoolean(
105        ::prefs::kAutofillDialogPayWithoutWallet, false);
106
107    TestAccountChooserModel model(delegate(),
108                                  incognito.get(),
109                                  false,
110                                  metric_logger());
111    EXPECT_FALSE(model.WalletIsSelected());
112  }
113}
114
115TEST_F(AccountChooserModelTest, IgnoresPrefChanges) {
116  ASSERT_FALSE(profile()->GetPrefs()->GetBoolean(
117      ::prefs::kAutofillDialogPayWithoutWallet));
118  EXPECT_TRUE(model()->WalletIsSelected());
119
120  // Check that nothing changes while this dialog is running if a pref changes
121  // (this could cause subtle bugs or annoyances if a user closes another
122  // running dialog).
123  profile()->GetPrefs()->SetBoolean(
124      ::prefs::kAutofillDialogPayWithoutWallet, true);
125  EXPECT_TRUE(model()->WalletIsSelected());
126}
127
128TEST_F(AccountChooserModelTest, HandlesError) {
129  EXPECT_CALL(*delegate(), AccountChoiceChanged()).Times(1);
130  EXPECT_CALL(*delegate(), UpdateAccountChooserView()).Times(1);
131
132  ASSERT_TRUE(model()->WalletIsSelected());
133  ASSERT_TRUE(model()->IsCommandIdEnabled(
134      TestAccountChooserModel::kWalletAccountsStartId));
135
136  model()->SetHadWalletError();
137  EXPECT_FALSE(model()->WalletIsSelected());
138  EXPECT_FALSE(model()->IsCommandIdEnabled(
139      TestAccountChooserModel::kWalletAccountsStartId));
140}
141
142TEST_F(AccountChooserModelTest, HandlesSigninError) {
143  EXPECT_CALL(*delegate(), AccountChoiceChanged()).Times(1);
144  EXPECT_CALL(*delegate(), UpdateAccountChooserView()).Times(2);
145
146  // 0. "Unknown" wallet account, we don't know if the user is signed-in yet.
147  ASSERT_TRUE(model()->WalletIsSelected());
148  ASSERT_TRUE(model()->IsCommandIdEnabled(
149      TestAccountChooserModel::kWalletAccountsStartId));
150  ASSERT_TRUE(model()->WalletIsSelected());
151  ASSERT_FALSE(model()->HasAccountsToChoose());
152  ASSERT_EQ(3, model()->GetItemCount());
153  EXPECT_EQ(base::string16(), model()->GetActiveWalletAccountName());
154
155  // 1. "Known" wallet account (e.g. after active/passive/automatic sign-in).
156  // Calls UpdateAccountChooserView.
157  std::vector<std::string> accounts;
158  accounts.push_back("john.doe@gmail.com");
159  model()->SetWalletAccounts(accounts, 0U);
160  ASSERT_TRUE(model()->WalletIsSelected());
161  ASSERT_TRUE(model()->IsCommandIdEnabled(
162      TestAccountChooserModel::kWalletAccountsStartId));
163  ASSERT_TRUE(model()->WalletIsSelected());
164  ASSERT_TRUE(model()->HasAccountsToChoose());
165  EXPECT_EQ(3, model()->GetItemCount());
166  EXPECT_EQ(ASCIIToUTF16(accounts[0]), model()->GetActiveWalletAccountName());
167
168  // 2. Sign-in failure.
169  // Autofill data should be selected and be the only valid choice.
170  // Calls UpdateAccountChooserView.
171  // Calls AccountChoiceChanged.
172  model()->SetHadWalletSigninError();
173  EXPECT_FALSE(model()->WalletIsSelected());
174  EXPECT_TRUE(model()->IsCommandIdEnabled(
175      TestAccountChooserModel::kWalletAccountsStartId));
176  EXPECT_FALSE(model()->WalletIsSelected());
177  EXPECT_FALSE(model()->HasAccountsToChoose());
178  EXPECT_EQ(2, model()->GetItemCount());
179  EXPECT_EQ(base::string16(), model()->GetActiveWalletAccountName());
180}
181
182TEST_F(AccountChooserModelTest, RespectsUserChoice) {
183  EXPECT_CALL(*delegate(), AccountChoiceChanged()).Times(2);
184
185  model()->ExecuteCommand(TestAccountChooserModel::kAutofillItemId, 0);
186  EXPECT_FALSE(model()->WalletIsSelected());
187
188  EXPECT_CALL(*delegate(), AddAccount());
189  model()->ExecuteCommand(TestAccountChooserModel::kWalletAddAccountId, 0);
190  EXPECT_FALSE(model()->WalletIsSelected());
191
192  model()->ExecuteCommand(TestAccountChooserModel::kWalletAccountsStartId, 0);
193  EXPECT_TRUE(model()->WalletIsSelected());
194}
195
196TEST_F(AccountChooserModelTest, HandlesMultipleAccounts) {
197  EXPECT_FALSE(model()->HasAccountsToChoose());
198
199  std::vector<std::string> accounts;
200  accounts.push_back("john.doe@gmail.com");
201  accounts.push_back("jane.smith@gmail.com");
202  model()->SetWalletAccounts(accounts, 0U);
203  EXPECT_TRUE(model()->HasAccountsToChoose());
204  EXPECT_TRUE(model()->WalletIsSelected());
205  ASSERT_EQ(4, model()->GetItemCount());
206  EXPECT_TRUE(model()->IsCommandIdEnabled(
207      TestAccountChooserModel::kWalletAccountsStartId));
208  EXPECT_TRUE(model()->IsCommandIdEnabled(
209      TestAccountChooserModel::kWalletAccountsStartId + 1));
210  EXPECT_EQ(ASCIIToUTF16(accounts[0]), model()->GetActiveWalletAccountName());
211  model()->SetWalletAccounts(accounts, 1U);
212  EXPECT_EQ(ASCIIToUTF16(accounts[1]), model()->GetActiveWalletAccountName());
213
214  model()->ExecuteCommand(TestAccountChooserModel::kWalletAccountsStartId, 0);
215  EXPECT_EQ(ASCIIToUTF16(accounts[0]), model()->GetActiveWalletAccountName());
216  model()->ExecuteCommand(TestAccountChooserModel::kWalletAccountsStartId + 1,
217                          0);
218  EXPECT_EQ(ASCIIToUTF16(accounts[1]), model()->GetActiveWalletAccountName());
219
220  // Setting the wallet accounts forces the switch to wallet.
221  model()->ExecuteCommand(TestAccountChooserModel::kAutofillItemId, 0);
222  EXPECT_FALSE(model()->WalletIsSelected());
223  model()->SetWalletAccounts(accounts, 1U);
224  EXPECT_TRUE(model()->WalletIsSelected());
225}
226
227}  // namespace autofill
228