chromium/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {FakeMethodResolver} from 'chrome://resources/ash/common/fake_method_resolver.js';
import {FakeObservables} from 'chrome://resources/ash/common/fake_observables.js';
import {assert} from 'chrome://resources/js/assert.js';

import {AcceleratorResultData, AcceleratorsUpdatedObserverRemote, EditDialogCompletedActions, PolicyUpdatedObserverRemote, Subactions, UserAction} from '../mojom-webui/shortcut_customization.mojom-webui.js';

import {Accelerator, AcceleratorCategory, AcceleratorConfigResult, AcceleratorSource, MetaKey, MojoAcceleratorConfig, MojoLayoutInfo, ShortcutProviderInterface} from './shortcut_types.js';


/**
 * @fileoverview
 * Implements a fake version of the FakeShortcutProvider mojo interface.
 */

// Method names.
const ON_ACCELERATORS_UPDATED_METHOD_NAME =
    'AcceleratorsUpdatedObserver_OnAcceleratorsUpdated';
const ON_POLICY_UPDATED_METHOD_NAME =
    'PolicyUpdatedObserver_OnCustomizationPolicyUpdated';
export class FakeShortcutProvider implements ShortcutProviderInterface {
  private methods: FakeMethodResolver;
  private observables: FakeObservables = new FakeObservables();
  private acceleratorsUpdatedRemote: AcceleratorsUpdatedObserverRemote|null =
      null;
  private acceleratorsUpdatedPromise: Promise<void>|null = null;
  private policyUpdateRemote: PolicyUpdatedObserverRemote|null = null;
  private policyUpdatedPromise: Promise<void>|null = null;
  private restoreDefaultCallCount: number = 0;
  private preventProcessingAcceleratorsCallCount: number = 0;
  private addAcceleratorCallCount: number = 0;
  private removeAcceleratorCallCount: number = 0;
  private lastRecordedUserAction: UserAction;
  private lastRecordedMainCategory: AcceleratorCategory;
  private lastRecoredEditDialogActions: EditDialogCompletedActions;
  private lastRecordedIsAdd: boolean = false;
  private lastRecorededSubactions: Subactions;

  constructor() {
    this.methods = new FakeMethodResolver();

    // Setup method resolvers.
    this.methods.register('getAccelerators');
    this.methods.register('getAcceleratorLayoutInfos');
    this.methods.register('isMutable');
    this.methods.register('isCustomizationAllowedByPolicy');
    this.methods.register('getMetaKeyToDisplay');
    this.methods.register('addAccelerator');
    this.methods.register('replaceAccelerator');
    this.methods.register('removeAccelerator');
    this.methods.register('restoreDefault');
    this.methods.register('restoreAllDefaults');
    this.methods.register('addObserver');
    this.methods.register('addPolicyObserver');
    this.methods.register('preventProcessingAccelerators');
    this.methods.register('getConflictAccelerator');
    this.methods.register('getDefaultAcceleratorsForId');
    this.methods.register('recordUserAction');
    this.methods.register('recordMainCategoryNavigation');
    this.methods.register('recordEditDialogCompetedActions');
    this.methods.register('recordAddOrEditSubactions');
    this.registerObservables();
  }

  registerObservables(): void {
    this.observables.register(ON_ACCELERATORS_UPDATED_METHOD_NAME);
    this.observables.register(ON_POLICY_UPDATED_METHOD_NAME);
  }

  // Disable all observers and reset provider to initial state.
  reset(): void {
    this.restoreDefaultCallCount = 0;
    this.preventProcessingAcceleratorsCallCount = 0;
    this.addAcceleratorCallCount = 0;
    this.removeAcceleratorCallCount = 0;
    this.observables = new FakeObservables();
    this.registerObservables();
  }

  triggerOnAcceleratorUpdated(): void {
    this.observables.trigger(ON_ACCELERATORS_UPDATED_METHOD_NAME);
  }

  getAcceleratorLayoutInfos(): Promise<{layoutInfos: MojoLayoutInfo[]}> {
    return this.methods.resolveMethod('getAcceleratorLayoutInfos');
  }

