Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7f565a9 authored by shihchienc's avatar shihchienc
Browse files

Add BluetoothLeAudioCodecsProvider Unit Test

Add unit test for BluetoothLeAudioCodecsProvider and simplify
the public interface of BluetoothLeAudioCodecsProvider class

Bug: 253569201
Test: atest VtsHalBluetoothAudioTargetTest
Test: atest BluetoothLeAudioCodecsProviderTest
Test: manual test
Change-Id: I064eb4058b129a571cf9dbb91b85bafe7236b735
parent 2b49939f
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -63,6 +63,31 @@ cc_library_shared {
    generated_headers: ["le_audio_codec_capabilities"],
}

cc_test {
    name: "BluetoothLeAudioCodecsProviderTest",
    srcs: [
        "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
        "aidl_session/BluetoothLeAudioCodecsProviderTest.cpp",
    ],
    header_libs: [
        "libxsdc-utils",
    ],
    shared_libs: [
        "libbase",
        "libbinder_ndk",
        "android.hardware.bluetooth.audio-V2-ndk",
        "libxml2",
    ],
    test_suites: [
        "general-tests",
    ],
    test_options: {
        unit_test: false,
    },
    generated_sources: ["le_audio_codec_capabilities"],
    generated_headers: ["le_audio_codec_capabilities"],
}

xsd_config {
    name: "le_audio_codec_capabilities",
    srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"],
+4 −1
Original line number Diff line number Diff line
@@ -398,8 +398,11 @@ BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(
  }

  if (kDefaultOffloadLeAudioCapabilities.empty()) {
    auto le_audio_offload_setting =
        BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile();
    kDefaultOffloadLeAudioCapabilities =
        BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities();
        BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
            le_audio_offload_setting);
  }

  return kDefaultOffloadLeAudioCapabilities;
+34 −5
Original line number Diff line number Diff line
@@ -34,20 +34,40 @@ static const AudioLocation kMonoAudio = AudioLocation::UNKNOWN;

static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;

static bool isInvalidFileContent = false;

std::optional<setting::LeAudioOffloadSetting>
BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile() {
  if (!leAudioCodecCapabilities.empty() || isInvalidFileContent) {
    return std::nullopt;
  }
  auto le_audio_offload_setting =
      setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
  if (!le_audio_offload_setting.has_value()) {
    LOG(ERROR) << __func__ << ": Failed to read "
               << kLeAudioCodecCapabilitiesFile;
  }
  return le_audio_offload_setting;
}

