OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/ui/cocoa/passwords/account_chooser_view_controller.h" | 5 #import "chrome/browser/ui/cocoa/passwords/account_chooser_view_controller.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/mac/foundation_util.h" | 9 #include "base/mac/foundation_util.h" |
10 #include "base/memory/scoped_vector.h" | |
11 #include "base/strings/string16.h" | 10 #include "base/strings/string16.h" |
12 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
13 #import "chrome/browser/ui/cocoa/bubble_combobox.h" | 12 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h" |
14 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h" | |
15 #import "chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h" | 13 #import "chrome/browser/ui/cocoa/passwords/account_avatar_fetcher_manager.h" |
16 #import "chrome/browser/ui/cocoa/passwords/account_chooser_view_controller.h" | 14 #import "chrome/browser/ui/cocoa/passwords/account_chooser_view_controller.h" |
17 #include "chrome/browser/ui/cocoa/passwords/base_passwords_controller_test.h" | 15 #include "chrome/browser/ui/passwords/password_dialog_controller.h" |
18 #include "chrome/browser/ui/passwords/account_chooser_more_combobox_model.h" | 16 #include "testing/gmock/include/gmock/gmock.h" |
19 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
20 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h" | |
21 #include "components/password_manager/core/common/password_manager_ui.h" | |
22 #include "testing/gtest_mac.h" | 18 #include "testing/gtest_mac.h" |
23 #include "url/gurl.h" | 19 #include "url/gurl.h" |
24 | 20 |
25 @interface ManagePasswordsBubbleAccountChooserViewController(Testing) | |
26 - (id)initWithModel:(ManagePasswordsBubbleModel*)model | |
27 avatarManager:(AccountAvatarFetcherManager*)avatarManager | |
28 delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate; | |
29 @property(nonatomic, readonly) NSButton* cancelButton; | |
30 @property(nonatomic, readonly) BubbleCombobox* moreButton; | |
31 @property(nonatomic, readonly) NSTableView* credentialsView; | |
32 @end | |
33 | 21 |
34 @interface CredentialItemView(Testing) | 22 @interface CredentialItemView(Testing) |
35 @property(nonatomic, readonly) NSTextField* upperLabel; | 23 @property(nonatomic, readonly) NSTextField* upperLabel; |
36 @end | 24 @end |
37 | 25 |
38 @interface AccountAvatarFetcherTestManager : AccountAvatarFetcherManager { | 26 @interface AccountAvatarFetcherTestManager : AccountAvatarFetcherManager { |
39 std::vector<GURL> fetchedAvatars_; | 27 std::vector<GURL> fetchedAvatars_; |
40 } | 28 } |
41 @property(nonatomic, readonly) const std::vector<GURL>& fetchedAvatars; | 29 @property(nonatomic, readonly) const std::vector<GURL>& fetchedAvatars; |
42 @end | 30 @end |
43 | 31 |
44 @implementation AccountAvatarFetcherTestManager | 32 @implementation AccountAvatarFetcherTestManager |
45 | 33 |
46 - (void)fetchAvatar:(const GURL&)avatarURL forView:(CredentialItemView*)view { | 34 - (void)fetchAvatar:(const GURL&)avatarURL forView:(CredentialItemView*)view { |
47 fetchedAvatars_.push_back(avatarURL); | 35 fetchedAvatars_.push_back(avatarURL); |
48 } | 36 } |
49 | 37 |
50 - (const std::vector<GURL>&)fetchedAvatars { | 38 - (const std::vector<GURL>&)fetchedAvatars { |
51 return fetchedAvatars_; | 39 return fetchedAvatars_; |
52 } | 40 } |
53 | 41 |
54 @end | 42 @end |
55 | 43 |
56 namespace { | 44 namespace { |
57 | 45 |
| 46 const char kDialogTitle[] = "Choose an account"; |
| 47 |
58 // Returns a PasswordForm with only a username. | 48 // Returns a PasswordForm with only a username. |
59 scoped_ptr<autofill::PasswordForm> Credential(const char* username) { | 49 scoped_ptr<autofill::PasswordForm> Credential(const char* username) { |
60 scoped_ptr<autofill::PasswordForm> credential(new autofill::PasswordForm); | 50 scoped_ptr<autofill::PasswordForm> credential(new autofill::PasswordForm); |
61 credential->username_value = base::ASCIIToUTF16(username); | 51 credential->username_value = base::ASCIIToUTF16(username); |
62 return credential; | 52 return credential; |
63 } | 53 } |
64 | 54 |
65 // Tests for the account chooser view of the password management bubble. | 55 class PasswordDialogControllerMock : public PasswordDialogController { |
66 class ManagePasswordsBubbleAccountChooserViewControllerTest | |
67 : public ManagePasswordsControllerTest { | |
68 public: | 56 public: |
69 ManagePasswordsBubbleAccountChooserViewControllerTest() : controller_(nil) {} | 57 MOCK_CONST_METHOD0(GetLocalForms, const FormsVector&()); |
| 58 MOCK_CONST_METHOD0(GetFederationsForms, const FormsVector&()); |
| 59 MOCK_CONST_METHOD0(GetAccoutChooserTitle, |
| 60 std::pair<base::string16, gfx::Range>()); |
| 61 MOCK_METHOD0(OnSmartLockLinkClicked, void()); |
| 62 MOCK_METHOD2(OnChooseCredentials, void( |
| 63 const autofill::PasswordForm& password_form, |
| 64 password_manager::CredentialType credential_type)); |
| 65 MOCK_METHOD0(OnCloseAccountChooser, void()); |
| 66 }; |
70 | 67 |
71 void SetUp() override { | 68 // Tests for the account chooser dialog view. |
72 ManagePasswordsControllerTest::SetUp(); | 69 class AccountChooserViewControllerTest : public CocoaProfileTest, |
73 delegate_.reset([[ContentViewDelegateMock alloc] init]); | 70 public AccountChooserBridge { |
74 avatar_manager_.reset([[AccountAvatarFetcherTestManager alloc] init]); | 71 public: |
| 72 void SetUp() override; |
| 73 |
| 74 PasswordDialogControllerMock& dialog_controller() { |
| 75 return dialog_controller_; |
75 } | 76 } |
76 | 77 |
77 ContentViewDelegateMock* delegate() { return delegate_.get(); } | |
78 | |
79 AccountAvatarFetcherTestManager* avatar_manager() { | 78 AccountAvatarFetcherTestManager* avatar_manager() { |
80 return avatar_manager_.get(); | 79 return avatar_manager_.get(); |
81 } | 80 } |
82 | 81 |
83 ManagePasswordsBubbleAccountChooserViewController* controller() { | 82 AccountChooserViewController* view_controller() { |
84 if (!controller_) { | 83 return view_controller_.get(); |
85 controller_.reset( | |
86 [[ManagePasswordsBubbleAccountChooserViewController alloc] | |
87 initWithModel:GetModelAndCreateIfNull() | |
88 avatarManager:avatar_manager() | |
89 delegate:delegate()]); | |
90 [controller_ loadView]; | |
91 } | |
92 return controller_.get(); | |
93 } | 84 } |
94 | 85 |
| 86 void SetUpAccountChooser( |
| 87 PasswordDialogController::FormsVector local, |
| 88 PasswordDialogController::FormsVector federations); |
| 89 |
| 90 MOCK_METHOD0(OnPerformClose, void()); |
| 91 |
| 92 // AccountChooserBridge: |
| 93 void PerformClose() override; |
| 94 PasswordDialogController* GetDialogController() override; |
| 95 net::URLRequestContextGetter* GetRequestContext() const override; |
| 96 |
95 private: | 97 private: |
| 98 PasswordDialogControllerMock dialog_controller_; |
96 base::scoped_nsobject<AccountAvatarFetcherTestManager> avatar_manager_; | 99 base::scoped_nsobject<AccountAvatarFetcherTestManager> avatar_manager_; |
97 base::scoped_nsobject<ManagePasswordsBubbleAccountChooserViewController> | 100 base::scoped_nsobject<AccountChooserViewController> view_controller_; |
98 controller_; | |
99 base::scoped_nsobject<ContentViewDelegateMock> delegate_; | |
100 }; | 101 }; |
101 | 102 |
102 TEST_F(ManagePasswordsBubbleAccountChooserViewControllerTest, ConfiguresViews) { | 103 void AccountChooserViewControllerTest::SetUp() { |
103 ScopedVector<const autofill::PasswordForm> local_forms; | 104 CocoaProfileTest::SetUp(); |
| 105 avatar_manager_.reset([[AccountAvatarFetcherTestManager alloc] init]); |
| 106 } |
| 107 |
| 108 void AccountChooserViewControllerTest::SetUpAccountChooser( |
| 109 PasswordDialogController::FormsVector local, |
| 110 PasswordDialogController::FormsVector federations) { |
| 111 view_controller_.reset([[AccountChooserViewController alloc] |
| 112 initWithBridge:this |
| 113 avatarManager:avatar_manager()]); |
| 114 EXPECT_CALL(dialog_controller_, GetLocalForms()) |
| 115 .WillOnce(testing::ReturnRef(local)); |
| 116 EXPECT_CALL(dialog_controller_, GetFederationsForms()) |
| 117 .WillOnce(testing::ReturnRef(federations)); |
| 118 EXPECT_CALL(dialog_controller_, GetAccoutChooserTitle()) |
| 119 .WillOnce(testing::Return(std::make_pair(base::ASCIIToUTF16(kDialogTitle), |
| 120 gfx::Range(0, 5)))); |
| 121 [view_controller_ view]; |
| 122 ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&dialog_controller_)); |
| 123 } |
| 124 |
| 125 void AccountChooserViewControllerTest::PerformClose() { |
| 126 view_controller_.reset(); |
| 127 OnPerformClose(); |
| 128 } |
| 129 |
| 130 PasswordDialogController* |
| 131 AccountChooserViewControllerTest::GetDialogController() { |
| 132 return &dialog_controller_; |
| 133 } |
| 134 |
| 135 net::URLRequestContextGetter* |
| 136 AccountChooserViewControllerTest::GetRequestContext() const { |
| 137 NOTREACHED(); |
| 138 return nullptr; |
| 139 } |
| 140 |
| 141 TEST_F(AccountChooserViewControllerTest, ConfiguresViews) { |
| 142 PasswordDialogController::FormsVector local_forms; |
104 local_forms.push_back(Credential("pizza")); | 143 local_forms.push_back(Credential("pizza")); |
105 ScopedVector<const autofill::PasswordForm> federated_forms; | 144 PasswordDialogController::FormsVector federated_forms; |
106 federated_forms.push_back(Credential("taco")); | 145 federated_forms.push_back(Credential("taco")); |
107 SetUpAccountChooser(std::move(local_forms), std::move(federated_forms)); | 146 SetUpAccountChooser(std::move(local_forms), std::move(federated_forms)); |
108 // Trigger creation of controller and check the views. | 147 // Trigger creation of controller and check the views. |
109 NSTableView* view = controller().credentialsView; | 148 NSTableView* view = view_controller().credentialsView; |
110 ASSERT_NSNE(nil, view); | 149 ASSERT_NSNE(nil, view); |
111 ASSERT_EQ(2U, view.numberOfRows); | 150 ASSERT_EQ(2U, view.numberOfRows); |
112 EXPECT_NSEQ( | 151 EXPECT_NSEQ( |
113 @"pizza", | 152 @"pizza", |
114 base::mac::ObjCCastStrict<CredentialItemView>( | 153 base::mac::ObjCCastStrict<CredentialItemView>( |
115 base::mac::ObjCCastStrict<CredentialItemCell>( | 154 base::mac::ObjCCastStrict<CredentialItemCell>( |
116 [view.delegate tableView:view dataCellForTableColumn:nil row:0]) | 155 [view.delegate tableView:view dataCellForTableColumn:nil row:0]) |
117 .view).upperLabel.stringValue); | 156 .view).upperLabel.stringValue); |
118 EXPECT_NSEQ( | 157 EXPECT_NSEQ( |
119 @"taco", | 158 @"taco", |
120 base::mac::ObjCCastStrict<CredentialItemView>( | 159 base::mac::ObjCCastStrict<CredentialItemView>( |
121 base::mac::ObjCCastStrict<CredentialItemCell>( | 160 base::mac::ObjCCastStrict<CredentialItemCell>( |
122 [view.delegate tableView:view dataCellForTableColumn:nil row:1]) | 161 [view.delegate tableView:view dataCellForTableColumn:nil row:1]) |
123 .view).upperLabel.stringValue); | 162 .view).upperLabel.stringValue); |
124 EXPECT_TRUE(avatar_manager().fetchedAvatars.empty()); | 163 EXPECT_TRUE(avatar_manager().fetchedAvatars.empty()); |
125 } | 164 } |
126 | 165 |
127 TEST_F(ManagePasswordsBubbleAccountChooserViewControllerTest, | 166 TEST_F(AccountChooserViewControllerTest, ForwardsAvatarFetchToManager) { |
128 ForwardsAvatarFetchToManager) { | 167 PasswordDialogController::FormsVector local_forms; |
129 ScopedVector<const autofill::PasswordForm> local_forms; | |
130 scoped_ptr<autofill::PasswordForm> form = Credential("taco"); | 168 scoped_ptr<autofill::PasswordForm> form = Credential("taco"); |
131 form->icon_url = GURL("http://foo"); | 169 form->icon_url = GURL("http://foo.com"); |
132 local_forms.push_back(std::move(form)); | 170 local_forms.push_back(std::move(form)); |
133 SetUpAccountChooser(std::move(local_forms), | 171 SetUpAccountChooser(std::move(local_forms), |
134 ScopedVector<const autofill::PasswordForm>()); | 172 PasswordDialogController::FormsVector()); |
135 // Trigger creation of the controller and check the fetched URLs. | |
136 controller(); | |
137 EXPECT_FALSE(avatar_manager().fetchedAvatars.empty()); | 173 EXPECT_FALSE(avatar_manager().fetchedAvatars.empty()); |
138 EXPECT_TRUE(std::find(avatar_manager().fetchedAvatars.begin(), | 174 EXPECT_TRUE(std::find(avatar_manager().fetchedAvatars.begin(), |
139 avatar_manager().fetchedAvatars.end(), | 175 avatar_manager().fetchedAvatars.end(), |
140 GURL("http://foo")) != | 176 GURL("http://foo.com")) != |
141 avatar_manager().fetchedAvatars.end()); | 177 avatar_manager().fetchedAvatars.end()); |
142 } | 178 } |
143 | 179 |
144 TEST_F(ManagePasswordsBubbleAccountChooserViewControllerTest, | 180 TEST_F(AccountChooserViewControllerTest, |
145 SelectingCredentialInformsModelAndClosesDialog) { | 181 SelectingCredentialInformsModelAndClosesDialog) { |
146 ScopedVector<const autofill::PasswordForm> local_forms; | 182 PasswordDialogController::FormsVector local_forms; |
147 local_forms.push_back(Credential("pizza")); | 183 local_forms.push_back(Credential("pizza")); |
148 ScopedVector<const autofill::PasswordForm> federated_forms; | 184 PasswordDialogController::FormsVector federated_forms; |
149 federated_forms.push_back(Credential("taco")); | 185 federated_forms.push_back(Credential("taco")); |
150 SetUpAccountChooser(std::move(local_forms), std::move(federated_forms)); | 186 SetUpAccountChooser(std::move(local_forms), std::move(federated_forms)); |
151 EXPECT_CALL(*ui_controller(), | 187 EXPECT_CALL(dialog_controller(), |
152 ChooseCredential( | 188 OnChooseCredentials( |
153 *Credential("taco"), | 189 *Credential("taco"), |
154 password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED)); | 190 password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED)); |
155 [controller().credentialsView | 191 [view_controller().credentialsView |
156 selectRowIndexes:[NSIndexSet indexSetWithIndex:1] | 192 selectRowIndexes:[NSIndexSet indexSetWithIndex:1] |
157 byExtendingSelection:NO]; | 193 byExtendingSelection:NO]; |
158 EXPECT_TRUE(delegate().dismissed); | |
159 } | 194 } |
160 | 195 |
161 TEST_F(ManagePasswordsBubbleAccountChooserViewControllerTest, | 196 TEST_F(AccountChooserViewControllerTest, SelectingNopeDismissesDialog) { |
162 SelectingNopeDismissesDialog) { | 197 PasswordDialogController::FormsVector local_forms; |
163 ScopedVector<const autofill::PasswordForm> local_forms; | |
164 local_forms.push_back(Credential("pizza")); | 198 local_forms.push_back(Credential("pizza")); |
165 SetUpAccountChooser(std::move(local_forms), | 199 SetUpAccountChooser(std::move(local_forms), |
166 ScopedVector<const autofill::PasswordForm>()); | 200 PasswordDialogController::FormsVector()); |
167 [controller().cancelButton performClick:nil]; | 201 EXPECT_CALL(*this, OnPerformClose()); |
168 EXPECT_TRUE(delegate().dismissed); | 202 [view_controller().cancelButton performClick:nil]; |
169 } | 203 } |
170 | 204 |
171 TEST_F(ManagePasswordsBubbleAccountChooserViewControllerTest, | 205 TEST_F(AccountChooserViewControllerTest, ClickTitleLink) { |
172 SelectingSettingsShowsSettingsPage) { | 206 PasswordDialogController::FormsVector local_forms; |
173 SetUpAccountChooser(ScopedVector<const autofill::PasswordForm>(), | 207 local_forms.push_back(Credential("pizza")); |
174 ScopedVector<const autofill::PasswordForm>()); | 208 SetUpAccountChooser(std::move(local_forms), |
175 BubbleCombobox* moreButton = controller().moreButton; | 209 PasswordDialogController::FormsVector()); |
176 EXPECT_TRUE(moreButton); | 210 EXPECT_CALL(dialog_controller(), OnSmartLockLinkClicked()); |
177 EXPECT_CALL(*ui_controller(), NavigateToPasswordManagerSettingsPage()); | 211 [view_controller().titleView clickedOnLink:@"" |
178 [[moreButton menu] performActionForItemAtIndex: | 212 atIndex:0]; |
179 AccountChooserMoreComboboxModel::INDEX_SETTINGS]; | |
180 EXPECT_TRUE(delegate().dismissed); | |
181 } | |
182 | |
183 TEST_F(ManagePasswordsBubbleAccountChooserViewControllerTest, | |
184 SelectingLearnMoreShowsHelpCenterArticle) { | |
185 SetUpAccountChooser(ScopedVector<const autofill::PasswordForm>(), | |
186 ScopedVector<const autofill::PasswordForm>()); | |
187 BubbleCombobox* moreButton = controller().moreButton; | |
188 EXPECT_TRUE(moreButton); | |
189 [[moreButton menu] performActionForItemAtIndex: | |
190 AccountChooserMoreComboboxModel::INDEX_LEARN_MORE]; | |
191 EXPECT_TRUE(delegate().dismissed); | |
192 // TODO(dconnelly): Test this when the article is written. | |
193 } | 213 } |
194 | 214 |
195 } // namespace | 215 } // namespace |
OLD | NEW |