  getAccelerators(): Promise<{config: MojoAcceleratorConfig}> {
    return this.methods.resolveMethod('getAccelerators');
  }

  isMutable(source: AcceleratorSource): Promise<{isMutable: boolean}> {
    this.methods.setResult(
        'isMutable', {isMutable: source !== AcceleratorSource.kBrowser});
    return this.methods.resolveMethod('isMutable');
  }

  isCustomizationAllowedByPolicy():
      Promise<{isCustomizationAllowedByPolicy: boolean}> {
    return this.methods.resolveMethod('isCustomizationAllowedByPolicy');
  }

  getMetaKeyToDisplay(): Promise<{metaKey: MetaKey}> {
    return this.methods.resolveMethod('getMetaKeyToDisplay');
  }

  addObserver(observer: AcceleratorsUpdatedObserverRemote): void {
    this.acceleratorsUpdatedPromise = this.observe(
        ON_ACCELERATORS_UPDATED_METHOD_NAME,
        (config: MojoAcceleratorConfig) => {
          observer.onAcceleratorsUpdated(config);
        });
  }

  addPolicyObserver(observer: PolicyUpdatedObserverRemote): void {
    this.policyUpdatedPromise =
        this.observe(ON_POLICY_UPDATED_METHOD_NAME, () => {
          observer.onCustomizationPolicyUpdated();
        });
  }

  getAcceleratorsUpdatedPromiseForTesting(): Promise<void> {
    assert(this.acceleratorsUpdatedPromise);
    return this.acceleratorsUpdatedPromise;
  }

  getPolicyUpdatedPromiseForTesting(): Promise<void> {
    assert(this.policyUpdatedPromise);
    return this.policyUpdatedPromise;
  }

  // Set the value that will be retuned when `onAcceleratorsUpdated()` is
  // called.
  setFakeAcceleratorsUpdated(config: MojoAcceleratorConfig[]): void {
    this.observables.setObservableData(
        ON_ACCELERATORS_UPDATED_METHOD_NAME, config);
  }

  setFakePolicyUpdated(): void {
    this.observables.setObservableData(ON_POLICY_UPDATED_METHOD_NAME, [true]);
  }

  addAccelerator(
      _source: AcceleratorSource, _actionId: number,
      _accelerator: Accelerator): Promise<{result: AcceleratorResultData}> {
    ++this.addAcceleratorCallCount;
    return this.methods.resolveMethod('addAccelerator');
  }

  replaceAccelerator(
      _source: AcceleratorSource, _actionId: number,
      _old_accelerator: Accelerator,
      _new_accelerator: Accelerator): Promise<{result: AcceleratorResultData}> {
    // Always return kSuccess in this fake.
    return this.methods.resolveMethod('replaceAccelerator');
  }

  removeAccelerator(): Promise<{result: AcceleratorResultData}> {
    // Always return kSuccess in this fake.
    ++this.removeAcceleratorCallCount;
    return this.methods.resolveMethod('removeAccelerator');
  }

  restoreDefault(_source: AcceleratorSource, _actionId: number):
      Promise<{result: AcceleratorResultData}> {
    ++this.restoreDefaultCallCount;
    return this.methods.resolveMethod('restoreDefault');
  }

  restoreAllDefaults(): Promise<{result: AcceleratorResultData}> {
    // Always return kSuccess in this fake.
    const result: AcceleratorResultData = {
      result: AcceleratorConfigResult.kSuccess,
      shortcutName: null,
    };
    this.methods.setResult('restoreAllDefaults', {result});
    return this.methods.resolveMethod('restoreAllDefaults');
  }

  recordUserAction(userAction: UserAction): void {
    this.lastRecordedUserAction = userAction;
  }

  recordEditDialogCompletedActions(completed_actions:
                                       EditDialogCompletedActions): void {
    this.lastRecoredEditDialogActions = completed_actions;
  }

  getLastEditDialogCompletedActions(): EditDialogCompletedActions {
    return this.lastRecoredEditDialogActions;
  }

  getLatestRecordedAction(): UserAction {
    return this.lastRecordedUserAction;
  }

