| 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 |