chromium/ios/chrome/browser/ui/settings/downloads/downloads_settings_table_view_controller_unittest.mm

// 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/downloads/downloads_settings_table_view_controller.h"

#import "base/apple/foundation_util.h"
#import "ios/chrome/browser/shared/ui/table_view/cells/table_view_switch_cell.h"
#import "ios/chrome/browser/shared/ui/table_view/legacy_chrome_table_view_controller_test.h"
#import "ios/chrome/browser/ui/authentication/views/identity_button_control.h"
#import "ios/chrome/browser/ui/settings/downloads/downloads_settings_table_view_controller_action_delegate.h"
#import "ios/chrome/browser/ui/settings/downloads/downloads_settings_table_view_controller_presentation_delegate.h"
#import "ios/chrome/browser/ui/settings/downloads/identity_button_cell.h"
#import "ios/chrome/browser/ui/settings/downloads/identity_button_item.h"
#import "ios/chrome/browser/ui/settings/downloads/save_to_photos/fake_save_to_photos_settings_mutator.h"
#import "ios/chrome/browser/ui/settings/downloads/save_to_photos/save_to_photos_settings_mutator.h"
#import "ios/chrome/grit/ios_strings.h"
#import "testing/gtest_mac.h"
#import "ui/base/l10n/l10n_util_mac.h"
#import "ui/base/test/ios/ui_image_test_utils.h"

namespace {

// Generates test image with given `width` and `height`.
UIImage* GenerateTestImage(CGFloat width, CGFloat height) {
  return ui::test::uiimage_utils::UIImageWithSizeAndSolidColor(
      CGSize{.width = width, .height = height}, UIColor.whiteColor);
}

}  // namespace

// Fake presentation delegate.
@interface FakeDownloadsSettingsTableViewControllerPresentationDelegate
    : NSObject <DownloadsSettingsTableViewControllerPresentationDelegate>

@property(nonatomic, assign) BOOL wasRemovedCalled;

@end

@implementation FakeDownloadsSettingsTableViewControllerPresentationDelegate

- (void)downloadsSettingsTableViewControllerWasRemoved:
    (DownloadsSettingsTableViewController*)controller {
  self.wasRemovedCalled = YES;
}

@end

// Fake action delegate.
@interface FakeDownloadsSettingsTableViewControllerActionDelegate
    : NSObject <DownloadsSettingsTableViewControllerActionDelegate>

@property(nonatomic, assign) BOOL selectSaveToPhotosAccountCalled;

@end

@implementation FakeDownloadsSettingsTableViewControllerActionDelegate

- (void)downloadsSettingsTableViewControllerOpenSaveToPhotosAccountSelection:
    (DownloadsSettingsTableViewController*)controller {
  self.selectSaveToPhotosAccountCalled = YES;
}

@end

// Unit tests for DownloadsSettingsTableViewController.
class DownloadsSettingsTableViewControllerTest
    : public LegacyChromeTableViewControllerTest {
 protected:
  void SetUp() final {
    LegacyChromeTableViewControllerTest::SetUp();

    save_to_photos_mutator_ = [[FakeSaveToPhotosSettingsMutator alloc] init];
    presentation_delegate_ =
        [[FakeDownloadsSettingsTableViewControllerPresentationDelegate alloc]
            init];
    action_delegate_ =
        [[FakeDownloadsSettingsTableViewControllerActionDelegate alloc] init];

    CreateController();
  }

  LegacyChromeTableViewController* InstantiateController() final {
    DownloadsSettingsTableViewController* controller =
        [[DownloadsSettingsTableViewController alloc] init];
    controller.saveToPhotosSettingsMutator = save_to_photos_mutator_;
    controller.presentationDelegate = presentation_delegate_;
    controller.actionDelegate = action_delegate_;
    return controller;
  }

  FakeSaveToPhotosSettingsMutator* save_to_photos_mutator_;
  FakeDownloadsSettingsTableViewControllerPresentationDelegate*
      presentation_delegate_;
  FakeDownloadsSettingsTableViewControllerActionDelegate* action_delegate_;
};

