chromium/chromeos/ash/components/audio/audio_device_metrics_handler_unittest.cc

// 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.

#include "chromeos/ash/components/audio/audio_device_metrics_handler.h"

#include "base/test/metrics/histogram_tester.h"
#include "chromeos/ash/components/audio/audio_device.h"
#include "chromeos/ash/components/audio/audio_device_encoding.h"
#include "chromeos/ash/components/audio/audio_device_selection_test_base.h"

namespace ash {

namespace {

constexpr uint16_t kTimeDeltaInMinute = 2;

}  // namespace

class AudioDeviceMetricsHandlerTest : public AudioDeviceSelectionTestBase {
 public:
  const base::HistogramTester& histogram_tester() { return histogram_tester_; }
  AudioDeviceMetricsHandler& audio_device_metrics_handler() {
    return audio_device_metrics_handler_;
  }

 private:
  base::HistogramTester histogram_tester_;
  AudioDeviceMetricsHandler audio_device_metrics_handler_;
};

TEST_F(AudioDeviceMetricsHandlerTest,
       RecordAudioSelectionMetrics_NonChromeRestarts) {
  AudioDevice input_USB = AudioDevice(NewInputNode("USB"));
  AudioDevice input_BLUETOOTH = AudioDevice(NewInputNode("BLUETOOTH"));
  AudioDeviceList previous_devices = {input_USB};
  AudioDeviceList current_devices = {input_USB, input_BLUETOOTH};

  for (const bool is_input : {true, false}) {
    for (const bool is_switched : {true, false}) {
      audio_device_metrics_handler()
          .RecordAudioSelectionMetricsSeparatedByChromeRestarts(
              is_input, is_switched, /*is_chrome_restarts=*/false,
              previous_devices, current_devices);

      std::string system_switch_histogram_name =
          is_input ? AudioDeviceMetricsHandler::
                         kSystemSwitchInputAudioNonChromeRestarts
                   : AudioDeviceMetricsHandler::
                         kSystemSwitchOutputAudioNonChromeRestarts;
      histogram_tester().ExpectBucketCount(system_switch_histogram_name,
                                           is_switched, 1);

      std::string device_count_histogram_name;
      if (is_switched) {
        device_count_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemSwitchInputAudioDeviceCountNonChromeRestarts
                     : AudioDeviceMetricsHandler::
                           kSystemSwitchOutputAudioDeviceCountNonChromeRestarts;
      } else {
        device_count_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::
                      kSystemNotSwitchInputAudioDeviceCountNonChromeRestarts
                : AudioDeviceMetricsHandler::
                      kSystemNotSwitchOutputAudioDeviceCountNonChromeRestarts;
      }
      histogram_tester().ExpectBucketCount(device_count_histogram_name,
                                           current_devices.size(),
                                           /*expected_count=*/1);

      std::string device_set_histogram_name;
      if (is_switched) {
        device_set_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemSwitchInputAudioDeviceSetNonChromeRestarts
                     : AudioDeviceMetricsHandler::
                           kSystemSwitchOutputAudioDeviceSetNonChromeRestarts;
      } else {
        device_set_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::
                      kSystemNotSwitchInputAudioDeviceSetNonChromeRestarts
                : AudioDeviceMetricsHandler::
                      kSystemNotSwitchOutputAudioDeviceSetNonChromeRestarts;
      }

      histogram_tester().ExpectBucketCount(
          device_set_histogram_name, EncodeAudioDeviceSet(current_devices),
          /*expected_count=*/1);

      std::string before_and_after_device_set_histogram_name;
      if (is_switched) {
        before_and_after_device_set_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::
                      kSystemSwitchInputBeforeAndAfterAudioDeviceSetNonChromeRestarts
                : AudioDeviceMetricsHandler::
                      kSystemSwitchOutputBeforeAndAfterAudioDeviceSetNonChromeRestarts;
      } else {
        before_and_after_device_set_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::
                      kSystemNotSwitchInputBeforeAndAfterAudioDeviceSetNonChromeRestarts
                : AudioDeviceMetricsHandler::
                      kSystemNotSwitchOutputBeforeAndAfterAudioDeviceSetNonChromeRestarts;
      }
      histogram_tester().ExpectBucketCount(
          before_and_after_device_set_histogram_name,
          EncodeBeforeAndAfterAudioDeviceSets(previous_devices,
                                              current_devices),
          /*expected_count=*/1);

      // Test user override metrics.
      audio_device_metrics_handler()
          .RecordUserOverrideMetricsSeparatedByChromeRestarts(
              is_input, is_switched, /*is_chrome_restarts=*/false,
              /*time_delta_since_system_decision=*/kTimeDeltaInMinute);

      std::string user_override_histogram_name;
      if (is_switched) {
        user_override_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::
                      kUserOverrideSystemSwitchInputAudioNonChromeRestarts
                : AudioDeviceMetricsHandler::
                      kUserOverrideSystemSwitchOutputAudioNonChromeRestarts;

      } else {
        user_override_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::
                      kUserOverrideSystemNotSwitchInputAudioNonChromeRestarts
                : AudioDeviceMetricsHandler::
                      kUserOverrideSystemNotSwitchOutputAudioNonChromeRestarts;
      }

      histogram_tester().ExpectTotalCount(user_override_histogram_name,
                                          /*expected_count=*/1);
      histogram_tester().ExpectTimeBucketCount(
          user_override_histogram_name,
          base::Minutes(kTimeDeltaInMinute) / base::Minutes(1).InMilliseconds(),
          /*expected_count=*/1);
    }
  }
}

TEST_F(AudioDeviceMetricsHandlerTest,
       RecordAudioSelectionMetrics_ChromeRestarts) {
  AudioDevice input_USB = AudioDevice(NewInputNode("USB"));
  AudioDevice input_BLUETOOTH = AudioDevice(NewInputNode("BLUETOOTH"));
  AudioDeviceList previous_devices = {};
  AudioDeviceList current_devices = {input_USB, input_BLUETOOTH};

  for (const bool is_input : {true, false}) {
    for (const bool is_switched : {true, false}) {
      audio_device_metrics_handler()
          .RecordAudioSelectionMetricsSeparatedByChromeRestarts(
              is_input, is_switched, /*is_chrome_restarts=*/true,
              previous_devices, current_devices);

      std::string system_switch_histogram_name =
          is_input
              ? AudioDeviceMetricsHandler::kSystemSwitchInputAudioChromeRestarts
              : AudioDeviceMetricsHandler::
                    kSystemSwitchOutputAudioChromeRestarts;
      histogram_tester().ExpectBucketCount(system_switch_histogram_name,
                                           is_switched, 1);

      std::string device_count_histogram_name;
      if (is_switched) {
        device_count_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemSwitchInputAudioDeviceCountChromeRestarts
                     : AudioDeviceMetricsHandler::
                           kSystemSwitchOutputAudioDeviceCountChromeRestarts;
      } else {
        device_count_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemNotSwitchInputAudioDeviceCountChromeRestarts
                     : AudioDeviceMetricsHandler::
                           kSystemNotSwitchOutputAudioDeviceCountChromeRestarts;
      }
      histogram_tester().ExpectBucketCount(device_count_histogram_name,
                                           current_devices.size(),
                                           /*expected_count=*/1);

      std::string device_set_histogram_name;
      if (is_switched) {
        device_set_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemSwitchInputAudioDeviceSetChromeRestarts
                     : AudioDeviceMetricsHandler::
                           kSystemSwitchOutputAudioDeviceSetChromeRestarts;
      } else {
        device_set_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemNotSwitchInputAudioDeviceSetChromeRestarts
                     : AudioDeviceMetricsHandler::
                           kSystemNotSwitchOutputAudioDeviceSetChromeRestarts;
      }
      histogram_tester().ExpectBucketCount(
          device_set_histogram_name, EncodeAudioDeviceSet(current_devices),
          /*expected_count=*/1);

      std::string before_and_after_device_set_histogram_name;
      if (is_switched) {
        before_and_after_device_set_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::
                      kSystemSwitchInputBeforeAndAfterAudioDeviceSetChromeRestarts
                : AudioDeviceMetricsHandler::
                      kSystemSwitchOutputBeforeAndAfterAudioDeviceSetChromeRestarts;
      } else {
        before_and_after_device_set_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::
                      kSystemNotSwitchInputBeforeAndAfterAudioDeviceSetChromeRestarts
                : AudioDeviceMetricsHandler::
                      kSystemNotSwitchOutputBeforeAndAfterAudioDeviceSetChromeRestarts;
      }
      histogram_tester().ExpectBucketCount(
          before_and_after_device_set_histogram_name,
          EncodeBeforeAndAfterAudioDeviceSets(previous_devices,
                                              current_devices),
          /*expected_count=*/1);

      // Test user override metrics.
      audio_device_metrics_handler()
          .RecordUserOverrideMetricsSeparatedByChromeRestarts(
              is_input, is_switched, /*is_chrome_restarts=*/true,
              /*time_delta_since_system_decision=*/kTimeDeltaInMinute);

      std::string user_override_histogram_name;
      if (is_switched) {
        user_override_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kUserOverrideSystemSwitchInputAudioChromeRestarts
                     : AudioDeviceMetricsHandler::
                           kUserOverrideSystemSwitchOutputAudioChromeRestarts;

      } else {
        user_override_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::
                      kUserOverrideSystemNotSwitchInputAudioChromeRestarts
                : AudioDeviceMetricsHandler::
                      kUserOverrideSystemNotSwitchOutputAudioChromeRestarts;
      }

      histogram_tester().ExpectTotalCount(user_override_histogram_name,
                                          /*expected_count=*/1);
      histogram_tester().ExpectTimeBucketCount(
          user_override_histogram_name,
          base::Minutes(kTimeDeltaInMinute) / base::Minutes(1).InMilliseconds(),
          /*expected_count=*/1);
    }
  }
}

// Tests that no audio selection metrics are fired when device set hasn't
// changed.
TEST_F(AudioDeviceMetricsHandlerTest,
       NoAudioSelectionMetricsRecordedWhenNoDeviceChanges) {
  AudioDevice input_USB = AudioDevice(NewInputNode("USB"));
  AudioDevice input_BLUETOOTH = AudioDevice(NewInputNode("BLUETOOTH"));
  AudioDeviceMap previous_devices_map;
  previous_devices_map[input_USB.id] = input_USB;
  previous_devices_map[input_BLUETOOTH.id] = input_BLUETOOTH;
  AudioDeviceMap current_devices_map;
  current_devices_map[input_USB.id] = input_USB;
  current_devices_map[input_BLUETOOTH.id] = input_BLUETOOTH;
  AudioDeviceList previous_devices = {input_USB, input_BLUETOOTH};
  AudioDeviceList current_devices = {input_USB, input_BLUETOOTH};

  for (const bool is_input : {true, false}) {
    for (const bool is_switched : {true, false}) {
      audio_device_metrics_handler().MaybeRecordSystemSwitchDecisionAndContext(
          is_input, /*has_alternative_device=*/true, is_switched,
          current_devices_map, previous_devices_map);

      std::string system_switch_histogram_name =
          is_input ? AudioDeviceMetricsHandler::kSystemSwitchInputAudio
                   : AudioDeviceMetricsHandler::kSystemSwitchOutputAudio;
      histogram_tester().ExpectTotalCount(system_switch_histogram_name, 0);

      std::string device_count_histogram_name;
      if (is_switched) {
        device_count_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::kSystemSwitchInputAudioDeviceCount
                : AudioDeviceMetricsHandler::
                      kSystemSwitchOutputAudioDeviceCount;
      } else {
        device_count_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemNotSwitchInputAudioDeviceCount
                     : AudioDeviceMetricsHandler::
                           kSystemNotSwitchOutputAudioDeviceCount;
      }
      histogram_tester().ExpectTotalCount(device_count_histogram_name,
                                          /*expected_count=*/0);

      std::string device_set_histogram_name;
      if (is_switched) {
        device_set_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::kSystemSwitchInputAudioDeviceSet
                : AudioDeviceMetricsHandler::kSystemSwitchOutputAudioDeviceSet;
      } else {
        device_set_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::kSystemNotSwitchInputAudioDeviceSet
                : AudioDeviceMetricsHandler::
                      kSystemNotSwitchOutputAudioDeviceSet;
      }

      histogram_tester().ExpectTotalCount(device_set_histogram_name,
                                          /*expected_count=*/0);

      std::string before_and_after_device_set_histogram_name;
      if (is_switched) {
        before_and_after_device_set_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemSwitchInputBeforeAndAfterAudioDeviceSet
                     : AudioDeviceMetricsHandler::
                           kSystemSwitchOutputBeforeAndAfterAudioDeviceSet;
      } else {
        before_and_after_device_set_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemNotSwitchInputBeforeAndAfterAudioDeviceSet
                     : AudioDeviceMetricsHandler::
                           kSystemNotSwitchOutputBeforeAndAfterAudioDeviceSet;
      }
      histogram_tester().ExpectTotalCount(
          before_and_after_device_set_histogram_name,
          /*expected_count=*/0);
    }
  }
}

TEST_F(AudioDeviceMetricsHandlerTest, RecordConsecutiveAudioDevicsChange) {
  uint16_t expected_input_devices_changed_count = 0;
  uint16_t expected_output_devices_changed_count = 0;
  uint16_t expected_input_devices_added_count = 0;
  uint16_t expected_output_devices_added_count = 0;
  for (const bool is_input : {true, false}) {
    for (const bool is_device_added : {true, false}) {
      audio_device_metrics_handler()
          .RecordConsecutiveAudioDevicsChangeTimeElapsed(is_input,
                                                         is_device_added);
      std::string devices_changed_histogram_name =
          is_input ? AudioDeviceMetricsHandler::kConsecutiveInputDevicsChanged
                   : AudioDeviceMetricsHandler::kConsecutiveOutputDevicsChanged;
      histogram_tester().ExpectTotalCount(
          devices_changed_histogram_name,
          (is_input ? expected_input_devices_changed_count
                    : expected_output_devices_changed_count)++);

      std::string devices_added_histogram_name =
          is_input ? AudioDeviceMetricsHandler::kConsecutiveInputDevicsChanged
                   : AudioDeviceMetricsHandler::kConsecutiveOutputDevicsChanged;
      histogram_tester().ExpectTotalCount(
          devices_added_histogram_name,
          is_input ? expected_input_devices_added_count
                   : expected_output_devices_added_count);
      if (is_device_added) {
        (is_input ? expected_input_devices_added_count
                  : expected_output_devices_added_count)++;
      }
    }
  }
}

TEST_F(AudioDeviceMetricsHandlerTest,
       RecordConsecutiveAudioDevicsChangeTimeElapsed) {
  constexpr uint16_t kTimeDeltaInSecondA = 5;
  constexpr uint16_t kTimeDeltaInSecondB = 5;

  for (const bool is_input : {true, false}) {
    // Test consecutive devices change.
    audio_device_metrics_handler()
        .RecordConsecutiveAudioDevicsChangeTimeElapsed(
            is_input,
            /*is_device_added=*/false);
    FastForwardBy(base::Seconds(kTimeDeltaInSecondA));
    audio_device_metrics_handler()
        .RecordConsecutiveAudioDevicsChangeTimeElapsed(
            is_input,
            /*is_device_added=*/false);
    std::string devices_changed_histogram_name =
        is_input ? AudioDeviceMetricsHandler::kConsecutiveInputDevicsChanged
                 : AudioDeviceMetricsHandler::kConsecutiveOutputDevicsChanged;
    histogram_tester().ExpectBucketCount(devices_changed_histogram_name,
                                         /*sample=*/kTimeDeltaInSecondA,
                                         /*expected_count=*/1);

    // Test consecutive devices addition.
    audio_device_metrics_handler()
        .RecordConsecutiveAudioDevicsChangeTimeElapsed(
            is_input,
            /*is_device_added=*/true);
    FastForwardBy(base::Seconds(kTimeDeltaInSecondB));
    audio_device_metrics_handler()
        .RecordConsecutiveAudioDevicsChangeTimeElapsed(
            is_input,
            /*is_device_added=*/true);
    std::string devices_added_histogram_name =
        is_input ? AudioDeviceMetricsHandler::kConsecutiveInputDevicsAdded
                 : AudioDeviceMetricsHandler::kConsecutiveOutputDevicsAdded;
    histogram_tester().ExpectBucketCount(devices_added_histogram_name,
                                         /*sample=*/kTimeDeltaInSecondB,
                                         /*expected_count=*/1);
  }
}

// Tests the audio selection exception rules metrics are fired.
TEST_F(AudioDeviceMetricsHandlerTest, RecordExceptionRulesMet) {
  for (int ruleInt = static_cast<int>(
           AudioDeviceMetricsHandler::AudioSelectionExceptionRules::
               kInputRule1HotPlugPrivilegedDevice);
       ruleInt !=
       static_cast<int>(
           AudioDeviceMetricsHandler::AudioSelectionExceptionRules::kMaxValue);
       ruleInt++) {
    AudioDeviceMetricsHandler::AudioSelectionExceptionRules rule =
        static_cast<AudioDeviceMetricsHandler::AudioSelectionExceptionRules>(
            ruleInt);

    // No histogram is recorded before firing.
    histogram_tester().ExpectBucketCount(
        AudioDeviceMetricsHandler::kAudioSelectionExceptionRuleMetrics,
        /*sample=*/rule,
        /*expected_count=*/0);

    audio_device_metrics_handler().RecordExceptionRulesMet(rule);

    // Histogram is recorded after firing.
    histogram_tester().ExpectBucketCount(
        AudioDeviceMetricsHandler::kAudioSelectionExceptionRuleMetrics,
        /*sample=*/rule,
        /*expected_count=*/1);
    histogram_tester().ExpectTotalCount(
        AudioDeviceMetricsHandler::kAudioSelectionExceptionRuleMetrics,
        /*expected_count=*/ruleInt + 1);
  }
}

// Tests the audio selection notification events metrics are fired.
TEST_F(AudioDeviceMetricsHandlerTest, NotificationEvents) {
  for (int eventInt = static_cast<int>(
           AudioDeviceMetricsHandler::AudioSelectionNotificationEvents::
               kNotificationWithBothInputAndOutputDevicesShowsUp);
       eventInt !=
       static_cast<int>(AudioDeviceMetricsHandler::
                            AudioSelectionNotificationEvents::kMaxValue);
       eventInt++) {
    AudioDeviceMetricsHandler::AudioSelectionNotificationEvents event =
        static_cast<
            AudioDeviceMetricsHandler::AudioSelectionNotificationEvents>(
            eventInt);

    // No histogram is recorded before firing.
    histogram_tester().ExpectBucketCount(
        AudioDeviceMetricsHandler::kAudioSelectionNotification,
        /*sample=*/event,
        /*expected_count=*/0);

    audio_device_metrics_handler().RecordNotificationEvents(event);

    // Histogram is recorded after firing.
    histogram_tester().ExpectBucketCount(
        AudioDeviceMetricsHandler::kAudioSelectionNotification,
        /*sample=*/event,
        /*expected_count=*/1);
    histogram_tester().ExpectTotalCount(
        AudioDeviceMetricsHandler::kAudioSelectionNotification,
        /*expected_count=*/eventInt + 1);
  }
}

// Tests that no audio selection metrics are fired when there is only one device
// currently connected.
TEST_F(AudioDeviceMetricsHandlerTest,
       NoAudioSelectionMetricsRecordedWhenOnlyOneAudioDeviceConnected) {
  AudioDevice input_USB = AudioDevice(NewInputNode("USB"));
  AudioDevice input_BLUETOOTH = AudioDevice(NewInputNode("BLUETOOTH"));
  AudioDeviceMap previous_devices_map;
  previous_devices_map[input_USB.id] = input_USB;
  previous_devices_map[input_BLUETOOTH.id] = input_BLUETOOTH;
  AudioDeviceMap current_devices_map;
  current_devices_map[input_USB.id] = input_USB;
  AudioDeviceList previous_devices = {input_USB, input_BLUETOOTH};
  AudioDeviceList current_devices = {input_USB};

  for (const bool is_input : {true, false}) {
    for (const bool is_switched : {true, false}) {
      audio_device_metrics_handler().MaybeRecordSystemSwitchDecisionAndContext(
          is_input, /*has_alternative_device=*/true, is_switched,
          current_devices_map, previous_devices_map);

      std::string system_switch_histogram_name =
          is_input ? AudioDeviceMetricsHandler::kSystemSwitchInputAudio
                   : AudioDeviceMetricsHandler::kSystemSwitchOutputAudio;
      histogram_tester().ExpectTotalCount(system_switch_histogram_name, 0);

      std::string device_count_histogram_name;
      if (is_switched) {
        device_count_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::kSystemSwitchInputAudioDeviceCount
                : AudioDeviceMetricsHandler::
                      kSystemSwitchOutputAudioDeviceCount;
      } else {
        device_count_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemNotSwitchInputAudioDeviceCount
                     : AudioDeviceMetricsHandler::
                           kSystemNotSwitchOutputAudioDeviceCount;
      }
      histogram_tester().ExpectTotalCount(device_count_histogram_name,
                                          /*expected_count=*/0);

      std::string device_set_histogram_name;
      if (is_switched) {
        device_set_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::kSystemSwitchInputAudioDeviceSet
                : AudioDeviceMetricsHandler::kSystemSwitchOutputAudioDeviceSet;
      } else {
        device_set_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::kSystemNotSwitchInputAudioDeviceSet
                : AudioDeviceMetricsHandler::
                      kSystemNotSwitchOutputAudioDeviceSet;
      }

      histogram_tester().ExpectTotalCount(device_set_histogram_name,
                                          /*expected_count=*/0);

      std::string before_and_after_device_set_histogram_name;
      if (is_switched) {
        before_and_after_device_set_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemSwitchInputBeforeAndAfterAudioDeviceSet
                     : AudioDeviceMetricsHandler::
                           kSystemSwitchOutputBeforeAndAfterAudioDeviceSet;
      } else {
        before_and_after_device_set_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemNotSwitchInputBeforeAndAfterAudioDeviceSet
                     : AudioDeviceMetricsHandler::
                           kSystemNotSwitchOutputBeforeAndAfterAudioDeviceSet;
      }
      histogram_tester().ExpectTotalCount(
          before_and_after_device_set_histogram_name,
          /*expected_count=*/0);
    }
  }
}

// Tests that no audio selection metrics are fired when there is no device
// currently connected.
TEST_F(AudioDeviceMetricsHandlerTest,
       NoAudioSelectionMetricsRecordedWhenNoAudioDeviceConnected) {
  AudioDevice input_USB = AudioDevice(NewInputNode("USB"));
  AudioDeviceMap previous_devices_map;
  previous_devices_map[input_USB.id] = input_USB;
  AudioDeviceMap current_devices_map;
  AudioDeviceList previous_devices = {input_USB};
  AudioDeviceList current_devices = {};

  for (const bool is_input : {true, false}) {
    for (const bool is_switched : {true, false}) {
      audio_device_metrics_handler().MaybeRecordSystemSwitchDecisionAndContext(
          is_input, /*has_alternative_device=*/true, is_switched,
          current_devices_map, previous_devices_map);

      std::string system_switch_histogram_name =
          is_input ? AudioDeviceMetricsHandler::kSystemSwitchInputAudio
                   : AudioDeviceMetricsHandler::kSystemSwitchOutputAudio;
      histogram_tester().ExpectTotalCount(system_switch_histogram_name, 0);

      std::string device_count_histogram_name;
      if (is_switched) {
        device_count_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::kSystemSwitchInputAudioDeviceCount
                : AudioDeviceMetricsHandler::
                      kSystemSwitchOutputAudioDeviceCount;
      } else {
        device_count_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemNotSwitchInputAudioDeviceCount
                     : AudioDeviceMetricsHandler::
                           kSystemNotSwitchOutputAudioDeviceCount;
      }
      histogram_tester().ExpectTotalCount(device_count_histogram_name,
                                          /*expected_count=*/0);

      std::string device_set_histogram_name;
      if (is_switched) {
        device_set_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::kSystemSwitchInputAudioDeviceSet
                : AudioDeviceMetricsHandler::kSystemSwitchOutputAudioDeviceSet;
      } else {
        device_set_histogram_name =
            is_input
                ? AudioDeviceMetricsHandler::kSystemNotSwitchInputAudioDeviceSet
                : AudioDeviceMetricsHandler::
                      kSystemNotSwitchOutputAudioDeviceSet;
      }

      histogram_tester().ExpectTotalCount(device_set_histogram_name,
                                          /*expected_count=*/0);

      std::string before_and_after_device_set_histogram_name;
      if (is_switched) {
        before_and_after_device_set_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemSwitchInputBeforeAndAfterAudioDeviceSet
                     : AudioDeviceMetricsHandler::
                           kSystemSwitchOutputBeforeAndAfterAudioDeviceSet;
      } else {
        before_and_after_device_set_histogram_name =
            is_input ? AudioDeviceMetricsHandler::
                           kSystemNotSwitchInputBeforeAndAfterAudioDeviceSet
                     : AudioDeviceMetricsHandler::
                           kSystemNotSwitchOutputBeforeAndAfterAudioDeviceSet;
      }
      histogram_tester().ExpectTotalCount(
          before_and_after_device_set_histogram_name,
          /*expected_count=*/0);
    }
  }
}

}  // namespace ash