// Copyright 2024 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/authentication/account_menu/ui/account_menu_view_controller.h"

#import "base/check_op.h"
#import "base/memory/raw_ptr.h"
#import "base/test/metrics/histogram_tester.h"
#import "base/test/metrics/user_action_tester.h"
#import "base/test/scoped_feature_list.h"
#import "components/sync/test/test_sync_service.h"
#import "components/test/ios/test_utils.h"
#import "google_apis/gaia/gaia_id.h"
#import "ios/chrome/browser/authentication/account_menu/ui/account_menu_data_source.h"
#import "ios/chrome/browser/authentication/account_menu/ui/account_menu_mutator.h"
#import "ios/chrome/browser/authentication/ui_bundled/cells/central_account_view.h"
#import "ios/chrome/browser/policy/model/management_state.h"
#import "ios/chrome/browser/settings/model/sync/utils/account_error_ui_info.h"
#import "ios/chrome/browser/settings/ui_bundled/settings_table_view_controller_constants.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/public/features/features.h"
#import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_item.h"
#import "ios/chrome/browser/shared/ui/table_view/content_configuration/table_view_cell_content_configuration.h"
#import "ios/chrome/browser/shared/ui/table_view/table_view_utils.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/avatar/avatar_provider.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/sync/model/sync_service_factory.h"
#import "ios/chrome/browser/sync/model/test_sync_service_utils.h"
#import "ios/chrome/grit/ios_branded_strings.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 "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
#import "ui/base/l10n/l10n_util.h"

namespace {

const FakeSystemIdentity* kPrimaryIdentity = [FakeSystemIdentity fakeIdentity1];
const FakeSystemIdentity* kSecondaryIdentity =
    [FakeSystemIdentity fakeIdentity2];
const FakeSystemIdentity* kSecondaryIdentity2 =
    [FakeSystemIdentity fakeIdentity3];
UIImage* kPrimaryAccountAvatar = [[UIImage alloc] init];

}  // namespace

// An account menu data source with a primary and a secondary identities.
@interface FakeAccountMenuDataSource : NSObject <AccountMenuDataSource>
@property(nonatomic, assign) ChromeAccountManagerService* accountManagerService;
@property(nonatomic, strong) AccountErrorUIInfo* accountErrorUIInfo;

// Redeclare properties as readwrite for testing.
@property(nonatomic, strong, readwrite) NSString* primaryAccountEmail;
@property(nonatomic, strong, readwrite) NSString* primaryAccountUserFullName;
@property(nonatomic, strong, readwrite) UIImage* primaryAccountAvatar;
@property(nonatomic, assign, readwrite) BOOL primaryAccountAvatarNeedsRing;
@property(nonatomic, strong, readwrite) NSString* primaryAccountAITierFullName;
@property(nonatomic, strong, readwrite) NSString* primaryAccountAITierName;
@end

@implementation FakeAccountMenuDataSource {
  std::vector<GaiaId> _secondaryAccountsGaiaIDs;
}
@synthesize primaryAccountEmail = _primaryAccountEmail;
@synthesize primaryAccountAvatar = _primaryAccountAvatar;
@synthesize primaryAccountAvatarNeedsRing = _primaryAccountAvatarNeedsRing;
@synthesize primaryAccountAITierFullName = _primaryAccountAITierFullName;
@synthesize primaryAccountUserFullName = _primaryAccountUserFullName;
@synthesize primaryAccountAITierName = _primaryAccountAITierName;
@synthesize managementDescription = _managementDescription;

- (instancetype)init {
  self = [super init];
  if (self) {
    _accountErrorUIInfo = nil;
    _secondaryAccountsGaiaIDs = {kSecondaryIdentity.gaiaId};
    _primaryAccountEmail = kPrimaryIdentity.userEmail;
    _primaryAccountAvatar = kPrimaryAccountAvatar;
    _primaryAccountAvatarNeedsRing = NO;
    _primaryAccountAITierFullName = nil;
    _primaryAccountAITierName = nil;
    _primaryAccountUserFullName = kPrimaryIdentity.userFullName;
    _managementDescription = @"managementDescription";
  }
  return self;
}