std::vector<LeAudioCodecCapabilitiesSetting>
BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() {
BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
    const std::optional<setting::LeAudioOffloadSetting>&
        le_audio_offload_setting) {
  if (!leAudioCodecCapabilities.empty()) {
    return leAudioCodecCapabilities;
  }

  const auto le_audio_offload_setting =
      setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
  if (!le_audio_offload_setting.has_value()) {
    LOG(ERROR) << __func__ << ": Failed to read "
               << kLeAudioCodecCapabilitiesFile;
    LOG(ERROR)
        << __func__
        << ": input le_audio_offload_setting content need to be non empty";
    return {};
  }

  ClearLeAudioCodecCapabilities();
  isInvalidFileContent = true;

  std::vector<setting::Scenario> supported_scenarios =
      GetScenarios(le_audio_offload_setting);
  if (supported_scenarios.empty()) {
@@ -79,9 +99,18 @@ BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() {

  leAudioCodecCapabilities =
      ComposeLeAudioCodecCapabilities(supported_scenarios);
  isInvalidFileContent = leAudioCodecCapabilities.empty();

  return leAudioCodecCapabilities;
}

void BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities() {
  leAudioCodecCapabilities.clear();
  configuration_map_.clear();
  codec_configuration_map_.clear();
  strategy_configuration_map_.clear();
}

std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
    const std::optional<setting::LeAudioOffloadSetting>&
        le_audio_offload_setting) {
+6 −1
Original line number Diff line number Diff line
@@ -31,8 +31,13 @@ namespace audio {

class BluetoothLeAudioCodecsProvider {
 public:
  static std::optional<setting::LeAudioOffloadSetting>
  ParseFromLeAudioOffloadSettingFile();
  static std::vector<LeAudioCodecCapabilitiesSetting>
  GetLeAudioCodecCapabilities();
  GetLeAudioCodecCapabilities(
      const std::optional<setting::LeAudioOffloadSetting>&
          le_audio_offload_setting);
  static void ClearLeAudioCodecCapabilities();

 private:
  static inline std::unordered_map<std::string, setting::Configuration>
+373 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <gtest/gtest.h>

#include <optional>
#include <tuple>

#include "BluetoothLeAudioCodecsProvider.h"

using aidl::android::hardware::bluetooth::audio::BluetoothLeAudioCodecsProvider;
using aidl::android::hardware::bluetooth::audio::
    LeAudioCodecCapabilitiesSetting;
using aidl::android::hardware::bluetooth::audio::setting::AudioLocation;
using aidl::android::hardware::bluetooth::audio::setting::CodecConfiguration;
using aidl::android::hardware::bluetooth::audio::setting::
    CodecConfigurationList;
using aidl::android::hardware::bluetooth::audio::setting::CodecType;
using aidl::android::hardware::bluetooth::audio::setting::Configuration;
using aidl::android::hardware::bluetooth::audio::setting::ConfigurationList;
using aidl::android::hardware::bluetooth::audio::setting::LeAudioOffloadSetting;
using aidl::android::hardware::bluetooth::audio::setting::Scenario;
using aidl::android::hardware::bluetooth::audio::setting::ScenarioList;
using aidl::android::hardware::bluetooth::audio::setting::StrategyConfiguration;
using aidl::android::hardware::bluetooth::audio::setting::
    StrategyConfigurationList;

typedef std::tuple<std::vector<ScenarioList>, std::vector<ConfigurationList>,
                   std::vector<CodecConfigurationList>,
                   std::vector<StrategyConfigurationList>>
    OffloadSetting;

// Define valid components for each list
// Scenario
static const Scenario kValidScenario(std::make_optional("OneChanStereo_16_1"),
                                     std::make_optional("OneChanStereo_16_1"));
// Configuration
static const Configuration kValidConfigOneChanStereo_16_1(
    std::make_optional("OneChanStereo_16_1"), std::make_optional("LC3_16k_1"),
    std::make_optional("STEREO_ONE_CIS_PER_DEVICE"));
// CodecConfiguration
static const CodecConfiguration kValidCodecLC3_16k_1(
    std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
    std::nullopt, std::make_optional(16000), std::make_optional(7500),
    std::make_optional(30), std::nullopt);
// StrategyConfiguration
static const StrategyConfiguration kValidStrategyStereoOneCis(
    std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
    std::make_optional(AudioLocation::STEREO), std::make_optional(2),
    std::make_optional(1));
static const StrategyConfiguration kValidStrategyStereoTwoCis(
    std::make_optional("STEREO_TWO_CISES_PER_DEVICE"),
    std::make_optional(AudioLocation::STEREO), std::make_optional(1),
    std::make_optional(2));
static const StrategyConfiguration kValidStrategyMonoOneCis(
    std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
    std::make_optional(AudioLocation::MONO), std::make_optional(1),
    std::make_optional(1));

// Define valid test list built from above valid components
// Scenario, Configuration, CodecConfiguration, StrategyConfiguration
static const std::vector<ScenarioList> kValidScenarioList = {
    ScenarioList(std::vector<Scenario>{kValidScenario})};
static const std::vector<ConfigurationList> kValidConfigurationList = {
    ConfigurationList(
        std::vector<Configuration>{kValidConfigOneChanStereo_16_1})};
static const std::vector<CodecConfigurationList> kValidCodecConfigurationList =
    {CodecConfigurationList(
        std::vector<CodecConfiguration>{kValidCodecLC3_16k_1})};
static const std::vector<StrategyConfigurationList>
    kValidStrategyConfigurationList = {
        StrategyConfigurationList(std::vector<StrategyConfiguration>{
            kValidStrategyStereoOneCis, kValidStrategyStereoTwoCis,
            kValidStrategyMonoOneCis})};

class BluetoothLeAudioCodecsProviderTest
    : public ::testing::TestWithParam<OffloadSetting> {
 public:
  static std::vector<OffloadSetting> CreateTestCases(
      const std::vector<ScenarioList>& scenario_lists,
      const std::vector<ConfigurationList>& configuration_lists,
      const std::vector<CodecConfigurationList>& codec_configuration_lists,
      const std::vector<StrategyConfigurationList>&
          strategy_configuration_lists) {
    // make each vector in output test_cases has only one element
    // to match the input of test params
    // normally only one vector in input has multiple elements
    // we just split elements in this vector to several vector
    std::vector<OffloadSetting> test_cases;
    for (const auto& scenario_list : scenario_lists) {
      for (const auto& configuration_list : configuration_lists) {
        for (const auto& codec_configuration_list : codec_configuration_lists) {
          for (const auto& strategy_configuration_list :
               strategy_configuration_lists) {
            test_cases.push_back(CreateTestCase(
                scenario_list, configuration_list, codec_configuration_list,
                strategy_configuration_list));
          }
        }
      }
    }
    return test_cases;
  }

 protected:
  void Initialize() {
    BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities();
  }

  std::vector<LeAudioCodecCapabilitiesSetting> RunTestCase() {
    auto& [scenario_lists, configuration_lists, codec_configuration_lists,
           strategy_configuration_lists] = GetParam();
    LeAudioOffloadSetting le_audio_offload_setting(
        scenario_lists, configuration_lists, codec_configuration_lists,
        strategy_configuration_lists);
    auto le_audio_codec_capabilities =
        BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
            std::make_optional(le_audio_offload_setting));
    return le_audio_codec_capabilities;
  }

 private:
  static inline OffloadSetting CreateTestCase(
      const ScenarioList& scenario_list,
      const ConfigurationList& configuration_list,
      const CodecConfigurationList& codec_configuration_list,
      const StrategyConfigurationList& strategy_configuration_list) {
    return std::make_tuple(
        std::vector<ScenarioList>{scenario_list},
        std::vector<ConfigurationList>{configuration_list},
        std::vector<CodecConfigurationList>{codec_configuration_list},
        std::vector<StrategyConfigurationList>{strategy_configuration_list});
  }
};

class GetScenariosTest : public BluetoothLeAudioCodecsProviderTest {
 public:
  static std::vector<ScenarioList> CreateInvalidScenarios() {
    std::vector<ScenarioList> invalid_scenario_test_cases;
    invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
        Scenario(std::nullopt, std::make_optional("OneChanStereo_16_1"))}));

    invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
        Scenario(std::make_optional("OneChanStereo_16_1"), std::nullopt)}));

    invalid_scenario_test_cases.push_back(ScenarioList(
        std::vector<Scenario>{Scenario(std::nullopt, std::nullopt)}));

    invalid_scenario_test_cases.push_back(
        ScenarioList(std::vector<Scenario>{}));

    return invalid_scenario_test_cases;
  }
};

