chromium/chrome/test/data/webui/chromeos/settings/device_page/fake_cros_audio_config_test.ts

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

import {crosAudioConfigMojom, fakeCrosAudioConfig} from 'chrome://os-settings/os_settings.js';
import {assertDeepEquals, assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {MockController, MockMethod} from 'chrome://webui-test/mock_controller.js';

suite('FakeCrosAudioConfig', () => {
  // Observer for testing updates which have not been added to mojo yet.
  class TestPropertiesObserver implements
      fakeCrosAudioConfig.FakePropertiesObserverInterface {
    onPropertiesUpdated() {}
  }

  const defaultProperties: crosAudioConfigMojom.AudioSystemProperties =
      fakeCrosAudioConfig.defaultFakeAudioSystemProperties;

  let crosAudioConfig: fakeCrosAudioConfig.FakeCrosAudioConfig;
  let fakeObserver: TestPropertiesObserver;
  let mockController: MockController;
  let onPropertiesUpdated: MockMethod;

  setup(() => {
    crosAudioConfig = new fakeCrosAudioConfig.FakeCrosAudioConfig();
    fakeObserver = new TestPropertiesObserver();
    mockController = new MockController();
    onPropertiesUpdated =
        mockController.createFunctionMock(fakeObserver, 'onPropertiesUpdated');
    onPropertiesUpdated.addExpectation(defaultProperties);
    crosAudioConfig.observeAudioSystemProperties(fakeObserver);
    assertTrue(!!onPropertiesUpdated);
  });

  test('VerifyObserversReceiveAudioSystemProperitesUpdates', () => {
    // `fakeObserver` observer initialized during setup.
    assertDeepEquals(defaultProperties, onPropertiesUpdated['calls_'][0]![0]);

    const observer = new TestPropertiesObserver();
    const onObserverPropertiesUpdated: MockMethod =
        mockController.createFunctionMock(observer, 'onPropertiesUpdated');

    assertTrue(!!onObserverPropertiesUpdated);
    assertEquals(0, onObserverPropertiesUpdated['calls_'].length);
    crosAudioConfig.observeAudioSystemProperties(observer);

    assertDeepEquals(
        defaultProperties, onObserverPropertiesUpdated['calls_'][0]![0]);
    assertDeepEquals(defaultProperties, onPropertiesUpdated['calls_'][1]![0]);

    const updatedProperties: crosAudioConfigMojom.AudioSystemProperties = {
      outputDevices: [fakeCrosAudioConfig.fakeSpeakerActive],
      outputVolumePercent: 0,
      outputMuteState: crosAudioConfigMojom.MuteState.kMutedByUser,
      inputGainPercent: 0,
      inputDevices: [],
      inputMuteState: crosAudioConfigMojom.MuteState.MIN_VALUE,
    };
    crosAudioConfig.setAudioSystemProperties(updatedProperties);

    assertDeepEquals(
        updatedProperties, onObserverPropertiesUpdated['calls_'][1]![0]);
    assertDeepEquals(updatedProperties, onPropertiesUpdated['calls_'][2]![0]);
  });

  test('VerifySetOutputVolumeTriggersMatchingPropertyUpdate', () => {
    const outputVolumePercentExpected = 47;
    const updatedVolumeProperties:
        crosAudioConfigMojom.AudioSystemProperties = {
      ...defaultProperties,
      outputVolumePercent: outputVolumePercentExpected,
    };
    onPropertiesUpdated.addExpectation(updatedVolumeProperties);
    crosAudioConfig.setOutputVolumePercent(outputVolumePercentExpected);

    mockController.verifyMocks();
  });

  test(
      'VerifySetActiveDeviceOutputDeviceTriggersMatchingPropertyUpdate', () => {
        const updateActiveOutputDevice:
            crosAudioConfigMojom.AudioSystemProperties = {
          ...defaultProperties,
          outputDevices: [
            fakeCrosAudioConfig.createAudioDevice(
                fakeCrosAudioConfig.defaultFakeSpeaker, /*isActive=*/ true),
            fakeCrosAudioConfig.createAudioDevice(
                fakeCrosAudioConfig.defaultFakeMicJack, /*isActive=*/ false),
          ],
        };
        onPropertiesUpdated.addExpectation(updateActiveOutputDevice);
        crosAudioConfig.setActiveDevice(
            fakeCrosAudioConfig.defaultFakeSpeaker.id);

        mockController.verifyMocks();
      });

  test('VerifySetActiveDeviceInputDeviceTriggersMatchingPropertyUpdate', () => {
    const updateActiveInputDevice:
        crosAudioConfigMojom.AudioSystemProperties = {
      ...defaultProperties,
      inputDevices: [
        fakeCrosAudioConfig.createAudioDevice(
            fakeCrosAudioConfig.fakeInternalFrontMic, /*isActive=*/ false),
        fakeCrosAudioConfig.createAudioDevice(
            fakeCrosAudioConfig.fakeBluetoothMic, /*isActive=*/ true),
      ],
    };
    onPropertiesUpdated.addExpectation(updateActiveInputDevice);
    crosAudioConfig.setActiveDevice(fakeCrosAudioConfig.fakeBluetoothMic.id);

    mockController.verifyMocks();
  });

  test('VerifySetOutputMutedTriggersMatchingPropertyUpdate', () => {
    const propertiesOutputMutedByUser:
        crosAudioConfigMojom.AudioSystemProperties = {
      ...defaultProperties,
      outputMuteState: crosAudioConfigMojom.MuteState.kMutedByUser,
    };
    onPropertiesUpdated.addExpectation(propertiesOutputMutedByUser);
    crosAudioConfig.setOutputMuted(/*muted=*/ true);
    assertDeepEquals(
        propertiesOutputMutedByUser, onPropertiesUpdated['calls_'][1]![0]);

    const propertiesOutputUnmute: crosAudioConfigMojom.AudioSystemProperties = {
      ...defaultProperties,
      outputMuteState: crosAudioConfigMojom.MuteState.kNotMuted,
    };
    onPropertiesUpdated.addExpectation(propertiesOutputUnmute);
    crosAudioConfig.setOutputMuted(/*muted=*/ false);
    assertDeepEquals(
        propertiesOutputUnmute, onPropertiesUpdated['calls_'][2]![0]);
  });

  test('VerifySetInputMutedTriggersMatchingPropertyUpdate', () => {
    assertEquals(
        crosAudioConfigMojom.MuteState.kNotMuted,
        onPropertiesUpdated['calls_'][0]![0].inputMuteState);

    const updateInputGainMuted: crosAudioConfigMojom.AudioSystemProperties = {
      ...defaultProperties,
      inputMuteState: crosAudioConfigMojom.MuteState.kMutedByUser,
    };
    onPropertiesUpdated.addExpectation(updateInputGainMuted);
    crosAudioConfig.setInputMuted(/*muted=*/ true);

    assertEquals(
        crosAudioConfigMojom.MuteState.kMutedByUser,
        onPropertiesUpdated['calls_'][1]![0].inputMuteState);
    onPropertiesUpdated.addExpectation(defaultProperties);
    crosAudioConfig.setInputMuted(/*muted=*/ false);

    assertEquals(
        crosAudioConfigMojom.MuteState.kNotMuted,
        onPropertiesUpdated['calls_'][2]![0].inputMuteState);
  });

  test('VerifySetInputGainTriggersMatchingPropertyUpdate', () => {
    const expectedGainPercent = 32;
    const updatedProperties: crosAudioConfigMojom.AudioSystemProperties = {
      ...defaultProperties,
      inputGainPercent: expectedGainPercent,
    };
    onPropertiesUpdated.addExpectation(updatedProperties);
    crosAudioConfig.setInputGainPercent(expectedGainPercent);

    mockController.verifyMocks();
  });

  test(
      'VerifySetNoiseCancellationEnabledTriggersMatchingPropertyUpdate', () => {
        const ncSupportedNotEnabled: crosAudioConfigMojom.AudioDevice =
            fakeCrosAudioConfig.createAudioDevice(
                fakeCrosAudioConfig.fakeInternalFrontMic, /*isActive=*/ true);
        ncSupportedNotEnabled.noiseCancellationState =
            crosAudioConfigMojom.AudioEffectState.kNotEnabled;

        const defaultNoiseCancellation:
            crosAudioConfigMojom.AudioSystemProperties = {
          ...defaultProperties,
          inputDevices: [ncSupportedNotEnabled],
        };
        crosAudioConfig.setAudioSystemProperties(defaultNoiseCancellation);
        assertDeepEquals(
            defaultNoiseCancellation, onPropertiesUpdated['calls_'][1]![0]);
        crosAudioConfig.setNoiseCancellationEnabled(/*enabled=*/ true);

        const ncSupportedEnabled: crosAudioConfigMojom.AudioDevice =
            fakeCrosAudioConfig.createAudioDevice(
                fakeCrosAudioConfig.fakeInternalFrontMic, /*isActive=*/ true);
        ncSupportedEnabled.noiseCancellationState =
            crosAudioConfigMojom.AudioEffectState.kEnabled;

        const enabledNoiseCancellation:
            crosAudioConfigMojom.AudioSystemProperties = {
          ...defaultNoiseCancellation,
          inputDevices: [ncSupportedEnabled],
        };
        assertDeepEquals(
            enabledNoiseCancellation, onPropertiesUpdated['calls_'][2]![0]);

        crosAudioConfig.setNoiseCancellationEnabled(/*enabled=*/ false);
        assertDeepEquals(
            defaultNoiseCancellation, onPropertiesUpdated['calls_'][2]![0]);
      });

  test(
      'VerifySetNoiseCancellationEnabledDoesNotUpdateUnsupportedDevice', () => {
        const ncNotSupported: crosAudioConfigMojom.AudioDevice =
            fakeCrosAudioConfig.createAudioDevice(
                fakeCrosAudioConfig.fakeInternalFrontMic, /*isActive=*/ true);
        ncNotSupported.noiseCancellationState =
            crosAudioConfigMojom.AudioEffectState.kNotSupported;

        const noNoiseCancellation:
            crosAudioConfigMojom.AudioSystemProperties = {
          ...defaultProperties,
          inputDevices: [ncNotSupported],
        };
        crosAudioConfig.setAudioSystemProperties(noNoiseCancellation);
        assertDeepEquals(
            noNoiseCancellation, onPropertiesUpdated['calls_'][1]![0]);
        const expectedCallCount = 2;
        assertEquals(expectedCallCount, onPropertiesUpdated['calls_'].length);
        crosAudioConfig.setNoiseCancellationEnabled(/*enabled=*/ true);
        crosAudioConfig.setNoiseCancellationEnabled(/*enabled=*/ false);
        assertEquals(expectedCallCount, onPropertiesUpdated['calls_'].length);
      });
});