// The only acceptable argument is the ID of a secondary id.
- (const FakeSystemIdentity*)identityForGaiaID:(const GaiaId&)gaiaID {
  if (gaiaID == kSecondaryIdentity.gaiaId) {
    return kSecondaryIdentity;
  } else if (gaiaID == kSecondaryIdentity2.gaiaId) {
    return kSecondaryIdentity2;
  } else {
    NOTREACHED();
  }
}

#pragma mark - AccountMenuDataSource

- (std::vector<GaiaId>)secondaryAccountsGaiaIDs {
  return _secondaryAccountsGaiaIDs;
}

- (NSString*)nameForGaiaID:(const GaiaId&)gaiaID {
  return [self identityForGaiaID:gaiaID].userFullName;
}

- (NSString*)emailForGaiaID:(const GaiaId&)gaiaID {
  return [self identityForGaiaID:gaiaID].userEmail;
}

- (UIImage*)imageForGaiaID:(const GaiaId&)gaiaID {
  return GetApplicationContext()
      ->GetIdentityAvatarProvider()
      ->GetIdentityAvatar([self identityForGaiaID:gaiaID],
                          IdentityAvatarSize::TableViewIcon);
}

- (BOOL)isGaiaIDManaged:(const GaiaId&)gaiaID {
  return NO;
}

@end

class AccountMenuViewControllerTest : public PlatformTest {
 public:
  AccountMenuViewControllerTest() = default;

  void SetUp() override {
    PlatformTest::SetUp();
    TestProfileIOS::Builder builder;
    builder.AddTestingFactory(
        AuthenticationServiceFactory::GetInstance(),
        AuthenticationServiceFactory::GetFactoryWithDelegateForTesting(
            std::make_unique<FakeAuthenticationServiceDelegate>()));
    builder.AddTestingFactory(SyncServiceFactory::GetInstance(),
                              base::BindRepeating(&CreateTestSyncService));
    profile_ = std::move(builder).Build();
    fake_system_identity_manager_ =
        FakeSystemIdentityManager::FromSystemIdentityManager(
            GetApplicationContext()->GetSystemIdentityManager());
    data_source_.accountManagerService =
        ChromeAccountManagerServiceFactory::GetForProfile(profile_.get());
    authentication_service_ =
        AuthenticationServiceFactory::GetForProfile(profile_.get());

    AddPrimaryIdentity();
    AddSecondaryIdentity();

    view_controller_ =
        [[AccountMenuViewController alloc] initWithHideEllipsisMenu:NO];
    mutator_ = OCMStrictProtocolMock(@protocol(AccountMenuMutator));

    view_controller_.dataSource = data_source_;
    view_controller_.mutator = mutator_;
    navigation_controller_ = [[UINavigationController alloc]
        initWithRootViewController:view_controller_];
    [view_controller_ viewDidLoad];
  }

  void ViewControllerWithEllipsisMenuHidden() {
    view_controller_ =
        [[AccountMenuViewController alloc] initWithHideEllipsisMenu:YES];
    mutator_ = OCMStrictProtocolMock(@protocol(AccountMenuMutator));

    view_controller_.dataSource = data_source_;
    view_controller_.mutator = mutator_;
    navigation_controller_ = [[UINavigationController alloc]
        initWithRootViewController:view_controller_];
    [view_controller_ viewDidLoad];
  }

  void TearDown() override {
    VerifyMock();
    PlatformTest::TearDown();
  }

 protected:
  // The navigation controller that displays the view_controller_.
  // It is not used in test. However, it’s accessed by the view controller, so
  // we must not let it be deallocated until tests are done.
  UINavigationController* navigation_controller_;
  AccountMenuViewController* view_controller_;
  raw_ptr<ChromeAccountManagerService> account_manager_service_;
  id<AccountMenuMutator> mutator_;
  FakeAccountMenuDataSource* data_source_ =
      [[FakeAccountMenuDataSource alloc] init];
  NSIndexPath* path_for_secondary_account_ = [NSIndexPath indexPathForRow:0
                                                                inSection:0];
  NSIndexPath* path_for_sign_out_ = [NSIndexPath indexPathForRow:0 inSection:1];
  NSIndexPath* path_for_add_account_ = [NSIndexPath indexPathForRow:1
                                                          inSection:0];
  raw_ptr<FakeSystemIdentityManager> fake_system_identity_manager_;
  base::UserActionTester user_actions_;