TEST_P(GetScenariosTest, InvalidScenarios) {
  Initialize();
  auto le_audio_codec_capabilities = RunTestCase();
  ASSERT_TRUE(le_audio_codec_capabilities.empty());
}

class UpdateConfigurationsToMapTest
    : public BluetoothLeAudioCodecsProviderTest {
 public:
  static std::vector<ConfigurationList> CreateInvalidConfigurations() {
    std::vector<ConfigurationList> invalid_configuration_test_cases;
    invalid_configuration_test_cases.push_back(
        ConfigurationList(std::vector<Configuration>{
            Configuration(std::nullopt, std::make_optional("LC3_16k_1"),
                          std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))}));

    invalid_configuration_test_cases.push_back(
        ConfigurationList(std::vector<Configuration>{Configuration(
            std::make_optional("OneChanStereo_16_1"), std::nullopt,
            std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))}));

    invalid_configuration_test_cases.push_back(
        ConfigurationList(std::vector<Configuration>{
            Configuration(std::make_optional("OneChanStereo_16_1"),
                          std::make_optional("LC3_16k_1"), std::nullopt)}));

    invalid_configuration_test_cases.push_back(
        ConfigurationList(std::vector<Configuration>{}));

    return invalid_configuration_test_cases;
  }
};

TEST_P(UpdateConfigurationsToMapTest, InvalidConfigurations) {
  Initialize();
  auto le_audio_codec_capabilities = RunTestCase();
  ASSERT_TRUE(le_audio_codec_capabilities.empty());
}

