chromium/ios/chrome/test/app/mock_reauthentication_module.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/test/app/mock_reauthentication_module.h"

#import "base/check.h"
#import "base/test/ios/wait_util.h"

// Type of the block used for delivering mocked reauth results.
typedef void (^ReauthenticationResultHandler)(ReauthenticationResult success);

@interface MockReauthenticationModule ()

// Last handler passed to attemptReauthWithLocalizedReason.
// Used for letting tests control the timing of emitting mock reauth results.
// This allows test to validate states before/after mocked reauth result is
// emitted.
@property(nonatomic) ReauthenticationResultHandler reauthResultHandler;

@end

@implementation MockReauthenticationModule

@synthesize localizedReasonForAuthentication =
    _localizedReasonForAuthentication;
@synthesize expectedResult = _expectedResult;
@synthesize canAttemptWithBiometrics = _canAttemptWithBiometrics;
@synthesize canAttempt = _canAttempt;

- (instancetype)init {
  self = [super init];
  if (self) {
    _shouldReturnSynchronously = YES;
  }
  return self;
}

- (void)setExpectedResult:(ReauthenticationResult)expectedResult {
  _canAttemptWithBiometrics = YES;
  _canAttempt = YES;
  _expectedResult = expectedResult;
}

- (BOOL)canAttemptReauthWithBiometrics {
  return _canAttemptWithBiometrics;
}

- (BOOL)canAttemptReauth {
  return _canAttempt;
}

- (void)attemptReauthWithLocalizedReason:(NSString*)localizedReason
                    canReusePreviousAuth:(BOOL)canReusePreviousAuth
                                 handler:(ReauthenticationResultHandler)
                                             reauthResultHandler {
  self.localizedReasonForAuthentication = localizedReason;

  if (self.shouldReturnSynchronously) {
    reauthResultHandler(_expectedResult);
  } else {
    if (self.reauthResultHandler) {
      // When multiple reauth requests are done without waiting for the result,
      // mimic native behavior and make the oldest request fail.
      self.reauthResultHandler(ReauthenticationResult::kFailure);
    }
    self.reauthResultHandler = reauthResultHandler;
  }
}

- (void)returnMockedReauthenticationResult {
  CHECK(!self.shouldReturnSynchronously);

  // Some test cases set the handler after UI events (e.g. animations).
  // Avoid race conditions by waiting until the handler is set.
  __weak __typeof(self) weakSelf = self;
  CHECK(base::test::ios::WaitUntilConditionOrTimeout(
      base::test::ios::kWaitForUIElementTimeout, ^{
        return [weakSelf reauthResultHandler] != nullptr;
      }));

  self.reauthResultHandler(_expectedResult);
  self.reauthResultHandler = nil;
}

@end