// Tests that DownloadsSettingsTableViewController has the expected content.
// Also tests that the view controller correctly calls the mutator when the
// switch is toggled, the action delegate when the identity button is tapped,
// and the presentation delegate when the controller is removed.
TEST_F(DownloadsSettingsTableViewControllerTest,
       CanToggleAskEveryTimeAndSelectSaveToPhotosAccount) {
  // Push an items configuration through consumer interface.
  DownloadsSettingsTableViewController* downloadsController =
      base::apple::ObjCCast<DownloadsSettingsTableViewController>(controller());
  ASSERT_TRUE(downloadsController);
  UIImage* identity_avatar = GenerateTestImage(30.0, 30.0);
  [downloadsController setIdentityButtonAvatar:identity_avatar
                                          name:@"Firstname Lastname"
                                         email:@"[email protected]"
                                        gaiaID:@"mygaiaid"
                          askEveryTimeSwitchOn:YES];

  EXPECT_EQ(1, NumberOfSections());
  CheckTitleWithId(IDS_IOS_SETTINGS_DOWNLOADS_TITLE);

  // Test Save to Photos selection section has expected content.
  CheckSectionHeaderWithId(IDS_IOS_SETTINGS_DOWNLOADS_SAVE_TO_PHOTOS_HEADER, 0);
  IdentityButtonItem* identity_button_item =
      base::apple::ObjCCast<IdentityButtonItem>(GetTableViewItem(0, 0));
  ASSERT_TRUE(identity_button_item);
  EXPECT_EQ(identity_avatar, identity_button_item.identityAvatar);
  EXPECT_NSEQ(@"Firstname Lastname", identity_button_item.identityName);
  EXPECT_NSEQ(@"[email protected]",
              identity_button_item.identityEmail);
  EXPECT_NSEQ(@"mygaiaid", identity_button_item.identityGaiaID);
  EXPECT_TRUE(identity_button_item.enabled);
  EXPECT_EQ(IdentityButtonControlArrowRight,
            identity_button_item.arrowDirection);
  EXPECT_EQ(IdentityViewStyleConsistency,
            identity_button_item.identityViewStyle);
  CheckSwitchCellStateAndTextWithId(
      YES, IDS_IOS_SAVE_TO_PHOTOS_ACCOUNT_PICKER_ASK_EVERY_TIME, 0, 1);

  // Test that disabling and re-enabling the switch updates the mutator.
  EXPECT_FALSE(save_to_photos_mutator_.selectedIdentityGaiaID);
  TableViewSwitchCell* switchCell = base::apple::ObjCCast<TableViewSwitchCell>(
      [controller() tableView:controller().tableView
          cellForRowAtIndexPath:[NSIndexPath indexPathForItem:1 inSection:0]]);
  ASSERT_TRUE(switchCell);
  switchCell.switchView.on = NO;
  [switchCell.switchView
      sendActionsForControlEvents:UIControlEventValueChanged];
  EXPECT_FALSE(save_to_photos_mutator_.askWhichAccountToUseEveryTime);
  switchCell.switchView.on = YES;
  [switchCell.switchView
      sendActionsForControlEvents:UIControlEventValueChanged];
  EXPECT_TRUE(save_to_photos_mutator_.askWhichAccountToUseEveryTime);

  // Test that tapping the Identity button calls the action delegate.
  EXPECT_FALSE(action_delegate_.selectSaveToPhotosAccountCalled);
  IdentityButtonCell* identityButtonCell =
      base::apple::ObjCCast<IdentityButtonCell>([controller()
                      tableView:controller().tableView
          cellForRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]);
  [identityButtonCell.identityButtonControl
      sendActionsForControlEvents:UIControlEventTouchUpInside];
  EXPECT_TRUE(action_delegate_.selectSaveToPhotosAccountCalled);

  // Test that removing the controller calls the presentation delegate.
  EXPECT_FALSE(presentation_delegate_.wasRemovedCalled);
  [controller() didMoveToParentViewController:nil];
  EXPECT_TRUE(presentation_delegate_.wasRemovedCalled);
}