class UpdateCodecConfigurationsToMapTest
    : public BluetoothLeAudioCodecsProviderTest {
 public:
  static std::vector<CodecConfigurationList>
  CreateInvalidCodecConfigurations() {
    std::vector<CodecConfigurationList> invalid_codec_configuration_test_cases;
    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
        std::vector<CodecConfiguration>{CodecConfiguration(
            std::nullopt, std::make_optional(CodecType::LC3), std::nullopt,
            std::make_optional(16000), std::make_optional(7500),
            std::make_optional(30), std::nullopt)}));

    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
        std::vector<CodecConfiguration>{CodecConfiguration(
            std::make_optional("LC3_16k_1"), std::nullopt, std::nullopt,
            std::make_optional(16000), std::make_optional(7500),
            std::make_optional(30), std::nullopt)}));

    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
        std::vector<CodecConfiguration>{CodecConfiguration(
            std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
            std::nullopt, std::nullopt, std::make_optional(7500),
            std::make_optional(30), std::nullopt)}));

    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
        std::vector<CodecConfiguration>{CodecConfiguration(
            std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
            std::nullopt, std::make_optional(16000), std::nullopt,
            std::make_optional(30), std::nullopt)}));

    invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
        std::vector<CodecConfiguration>{CodecConfiguration(
            std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
            std::nullopt, std::make_optional(16000), std::make_optional(7500),
            std::nullopt, std::nullopt)}));

    invalid_codec_configuration_test_cases.push_back(
        CodecConfigurationList(std::vector<CodecConfiguration>{}));

    return invalid_codec_configuration_test_cases;
  }
};

TEST_P(UpdateCodecConfigurationsToMapTest, InvalidCodecConfigurations) {
  Initialize();
  auto le_audio_codec_capabilities = RunTestCase();
  ASSERT_TRUE(le_audio_codec_capabilities.empty());
}