  // Verify that all mocks expectation are fulfilled.
  void VerifyMock() { EXPECT_OCMOCK_VERIFY((id)mutator_); }

  // The UITableView* of the account menu view controller.
  UITableView* TableView() { return view_controller_.view.subviews[0]; }

  //  Returns the cell at `path`.
  UITableViewCell* GetCell(NSIndexPath* path) {
    return [TableView().dataSource tableView:TableView()
                       cellForRowAtIndexPath:path];
  }

  // Expects that the cell at `path` has `text` as title.
  void ExpectTextAtPath(NSString* text, NSIndexPath* path) {
    UITableViewCell* add_account_cell = GetCell(path);
    EXPECT_TRUE([add_account_cell.contentConfiguration
        isKindOfClass:[TableViewCellContentConfiguration class]]);
    TableViewCellContentConfiguration* content_configuration =
        static_cast<TableViewCellContentConfiguration*>(
            add_account_cell.contentConfiguration);
    EXPECT_NSEQ(content_configuration.title, text);
  }

  // Expects that the cell at `path` has `text` as subtitle.
  void ExpectSubtitleAtPath(NSString* text, NSIndexPath* path) {
    UITableViewCell* add_account_cell = GetCell(path);
    EXPECT_TRUE([add_account_cell.contentConfiguration
        isKindOfClass:[TableViewCellContentConfiguration class]]);
    TableViewCellContentConfiguration* content_configuration =
        static_cast<TableViewCellContentConfiguration*>(
            add_account_cell.contentConfiguration);
    EXPECT_NSEQ(content_configuration.subtitle, text);
  }

  // Selects the cell at `path`.
  void SelectCell(NSIndexPath* path) {
    [TableView().delegate tableView:TableView() didSelectRowAtIndexPath:path];
  }

 private:
  // Signs in kPrimaryIdentity as primary identity.
  void AddPrimaryIdentity() {
    fake_system_identity_manager_->AddIdentity(kPrimaryIdentity);
    authentication_service_->SignIn(kPrimaryIdentity,
                                    signin_metrics::AccessPoint::kStartPage);
  }

  // Add kSecondaryIdentity as a secondary identity.
  void AddSecondaryIdentity() {
    fake_system_identity_manager_->AddIdentity(kSecondaryIdentity);
  }

  web::WebTaskEnvironment task_environment_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  IOSChromeScopedTestingLocalState scoped_testing_local_state_;
  std::unique_ptr<TestProfileIOS> profile_;
  raw_ptr<AuthenticationService> authentication_service_;
};

// Test the view controller when it starts.
TEST_F(AccountMenuViewControllerTest, TestDefaultSetting) {
  EXPECT_EQ(2, TableView().numberOfSections);
  // The secondary account, Add Account....
  EXPECT_EQ(2, [TableView() numberOfRowsInSection:0]);
  // Sign Out
  EXPECT_EQ(1, [TableView() numberOfRowsInSection:1]);
  ExpectTextAtPath(
      l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_ADD_ACCOUNT_BUTTON),
      path_for_add_account_);
  ExpectTextAtPath(
      l10n_util::GetNSString(IDS_IOS_GOOGLE_ACCOUNT_SETTINGS_SIGN_OUT_ITEM),
      path_for_sign_out_);
  UIView* table_header_view_ = TableView().tableHeaderView;
  EXPECT_TRUE([table_header_view_ isKindOfClass:[CentralAccountView class]]);
  CentralAccountView* table_header_view =
      static_cast<CentralAccountView*>(table_header_view_);
  EXPECT_EQ(table_header_view.avatarImage, kPrimaryAccountAvatar);
  EXPECT_EQ(table_header_view.title, kPrimaryIdentity.userFullName);
  EXPECT_EQ(table_header_view.subtitle, kPrimaryIdentity.userEmail);
  EXPECT_EQ(table_header_view.managed, true);
}

