| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/browser/ui/settings/password_details_collection_view_controller.h" |
| |
| #include "base/mac/foundation_util.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "components/autofill/core/common/password_form.h" |
| #import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h" |
| #import "ios/chrome/browser/ui/settings/cells/password_details_item.h" |
| #import "ios/chrome/browser/ui/settings/reauthentication_module.h" |
| #import "ios/chrome/browser/web/chrome_web_test.h" |
| #include "ios/chrome/grit/ios_strings.h" |
| #include "ios/web/public/test/test_web_thread_bundle.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #import "testing/gtest_mac.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "url/gurl.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| @interface MockReauthenticationModule : NSObject<ReauthenticationProtocol> |
| |
| @property(nonatomic, copy) NSString* localizedReasonForAuthentication; |
| |
| @end |
| |
| @implementation MockReauthenticationModule |
| |
| @synthesize localizedReasonForAuthentication = |
| _localizedReasonForAuthentication; |
| |
| - (BOOL)canAttemptReauth { |
| return YES; |
| } |
| |
| - (void)attemptReauthWithLocalizedReason:(NSString*)localizedReason |
| handler:(void (^)(BOOL success)) |
| showCopyPasswordsHandler { |
| self.localizedReasonForAuthentication = localizedReason; |
| showCopyPasswordsHandler(YES); |
| } |
| |
| @end |
| |
| @interface MockSavePasswordsCollectionViewController |
| : NSObject<PasswordDetailsCollectionViewControllerDelegate> |
| |
| - (void)deletePassword:(const autofill::PasswordForm&)passwordForm; |
| |
| @end |
| |
| @implementation MockSavePasswordsCollectionViewController |
| |
| - (void)deletePassword:(const autofill::PasswordForm&)passwordForm { |
| } |
| |
| @end |
| |
| namespace { |
| |
| NSString* const kSite = @"https://testorigin.com/"; |
| NSString* const kUsername = @"testusername"; |
| NSString* const kPassword = @"testpassword"; |
| |
| // Indices related to the layout for a non-blacklisted, non-federated password. |
| const int kSiteSection = 0; |
| const int kSiteItem = 0; |
| const int kCopySiteButtonItem = 1; |
| |
| const int kUsernameSection = 1; |
| const int kUsernameItem = 0; |
| const int kCopyUsernameButtonItem = 1; |
| |
| const int kPasswordSection = 2; |
| const int kPasswordItem = 0; |
| const int kCopyPasswordButtonItem = 1; |
| const int kShowHideButtonItem = 2; |
| |
| const int kDeleteSection = 3; |
| const int kDeleteButtonItem = 0; |
| |
| class PasswordDetailsCollectionViewControllerTest |
| : public CollectionViewControllerTest { |
| protected: |
| PasswordDetailsCollectionViewControllerTest() |
| : thread_bundle_(web::TestWebThreadBundle::REAL_DB_THREAD) { |
| origin_ = kSite; |
| form_.username_value = base::SysNSStringToUTF16(kUsername); |
| form_.password_value = base::SysNSStringToUTF16(kPassword); |
| form_.signon_realm = base::SysNSStringToUTF8(origin_); |
| form_.origin = GURL(form_.signon_realm); |
| } |
| |
| void SetUp() override { |
| CollectionViewControllerTest::SetUp(); |
| delegate_ = [[MockSavePasswordsCollectionViewController alloc] init]; |
| reauthenticationModule_ = [[MockReauthenticationModule alloc] init]; |
| } |
| |
| CollectionViewController* InstantiateController() override { |
| return [[PasswordDetailsCollectionViewController alloc] |
| initWithPasswordForm:form_ |
| delegate:delegate_ |
| reauthenticationModule:reauthenticationModule_]; |
| } |
| |
| web::TestWebThreadBundle thread_bundle_; |
| MockSavePasswordsCollectionViewController* delegate_; |
| MockReauthenticationModule* reauthenticationModule_; |
| NSString* origin_; |
| autofill::PasswordForm form_; |
| }; |
| |
| TEST_F(PasswordDetailsCollectionViewControllerTest, |
| TestInitialization_NormalPassword) { |
| CreateController(); |
| CheckController(); |
| EXPECT_EQ(4, NumberOfSections()); |
| // Site section |
| EXPECT_EQ(2, NumberOfItemsInSection(kSiteSection)); |
| CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_SITE, kSiteSection); |
| PasswordDetailsItem* siteItem = |
| GetCollectionViewItem(kSiteSection, kSiteItem); |
| EXPECT_NSEQ(origin_, siteItem.text); |
| EXPECT_TRUE(siteItem.showingText); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_SITE_COPY_BUTTON, kSiteSection, |
| kCopySiteButtonItem); |
| // Username section |
| EXPECT_EQ(2, NumberOfItemsInSection(kUsernameSection)); |
| CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME, |
| kUsernameSection); |
| PasswordDetailsItem* usernameItem = |
| GetCollectionViewItem(kUsernameSection, kUsernameItem); |
| EXPECT_NSEQ(kUsername, usernameItem.text); |
| EXPECT_TRUE(usernameItem.showingText); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_USERNAME_COPY_BUTTON, |
| kUsernameSection, kCopyUsernameButtonItem); |
| // Password section |
| EXPECT_EQ(3, NumberOfItemsInSection(kPasswordSection)); |
| CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD, |
| kPasswordSection); |
| PasswordDetailsItem* passwordItem = |
| GetCollectionViewItem(kPasswordSection, kPasswordItem); |
| EXPECT_NSEQ(kPassword, passwordItem.text); |
| EXPECT_FALSE(passwordItem.showingText); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_PASSWORD_COPY_BUTTON, |
| kPasswordSection, kCopyPasswordButtonItem); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_PASSWORD_SHOW_BUTTON, |
| kPasswordSection, kShowHideButtonItem); |
| // Delete section |
| EXPECT_EQ(1, NumberOfItemsInSection(kDeleteSection)); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON, |
| kDeleteSection, kDeleteButtonItem); |
| } |
| |
| TEST_F(PasswordDetailsCollectionViewControllerTest, |
| TestInitialization_Blacklisted) { |
| constexpr int kBlacklistedSiteSection = 0; |
| constexpr int kBlacklistedSiteItem = 0; |
| constexpr int kBlacklistedCopySiteButtonItem = 1; |
| |
| constexpr int kBlacklistedDeleteSection = 1; |
| constexpr int kBlacklistedDeleteButtonItem = 0; |
| |
| form_.username_value.clear(); |
| form_.password_value.clear(); |
| form_.blacklisted_by_user = true; |
| CreateController(); |
| CheckController(); |
| EXPECT_EQ(2, NumberOfSections()); |
| // Site section |
| EXPECT_EQ(2, NumberOfItemsInSection(kBlacklistedSiteSection)); |
| CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_SITE, |
| kBlacklistedSiteSection); |
| PasswordDetailsItem* siteItem = |
| GetCollectionViewItem(kBlacklistedSiteSection, kBlacklistedSiteItem); |
| EXPECT_NSEQ(origin_, siteItem.text); |
| EXPECT_TRUE(siteItem.showingText); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_SITE_COPY_BUTTON, |
| kBlacklistedSiteSection, |
| kBlacklistedCopySiteButtonItem); |
| // Delete section |
| EXPECT_EQ(1, NumberOfItemsInSection(kBlacklistedDeleteSection)); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON, |
| kBlacklistedDeleteSection, |
| kBlacklistedDeleteButtonItem); |
| } |
| |
| TEST_F(PasswordDetailsCollectionViewControllerTest, |
| TestInitialization_Federated) { |
| constexpr int kFederatedSiteSection = 0; |
| constexpr int kFederatedSiteItem = 0; |
| constexpr int kFederatedCopySiteButtonItem = 1; |
| |
| constexpr int kFederatedUsernameSection = 1; |
| constexpr int kFederatedUsernameItem = 0; |
| constexpr int kFederatedCopyUsernameButtonItem = 1; |
| |
| constexpr int kFederatedFederationSection = 2; |
| constexpr int kFederatedFederationItem = 0; |
| |
| constexpr int kFederatedDeleteSection = 3; |
| constexpr int kFederatedDeleteButtonItem = 0; |
| |
| form_.password_value.clear(); |
| form_.federation_origin = url::Origin(GURL("https://famous.provider.net")); |
| CreateController(); |
| CheckController(); |
| EXPECT_EQ(4, NumberOfSections()); |
| // Site section |
| EXPECT_EQ(2, NumberOfItemsInSection(kFederatedSiteSection)); |
| CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_SITE, |
| kFederatedSiteSection); |
| PasswordDetailsItem* siteItem = |
| GetCollectionViewItem(kFederatedSiteSection, kFederatedSiteItem); |
| EXPECT_NSEQ(origin_, siteItem.text); |
| EXPECT_TRUE(siteItem.showingText); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_SITE_COPY_BUTTON, |
| kFederatedSiteSection, kFederatedCopySiteButtonItem); |
| // Username section |
| EXPECT_EQ(2, NumberOfItemsInSection(kFederatedUsernameSection)); |
| CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME, |
| kFederatedUsernameSection); |
| PasswordDetailsItem* usernameItem = |
| GetCollectionViewItem(kFederatedUsernameSection, kFederatedUsernameItem); |
| EXPECT_NSEQ(kUsername, usernameItem.text); |
| EXPECT_TRUE(usernameItem.showingText); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_USERNAME_COPY_BUTTON, |
| kFederatedUsernameSection, |
| kFederatedCopyUsernameButtonItem); |
| // Federated section |
| EXPECT_EQ(1, NumberOfItemsInSection(kFederatedFederationSection)); |
| CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_FEDERATION, |
| kFederatedFederationSection); |
| PasswordDetailsItem* federationItem = GetCollectionViewItem( |
| kFederatedFederationSection, kFederatedFederationItem); |
| EXPECT_NSEQ(@"famous.provider.net", federationItem.text); |
| EXPECT_TRUE(federationItem.showingText); |
| // Delete section |
| EXPECT_EQ(1, NumberOfItemsInSection(kFederatedDeleteSection)); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON, |
| kFederatedDeleteSection, kFederatedDeleteButtonItem); |
| } |
| |
| struct SimplifyOriginTestData { |
| GURL origin; |
| NSString* expectedSimplifiedOrigin; |
| }; |
| |
| TEST_F(PasswordDetailsCollectionViewControllerTest, SimplifyOrigin) { |
| SimplifyOriginTestData test_data[] = { |
| {GURL("http://test.com/index.php"), @"test.com"}, |
| {GURL("https://example.com/index.php"), @"example.com"}, |
| {GURL("android://" |
| "Qllt1FacrB0NYCeSFvmudHvssWBPFfC54EbtHTpFxukvw2wClI1rafcVB3kQOMxfJg" |
| "xbVAkGXvC_A52kbPL1EQ==@com.parkingpanda.mobile/"), |
| @"mobile.parkingpanda.com"}}; |
| |
| for (const auto& data : test_data) { |
| origin_ = base::SysUTF8ToNSString(data.origin.spec()); |
| form_.signon_realm = base::SysNSStringToUTF8(origin_); |
| form_.origin = GURL(form_.signon_realm); |
| CreateController(); |
| EXPECT_NSEQ(data.expectedSimplifiedOrigin, controller().title) |
| << " for origin " << data.origin; |
| ResetController(); |
| } |
| } |
| |
| TEST_F(PasswordDetailsCollectionViewControllerTest, CopySite) { |
| CreateController(); |
| [controller() collectionView:[controller() collectionView] |
| didSelectItemAtIndexPath:[NSIndexPath indexPathForRow:kCopySiteButtonItem |
| inSection:kSiteSection]]; |
| UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard]; |
| EXPECT_NSEQ(origin_, generalPasteboard.string); |
| } |
| |
| TEST_F(PasswordDetailsCollectionViewControllerTest, CopyUsername) { |
| CreateController(); |
| [controller() collectionView:[controller() collectionView] |
| didSelectItemAtIndexPath:[NSIndexPath |
| indexPathForRow:kCopyUsernameButtonItem |
| inSection:kUsernameSection]]; |
| UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard]; |
| EXPECT_NSEQ(kUsername, generalPasteboard.string); |
| } |
| |
| TEST_F(PasswordDetailsCollectionViewControllerTest, ShowPassword) { |
| CreateController(); |
| [controller() collectionView:[controller() collectionView] |
| didSelectItemAtIndexPath:[NSIndexPath indexPathForRow:kShowHideButtonItem |
| inSection:kPasswordSection]]; |
| PasswordDetailsItem* passwordItem = |
| GetCollectionViewItem(kPasswordSection, kPasswordItem); |
| EXPECT_NSEQ(kPassword, passwordItem.text); |
| EXPECT_TRUE(passwordItem.showingText); |
| EXPECT_NSEQ( |
| l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_SHOW), |
| reauthenticationModule_.localizedReasonForAuthentication); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_PASSWORD_HIDE_BUTTON, |
| kPasswordSection, kShowHideButtonItem); |
| } |
| |
| TEST_F(PasswordDetailsCollectionViewControllerTest, HidePassword) { |
| CreateController(); |
| // First show the password. |
| [controller() collectionView:[controller() collectionView] |
| didSelectItemAtIndexPath:[NSIndexPath indexPathForRow:kShowHideButtonItem |
| inSection:kPasswordSection]]; |
| // Then hide it. |
| [controller() collectionView:[controller() collectionView] |
| didSelectItemAtIndexPath:[NSIndexPath indexPathForRow:kShowHideButtonItem |
| inSection:kPasswordSection]]; |
| PasswordDetailsItem* passwordItem = |
| GetCollectionViewItem(kPasswordSection, kPasswordItem); |
| EXPECT_NSEQ(kPassword, passwordItem.text); |
| EXPECT_FALSE(passwordItem.showingText); |
| CheckTextCellTitleWithId(IDS_IOS_SETTINGS_PASSWORD_SHOW_BUTTON, |
| kPasswordSection, kShowHideButtonItem); |
| } |
| |
| TEST_F(PasswordDetailsCollectionViewControllerTest, CopyPassword) { |
| CreateController(); |
| [controller() collectionView:[controller() collectionView] |
| didSelectItemAtIndexPath:[NSIndexPath |
| indexPathForRow:kCopyPasswordButtonItem |
| inSection:kPasswordSection]]; |
| UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard]; |
| EXPECT_NSEQ(kPassword, generalPasteboard.string); |
| EXPECT_NSEQ( |
| l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_COPY), |
| reauthenticationModule_.localizedReasonForAuthentication); |
| } |
| |
| } // namespace |