blob: 0f52a900c24fee41288027ddcdc0473034966e5d [file] [log] [blame]
/*
* Copyright (C) 2020 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.
*/
// pull in all the <= 6.0 tests
#include "6.0/AudioPrimaryHidlHalTest.cpp"
static std::vector<AudioConfig> combineAudioConfig(std::vector<xsd::AudioChannelMask> channelMasks,
std::vector<int64_t> sampleRates,
const std::string& format) {
std::vector<AudioConfig> configs;
configs.reserve(channelMasks.size() * sampleRates.size());
for (auto channelMask : channelMasks) {
for (auto sampleRate : sampleRates) {
AudioConfig config{};
config.base.channelMask = toString(channelMask);
config.base.sampleRateHz = sampleRate;
config.base.format = format;
configs.push_back(config);
}
}
return configs;
}
static std::tuple<std::vector<AudioInOutFlag>, bool> generateOutFlags(
const xsd::MixPorts::MixPort& mixPort) {
static const std::vector<AudioInOutFlag> offloadFlags = {
toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)};
std::vector<AudioInOutFlag> flags;
bool isOffload = false;
if (mixPort.hasFlags()) {
auto xsdFlags = mixPort.getFlags();
isOffload = std::find(xsdFlags.begin(), xsdFlags.end(),
xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
xsdFlags.end();
if (!isOffload) {
for (auto flag : xsdFlags) {
if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
flags.push_back(toString(flag));
}
}
} else {
flags = offloadFlags;
}
}
return {flags, isOffload};
}
static AudioOffloadInfo generateOffloadInfo(const AudioConfigBase& base) {
return AudioOffloadInfo{
.base = base,
.streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC),
.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
.bitRatePerSecond = 320,
.durationMicroseconds = -1,
.bitWidth = 16,
.bufferSize = 256 // arbitrary value
};
}
static std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(
bool oneProfilePerDevice) {
std::vector<DeviceConfigParameter> result;
for (const auto& device : getDeviceParameters()) {
auto module =
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
if (!module || !module->getFirstMixPorts()) break;
for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile
auto [flags, isOffload] = generateOutFlags(mixPort);
for (const auto& profile : mixPort.getProfile()) {
auto configs = combineAudioConfig(profile.getChannelMasks(),
profile.getSamplingRates(), profile.getFormat());
for (auto& config : configs) {
// Some combinations of flags declared in the config file require special
// treatment.
if (isOffload) {
config.offloadInfo.info(generateOffloadInfo(config.base));
}
result.emplace_back(device, config, flags);
if (oneProfilePerDevice) break;
}
if (oneProfilePerDevice) break;
}
if (oneProfilePerDevice) break;
}
}
return result;
}
const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
static std::vector<DeviceConfigParameter> parameters =
generateOutputDeviceConfigParameters(false);
return parameters;
}
const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters() {
static std::vector<DeviceConfigParameter> parameters =
generateOutputDeviceConfigParameters(true);
return parameters;
}
const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters(
bool generateInvalidFlags = true) {
static std::vector<DeviceConfigParameter> parameters = [&] {
std::vector<DeviceConfigParameter> result;
for (const auto& device : getDeviceParameters()) {
auto module =
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
if (!module || !module->getFirstMixPorts()) break;
bool hasRegularConfig = false, hasOffloadConfig = false;
for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile
auto [validFlags, isOffload] = generateOutFlags(mixPort);
if ((!isOffload && hasRegularConfig) || (isOffload && hasOffloadConfig)) continue;
for (const auto& profile : mixPort.getProfile()) {
if (!profile.hasFormat() || !profile.hasSamplingRates() ||
!profile.hasChannelMasks())
continue;
AudioConfigBase validBase = {
profile.getFormat(),
static_cast<uint32_t>(profile.getSamplingRates()[0]),
toString(profile.getChannelMasks()[0])};
{
AudioConfig config{.base = validBase};
config.base.channelMask = "random_string";
if (isOffload) {
config.offloadInfo.info(generateOffloadInfo(validBase));
}
result.emplace_back(device, config, validFlags);
}
{
AudioConfig config{.base = validBase};
config.base.format = "random_string";
if (isOffload) {
config.offloadInfo.info(generateOffloadInfo(validBase));
}
result.emplace_back(device, config, validFlags);
}
if (generateInvalidFlags) {
AudioConfig config{.base = validBase};
if (isOffload) {
config.offloadInfo.info(generateOffloadInfo(validBase));
}
std::vector<AudioInOutFlag> flags = {"random_string", ""};
result.emplace_back(device, config, flags);
}
if (isOffload) {
{
AudioConfig config{.base = validBase};
config.offloadInfo.info(generateOffloadInfo(validBase));
config.offloadInfo.info().base.channelMask = "random_string";
}
{
AudioConfig config{.base = validBase};
config.offloadInfo.info(generateOffloadInfo(validBase));
config.offloadInfo.info().base.format = "random_string";
}
{
AudioConfig config{.base = validBase};
config.offloadInfo.info(generateOffloadInfo(validBase));
config.offloadInfo.info().streamType = "random_string";
}
{
AudioConfig config{.base = validBase};
config.offloadInfo.info(generateOffloadInfo(validBase));
config.offloadInfo.info().usage = "random_string";
}
hasOffloadConfig = true;
} else {
hasRegularConfig = true;
}
break;
}
if (hasOffloadConfig && hasRegularConfig) break;
}
}
return result;
}();
return parameters;
}
static std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(
bool oneProfilePerDevice) {
std::vector<DeviceConfigParameter> result;
for (const auto& device : getDeviceParameters()) {
auto module =
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
if (!module || !module->getFirstMixPorts()) break;
for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
std::vector<AudioInOutFlag> flags;
if (mixPort.hasFlags()) {
std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
std::back_inserter(flags), [](auto flag) { return toString(flag); });
}
for (const auto& profile : mixPort.getProfile()) {
auto configs = combineAudioConfig(profile.getChannelMasks(),
profile.getSamplingRates(), profile.getFormat());
for (const auto& config : configs) {
result.emplace_back(device, config, flags);
if (oneProfilePerDevice) break;
}
if (oneProfilePerDevice) break;
}
if (oneProfilePerDevice) break;
}
}
return result;
}
const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
static std::vector<DeviceConfigParameter> parameters =
generateInputDeviceConfigParameters(false);
return parameters;
}
const std::vector<DeviceConfigParameter>& getInputDeviceSingleConfigParameters() {
static std::vector<DeviceConfigParameter> parameters =
generateInputDeviceConfigParameters(true);
return parameters;
}
const std::vector<DeviceConfigParameter>& getInputDeviceInvalidConfigParameters(
bool generateInvalidFlags = true) {
static std::vector<DeviceConfigParameter> parameters = [&] {
std::vector<DeviceConfigParameter> result;
for (const auto& device : getDeviceParameters()) {
auto module =
getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
if (!module || !module->getFirstMixPorts()) break;
bool hasConfig = false;
for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
std::vector<AudioInOutFlag> validFlags;
if (mixPort.hasFlags()) {
std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
std::back_inserter(validFlags),
[](auto flag) { return toString(flag); });
}
for (const auto& profile : mixPort.getProfile()) {
if (!profile.hasFormat() || !profile.hasSamplingRates() ||
!profile.hasChannelMasks())
continue;
AudioConfigBase validBase = {
profile.getFormat(),
static_cast<uint32_t>(profile.getSamplingRates()[0]),
toString(profile.getChannelMasks()[0])};
{
AudioConfig config{.base = validBase};
config.base.channelMask = "random_string";
result.emplace_back(device, config, validFlags);
}
{
AudioConfig config{.base = validBase};
config.base.format = "random_string";
result.emplace_back(device, config, validFlags);
}
if (generateInvalidFlags) {
AudioConfig config{.base = validBase};
std::vector<AudioInOutFlag> flags = {"random_string", ""};
result.emplace_back(device, config, flags);
}
hasConfig = true;
break;
}
if (hasConfig) break;
}
}
return result;
}();
return parameters;
}
class InvalidInputConfigNoFlagsTest : public AudioHidlTestWithDeviceConfigParameter {};
TEST_P(InvalidInputConfigNoFlagsTest, InputBufferSizeTest) {
doc::test("Verify that invalid config is rejected by IDevice::getInputBufferSize method.");
uint64_t bufferSize;
ASSERT_OK(getDevice()->getInputBufferSize(getConfig(), returnIn(res, bufferSize)));
EXPECT_EQ(Result::INVALID_ARGUMENTS, res);
}
INSTANTIATE_TEST_CASE_P(
InputBufferSizeInvalidConfig, InvalidInputConfigNoFlagsTest,
::testing::ValuesIn(getInputDeviceInvalidConfigParameters(false /*generateInvalidFlags*/)),
&DeviceConfigParameterToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputBufferSizeInvalidConfig);
static const DeviceAddress& getInvalidDeviceAddress() {
static const DeviceAddress valid = {.deviceType = "random_string"};
return valid;
}
TEST_P(AudioHidlDeviceTest, SetConnectedStateInvalidDeviceAddress) {
doc::test("Check that invalid device address is rejected by IDevice::setConnectedState");
EXPECT_RESULT(Result::INVALID_ARGUMENTS,
getDevice()->setConnectedState(getInvalidDeviceAddress(), true));
EXPECT_RESULT(Result::INVALID_ARGUMENTS,
getDevice()->setConnectedState(getInvalidDeviceAddress(), false));
}
enum { PARAM_DEVICE_CONFIG, PARAM_ADDRESS, PARAM_METADATA };
enum { INDEX_SINK, INDEX_SOURCE };
using SinkOrSourceMetadata = std::variant<SinkMetadata, SourceMetadata>;
using StreamOpenParameter = std::tuple<DeviceConfigParameter, DeviceAddress, SinkOrSourceMetadata>;
static std::string StreamOpenParameterToString(
const ::testing::TestParamInfo<StreamOpenParameter>& info) {
return DeviceConfigParameterToString(::testing::TestParamInfo<DeviceConfigParameter>{
std::get<PARAM_DEVICE_CONFIG>(info.param), info.index}) +
"__" +
SanitizeStringForGTestName(
::testing::PrintToString(std::get<PARAM_ADDRESS>(info.param))) +
"__" +
SanitizeStringForGTestName(std::visit(
[](auto&& arg) -> std::string { return ::testing::PrintToString(arg); },
std::get<PARAM_METADATA>(info.param)));
}
class StreamOpenTest : public HidlTest, public ::testing::WithParamInterface<StreamOpenParameter> {
protected:
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base
ASSERT_TRUE(getDevicesFactory() != nullptr);
ASSERT_TRUE(getDevice() != nullptr);
}
const std::string& getFactoryName() const override {
return std::get<PARAM_FACTORY_NAME>(
std::get<PARAM_DEVICE>(std::get<PARAM_DEVICE_CONFIG>(GetParam())));
}
const std::string& getDeviceName() const override {
return std::get<PARAM_DEVICE_NAME>(
std::get<PARAM_DEVICE>(std::get<PARAM_DEVICE_CONFIG>(GetParam())));
}
const AudioConfig& getConfig() const {
return std::get<PARAM_CONFIG>(std::get<PARAM_DEVICE_CONFIG>(GetParam()));
}
const hidl_vec<AudioInOutFlag> getFlags() const {
return std::get<PARAM_FLAGS>(std::get<PARAM_DEVICE_CONFIG>(GetParam()));
}
const DeviceAddress& getDeviceAddress() const { return std::get<PARAM_ADDRESS>(GetParam()); }
bool isParamForInputStream() const {
return std::get<PARAM_METADATA>(GetParam()).index() == INDEX_SINK;
}
const SinkMetadata& getSinkMetadata() const {
return std::get<INDEX_SINK>(std::get<PARAM_METADATA>(GetParam()));
}
const SourceMetadata& getSourceMetadata() const {
return std::get<INDEX_SOURCE>(std::get<PARAM_METADATA>(GetParam()));
}
};
static const DeviceAddress& getValidInputDeviceAddress() {
static const DeviceAddress valid = {
.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)};
return valid;
}
static const DeviceAddress& getValidOutputDeviceAddress() {
static const DeviceAddress valid = {
.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)};
return valid;
}
static const RecordTrackMetadata& getValidRecordTrackMetadata() {
static const RecordTrackMetadata valid = {
.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), .gain = 1};
return valid;
}
static const RecordTrackMetadata& getValidRecordTrackMetadataWithDest() {
static const RecordTrackMetadata valid = {
.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT),
.gain = 1,
.destination = [] {
RecordTrackMetadata::Destination dest;
dest.device(getValidOutputDeviceAddress());
return dest;
}()};
return valid;
}
static const RecordTrackMetadata& getInvalidSourceRecordTrackMetadata() {
static const RecordTrackMetadata invalid = {.source = "random_string", .gain = 1};
return invalid;
}
static const RecordTrackMetadata& getRecordTrackMetadataWithInvalidDest() {
static const RecordTrackMetadata invalid = {
.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT),
.gain = 1,
.destination = [] {
RecordTrackMetadata::Destination dest;
dest.device(getInvalidDeviceAddress());
return dest;
}()};
return invalid;
}
static const RecordTrackMetadata& getInvalidChannelMaskRecordTrackMetadata() {
static const RecordTrackMetadata invalid = {
.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT),
.gain = 1,
.channelMask = "random_string"};
return invalid;
}
static const RecordTrackMetadata& getInvalidTagsRecordTrackMetadata() {
static const RecordTrackMetadata invalid = {
.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT),
.gain = 1,
.tags = {{"random_string"}}};
return invalid;
}
static const PlaybackTrackMetadata& getValidPlaybackTrackMetadata() {
static const PlaybackTrackMetadata valid = {
.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
.contentType = toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
.gain = 1};
return valid;
}
static const PlaybackTrackMetadata& getInvalidUsagePlaybackTrackMetadata() {
static const PlaybackTrackMetadata invalid = {
.usage = "random_string",
.contentType = toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
.gain = 1};
return invalid;
}
static const PlaybackTrackMetadata& getInvalidContentTypePlaybackTrackMetadata() {
static const PlaybackTrackMetadata invalid = {
.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
.contentType = "random_string",
.gain = 1};
return invalid;
}
static const PlaybackTrackMetadata& getInvalidChannelMaskPlaybackTrackMetadata() {
static const PlaybackTrackMetadata invalid = {
.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
.contentType = toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
.gain = 1,
.channelMask = "random_string"};
return invalid;
}
static const PlaybackTrackMetadata& getInvalidTagsPlaybackTrackMetadata() {
static const PlaybackTrackMetadata invalid = {
.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
.contentType = toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
.gain = 1,
.tags = {{"random_string"}}};
return invalid;
}
static const std::vector<SourceMetadata>& getInvalidSourceMetadatas() {
static const std::vector<SourceMetadata> invalids = {
SourceMetadata{.tracks = {{getInvalidUsagePlaybackTrackMetadata()}}},
SourceMetadata{.tracks = {{getInvalidContentTypePlaybackTrackMetadata()}}},
SourceMetadata{.tracks = {{getInvalidChannelMaskPlaybackTrackMetadata()}}},
SourceMetadata{.tracks = {{getInvalidTagsPlaybackTrackMetadata()}}},
SourceMetadata{.tracks = {{getValidPlaybackTrackMetadata(),
getInvalidUsagePlaybackTrackMetadata()}}},
SourceMetadata{.tracks = {{getValidPlaybackTrackMetadata(),
getInvalidContentTypePlaybackTrackMetadata()}}},
SourceMetadata{.tracks = {{getValidPlaybackTrackMetadata(),
getInvalidChannelMaskPlaybackTrackMetadata()}}},
SourceMetadata{.tracks = {{getValidPlaybackTrackMetadata(),
getInvalidTagsPlaybackTrackMetadata()}}}};
return invalids;
}
static const std::vector<SinkMetadata>& getInvalidSinkMetadatas() {
static const std::vector<SinkMetadata> invalids = {
SinkMetadata{.tracks = {{getInvalidSourceRecordTrackMetadata()}}},
SinkMetadata{.tracks = {{getRecordTrackMetadataWithInvalidDest()}}},
SinkMetadata{.tracks = {{getInvalidChannelMaskRecordTrackMetadata()}}},
SinkMetadata{.tracks = {{getInvalidTagsRecordTrackMetadata()}}},
SinkMetadata{.tracks = {{getValidRecordTrackMetadata(),
getInvalidSourceRecordTrackMetadata()}}},
SinkMetadata{.tracks = {{getValidRecordTrackMetadata(),
getRecordTrackMetadataWithInvalidDest()}}},
SinkMetadata{.tracks = {{getValidRecordTrackMetadata(),
getInvalidChannelMaskRecordTrackMetadata()}}},
SinkMetadata{.tracks = {{getValidRecordTrackMetadata(),
getInvalidTagsRecordTrackMetadata()}}}};
return invalids;
}
template <typename T>
static inline std::vector<SinkOrSourceMetadata> wrapMetadata(const std::vector<T>& metadata) {
return std::vector<SinkOrSourceMetadata>{metadata.begin(), metadata.end()};
}
TEST_P(StreamOpenTest, OpenInputOrOutputStreamTest) {
doc::test(
"Verify that invalid arguments are rejected by "
"IDevice::open{Input|Output}Stream method.");
AudioConfig suggestedConfig{};
if (isParamForInputStream()) {
sp<IStreamIn> stream;
ASSERT_OK(getDevice()->openInputStream(AudioIoHandle{}, getDeviceAddress(), getConfig(),
getFlags(), getSinkMetadata(),
returnIn(res, stream, suggestedConfig)));
ASSERT_TRUE(stream == nullptr);
} else {
sp<IStreamOut> stream;
ASSERT_OK(getDevice()->openOutputStream(AudioIoHandle{}, getDeviceAddress(), getConfig(),
getFlags(), getSourceMetadata(),
returnIn(res, stream, suggestedConfig)));
ASSERT_TRUE(stream == nullptr);
}
EXPECT_EQ(Result::INVALID_ARGUMENTS, res);
EXPECT_EQ(AudioConfig{}, suggestedConfig);
}
INSTANTIATE_TEST_CASE_P(
InputStreamInvalidConfig, StreamOpenTest,
::testing::Combine(::testing::ValuesIn(getInputDeviceInvalidConfigParameters()),
::testing::Values(getValidInputDeviceAddress()),
::testing::Values(SinkMetadata{
.tracks = {{getValidRecordTrackMetadata(),
getValidRecordTrackMetadataWithDest()}}})),
&StreamOpenParameterToString);
INSTANTIATE_TEST_CASE_P(
InputStreamInvalidAddress, StreamOpenTest,
::testing::Combine(::testing::ValuesIn(getInputDeviceSingleConfigParameters()),
::testing::Values(getInvalidDeviceAddress()),
::testing::Values(SinkMetadata{
.tracks = {{getValidRecordTrackMetadata(),
getValidRecordTrackMetadataWithDest()}}})),
&StreamOpenParameterToString);
INSTANTIATE_TEST_CASE_P(
InputStreamInvalidMetadata, StreamOpenTest,
::testing::Combine(::testing::ValuesIn(getInputDeviceSingleConfigParameters()),
::testing::Values(getValidInputDeviceAddress()),
::testing::ValuesIn(wrapMetadata(getInvalidSinkMetadatas()))),
&StreamOpenParameterToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidConfig);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidAddress);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputStreamInvalidMetadata);
INSTANTIATE_TEST_CASE_P(
OutputStreamInvalidConfig, StreamOpenTest,
::testing::Combine(::testing::ValuesIn(getOutputDeviceInvalidConfigParameters()),
::testing::Values(getValidOutputDeviceAddress()),
::testing::Values(SourceMetadata{
.tracks = {{getValidPlaybackTrackMetadata()}}})),
&StreamOpenParameterToString);
INSTANTIATE_TEST_CASE_P(
OutputStreamInvalidAddress, StreamOpenTest,
::testing::Combine(::testing::ValuesIn(getOutputDeviceSingleConfigParameters()),
::testing::Values(getInvalidDeviceAddress()),
::testing::Values(SourceMetadata{
.tracks = {{getValidPlaybackTrackMetadata()}}})),
&StreamOpenParameterToString);
INSTANTIATE_TEST_CASE_P(
OutputStreamInvalidMetadata, StreamOpenTest,
::testing::Combine(::testing::ValuesIn(getOutputDeviceSingleConfigParameters()),
::testing::Values(getValidOutputDeviceAddress()),
::testing::ValuesIn(wrapMetadata(getInvalidSourceMetadatas()))),
&StreamOpenParameterToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidConfig);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidAddress);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OutputStreamInvalidMetadata);
#define TEST_SINGLE_CONFIG_IO_STREAM(test_name, documentation, code) \
TEST_P(SingleConfigInputStreamTest, test_name) { \
doc::test(documentation); \
code; \
} \
TEST_P(SingleConfigOutputStreamTest, test_name) { \
doc::test(documentation); \
code; \
}
static void testSetDevicesInvalidDeviceAddress(IStream* stream) {
ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->setDevices({getInvalidDeviceAddress()}));
}
TEST_SINGLE_CONFIG_IO_STREAM(
SetDevicesInvalidDeviceAddress,
"Verify that invalid device address is rejected by IStream::setDevices",
areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported")
: testSetDevicesInvalidDeviceAddress(stream.get()));
static void testSetAudioPropertiesInvalidArguments(IStream* stream, const AudioConfigBase& base) {
AudioConfigBase invalidFormat = base;
invalidFormat.format = "random_string";
ASSERT_RESULT(invalidArgsOrNotSupported, stream->setAudioProperties(invalidFormat));
AudioConfigBase invalidChannelMask = base;
invalidChannelMask.channelMask = "random_string";
ASSERT_RESULT(invalidArgsOrNotSupported, stream->setAudioProperties(invalidChannelMask));
}
TEST_SINGLE_CONFIG_IO_STREAM(
SetAudioPropertiesInvalidArguments,
"Verify that invalid arguments are rejected by IStream::setAudioProperties",
testSetAudioPropertiesInvalidArguments(stream.get(), audioConfig.base));
TEST_P(SingleConfigOutputStreamTest, UpdateInvalidSourceMetadata) {
doc::test("Verify that invalid metadata is rejected by IStreamOut::updateSourceMetadata");
for (const auto& metadata : getInvalidSourceMetadatas()) {
ASSERT_RESULT(invalidArgsOrNotSupported, stream->updateSourceMetadata(metadata))
<< ::testing::PrintToString(metadata);
}
}
TEST_P(SingleConfigInputStreamTest, UpdateInvalidSinkMetadata) {
doc::test("Verify that invalid metadata is rejected by IStreamIn::updateSinkMetadata");
for (const auto& metadata : getInvalidSinkMetadatas()) {
ASSERT_RESULT(invalidArgsOrNotSupported, stream->updateSinkMetadata(metadata))
<< ::testing::PrintToString(metadata);
}
}