class UpdateStrategyConfigurationsToMapTest
    : public BluetoothLeAudioCodecsProviderTest {
 public:
  static std::vector<StrategyConfigurationList>
  CreateInvalidStrategyConfigurations() {
    std::vector<StrategyConfigurationList>
        invalid_strategy_configuration_test_cases;
    invalid_strategy_configuration_test_cases.push_back(
        StrategyConfigurationList(
            std::vector<StrategyConfiguration>{StrategyConfiguration(
                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
                std::make_optional(AudioLocation::STEREO),
                std::make_optional(2), std::make_optional(2))}));

    invalid_strategy_configuration_test_cases.push_back(
        StrategyConfigurationList(
            std::vector<StrategyConfiguration>{StrategyConfiguration(
                std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
                std::make_optional(AudioLocation::STEREO),
                std::make_optional(2), std::make_optional(2))}));

    invalid_strategy_configuration_test_cases.push_back(
        StrategyConfigurationList(
            std::vector<StrategyConfiguration>{StrategyConfiguration(
                std::nullopt, std::make_optional(AudioLocation::STEREO),
                std::make_optional(2), std::make_optional(1))}));

    invalid_strategy_configuration_test_cases.push_back(
        StrategyConfigurationList(
            std::vector<StrategyConfiguration>{StrategyConfiguration(
                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
                std::make_optional(2), std::make_optional(1))}));

    invalid_strategy_configuration_test_cases.push_back(
        StrategyConfigurationList(
            std::vector<StrategyConfiguration>{StrategyConfiguration(
                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
                std::make_optional(AudioLocation::STEREO), std::nullopt,
                std::make_optional(1))}));

    invalid_strategy_configuration_test_cases.push_back(
        StrategyConfigurationList(
            std::vector<StrategyConfiguration>{StrategyConfiguration(
                std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
                std::make_optional(AudioLocation::STEREO),
                std::make_optional(2), std::nullopt)}));

    invalid_strategy_configuration_test_cases.push_back(
        StrategyConfigurationList(std::vector<StrategyConfiguration>{}));

    return invalid_strategy_configuration_test_cases;
  }
};

TEST_P(UpdateStrategyConfigurationsToMapTest, InvalidStrategyConfigurations) {
  Initialize();
  auto le_audio_codec_capabilities = RunTestCase();
  ASSERT_TRUE(le_audio_codec_capabilities.empty());
}

class ComposeLeAudioCodecCapabilitiesTest
    : public BluetoothLeAudioCodecsProviderTest {
 public:
};

TEST_P(ComposeLeAudioCodecCapabilitiesTest, CodecCapabilitiesNotEmpty) {
  Initialize();
  auto le_audio_codec_capabilities = RunTestCase();
  ASSERT_TRUE(!le_audio_codec_capabilities.empty());
}

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GetScenariosTest);
INSTANTIATE_TEST_SUITE_P(
    BluetoothLeAudioCodecsProviderTest, GetScenariosTest,
    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
        GetScenariosTest::CreateInvalidScenarios(), kValidConfigurationList,
        kValidCodecConfigurationList, kValidStrategyConfigurationList)));

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UpdateConfigurationsToMapTest);
INSTANTIATE_TEST_SUITE_P(
    BluetoothLeAudioCodecsProviderTest, UpdateConfigurationsToMapTest,
    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
        kValidScenarioList,
        UpdateConfigurationsToMapTest::CreateInvalidConfigurations(),
        kValidCodecConfigurationList, kValidStrategyConfigurationList)));

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
    UpdateCodecConfigurationsToMapTest);
INSTANTIATE_TEST_SUITE_P(
    BluetoothLeAudioCodecsProviderTest, UpdateCodecConfigurationsToMapTest,
    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
        kValidScenarioList, kValidConfigurationList,
        UpdateCodecConfigurationsToMapTest::CreateInvalidCodecConfigurations(),
        kValidStrategyConfigurationList)));

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
    UpdateStrategyConfigurationsToMapTest);
INSTANTIATE_TEST_SUITE_P(
    BluetoothLeAudioCodecsProviderTest, UpdateStrategyConfigurationsToMapTest,
    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
        kValidScenarioList, kValidConfigurationList,
        kValidCodecConfigurationList,
        UpdateStrategyConfigurationsToMapTest::
            CreateInvalidStrategyConfigurations())));

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
    ComposeLeAudioCodecCapabilitiesTest);
INSTANTIATE_TEST_SUITE_P(
    BluetoothLeAudioCodecsProviderTest, ComposeLeAudioCodecCapabilitiesTest,
    ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
        kValidScenarioList, kValidConfigurationList,
        kValidCodecConfigurationList, kValidStrategyConfigurationList)));

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}