414 lines
12 KiB
C++
414 lines
12 KiB
C++
|
|
#include <array>
|
||
|
|
#include <gtest/gtest.h>
|
||
|
|
#include <support/exceptionAssertions.h>
|
||
|
|
#include <user/deviceAttachmentSpec.h>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
namespace smo {
|
||
|
|
namespace device {
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
using ParamList = std::vector<std::pair<std::string, std::string>>;
|
||
|
|
|
||
|
|
ParamList makeParams(std::initializer_list<std::pair<const char*, const char*>> entries)
|
||
|
|
{
|
||
|
|
ParamList params;
|
||
|
|
for (const auto& entry : entries)
|
||
|
|
{
|
||
|
|
params.emplace_back(entry.first, entry.second);
|
||
|
|
}
|
||
|
|
|
||
|
|
return params;
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecNamesContainTest, MatchesVectorAndArraySynonyms)
|
||
|
|
{
|
||
|
|
const std::vector<std::string> widthSynonyms = {
|
||
|
|
"frame-width",
|
||
|
|
"dim-w",
|
||
|
|
};
|
||
|
|
|
||
|
|
EXPECT_TRUE(DeviceAttachmentSpec::namesContain(widthSynonyms, "dim-w"));
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::namesContain(widthSynonyms, "dim-h"));
|
||
|
|
|
||
|
|
const std::array<std::string_view, 2> heightSynonyms = {
|
||
|
|
"frame-height",
|
||
|
|
"dim-h",
|
||
|
|
};
|
||
|
|
|
||
|
|
EXPECT_TRUE(DeviceAttachmentSpec::namesContain(heightSynonyms, "frame-height"));
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::namesContain(heightSynonyms, "frame-width"));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParamsContainTest, DetectsExactParamName)
|
||
|
|
{
|
||
|
|
const ParamList params = makeParams({
|
||
|
|
{"display", "0"},
|
||
|
|
{"screen", "1"},
|
||
|
|
});
|
||
|
|
|
||
|
|
EXPECT_TRUE(DeviceAttachmentSpec::paramsContain(params, "display"));
|
||
|
|
EXPECT_TRUE(DeviceAttachmentSpec::paramsContain(params, "screen"));
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::paramsContain(params, "width"));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParamNameMatchesAnySynonymGroupTest, MatchesAcrossGroups)
|
||
|
|
{
|
||
|
|
const std::vector<std::string> widthSynonyms = {"dim-w", "frame-w"};
|
||
|
|
const std::vector<std::string> heightSynonyms = {"dim-h", "frame-h"};
|
||
|
|
|
||
|
|
EXPECT_TRUE(DeviceAttachmentSpec::paramNameMatchesAnySynonymGroup(
|
||
|
|
"dim-w", widthSynonyms, heightSynonyms));
|
||
|
|
EXPECT_TRUE(DeviceAttachmentSpec::paramNameMatchesAnySynonymGroup(
|
||
|
|
"frame-h", widthSynonyms, heightSynonyms));
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::paramNameMatchesAnySynonymGroup(
|
||
|
|
"colour-space", widthSynonyms, heightSynonyms));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecNormalizeParamTokenTest, TrimsAndLowercases)
|
||
|
|
{
|
||
|
|
EXPECT_EQ(DeviceAttachmentSpec::normalizeParamToken(" TRUE "), "true");
|
||
|
|
EXPECT_EQ(DeviceAttachmentSpec::normalizeParamToken("YUV"), "yuv");
|
||
|
|
EXPECT_EQ(DeviceAttachmentSpec::normalizeParamToken("480p"), "480p");
|
||
|
|
EXPECT_EQ(DeviceAttachmentSpec::normalizeParamToken(""), "");
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecFindOptionalParamTest, LattermostExactNameWins)
|
||
|
|
{
|
||
|
|
const ParamList params = makeParams({
|
||
|
|
{"display", "0"},
|
||
|
|
{"other", "ignored"},
|
||
|
|
{"display", "2"},
|
||
|
|
});
|
||
|
|
|
||
|
|
const std::optional<std::pair<std::string, std::string>> matched =
|
||
|
|
DeviceAttachmentSpec::findOptionalParam(params, "display");
|
||
|
|
|
||
|
|
ASSERT_TRUE(matched.has_value());
|
||
|
|
EXPECT_EQ(matched->first, "display");
|
||
|
|
EXPECT_EQ(matched->second, "2");
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecFindOptionalParamWithSynonymsTest, LattermostSynonymWins)
|
||
|
|
{
|
||
|
|
const std::vector<std::string> synonyms = {
|
||
|
|
"cmd-timeout-ms",
|
||
|
|
"command-timeout-ms",
|
||
|
|
};
|
||
|
|
|
||
|
|
const ParamList params = makeParams({
|
||
|
|
{"cmd-timeout-ms", "5"},
|
||
|
|
{"command-timeout-ms", "25"},
|
||
|
|
});
|
||
|
|
|
||
|
|
const std::optional<std::pair<std::string, std::string>> matched =
|
||
|
|
DeviceAttachmentSpec::findOptionalParamWithSynonyms(params, synonyms);
|
||
|
|
|
||
|
|
ASSERT_TRUE(matched.has_value());
|
||
|
|
EXPECT_EQ(matched->first, "command-timeout-ms");
|
||
|
|
EXPECT_EQ(matched->second, "25");
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecFindOptionalParamWithSynonymsTest, AbsentReturnsNullopt)
|
||
|
|
{
|
||
|
|
const std::vector<std::string> synonyms = {"data-port"};
|
||
|
|
const ParamList params = makeParams({{"cmd-port", "56001"}});
|
||
|
|
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::findOptionalParamWithSynonyms(
|
||
|
|
params, synonyms).has_value());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseParamValueAsIntTest, ParsesValidInteger)
|
||
|
|
{
|
||
|
|
EXPECT_EQ(
|
||
|
|
DeviceAttachmentSpec::parseParamValueAsInt("width", "1280"),
|
||
|
|
1280);
|
||
|
|
EXPECT_EQ(
|
||
|
|
DeviceAttachmentSpec::parseParamValueAsInt("width", "-42"),
|
||
|
|
-42);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseParamValueAsIntTest, InvalidIntegerThrows)
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
DeviceAttachmentSpec::parseParamValueAsInt("width", "not-a-number");
|
||
|
|
FAIL() << "Expected std::runtime_error";
|
||
|
|
}
|
||
|
|
catch (const std::runtime_error& exception)
|
||
|
|
{
|
||
|
|
sscl::tests::expectExceptionMessageContains(
|
||
|
|
exception, "Failed to parse 'width'");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseParamValueAsIntTest, OutOfRangeThrows)
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
DeviceAttachmentSpec::parseParamValueAsInt(
|
||
|
|
"width",
|
||
|
|
"999999999999999999999");
|
||
|
|
FAIL() << "Expected std::runtime_error";
|
||
|
|
}
|
||
|
|
catch (const std::runtime_error& exception)
|
||
|
|
{
|
||
|
|
sscl::tests::expectExceptionMessageContains(
|
||
|
|
exception, "out of range");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseParamValueAsPositiveIntTest, RejectsNonPositive)
|
||
|
|
{
|
||
|
|
EXPECT_EQ(
|
||
|
|
DeviceAttachmentSpec::parseParamValueAsPositiveInt("width", "640"),
|
||
|
|
640);
|
||
|
|
|
||
|
|
try {
|
||
|
|
DeviceAttachmentSpec::parseParamValueAsPositiveInt("width", "0");
|
||
|
|
FAIL() << "Expected std::runtime_error";
|
||
|
|
}
|
||
|
|
catch (const std::runtime_error& exception)
|
||
|
|
{
|
||
|
|
sscl::tests::expectExceptionMessageContains(
|
||
|
|
exception, "must be positive");
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
DeviceAttachmentSpec::parseParamValueAsPositiveInt("width", "-10");
|
||
|
|
FAIL() << "Expected std::runtime_error";
|
||
|
|
}
|
||
|
|
catch (const std::runtime_error& exception)
|
||
|
|
{
|
||
|
|
sscl::tests::expectExceptionMessageContains(
|
||
|
|
exception, "must be positive");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseParamValueAsBoolTest, ParsesRecognizedValues)
|
||
|
|
{
|
||
|
|
EXPECT_TRUE(DeviceAttachmentSpec::parseParamValueAsBool(""));
|
||
|
|
EXPECT_TRUE(DeviceAttachmentSpec::parseParamValueAsBool("true"));
|
||
|
|
EXPECT_TRUE(DeviceAttachmentSpec::parseParamValueAsBool(" YES "));
|
||
|
|
EXPECT_TRUE(DeviceAttachmentSpec::parseParamValueAsBool("1"));
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::parseParamValueAsBool("false"));
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::parseParamValueAsBool("0"));
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::parseParamValueAsBool("no"));
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::parseParamValueAsBool(
|
||
|
|
"", /*emptyMeansTrue=*/false));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseParamValueAsBoolTest, UnknownValueThrows)
|
||
|
|
{
|
||
|
|
EXPECT_THROW(
|
||
|
|
DeviceAttachmentSpec::parseParamValueAsBool("maybe"),
|
||
|
|
std::runtime_error);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseRequiredParamAsIntTest, MissingParamThrows)
|
||
|
|
{
|
||
|
|
const ParamList params = makeParams({{"screen", "1"}});
|
||
|
|
|
||
|
|
try {
|
||
|
|
DeviceAttachmentSpec::parseRequiredParamAsInt(params, "display");
|
||
|
|
FAIL() << "Expected std::runtime_error";
|
||
|
|
}
|
||
|
|
catch (const std::runtime_error& exception)
|
||
|
|
{
|
||
|
|
sscl::tests::expectExceptionMessageContains(
|
||
|
|
exception, "No display specified in params");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseRequiredParamAsIntTest, LattermostValueWins)
|
||
|
|
{
|
||
|
|
const ParamList params = makeParams({
|
||
|
|
{"display", "0"},
|
||
|
|
{"display", "3"},
|
||
|
|
});
|
||
|
|
|
||
|
|
EXPECT_EQ(
|
||
|
|
DeviceAttachmentSpec::parseRequiredParamAsInt(params, "display"),
|
||
|
|
3);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseOptionalParamAsIntTest, ReturnsDefaultWhenAbsent)
|
||
|
|
{
|
||
|
|
const ParamList params = makeParams({{"screen", "1"}});
|
||
|
|
|
||
|
|
EXPECT_EQ(
|
||
|
|
DeviceAttachmentSpec::parseOptionalParamAsInt(params, "display", 42),
|
||
|
|
42);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseOptionalParamAsIntWithSynonymsTest, SynonymLattermostWins)
|
||
|
|
{
|
||
|
|
const std::vector<std::string> synonyms = {
|
||
|
|
"n-dgrams-per-frame",
|
||
|
|
"num-dgrams-per-frame",
|
||
|
|
};
|
||
|
|
|
||
|
|
const ParamList params = makeParams({
|
||
|
|
{"n-dgrams-per-frame", "10"},
|
||
|
|
{"num-dgrams-per-frame", "99"},
|
||
|
|
});
|
||
|
|
|
||
|
|
EXPECT_EQ(
|
||
|
|
DeviceAttachmentSpec::parseOptionalParamAsIntWithSynonyms(
|
||
|
|
params, synonyms, 84),
|
||
|
|
99);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseRequiredParamAsIntWithSynonymsTest, ParsesMatchedSynonym)
|
||
|
|
{
|
||
|
|
const std::vector<std::string> synonyms = {
|
||
|
|
"cmd-timeout-ms",
|
||
|
|
"command-timeout-ms",
|
||
|
|
};
|
||
|
|
|
||
|
|
const ParamList params = makeParams({
|
||
|
|
{"command-timeout-ms", "15"},
|
||
|
|
});
|
||
|
|
|
||
|
|
EXPECT_EQ(
|
||
|
|
DeviceAttachmentSpec::parseRequiredParamAsIntWithSynonyms(
|
||
|
|
params,
|
||
|
|
synonyms,
|
||
|
|
"missing timeout"),
|
||
|
|
15);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseRequiredParamValueWithSynonymsTest, RequiresNonEmptyValue)
|
||
|
|
{
|
||
|
|
const std::vector<std::string> synonyms = {"colour-space"};
|
||
|
|
const ParamList missing = makeParams({{"width", "640"}});
|
||
|
|
|
||
|
|
try {
|
||
|
|
DeviceAttachmentSpec::parseRequiredParamValueWithSynonyms(
|
||
|
|
missing, synonyms, "colour-space required");
|
||
|
|
FAIL() << "Expected std::runtime_error";
|
||
|
|
}
|
||
|
|
catch (const std::runtime_error& exception)
|
||
|
|
{
|
||
|
|
sscl::tests::expectExceptionMessageContains(
|
||
|
|
exception, "colour-space required");
|
||
|
|
}
|
||
|
|
|
||
|
|
const ParamList emptyValue = makeParams({{"colour-space", ""}});
|
||
|
|
|
||
|
|
try {
|
||
|
|
DeviceAttachmentSpec::parseRequiredParamValueWithSynonyms(
|
||
|
|
emptyValue, synonyms, "colour-space required");
|
||
|
|
FAIL() << "Expected std::runtime_error";
|
||
|
|
}
|
||
|
|
catch (const std::runtime_error& exception)
|
||
|
|
{
|
||
|
|
sscl::tests::expectExceptionMessageContains(
|
||
|
|
exception, "colour-space required");
|
||
|
|
}
|
||
|
|
|
||
|
|
const ParamList present = makeParams({{"colour-space", "yuv"}});
|
||
|
|
EXPECT_EQ(
|
||
|
|
DeviceAttachmentSpec::parseRequiredParamValueWithSynonyms(
|
||
|
|
present, synonyms, "colour-space required"),
|
||
|
|
"yuv");
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseOptionalParamValueWithSynonymsTest, OptionalStringValue)
|
||
|
|
{
|
||
|
|
const std::vector<std::string> synonyms = {"colour-space"};
|
||
|
|
const ParamList absent = makeParams({{"width", "640"}});
|
||
|
|
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::parseOptionalParamValueWithSynonyms(
|
||
|
|
absent, synonyms, "empty colour-space").has_value());
|
||
|
|
|
||
|
|
const ParamList emptyValue = makeParams({{"colour-space", ""}});
|
||
|
|
try {
|
||
|
|
DeviceAttachmentSpec::parseOptionalParamValueWithSynonyms(
|
||
|
|
emptyValue, synonyms, "empty colour-space");
|
||
|
|
FAIL() << "Expected std::runtime_error";
|
||
|
|
}
|
||
|
|
catch (const std::runtime_error& exception)
|
||
|
|
{
|
||
|
|
sscl::tests::expectExceptionMessageContains(
|
||
|
|
exception, "empty colour-space");
|
||
|
|
}
|
||
|
|
|
||
|
|
const ParamList present = makeParams({{"colour-space", "yuv"}});
|
||
|
|
const std::optional<std::string> parsed =
|
||
|
|
DeviceAttachmentSpec::parseOptionalParamValueWithSynonyms(
|
||
|
|
present, synonyms, "empty colour-space");
|
||
|
|
|
||
|
|
ASSERT_TRUE(parsed.has_value());
|
||
|
|
EXPECT_EQ(*parsed, "yuv");
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecParseOptionalParamAsBoolWithSynonymsTest, ParsesPresenceAndValues)
|
||
|
|
{
|
||
|
|
const std::vector<std::string> synonyms = {
|
||
|
|
"full-planar-is-optional",
|
||
|
|
"opt-planar",
|
||
|
|
};
|
||
|
|
|
||
|
|
const ParamList absent = makeParams({{"width", "640"}});
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::parseOptionalParamAsBoolWithSynonyms(
|
||
|
|
absent, synonyms, false));
|
||
|
|
|
||
|
|
const ParamList presentEmpty = makeParams({{"opt-planar", ""}});
|
||
|
|
EXPECT_TRUE(DeviceAttachmentSpec::parseOptionalParamAsBoolWithSynonyms(
|
||
|
|
presentEmpty, synonyms, false));
|
||
|
|
|
||
|
|
const ParamList presentFalse = makeParams({{"opt-planar", "false"}});
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::parseOptionalParamAsBoolWithSynonyms(
|
||
|
|
presentFalse, synonyms, true));
|
||
|
|
|
||
|
|
const ParamList lattermostWins = makeParams({
|
||
|
|
{"opt-planar", "true"},
|
||
|
|
{"full-planar-is-optional", "false"},
|
||
|
|
});
|
||
|
|
EXPECT_FALSE(DeviceAttachmentSpec::parseOptionalParamAsBoolWithSynonyms(
|
||
|
|
lattermostWins, synonyms, true));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecRejectUnknownParamsTest, RejectsUnknownNames)
|
||
|
|
{
|
||
|
|
const std::vector<std::string> knownA = {"width", "dim-w"};
|
||
|
|
const std::vector<std::string> knownB = {"height", "dim-h"};
|
||
|
|
const ParamList params = makeParams({
|
||
|
|
{"dim-w", "640"},
|
||
|
|
{"unknown-param", "1"},
|
||
|
|
});
|
||
|
|
|
||
|
|
try {
|
||
|
|
DeviceAttachmentSpec::rejectUnknownParams(
|
||
|
|
params,
|
||
|
|
"unknown param '",
|
||
|
|
knownA,
|
||
|
|
knownB);
|
||
|
|
FAIL() << "Expected std::runtime_error";
|
||
|
|
}
|
||
|
|
catch (const std::runtime_error& exception)
|
||
|
|
{
|
||
|
|
sscl::tests::expectExceptionMessageContains(
|
||
|
|
exception, "unknown-param");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(DeviceAttachmentSpecRejectUnknownParamsTest, AcceptsAllKnownNames)
|
||
|
|
{
|
||
|
|
const std::vector<std::string> knownA = {"width", "dim-w"};
|
||
|
|
const std::vector<std::string> knownB = {"height", "dim-h"};
|
||
|
|
const ParamList params = makeParams({
|
||
|
|
{"dim-w", "640"},
|
||
|
|
{"dim-h", "480"},
|
||
|
|
});
|
||
|
|
|
||
|
|
EXPECT_NO_THROW(DeviceAttachmentSpec::rejectUnknownParams(
|
||
|
|
params,
|
||
|
|
"unknown param '",
|
||
|
|
knownA,
|
||
|
|
knownB));
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
} // namespace device
|
||
|
|
} // namespace smo
|