  recordMainCategoryNavigation(category: AcceleratorCategory): void {
    this.lastRecordedMainCategory = category;
  }

  getLatestMainCategoryNavigated(): AcceleratorCategory {
    return this.lastRecordedMainCategory;
  }

  recordAddOrEditSubactions(isAdd: boolean, subactions: Subactions): void {
    this.lastRecordedIsAdd = isAdd;
    this.lastRecorededSubactions = subactions;
  }

  getLastRecordedIsAdd(): boolean {
    return this.lastRecordedIsAdd;
  }

  getLastRecordedSubactions(): Subactions {
    return this.lastRecorededSubactions;
  }

  preventProcessingAccelerators(_preventProcessingAccelerators: boolean):
      Promise<void> {
    ++this.preventProcessingAcceleratorsCallCount;
    return this.methods.resolveMethod('preventProcessingAccelerators');
  }

  getConflictAccelerator(
      _source: AcceleratorSource, _actionId: number,
      _accelerator: Accelerator): Promise<{result: AcceleratorResultData}> {
    return this.methods.resolveMethod('getConflictAccelerator');
  }

  getDefaultAcceleratorsForId(
      _actionId: number,
      ): Promise<{accelerators: Accelerator[]}> {
    return this.methods.resolveMethod('getDefaultAcceleratorsForId');
  }

  /**
   * Set the config result that will be returned when calling
   * `getConflictAccelerator()`.
   */
  setFakeGetConflictAccelerator(result: AcceleratorResultData): void {
    this.methods.setResult('getConflictAccelerator', {result});
  }

  /**
   * Set the default accelerators that will be returned when calling
   * `getDefaultAcceleratorsForId()`.
   */
  setFakeGetDefaultAcceleratorsForId(accelerators: Accelerator[]): void {
    this.methods.setResult('getDefaultAcceleratorsForId', {accelerators});
  }

  /**
   * Sets the value that will be returned when calling
   * getAccelerators().
   */
  setFakeAcceleratorConfig(config: MojoAcceleratorConfig): void {
    this.methods.setResult('getAccelerators', {config});
  }

  /**
   * Sets the value that will be returned when calling
   * getAcceleratorLayoutInfos().
   */
  setFakeAcceleratorLayoutInfos(layoutInfos: MojoLayoutInfo[]): void {
    this.methods.setResult('getAcceleratorLayoutInfos', {layoutInfos});
  }

  getRestoreDefaultCallCount(): number {
    return this.restoreDefaultCallCount;
  }

  getPreventProcessingAcceleratorsCallCount(): number {
    return this.preventProcessingAcceleratorsCallCount;
  }

  getAddAcceleratorCallCount(): number {
    return this.addAcceleratorCallCount;
  }

  getRemoveAcceleratorCallCount(): number {
    return this.removeAcceleratorCallCount;
  }

  setFakeMetaKeyToDisplay(metaKey: MetaKey): void {
    this.methods.setResult('getMetaKeyToDisplay', {metaKey});
  }

  setFakeAddAcceleratorResult(result: AcceleratorResultData): void {
    this.methods.setResult('addAccelerator', {result});
  }

  setFakeReplaceAcceleratorResult(result: AcceleratorResultData): void {
    this.methods.setResult('replaceAccelerator', {result});
  }

  setFakeRestoreDefaultResult(result: AcceleratorResultData): void {
    this.methods.setResult('restoreDefault', {result});
  }

  setFakeRemoveAcceleratorResult(result: AcceleratorResultData): void {
    this.methods.setResult('removeAccelerator', {result});
  }

  setFakeIsCustomizationAllowedByPolicy(isCustomizationAllowedByPolicy:
                                            boolean): void {
    this.methods.setResult(
        'isCustomizationAllowedByPolicy', {isCustomizationAllowedByPolicy});
  }

  // Sets up an observer for methodName.
  private observe(methodName: string, callback: (T: any) => void):
      Promise<void> {
    return new Promise((resolve) => {
      this.observables.observe(methodName, callback);
      resolve();
    });
  }
}