// Copyright 2023 The Chromium Authors
// 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/password_sharing/sharing_status_mediator.h"
#import "base/strings/sys_string_conversions.h"
#import "components/password_manager/core/browser/sharing/recipients_fetcher.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_favicon_loader_factory.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
#import "ios/chrome/browser/signin/model/authentication_service.h"
#import "ios/chrome/browser/signin/model/authentication_service_factory.h"
#import "ios/chrome/browser/signin/model/chrome_account_manager_service.h"
#import "ios/chrome/browser/signin/model/chrome_account_manager_service_factory.h"
#import "ios/chrome/browser/signin/model/fake_authentication_service_delegate.h"
#import "ios/chrome/browser/signin/model/fake_system_identity.h"
#import "ios/chrome/browser/signin/model/fake_system_identity_manager.h"
#import "ios/chrome/browser/ui/authentication/authentication_constants.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/recipient_info.h"
#import "ios/chrome/browser/ui/settings/password/password_sharing/sharing_status_consumer.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#import "ui/base/l10n/l10n_util.h"
#import "url/gurl.h"
namespace {
constexpr NSString* kWebsite = @"example.com";
const CGFloat kProfileImageSize = 60.0;
const GURL kGURL = GURL("www.example.com");
NSArray<RecipientInfoForIOSDisplay*>* CreateRecipients(int amount) {
NSMutableArray<RecipientInfoForIOSDisplay*>* recipients =
[NSMutableArray array];
for (int i = 0; i < amount; i++) {
password_manager::RecipientInfo recipient;
recipient.user_name = "test" + base::NumberToString(i) + "@gmail.com";
[recipients addObject:([[RecipientInfoForIOSDisplay alloc]
initWithRecipientInfo:recipient])];
}
return recipients;
}
} // namespace
// Test class that conforms to SharingStatusConsumer in order to test the
// consumer methods are called correctly.
@interface FakeSharingStatusConsumer : NSObject <SharingStatusConsumer>
@property(nonatomic, strong) UIImage* senderImage;
@property(nonatomic, strong) UIImage* recipientImage;
@property(nonatomic, strong) NSString* subtitleString;
@property(nonatomic, strong) NSString* footerString;
@property(nonatomic, readonly) GURL URL;
@end
@implementation FakeSharingStatusConsumer
- (void)setSenderImage:(UIImage*)senderImage {
_senderImage = senderImage;
}
- (void)setRecipientImage:(UIImage*)recipientImage {
_recipientImage = recipientImage;
}
- (void)setSubtitleString:(NSString*)subtitleString {
_subtitleString = subtitleString;
}
- (void)setFooterString:(NSString*)footerString {
_footerString = footerString;
}
- (void)setURL:(const GURL&)URL {
_URL = URL;
}
@end
class SharingStatusMediatorTest : public PlatformTest {
protected:
SharingStatusMediatorTest() {
fake_identity_ = [FakeSystemIdentity fakeIdentity1];
FakeSystemIdentityManager* system_identity_manager =
FakeSystemIdentityManager::FromSystemIdentityManager(
GetApplicationContext()->GetSystemIdentityManager());
system_identity_manager->AddIdentity(fake_identity_);
TestChromeBrowserState::Builder builder;
builder.AddTestingFactory(
AuthenticationServiceFactory::GetInstance(),
AuthenticationServiceFactory::GetDefaultFactory());
browser_state_ = std::move(builder).Build();
AuthenticationServiceFactory::CreateAndInitializeForBrowserState(
browser_state_.get(),
std::make_unique<FakeAuthenticationServiceDelegate>());
}
id<SystemIdentity> fake_identity() { return fake_identity_; }
AuthenticationService* GetAuthenticationService() {
return AuthenticationServiceFactory::GetForBrowserState(
browser_state_.get());
}
ChromeAccountManagerService* GetAccountManagerService() {
return ChromeAccountManagerServiceFactory::GetForBrowserState(
browser_state_.get());
}
FaviconLoader* GetFaviconLoader() {
return IOSChromeFaviconLoaderFactory::GetForBrowserState(
browser_state_.get());
}
private:
web::WebTaskEnvironment task_environment_;
IOSChromeScopedTestingLocalState scoped_testing_local_state_;
std::unique_ptr<TestChromeBrowserState> browser_state_;
id<SystemIdentity> fake_identity_;
};
TEST_F(SharingStatusMediatorTest, NotifiesSignedInConsumerAboutTheirAvatar) {
GetAuthenticationService()->SignIn(
fake_identity(), signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN);
auto* consumer = [[FakeSharingStatusConsumer alloc] init];
auto* mediator = [[SharingStatusMediator alloc]
initWithAuthService:GetAuthenticationService()
accountManagerService:GetAccountManagerService()
faviconLoader:GetFaviconLoader()
recipients:CreateRecipients(1)
website:kWebsite
URL:kGURL
changePasswordURL:std::nullopt];
mediator.consumer = consumer;
EXPECT_NSEQ(UIImagePNGRepresentation(CircularImageFromImage(
GetAccountManagerService()->GetIdentityAvatarWithIdentity(
fake_identity(), IdentityAvatarSize::Large),
kProfileImageSize)),
UIImagePNGRepresentation(consumer.senderImage));
}
TEST_F(SharingStatusMediatorTest, NotifiesSignedOutConsumerWithDefaultAvatar) {
auto* consumer = [[FakeSharingStatusConsumer alloc] init];
auto* mediator = [[SharingStatusMediator alloc]
initWithAuthService:GetAuthenticationService()
accountManagerService:GetAccountManagerService()
faviconLoader:GetFaviconLoader()
recipients:CreateRecipients(1)
website:kWebsite
URL:kGURL
changePasswordURL:std::nullopt];
mediator.consumer = consumer;
EXPECT_NSEQ(UIImagePNGRepresentation(DefaultSymbolTemplateWithPointSize(
kPersonCropCircleSymbol, kProfileImageSize)),
UIImagePNGRepresentation(consumer.senderImage));
}
TEST_F(SharingStatusMediatorTest, NotifiesConsumerWithRecipientImage) {
auto* consumer = [[FakeSharingStatusConsumer alloc] init];
auto* mediator = [[SharingStatusMediator alloc]
initWithAuthService:GetAuthenticationService()
accountManagerService:GetAccountManagerService()
faviconLoader:GetFaviconLoader()
recipients:CreateRecipients(1)
website:kWebsite
URL:kGURL
changePasswordURL:std::nullopt];
mediator.consumer = consumer;
EXPECT_NSEQ(UIImagePNGRepresentation(CircularImageFromImage(
DefaultSymbolTemplateWithPointSize(
kPersonCropCircleSymbol, kAccountProfilePhotoDimension),
60.0)),
UIImagePNGRepresentation(consumer.recipientImage));
}
TEST_F(SharingStatusMediatorTest,
NotifiesConsumerAboutSingleRecipientSubtitle) {
auto* consumer = [[FakeSharingStatusConsumer alloc] init];
auto* mediator = [[SharingStatusMediator alloc]
initWithAuthService:GetAuthenticationService()
accountManagerService:GetAccountManagerService()
faviconLoader:GetFaviconLoader()
recipients:CreateRecipients(1)
website:kWebsite
URL:kGURL
changePasswordURL:std::nullopt];
mediator.consumer = consumer;
EXPECT_NSEQ(base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE, u"[email protected]",
u"example.com")),
consumer.subtitleString);
}
TEST_F(SharingStatusMediatorTest,
NotifiesConsumerAboutMultipleRecipientsSubtitle) {
auto* consumer = [[FakeSharingStatusConsumer alloc] init];
auto* mediator = [[SharingStatusMediator alloc]
initWithAuthService:GetAuthenticationService()
accountManagerService:GetAccountManagerService()
faviconLoader:GetFaviconLoader()
recipients:CreateRecipients(2)
website:kWebsite
URL:kGURL
changePasswordURL:std::nullopt];
mediator.consumer = consumer;
EXPECT_NSEQ(base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
IDS_IOS_PASSWORD_SHARING_SUCCESS_SUBTITLE_MULTIPLE_RECIPIENTS,
u"example.com")),
consumer.subtitleString);
}
TEST_F(SharingStatusMediatorTest, NotifiesConsumerAboutFooterForWebsite) {
auto* consumer = [[FakeSharingStatusConsumer alloc] init];
auto* mediator = [[SharingStatusMediator alloc]
initWithAuthService:GetAuthenticationService()
accountManagerService:GetAccountManagerService()
faviconLoader:GetFaviconLoader()
recipients:CreateRecipients(2)
website:kWebsite
URL:kGURL
changePasswordURL:kGURL];
mediator.consumer = consumer;
EXPECT_NSEQ(base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
IDS_IOS_PASSWORD_SHARING_SUCCESS_FOOTNOTE, u"example.com")),
consumer.footerString);
}
TEST_F(SharingStatusMediatorTest, NotifiesConsumerAboutFooterForAndroidApp) {
auto* consumer = [[FakeSharingStatusConsumer alloc] init];
auto* mediator = [[SharingStatusMediator alloc]
initWithAuthService:GetAuthenticationService()
accountManagerService:GetAccountManagerService()
faviconLoader:GetFaviconLoader()
recipients:CreateRecipients(2)
website:kWebsite
URL:kGURL
changePasswordURL:std::nullopt];
mediator.consumer = consumer;
EXPECT_NSEQ(base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
IDS_IOS_PASSWORD_SHARING_SUCCESS_FOOTNOTE_ANDROID_APP,
u"example.com")),
consumer.footerString);
}
TEST_F(SharingStatusMediatorTest, NotifiesConsumerAboutGURL) {
auto* consumer = [[FakeSharingStatusConsumer alloc] init];
auto* mediator = [[SharingStatusMediator alloc]
initWithAuthService:GetAuthenticationService()
accountManagerService:GetAccountManagerService()
faviconLoader:GetFaviconLoader()
recipients:CreateRecipients(2)
website:kWebsite
URL:kGURL
changePasswordURL:std::nullopt];
mediator.consumer = consumer;
EXPECT_EQ(kGURL, consumer.URL);
}