// Test the account menu without ellipsis.
TEST_F(AccountMenuViewControllerTest, TestAccountMenuWithoutEllipsis) {
  ViewControllerWithEllipsisMenuHidden();

  [view_controller_ updatePrimaryAccount];
  ExpectTextAtPath(
      l10n_util::GetNSString(IDS_IOS_ACCOUNT_MENU_EDIT_ACCOUNT_LIST),
      [NSIndexPath indexPathForRow:0 inSection:1]);
  ExpectTextAtPath(
      l10n_util::GetNSString(IDS_IOS_GOOGLE_ACCOUNT_SETTINGS_SIGN_OUT_ITEM),
      [NSIndexPath indexPathForRow:1 inSection:1]);

  EXPECT_EQ(2, TableView().numberOfSections);
  // The secondary account, and Add Account....
  EXPECT_EQ(2, [TableView() numberOfRowsInSection:0]);
  // Manage Accounts, and Sign Out
  EXPECT_EQ(2, [TableView() numberOfRowsInSection:1]);
}

#pragma mark - Test tapping on the views.

// Tests tapping on the secondary account cell.
TEST_F(AccountMenuViewControllerTest, TestTapSecondaryAccount) {
  OCMExpect([mutator_
                accountTappedWithGaiaID:ios::OCM::AnyPointer<const GaiaId>()
                             targetRect:CGRect()])
      .ignoringNonObjectArgs()
      .andCompareObjectAtIndex(kSecondaryIdentity.gaiaId, 0);
  SelectCell(path_for_secondary_account_);
  EXPECT_EQ(1,
            user_actions_.GetActionCount("Signin_AccountMenu_SelectAccount"));
}

// Tests tapping on the add account cell.
TEST_F(AccountMenuViewControllerTest, TestTapAddAccount) {
  OCMExpect([mutator_ didTapAddAccount]);
  SelectCell(path_for_add_account_);
  EXPECT_EQ(1, user_actions_.GetActionCount("Signin_AccountMenu_AddAccount"));
}

// Tests tapping on the sign-out cell.
TEST_F(AccountMenuViewControllerTest, TestTapSignOut) {
  OCMExpect([mutator_ signOutFromTargetRect:CGRect()]).ignoringNonObjectArgs();
  SelectCell(path_for_sign_out_);
  EXPECT_EQ(1, user_actions_.GetActionCount("Signin_AccountMenu_Signout"));
}

#pragma mark - AccountMenuConsumer

// Tests tapping on error action button.
TEST_F(AccountMenuViewControllerTest, TestSetError) {
  base::HistogramTester histogram_tester;

  AccountErrorUIInfo* errorInfo = [[AccountErrorUIInfo alloc]
       initWithErrorType:syncer::SyncService::UserActionableError::
                             kNeedsPassphrase
      userActionableType:AccountErrorUserActionableType::kEnterPassphrase
               messageID:IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_MESSAGE
           buttonLabelID:IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_BUTTON];
  data_source_.accountErrorUIInfo = errorInfo;
  [view_controller_ updateErrorSection:errorInfo];
  EXPECT_EQ(3, TableView().numberOfSections);
  // The error section
  EXPECT_EQ(2, [TableView() numberOfRowsInSection:0]);
  // The secondary account, Add Account....
  EXPECT_EQ(2, [TableView() numberOfRowsInSection:1]);
  // Sign Out
  EXPECT_EQ(1, [TableView() numberOfRowsInSection:2]);

  NSIndexPath* path_for_error_message = [NSIndexPath indexPathForRow:0
                                                           inSection:0];
  ExpectSubtitleAtPath(
      l10n_util::GetNSString(
          IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_MESSAGE),
      path_for_error_message);

  NSIndexPath* path_for_error_button = [NSIndexPath indexPathForRow:1
                                                          inSection:0];
  ExpectTextAtPath(l10n_util::GetNSString(
                       IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_BUTTON),
                   path_for_error_button);

  OCMExpect([mutator_ didTapErrorButton]);
  SelectCell(path_for_error_button);

  histogram_tester.ExpectUniqueSample(
      "Sync.AccountMenu.UserActionableError",
      syncer::SyncService::UserActionableError::kNeedsPassphrase,
      /*expected_bucket_count=*/1);
}

