chromium/ios/chrome/browser/account_picker/ui_bundled/account_picker_coordinator_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/account_picker/ui_bundled/account_picker_coordinator.h"

#import "base/apple/foundation_util.h"
#import "base/test/task_environment.h"
#import "ios/chrome/browser/account_picker/ui_bundled/account_picker_configuration.h"
#import "ios/chrome/browser/account_picker/ui_bundled/account_picker_confirmation/account_picker_confirmation_screen_coordinator.h"
#import "ios/chrome/browser/account_picker/ui_bundled/account_picker_confirmation/account_picker_confirmation_screen_coordinator_delegate.h"
#import "ios/chrome/browser/account_picker/ui_bundled/account_picker_layout_delegate.h"
#import "ios/chrome/browser/account_picker/ui_bundled/account_picker_screen/account_picker_screen_navigation_controller.h"
#import "ios/chrome/browser/account_picker/ui_bundled/account_picker_screen/account_picker_screen_view_controller.h"
#import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/test/fakes/fake_ui_view_controller.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"

// Unit tests for the AccountPickerCoordinator.
class AccountPickerCoordinatorTest : public PlatformTest {
 protected:
  void SetUp() final {
    TestChromeBrowserState::Builder builder;
    browser_state_ = std::move(builder).Build();
    browser_ = std::make_unique<TestBrowser>(browser_state_.get());
    base_view_controller_ = [[FakeUIViewController alloc] init];
  }

  void TearDown() final {}

  // Create a AccountPickerCoordinator to test.
  AccountPickerCoordinator* CreateAccountPickerCoordinator(
      AccountPickerConfiguration* configuration) {
    return [[AccountPickerCoordinator alloc]
        initWithBaseViewController:base_view_controller_
                           browser:browser_.get()
                     configuration:configuration];
  }

  AccountPickerConfiguration* CreateAccountPickerConfiguration() {
    AccountPickerConfiguration* configuration =
        [[AccountPickerConfiguration alloc] init];
    configuration.titleText = @"Account picker";
    configuration.bodyText = @"This is the body text of the account picker.";
    configuration.submitButtonTitle = @"Submit";
    configuration.askEveryTimeSwitchLabelText = @"Ask every time";
    return configuration;
  }

  base::test::TaskEnvironment task_environment_;
  std::unique_ptr<TestChromeBrowserState> browser_state_;
  std::unique_ptr<TestBrowser> browser_;
  UIViewController* base_view_controller_;
};

// Tests that the AccountPickerCoordinator creates/destroys an
// AccountPickerConfirmationScreenCoordinator with the expected configuration
// when it starts/stops. Also tests that an
// AccountPickerScreenNavigationController is created and presented/dismissed
// and destroyed when the coordinator starts/stops.
TEST_F(AccountPickerCoordinatorTest, PushesAndPopsConfirmationScreen) {
  AccountPickerConfiguration* configuration =
      CreateAccountPickerConfiguration();
  AccountPickerCoordinator* coordinator =
      CreateAccountPickerCoordinator(configuration);

  id mock_confirmation_screen_coordinator =
      OCMClassMock([AccountPickerConfirmationScreenCoordinator class]);
  OCMExpect([mock_confirmation_screen_coordinator alloc])
      .andReturn(mock_confirmation_screen_coordinator);
  OCMExpect([mock_confirmation_screen_coordinator
                initWithBaseViewController:OCMOCK_ANY
                                   browser:browser_.get()
                             configuration:configuration])
      .andReturn(mock_confirmation_screen_coordinator);
  ASSERT_TRUE([coordinator
      conformsToProtocol:
          @protocol(AccountPickerConfirmationScreenCoordinatorDelegate)]);
  OCMExpect([mock_confirmation_screen_coordinator
      setDelegate:static_cast<
                      id<AccountPickerConfirmationScreenCoordinatorDelegate>>(
                      coordinator)]);
  ASSERT_TRUE(
      [coordinator conformsToProtocol:@protocol(AccountPickerLayoutDelegate)]);
  OCMExpect([mock_confirmation_screen_coordinator
      setLayoutDelegate:static_cast<id<AccountPickerLayoutDelegate>>(
                            coordinator)]);
  OCMExpect([base::apple::ObjCCast<AccountPickerConfirmationScreenCoordinator>(
      mock_confirmation_screen_coordinator) start]);
  id mock_confirmation_screen_view_controller =
      OCMProtocolMock(@protocol(AccountPickerScreenViewController));
  OCMStub([mock_confirmation_screen_coordinator viewController])
      .andReturn(mock_confirmation_screen_view_controller);

  // Expect that the AccountPickerScreenNavigationController is created and
  // presented.
  id mock_navigation_controller =
      OCMClassMock([AccountPickerScreenNavigationController class]);
  OCMExpect([mock_navigation_controller alloc])
      .andReturn(mock_navigation_controller);
  OCMExpect(
      [mock_navigation_controller
          initWithRootViewController:mock_confirmation_screen_view_controller])
      .andReturn(mock_navigation_controller);
  ASSERT_TRUE([coordinator
      conformsToProtocol:@protocol(UINavigationControllerDelegate)]);
  OCMExpect([mock_navigation_controller
      setDelegate:static_cast<id<UINavigationControllerDelegate>>(
                      coordinator)]);
  OCMExpect([mock_navigation_controller
      setModalPresentationStyle:UIModalPresentationCustom]);
  ASSERT_TRUE([coordinator
      conformsToProtocol:@protocol(UIViewControllerTransitioningDelegate)]);
  OCMExpect([mock_navigation_controller
      setTransitioningDelegate:static_cast<
                                   id<UIViewControllerTransitioningDelegate>>(
                                   coordinator)]);

  // Verify that the confirmation screen has been created and started and that
  // the account picker navigation controller has been created and presented.
  [coordinator start];
  EXPECT_OCMOCK_VERIFY(mock_confirmation_screen_coordinator);
  EXPECT_EQ(base_view_controller_.presentedViewController,
            mock_navigation_controller);

  OCMStub([mock_navigation_controller presentingViewController])
      .andReturn(base_view_controller_);

  // Expect the AccountPickerConfirmationScreenCoordinator is stopped when the
  // account picker is stopped.
  OCMExpect([base::apple::ObjCCast<AccountPickerConfirmationScreenCoordinator>(
      mock_confirmation_screen_coordinator) stop]);
  [coordinator stop];

  // Check that the account picker navigation controller is dismissed and verify
  // that the confirmation screen coordinator has been stopped.
  EXPECT_EQ(base_view_controller_.presentedViewController, nil);
  EXPECT_OCMOCK_VERIFY(mock_confirmation_screen_coordinator);
}