blob: 31ecca201e57d8f12bd258fda3d78e91232bf4e3 [file] [log] [blame]
// 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/settings/ui_bundled/downloads/save_to_photos/save_to_photos_settings_mediator.h"
#import "base/strings/sys_string_conversions.h"
#import "base/test/task_environment.h"
#import "components/prefs/pref_service.h"
#import "components/signin/public/identity_manager/identity_test_utils.h"
#import "ios/chrome/browser/account_picker/ui_bundled/account_picker_selection/account_picker_selection_screen_identity_item_configurator.h"
#import "ios/chrome/browser/photos/model/photos_service_factory.h"
#import "ios/chrome/browser/settings/ui_bundled/downloads/save_to_photos/save_to_photos_settings_account_confirmation_consumer.h"
#import "ios/chrome/browser/settings/ui_bundled/downloads/save_to_photos/save_to_photos_settings_account_selection_consumer.h"
#import "ios/chrome/browser/settings/ui_bundled/downloads/save_to_photos/save_to_photos_settings_mediator_delegate.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.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_system_identity.h"
#import "ios/chrome/browser/signin/model/fake_system_identity_manager.h"
#import "ios/chrome/browser/signin/model/identity_manager_factory.h"
#import "ios/chrome/browser/signin/model/identity_test_environment_browser_state_adaptor.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
// Fake consumer for the mediator.
@interface FakeSaveToPhotosSettingsConsumer
: NSObject <SaveToPhotosSettingsAccountConfirmationConsumer,
SaveToPhotosSettingsAccountSelectionConsumer>
@property(nonatomic, strong) UIImage* identityAvatar;
@property(nonatomic, copy) NSString* identityName;
@property(nonatomic, copy) NSString* identityEmail;
@property(nonatomic, copy) NSString* identityGaiaID;
@property(nonatomic, assign) BOOL askEveryTimeSwitchOn;
@property(nonatomic, strong)
NSArray<AccountPickerSelectionScreenIdentityItemConfigurator*>*
identityConfigurators;
@end
@implementation FakeSaveToPhotosSettingsConsumer
- (void)setIdentityButtonAvatar:(UIImage*)avatar
name:(NSString*)name
email:(NSString*)email
gaiaID:(NSString*)gaiaID
askEveryTimeSwitchOn:(BOOL)askEveryTimeSwitchOn {
self.identityAvatar = avatar;
self.identityName = name;
self.identityEmail = email;
self.identityGaiaID = gaiaID;
self.askEveryTimeSwitchOn = askEveryTimeSwitchOn;
}
- (void)populateAccountsOnDevice:
(NSArray<AccountPickerSelectionScreenIdentityItemConfigurator*>*)
configurators {
self.identityConfigurators = configurators;
}
- (void)displaySaveToPhotosSettingsUI {
}
- (void)hideSaveToPhotosSettingsUI {
}
@end
// Fake delegate.
@interface FakeSaveToPhotosSettingsMediatorDelegate
: NSObject <SaveToPhotosSettingsMediatorDelegate>
@property(nonatomic, assign) BOOL hideSaveToPhotosSettingsCalled;
@end
@implementation FakeSaveToPhotosSettingsMediatorDelegate
- (void)hideSaveToPhotosSettings {
self.hideSaveToPhotosSettingsCalled = YES;
}
@end
// SaveToPhotosSettingsMediator unit tests.
class SaveToPhotosSettingsMediatorTest : public PlatformTest {
protected:
void SetUp() final {
TestProfileIOS::Builder builder;
builder.AddTestingFactory(
IdentityManagerFactory::GetInstance(),
base::BindRepeating(IdentityTestEnvironmentBrowserStateAdaptor::
BuildIdentityManagerForTests));
profile_ = std::move(builder).Build();
fake_identity_a_ = [FakeSystemIdentity fakeIdentity1];
AddIdentity(fake_identity_a_, /*as_primary=*/true);
fake_identity_b_ = [FakeSystemIdentity fakeIdentity2];
AddIdentity(fake_identity_b_, /*as_primary=*/false);
}
void TearDown() final { [mediator_ disconnect]; }
void AddIdentity(id<SystemIdentity> identity, bool as_primary) {
FakeSystemIdentityManager* system_identity_manager =
FakeSystemIdentityManager::FromSystemIdentityManager(
GetApplicationContext()->GetSystemIdentityManager());
system_identity_manager->AddIdentity(identity);
// Note: The (cross-platform) IdentityManager isn't fully hooked up to the
// (iOS-specific) SystemIdentityManager in this test, so update it
// separately.
// TODO(crbug.com/368409110): Improve the test plumbing so that this isn't
// necessary. This likely means either adding plumbing towards
// SystemIdentityManager to FakeProfileOAuth2TokenService, or alternatively
// using the real ProfileOAuth2TokenServiceIOSDelegate here.
auto options = signin::AccountAvailabilityOptionsBuilder().WithGaiaId(
GaiaId(identity.gaiaID));
if (as_primary) {
options = options.AsPrimary(signin::ConsentLevel::kSignin);
}
signin::MakeAccountAvailable(
IdentityManagerFactory::GetForProfile(profile_.get()),
options.Build(base::SysNSStringToUTF8(identity.userEmail)));
}
void ForgetIdentity(id<SystemIdentity> identity) {
FakeSystemIdentityManager* system_identity_manager =
FakeSystemIdentityManager::FromSystemIdentityManager(
GetApplicationContext()->GetSystemIdentityManager());
system_identity_manager->ForgetIdentityFromOtherApplication(identity);
// Note: The (cross-platform) IdentityManager isn't fully hooked up to the
// (iOS-specific) SystemIdentityManager in this test, so update it
// separately.
// TODO(crbug.com/368409110): Improve the test plumbing so that this isn't
// necessary. This likely means either adding plumbing towards
// SystemIdentityManager to FakeProfileOAuth2TokenService, or alternatively
// using the real ProfileOAuth2TokenServiceIOSDelegate here.
signin::RemoveRefreshTokenForAccount(
IdentityManagerFactory::GetForProfile(profile_.get()),
CoreAccountId::FromGaiaId(GaiaId(identity.gaiaID)));
}
// Creates a SaveToPhotosSettingsMediator with services from the test browser
// state.
SaveToPhotosSettingsMediator* CreateSaveToPhotosSettingsMediator() {
PrefService* pref_service = profile_->GetPrefs();
ChromeAccountManagerService* account_manager_service =
ChromeAccountManagerServiceFactory::GetForProfile(profile_.get());
signin::IdentityManager* identity_manager =
IdentityManagerFactory::GetForProfile(profile_.get());
mediator_ = [[SaveToPhotosSettingsMediator alloc]
initWithAccountManagerService:account_manager_service
prefService:pref_service
identityManager:identity_manager
photosService:PhotosServiceFactory::GetForProfile(
profile_.get())];
return mediator_;
}
ChromeAccountManagerService* GetAccountManagerService() {
return ChromeAccountManagerServiceFactory::GetForProfile(profile_.get());
}
// Checks that the identities given to the consumer, either through the
// primary or secondary consumer interfaces, match an expected value
// `saved_identity`. It does not test the values of `askEveryTimeSwitchOn` or
// `identityEnabled` in `fake_consumer`.
void CheckFakeConsumerIdentities(
FakeSaveToPhotosSettingsConsumer* fake_consumer,
id<SystemIdentity> saved_identity) {
UIImage* saved_identity_avatar =
GetAccountManagerService()->GetIdentityAvatarWithIdentity(
saved_identity, IdentityAvatarSize::TableViewIcon);
// Test that the presented identity is the expected one.
EXPECT_NSEQ(saved_identity_avatar, fake_consumer.identityAvatar);
EXPECT_NSEQ(saved_identity.userFullName, fake_consumer.identityName);
EXPECT_NSEQ(saved_identity.userEmail, fake_consumer.identityEmail);
EXPECT_NSEQ(saved_identity.gaiaID, fake_consumer.identityGaiaID);
// Tests that if there is at least an element, it matches `fake_identity_a_`
// and is selected if its GAIA ID matches that of the expected selected
// identity.
if (fake_consumer.identityConfigurators.count > 0) {
UIImage* fake_identity_a_avatar =
GetAccountManagerService()->GetIdentityAvatarWithIdentity(
fake_identity_a_, IdentityAvatarSize::TableViewIcon);
EXPECT_NSEQ(fake_identity_a_.gaiaID,
fake_consumer.identityConfigurators[0].gaiaID);
EXPECT_NSEQ(fake_identity_a_.userFullName,
fake_consumer.identityConfigurators[0].name);
EXPECT_NSEQ(fake_identity_a_.userEmail,
fake_consumer.identityConfigurators[0].email);
EXPECT_NSEQ(fake_identity_a_avatar,
fake_consumer.identityConfigurators[0].avatar);
EXPECT_EQ([fake_consumer.identityConfigurators[0].gaiaID
isEqual:saved_identity.gaiaID],
fake_consumer.identityConfigurators[0].selected);
}
// Tests that if there is at least a second element, it matches
// `fake_identity_b_` and is selected if its GAIA ID matches that of the
// expected selected identity.
if (fake_consumer.identityConfigurators.count > 1) {
UIImage* fake_identity_b_avatar =
GetAccountManagerService()->GetIdentityAvatarWithIdentity(
fake_identity_b_, IdentityAvatarSize::TableViewIcon);
EXPECT_NSEQ(fake_identity_b_.gaiaID,
fake_consumer.identityConfigurators[1].gaiaID);
EXPECT_NSEQ(fake_identity_b_.userFullName,
fake_consumer.identityConfigurators[1].name);
EXPECT_NSEQ(fake_identity_b_.userEmail,
fake_consumer.identityConfigurators[1].email);
EXPECT_NSEQ(fake_identity_b_avatar,
fake_consumer.identityConfigurators[1].avatar);
EXPECT_EQ([fake_consumer.identityConfigurators[1].gaiaID
isEqual:saved_identity.gaiaID],
fake_consumer.identityConfigurators[1].selected);
}
}
base::test::TaskEnvironment task_environment_;
std::unique_ptr<TestProfileIOS> profile_;
id<SystemIdentity> fake_identity_a_;
id<SystemIdentity> fake_identity_b_;
SaveToPhotosSettingsMediator* mediator_;
};
// Tests that invoking the SaveToPhotosSettingsMutator interface on the mediator
// leads to the expected changes in the preferences.
TEST_F(SaveToPhotosSettingsMediatorTest, CanMutateSelectedIdentity) {
SaveToPhotosSettingsMediator* mediator = CreateSaveToPhotosSettingsMediator();
profile_->GetPrefs()->SetString(
prefs::kIosSaveToPhotosDefaultGaiaId,
base::SysNSStringToUTF8(fake_identity_a_.gaiaID));
profile_->GetPrefs()->SetBoolean(prefs::kIosSaveToPhotosSkipAccountPicker,
true);
FakeSaveToPhotosSettingsConsumer* fake_consumer =
[[FakeSaveToPhotosSettingsConsumer alloc] init];
mediator.accountConfirmationConsumer = fake_consumer;
mediator.accountSelectionConsumer = fake_consumer;
[mediator setSelectedIdentityGaiaID:fake_identity_b_.gaiaID];
EXPECT_EQ(
base::SysNSStringToUTF8(fake_identity_b_.gaiaID),
profile_->GetPrefs()->GetString(prefs::kIosSaveToPhotosDefaultGaiaId));
EXPECT_TRUE(profile_->GetPrefs()->GetBoolean(
prefs::kIosSaveToPhotosSkipAccountPicker));
[mediator setAskWhichAccountToUseEveryTime:YES];
EXPECT_EQ(
base::SysNSStringToUTF8(fake_identity_b_.gaiaID),
profile_->GetPrefs()->GetString(prefs::kIosSaveToPhotosDefaultGaiaId));
EXPECT_FALSE(profile_->GetPrefs()->GetBoolean(
prefs::kIosSaveToPhotosSkipAccountPicker));
[mediator disconnect];
}
// Tests that external changes in preferences leads to expected changes in the
// consumer.
TEST_F(SaveToPhotosSettingsMediatorTest, ExternalPrefChangeUpdatesConsumers) {
SaveToPhotosSettingsMediator* mediator = CreateSaveToPhotosSettingsMediator();
profile_->GetPrefs()->SetString(
prefs::kIosSaveToPhotosDefaultGaiaId,
base::SysNSStringToUTF8(fake_identity_a_.gaiaID));
profile_->GetPrefs()->SetBoolean(prefs::kIosSaveToPhotosSkipAccountPicker,
true);
FakeSaveToPhotosSettingsConsumer* fake_consumer =
[[FakeSaveToPhotosSettingsConsumer alloc] init];
mediator.accountConfirmationConsumer = fake_consumer;
mediator.accountSelectionConsumer = fake_consumer;
CheckFakeConsumerIdentities(fake_consumer, fake_identity_a_);
EXPECT_TRUE(fake_consumer.askEveryTimeSwitchOn);
profile_->GetPrefs()->SetString(
prefs::kIosSaveToPhotosDefaultGaiaId,
base::SysNSStringToUTF8(fake_identity_b_.gaiaID));
CheckFakeConsumerIdentities(fake_consumer, fake_identity_b_);
EXPECT_TRUE(fake_consumer.askEveryTimeSwitchOn);
profile_->GetPrefs()->ClearPref(prefs::kIosSaveToPhotosSkipAccountPicker);
CheckFakeConsumerIdentities(fake_consumer, fake_identity_b_);
EXPECT_FALSE(fake_consumer.askEveryTimeSwitchOn);
[mediator disconnect];
}
// Tests that external changes in the list of accounts authenticated on the
// device leads to expected changes in the consumer.
TEST_F(SaveToPhotosSettingsMediatorTest,
ExternalAccountsChangeUpdatesConsumers) {
SaveToPhotosSettingsMediator* mediator = CreateSaveToPhotosSettingsMediator();
profile_->GetPrefs()->SetString(
prefs::kIosSaveToPhotosDefaultGaiaId,
base::SysNSStringToUTF8(fake_identity_a_.gaiaID));
profile_->GetPrefs()->SetBoolean(prefs::kIosSaveToPhotosSkipAccountPicker,
true);
FakeSaveToPhotosSettingsConsumer* fake_consumer =
[[FakeSaveToPhotosSettingsConsumer alloc] init];
mediator.accountConfirmationConsumer = fake_consumer;
mediator.accountSelectionConsumer = fake_consumer;
ASSERT_EQ(2U, fake_consumer.identityConfigurators.count);
CheckFakeConsumerIdentities(fake_consumer, fake_identity_a_);
EXPECT_TRUE(fake_consumer.askEveryTimeSwitchOn);
ForgetIdentity(fake_identity_b_);
CheckFakeConsumerIdentities(fake_consumer, fake_identity_a_);
EXPECT_TRUE(fake_consumer.askEveryTimeSwitchOn);
EXPECT_EQ(1U, fake_consumer.identityConfigurators.count);
fake_identity_b_ = [FakeSystemIdentity fakeIdentity3];
AddIdentity(fake_identity_b_, /*as_primary=*/false);
CheckFakeConsumerIdentities(fake_consumer, fake_identity_a_);
EXPECT_TRUE(fake_consumer.askEveryTimeSwitchOn);
EXPECT_EQ(2U, fake_consumer.identityConfigurators.count);
[mediator disconnect];
}