// Tests that adding an account adds an extra row in the secondary account
// section.
TEST_F(AccountMenuViewControllerTest, TestAddAccount) {
  fake_system_identity_manager_->AddIdentity(kSecondaryIdentity2);
  [view_controller_ updateAccountListWithGaiaIDsToAdd:@[
    kSecondaryIdentity2.gaiaId.ToNSString()
  ]
                                      gaiaIDsToRemove:@[]
                                        gaiaIDsToKeep:@[
                                          kSecondaryIdentity.gaiaId.ToNSString()
                                        ]];
  EXPECT_EQ(2, TableView().numberOfSections);
  // The secondary account, Add Account....
  EXPECT_EQ(3, [TableView() numberOfRowsInSection:0]);
  // Sign Out
  EXPECT_EQ(1, [TableView() numberOfRowsInSection:1]);
}

// Test that removing a secondary account remove a row in the secondary account
// section.
TEST_F(AccountMenuViewControllerTest, TestRemoveAccount) {
  [view_controller_ updateAccountListWithGaiaIDsToAdd:@[]
                                      gaiaIDsToRemove:@[
                                        kSecondaryIdentity.gaiaId.ToNSString()
                                      ]
                                        gaiaIDsToKeep:@[]];
  EXPECT_EQ(2, TableView().numberOfSections);
  // No Secondary account. Just Add Account....
  EXPECT_EQ(1, [TableView() numberOfRowsInSection:0]);
}

// Test that updating the primary account has no discernable impact on the view
// controller.
TEST_F(AccountMenuViewControllerTest, TestUpdatePrimaryAccount) {
  [view_controller_ updatePrimaryAccount];
  EXPECT_EQ(2, TableView().numberOfSections);
  // The secondary account, Add Account....
  EXPECT_EQ(2, [TableView() numberOfRowsInSection:0]);
  // Sign Out
  EXPECT_EQ(1, [TableView() numberOfRowsInSection:1]);
}

// Test the account menu with an identity with missing given name.
TEST_F(AccountMenuViewControllerTest, TestMissingGivenName) {
  FakeSystemIdentity* identity =
      [FakeSystemIdentity fakeIdentityWithMissingGivenName];
  fake_system_identity_manager_->AddIdentity(identity);

  data_source_.primaryAccountEmail = identity.userEmail;
  data_source_.primaryAccountUserFullName = identity.userFullName;

  AccountMenuViewController* viewController =
      [[AccountMenuViewController alloc] initWithHideEllipsisMenu:NO];
  viewController.dataSource = data_source_;
  viewController.mutator = mutator_;
  [viewController view];

  UITableView* tableView = viewController.view.subviews[0];
  UIView* header = tableView.tableHeaderView;
  EXPECT_TRUE([header isKindOfClass:[CentralAccountView class]]);
  CentralAccountView* centralAccountView =
      static_cast<CentralAccountView*>(header);
  EXPECT_NSEQ(centralAccountView.title, identity.userFullName);
  EXPECT_NSEQ(centralAccountView.subtitle, identity.userEmail);
}

// Test the account menu with an identity with missing names.
TEST_F(AccountMenuViewControllerTest, TestMissingNames) {
  FakeSystemIdentity* identity =
      [FakeSystemIdentity fakeIdentityWithMissingNames];
  fake_system_identity_manager_->AddIdentity(identity);

  data_source_.primaryAccountEmail = identity.userEmail;
  data_source_.primaryAccountUserFullName = identity.userFullName;

  AccountMenuViewController* viewController =
      [[AccountMenuViewController alloc] initWithHideEllipsisMenu:NO];
  viewController.dataSource = data_source_;
  viewController.mutator = mutator_;
  [viewController view];

  UITableView* tableView = viewController.view.subviews[0];
  UIView* header = tableView.tableHeaderView;
  EXPECT_TRUE([header isKindOfClass:[CentralAccountView class]]);
  CentralAccountView* centralAccountView =
      static_cast<CentralAccountView*>(header);
  EXPECT_NSEQ(centralAccountView.title, identity.userEmail);
  EXPECT_NSEQ(centralAccountView.subtitle, nil);
}

