From 27d5d1a4f778fe76867dd03537eadfaf6cc21087 Mon Sep 17 00:00:00 2001 From: dvdli Date: Mon, 23 Nov 2020 11:39:27 +0800 Subject: add unit tests for mixer related functions --- tests/src/mixer_test.cc | 264 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 tests/src/mixer_test.cc diff --git a/tests/src/mixer_test.cc b/tests/src/mixer_test.cc new file mode 100644 index 0000000..333c9d7 --- /dev/null +++ b/tests/src/mixer_test.cc @@ -0,0 +1,264 @@ +/* mixer_test.c +** +** Copyright 2020, The Android Open Source Project +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** * Neither the name of The Android Open Source Project nor the names of +** its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +** DAMAGE. +*/ +#include "pcm_test_device.h" + +#include +#include +#include +#include + +#include + +#include "tinyalsa/mixer.h" + +namespace tinyalsa { +namespace testing { + +class MixerTest : public ::testing::TestWithParam { + protected: + MixerTest() : mixer_object(nullptr) {} + virtual ~MixerTest() = default; + + virtual void SetUp() override { + unsigned int card = GetParam(); + mixer_object = mixer_open(card); + ASSERT_NE(mixer_object, nullptr); + } + + virtual void TearDown() override { + mixer_close(mixer_object); + } + + mixer *mixer_object; +}; + +TEST_P(MixerTest, AddNewControls) { + ASSERT_EQ(mixer_add_new_ctls(mixer_object), 0); +} + +TEST_P(MixerTest, GetName) { + const char *name = mixer_get_name(mixer_object); + std::cout << name << std::endl; + ASSERT_STRNE(name, ""); +} + +TEST_P(MixerTest, GetNumberOfControls) { + unsigned int nums = mixer_get_num_ctls(mixer_object); + std::cout << nums << std::endl; + ASSERT_GT(nums, 0); +} + +class MixerControlsTest : public MixerTest { + protected: + MixerControlsTest() : number_of_controls(0), controls(nullptr) {} + virtual ~MixerControlsTest() = default; + + virtual void SetUp() override { + MixerTest::SetUp(); + + number_of_controls = mixer_get_num_ctls(mixer_object); + ASSERT_GT(number_of_controls, 0); + + controls = std::make_unique(number_of_controls); + ASSERT_NE(controls, nullptr); + + for (unsigned int i = 0; i < number_of_controls; i++) { + controls[i] = mixer_get_ctl_const(mixer_object, i); + ASSERT_EQ(mixer_ctl_get_id(controls[i]), i); + ASSERT_STRNE(mixer_ctl_get_name(controls[i]), ""); + ASSERT_NE(controls[i], nullptr); + } + } + + virtual void TearDown() override { + controls = nullptr; + MixerTest::TearDown(); + } + + unsigned int number_of_controls; + std::unique_ptr controls; +}; + +TEST_P(MixerControlsTest, GetNumberOfControlsByName) { + for (unsigned int i = 0; i < number_of_controls; ++i) { + const char *name = mixer_ctl_get_name(controls[i]); + ASSERT_GE(mixer_get_num_ctls_by_name(mixer_object, name), 1); + } + + std::string name{mixer_ctl_get_name(controls[0])}; + name += "1"; + ASSERT_EQ(mixer_get_num_ctls_by_name(mixer_object, name.c_str()), 0); +} + +TEST_P(MixerControlsTest, GetControlById) { + for (unsigned int i = 0; i < number_of_controls; ++i) { + ASSERT_EQ(mixer_get_ctl(mixer_object, i), controls[i]); + } + + ASSERT_EQ(mixer_get_ctl(mixer_object, number_of_controls), nullptr); +} + +TEST_P(MixerControlsTest, GetControlByName) { + std::unordered_set visited_names_set; + for (unsigned int i = 0; i < number_of_controls; ++i) { + std::string name{mixer_ctl_get_name(controls[i])}; + if (visited_names_set.find(name) == visited_names_set.end()) { + ASSERT_EQ(mixer_get_ctl_by_name(mixer_object, name.c_str()), controls[i]); + visited_names_set.insert(name); + } + } +} + +TEST_P(MixerControlsTest, GetControlByNameAndIndex) { + std::unordered_map visited_names_and_count_map; + for (unsigned int i = 0; i < number_of_controls; ++i) { + std::string name{mixer_ctl_get_name(controls[i])}; + if (visited_names_and_count_map.find(name) == visited_names_and_count_map.end()) { + visited_names_and_count_map[name] = 0; + } + ASSERT_EQ( + mixer_get_ctl_by_name_and_index(mixer_object, + name.c_str(), + visited_names_and_count_map[name]), + controls[i]); + visited_names_and_count_map[name] = visited_names_and_count_map[name] + 1; + } +} + +static inline bool IsValidTypeString(std::string& type) { + return type == "BOOL" || type == "INT" || type == "ENUM" || type == "BYTE" || + type == "IEC958" || type == "INT64"; +} + +TEST_P(MixerControlsTest, GetControlTypeString) { + ASSERT_STREQ(mixer_ctl_get_type_string(nullptr), ""); + + for (unsigned int i = 0; i < number_of_controls; ++i) { + std::string type{mixer_ctl_get_type_string(controls[i])}; + ASSERT_TRUE(IsValidTypeString(type)); + } +} + +TEST_P(MixerControlsTest, GetNumberOfValues) { + ASSERT_EQ(mixer_ctl_get_num_values(nullptr), 0); +} + +TEST_P(MixerControlsTest, GetNumberOfEnumsAndEnumString) { + for (unsigned int i = 0; i < number_of_controls; ++i) { + const mixer_ctl *control = controls[i]; + if (mixer_ctl_get_type(control) == MIXER_CTL_TYPE_ENUM) { + unsigned int number_of_enums = mixer_ctl_get_num_enums(control); + ASSERT_GT(number_of_enums, 0); + for (unsigned int enum_id = 0; enum_id < number_of_enums; ++enum_id) { + const char *enum_name = mixer_ctl_get_enum_string( + const_cast(control), + enum_id); + ASSERT_STRNE(enum_name, ""); + } + } + } +} + +TEST_P(MixerControlsTest, UpdateControl) { + for (unsigned int i = 0; i < number_of_controls; ++i) { + mixer_ctl_update(const_cast(controls[i])); + } +} + +TEST_P(MixerControlsTest, GetPercent) { + for (unsigned int i = 0; i < number_of_controls; ++i) { + const mixer_ctl *control = controls[i]; + if (mixer_ctl_get_type(control) == MIXER_CTL_TYPE_INT) { + unsigned int number_of_values = mixer_ctl_get_num_values(controls[i]); + std::unique_ptr values = std::make_unique(number_of_values); + mixer_ctl_get_array(control, values.get(), number_of_values); + for (unsigned int value_id = 0; value_id < number_of_values; ++value_id) { + int max = mixer_ctl_get_range_max(control); + int min = mixer_ctl_get_range_min(control); + int percent = mixer_ctl_get_percent(control, value_id); + ASSERT_GE(percent, 0); + ASSERT_LE(percent, 100); + int range = max - min; + ASSERT_EQ(percent, (values[value_id] - min) * 100 / range); + } + } else { + ASSERT_EQ(mixer_ctl_get_percent(control, 0), -EINVAL); + } + } +} + +TEST_P(MixerControlsTest, SetPercent) { + for (unsigned int i = 0; i < number_of_controls; ++i) { + const mixer_ctl *control = controls[i]; + if (mixer_ctl_get_type(control) == MIXER_CTL_TYPE_INT) { + unsigned int number_of_values = mixer_ctl_get_num_values(controls[i]); + std::unique_ptr values = std::make_unique(number_of_values); + mixer_ctl_get_array(control, values.get(), number_of_values); + for (unsigned int value_id = 0; value_id < number_of_values; ++value_id) { + int max = mixer_ctl_get_range_max(control); + int min = mixer_ctl_get_range_min(control); + int value = values[value_id]; + int percent = mixer_ctl_get_percent(control, value_id); + if (mixer_ctl_set_percent(const_cast(control), value_id, 100) == 0) { + // note: some controls are able to be written, but their values might not be + // changed. + mixer_ctl_get_array(control, values.get(), number_of_values); + int new_value = values[value_id]; + ASSERT_TRUE(new_value == value || new_value == max); + } + if (mixer_ctl_set_percent(const_cast(control), value_id, 0) == 0) { + mixer_ctl_get_array(control, values.get(), number_of_values); + int new_value = values[value_id]; + ASSERT_TRUE(new_value == value || new_value == min); + } + mixer_ctl_set_percent(const_cast(control), value_id, percent); + } + } else { + ASSERT_EQ(mixer_ctl_get_percent(control, 0), -EINVAL); + } + } +} + +INSTANTIATE_TEST_SUITE_P( + MixerTest, + MixerTest, + ::testing::Range( + 0, + kLoopbackCard + 1 + )); + +INSTANTIATE_TEST_SUITE_P( + MixerControlsTest, + MixerControlsTest, + ::testing::Range( + 0, + kLoopbackCard + 1 + )); + +} // namespace testing +} // namespace tinyalse -- cgit v1.2.3