// Tests that calling `-[AccountMenuViewController updateErrorSection:nil]`
// does not crash when the snapshot has no error section (e.g. when opening
// the menu without an active sync error).
TEST_F(AccountMenuViewControllerTest, UpdateErrorSectionWithNilWhenNoError) {
  EXPECT_EQ(2, TableView().numberOfSections);
  [view_controller_ updateErrorSection:nil];
  EXPECT_EQ(2, TableView().numberOfSections);
}

// Tests adding an error section and then clearing it with
// `-[AccountMenuViewController updateErrorSection:nil]`.
TEST_F(AccountMenuViewControllerTest, ClearErrorSection) {
  AccountErrorUIInfo* errorInfo = [[AccountErrorUIInfo alloc]
       initWithErrorType:syncer::SyncService::UserActionableError::
                             kNeedsPassphrase
      userActionableType:AccountErrorUserActionableType::kEnterPassphrase
               messageID:IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_MESSAGE
           buttonLabelID:IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_BUTTON];
  data_source_.accountErrorUIInfo = errorInfo;
  [view_controller_ updateErrorSection:errorInfo];
  EXPECT_EQ(3, TableView().numberOfSections);

  data_source_.accountErrorUIInfo = nil;
  [view_controller_ updateErrorSection:nil];
  EXPECT_EQ(2, TableView().numberOfSections);
}

// Tests updating the error section from one error type to another, ensuring
// the message and button label update properly.
TEST_F(AccountMenuViewControllerTest, TransitionBetweenErrorTypes) {
  AccountErrorUIInfo* errorInfo1 = [[AccountErrorUIInfo alloc]
       initWithErrorType:syncer::SyncService::UserActionableError::
                             kNeedsPassphrase
      userActionableType:AccountErrorUserActionableType::kEnterPassphrase
               messageID:IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_MESSAGE
           buttonLabelID:IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_BUTTON];
  data_source_.accountErrorUIInfo = errorInfo1;
  [view_controller_ updateErrorSection:errorInfo1];
  EXPECT_EQ(3, TableView().numberOfSections);

  NSIndexPath* path_for_error_message = [NSIndexPath indexPathForRow:0
                                                           inSection:0];
  NSIndexPath* path_for_error_button = [NSIndexPath indexPathForRow:1
                                                          inSection:0];
  ExpectSubtitleAtPath(
      l10n_util::GetNSString(
          IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_MESSAGE),
      path_for_error_message);
  ExpectTextAtPath(l10n_util::GetNSString(
                       IDS_IOS_ACCOUNT_TABLE_ERROR_ENTER_PASSPHRASE_BUTTON),
                   path_for_error_button);

  AccountErrorUIInfo* errorInfo2 = [[AccountErrorUIInfo alloc]
       initWithErrorType:syncer::SyncService::UserActionableError::
                             kSignInNeedsUpdate
      userActionableType:AccountErrorUserActionableType::
                             kReauthToResolveSigninError
               messageID:IDS_IOS_ACCOUNT_TABLE_ERROR_VERIFY_ITS_YOU_MESSAGE
           buttonLabelID:IDS_IOS_ACCOUNT_TABLE_ERROR_VERIFY_ITS_YOU_BUTTON];
  data_source_.accountErrorUIInfo = errorInfo2;
  [view_controller_ updateErrorSection:errorInfo2];
  EXPECT_EQ(3, TableView().numberOfSections);

  ExpectSubtitleAtPath(l10n_util::GetNSString(
                           IDS_IOS_ACCOUNT_TABLE_ERROR_VERIFY_ITS_YOU_MESSAGE),
                       path_for_error_message);
  ExpectTextAtPath(
      l10n_util::GetNSString(IDS_IOS_ACCOUNT_TABLE_ERROR_VERIFY_ITS_YOU_BUTTON),
      path_for_error_button);
}

// Tests the effect of centralAccountViewDidTapAISubscriptionChip.
TEST_F(AccountMenuViewControllerTest,
       TestcentralAccountViewDidTapAISubscriptionChip) {
  EXPECT_EQ(user_actions_.GetActionCount("Signin_AccountMenu_SubscriptionChip"),
            0);
  [(id<CentralAccountViewDelegate>)view_controller_
      centralAccountViewDidTapAISubscriptionChip:nil];
  EXPECT_EQ(user_actions_.GetActionCount("Signin_AccountMenu_SubscriptionChip"),
            1);
}
