42c9fcdfdf
Delegate threshold param parsing to the new DeviceAttachmentSpec primitives so intrin modules stay aligned with stimBuff param conventions. Co-authored-by: Cursor <cursoragent@cursor.com>
332 lines
8.7 KiB
C++
332 lines
8.7 KiB
C++
#include <gtest/gtest.h>
|
|
#include <support/exceptionAssertions.h>
|
|
#include <user/intrinThresholdParams.h>
|
|
#include <vector>
|
|
|
|
namespace smo {
|
|
namespace intrin {
|
|
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(IntrinThresholdArrayContainsTest, MatchesCanonicalNames)
|
|
{
|
|
EXPECT_TRUE(arrayContains(kIntrinInterestPcNames, "interest-pc"));
|
|
EXPECT_TRUE(arrayContains(kIntrinInterestThrNames, "interest-thr"));
|
|
EXPECT_FALSE(arrayContains(kForbiddenUnitlessIntrinStems, "interest-pc"));
|
|
}
|
|
|
|
TEST(IntrinThresholdIsKnownParamNameTest, RecognizesAllCanonicalFamilies)
|
|
{
|
|
EXPECT_TRUE(isKnownIntrinThresholdParamName("interest-pc"));
|
|
EXPECT_TRUE(isKnownIntrinThresholdParamName("interest-threshold"));
|
|
EXPECT_TRUE(isKnownIntrinThresholdParamName("distraction-percentage"));
|
|
EXPECT_TRUE(isKnownIntrinThresholdParamName("distraction-thr"));
|
|
EXPECT_TRUE(isKnownIntrinThresholdParamName("stupefying-pc"));
|
|
EXPECT_TRUE(isKnownIntrinThresholdParamName("stupefaction-thresh"));
|
|
EXPECT_TRUE(isKnownIntrinThresholdParamName("intolerable-pc"));
|
|
EXPECT_TRUE(isKnownIntrinThresholdParamName("intolerable-threshold"));
|
|
|
|
EXPECT_FALSE(isKnownIntrinThresholdParamName("interest"));
|
|
EXPECT_FALSE(isKnownIntrinThresholdParamName("passband-count-gt-val"));
|
|
}
|
|
|
|
TEST(IntrinThresholdValidateNoIntrinParamsOnQualeIfaceTest, RejectsKnownIntrinNames)
|
|
{
|
|
const ParamList params = makeParams({{"interest-pc", "85"}});
|
|
|
|
try {
|
|
validateNoIntrinParamsOnQualeIface("pcloudLightAmbience", params);
|
|
FAIL() << "Expected std::runtime_error";
|
|
}
|
|
catch (const std::runtime_error& exception)
|
|
{
|
|
sscl::tests::expectExceptionMessageContains(
|
|
exception, "not valid on qualeIfaceApi");
|
|
}
|
|
}
|
|
|
|
TEST(IntrinThresholdValidateNoIntrinParamsOnQualeIfaceTest, RejectsUnitlessStems)
|
|
{
|
|
const ParamList params = makeParams({{"distraction", "10"}});
|
|
|
|
try {
|
|
validateNoIntrinParamsOnQualeIface("mesh", params);
|
|
FAIL() << "Expected std::runtime_error";
|
|
}
|
|
catch (const std::runtime_error& exception)
|
|
{
|
|
sscl::tests::expectExceptionMessageContains(
|
|
exception, "invalid without a unit suffix");
|
|
}
|
|
}
|
|
|
|
TEST(IntrinThresholdValidateNoIntrinParamsOnQualeIfaceTest, RejectsFromStimbuffMarker)
|
|
{
|
|
const ParamList params = makeParams({{"from-stimbuff", ""}});
|
|
|
|
try {
|
|
validateNoIntrinParamsOnQualeIface("mesh", params);
|
|
FAIL() << "Expected std::runtime_error";
|
|
}
|
|
catch (const std::runtime_error& exception)
|
|
{
|
|
sscl::tests::expectExceptionMessageContains(
|
|
exception, "from-stimbuff");
|
|
}
|
|
}
|
|
|
|
TEST(IntrinThresholdValidateNoIntrinParamsOnQualeIfaceTest, AllowsSensoryParams)
|
|
{
|
|
const ParamList params = makeParams({
|
|
{"passband-count-gt-val", "12"},
|
|
{"histbuff-ms", "30000"},
|
|
});
|
|
|
|
EXPECT_NO_THROW(validateNoIntrinParamsOnQualeIface(
|
|
"pcloudLightAmbience", params));
|
|
}
|
|
|
|
TEST(IntrinThresholdValidateIntrinSegmentParamsTest, RejectsUnitlessStems)
|
|
{
|
|
const ParamList params = makeParams({{"stupefaction", "5"}});
|
|
|
|
try {
|
|
validateIntrinSegmentParams("postrin", params);
|
|
FAIL() << "Expected std::runtime_error";
|
|
}
|
|
catch (const std::runtime_error& exception)
|
|
{
|
|
sscl::tests::expectExceptionMessageContains(
|
|
exception, "invalid without a unit suffix");
|
|
}
|
|
}
|
|
|
|
TEST(IntrinThresholdValidateIntrinSegmentParamsTest, AllowsSuffixedNames)
|
|
{
|
|
const ParamList params = makeParams({
|
|
{"interest-pc", "85"},
|
|
{"distraction-thr", "12"},
|
|
});
|
|
|
|
EXPECT_NO_THROW(validateIntrinSegmentParams("negtrin", params));
|
|
}
|
|
|
|
TEST(IntrinThresholdParseOptionalThresholdParamTest, ReturnsDefaultWhenAbsent)
|
|
{
|
|
const ParamList params = makeParams({{"other-param", "1"}});
|
|
|
|
const ParsedThresholdParam parsed = parseOptionalThresholdParam(
|
|
params,
|
|
kIntrinInterestPcNames,
|
|
kIntrinInterestThrNames,
|
|
/*defaultValue=*/7,
|
|
/*defaultUnit=*/ThresholdUnit::Absolute);
|
|
|
|
EXPECT_FALSE(parsed.wasSpecified);
|
|
EXPECT_EQ(parsed.value, 7);
|
|
EXPECT_EQ(parsed.unit, ThresholdUnit::Absolute);
|
|
EXPECT_TRUE(parsed.matchedName.empty());
|
|
}
|
|
|
|
TEST(IntrinThresholdParseOptionalThresholdParamTest, ParsesPercentageParam)
|
|
{
|
|
const ParamList params = makeParams({{"interest-percentage", "50"}});
|
|
|
|
const ParsedThresholdParam parsed = parseOptionalThresholdParam(
|
|
params,
|
|
kIntrinInterestPcNames,
|
|
kIntrinInterestThrNames,
|
|
0,
|
|
ThresholdUnit::Absolute);
|
|
|
|
EXPECT_TRUE(parsed.wasSpecified);
|
|
EXPECT_EQ(parsed.value, 50);
|
|
EXPECT_EQ(parsed.unit, ThresholdUnit::Percentage);
|
|
EXPECT_EQ(parsed.matchedName, "interest-percentage");
|
|
}
|
|
|
|
TEST(IntrinThresholdParseOptionalThresholdParamTest, ParsesAbsoluteParam)
|
|
{
|
|
const ParamList params = makeParams({{"interest-threshold", "42"}});
|
|
|
|
const ParsedThresholdParam parsed = parseOptionalThresholdParam(
|
|
params,
|
|
kIntrinInterestPcNames,
|
|
kIntrinInterestThrNames,
|
|
0,
|
|
ThresholdUnit::Percentage);
|
|
|
|
EXPECT_TRUE(parsed.wasSpecified);
|
|
EXPECT_EQ(parsed.value, 42);
|
|
EXPECT_EQ(parsed.unit, ThresholdUnit::Absolute);
|
|
EXPECT_EQ(parsed.matchedName, "interest-threshold");
|
|
}
|
|
|
|
TEST(IntrinThresholdParseOptionalThresholdParamTest, LattermostMatchingParamWins)
|
|
{
|
|
const ParamList params = makeParams({
|
|
{"interest-pc", "10"},
|
|
{"interest-threshold", "99"},
|
|
});
|
|
|
|
const ParsedThresholdParam parsed = parseOptionalThresholdParam(
|
|
params,
|
|
kIntrinInterestPcNames,
|
|
kIntrinInterestThrNames,
|
|
0,
|
|
ThresholdUnit::Percentage);
|
|
|
|
EXPECT_TRUE(parsed.wasSpecified);
|
|
EXPECT_EQ(parsed.value, 99);
|
|
EXPECT_EQ(parsed.unit, ThresholdUnit::Absolute);
|
|
EXPECT_EQ(parsed.matchedName, "interest-threshold");
|
|
}
|
|
|
|
TEST(IntrinThresholdParseOptionalThresholdParamTest, LattermostPercentageWinsOverEarlierAbsolute)
|
|
{
|
|
const ParamList params = makeParams({
|
|
{"interest-thr", "12"},
|
|
{"interest-pc", "75"},
|
|
});
|
|
|
|
const ParsedThresholdParam parsed = parseOptionalThresholdParam(
|
|
params,
|
|
kIntrinInterestPcNames,
|
|
kIntrinInterestThrNames,
|
|
0,
|
|
ThresholdUnit::Absolute);
|
|
|
|
EXPECT_TRUE(parsed.wasSpecified);
|
|
EXPECT_EQ(parsed.value, 75);
|
|
EXPECT_EQ(parsed.unit, ThresholdUnit::Percentage);
|
|
EXPECT_EQ(parsed.matchedName, "interest-pc");
|
|
}
|
|
|
|
TEST(IntrinThresholdParseOptionalThresholdParamTest, InvalidIntegerThrows)
|
|
{
|
|
const ParamList params = makeParams({{"interest-pc", "not-int"}});
|
|
|
|
try {
|
|
parseOptionalThresholdParam(
|
|
params,
|
|
kIntrinInterestPcNames,
|
|
kIntrinInterestThrNames,
|
|
0,
|
|
ThresholdUnit::Absolute);
|
|
FAIL() << "Expected std::runtime_error";
|
|
}
|
|
catch (const std::runtime_error& exception)
|
|
{
|
|
sscl::tests::expectExceptionMessageContains(
|
|
exception, "Failed to parse 'interest-pc'");
|
|
}
|
|
}
|
|
|
|
TEST(IntrinThresholdResolveThresholdValueTest, PercentageUsesBase)
|
|
{
|
|
const ParsedThresholdParam percentageParam = {
|
|
.value = 50,
|
|
.unit = ThresholdUnit::Percentage,
|
|
.matchedName = "interest-pc",
|
|
.wasSpecified = true,
|
|
};
|
|
|
|
EXPECT_EQ(resolveThresholdValue(percentageParam, 84), 42u);
|
|
}
|
|
|
|
TEST(IntrinThresholdResolveThresholdValueTest, AbsolutePassesThrough)
|
|
{
|
|
const ParsedThresholdParam absoluteParam = {
|
|
.value = 17,
|
|
.unit = ThresholdUnit::Absolute,
|
|
.matchedName = "interest-thr",
|
|
.wasSpecified = true,
|
|
};
|
|
|
|
EXPECT_EQ(resolveThresholdValue(absoluteParam, 84), 17u);
|
|
}
|
|
|
|
TEST(IntrinThresholdResolveThresholdValueTest, PercentageTruncatesTowardZero)
|
|
{
|
|
const ParsedThresholdParam percentageParam = {
|
|
.value = 33,
|
|
.unit = ThresholdUnit::Percentage,
|
|
.matchedName = "interest-pc",
|
|
.wasSpecified = true,
|
|
};
|
|
|
|
EXPECT_EQ(resolveThresholdValue(percentageParam, 100), 33u);
|
|
EXPECT_EQ(resolveThresholdValue(percentageParam, 10), 3u);
|
|
}
|
|
|
|
TEST(IntrinThresholdSynonymCoverageTest, AllThrSynonymsParseAsAbsolute)
|
|
{
|
|
const std::array<std::string_view, 3> thrNames = {
|
|
"interest-threshold",
|
|
"interest-thresh",
|
|
"interest-thr",
|
|
};
|
|
|
|
for (const std::string_view thrName : thrNames)
|
|
{
|
|
const ParamList params = makeParams({
|
|
{thrName.data(), "11"},
|
|
});
|
|
|
|
const ParsedThresholdParam parsed = parseOptionalThresholdParam(
|
|
params,
|
|
kIntrinInterestPcNames,
|
|
kIntrinInterestThrNames,
|
|
0,
|
|
ThresholdUnit::Percentage);
|
|
|
|
EXPECT_TRUE(parsed.wasSpecified);
|
|
EXPECT_EQ(parsed.unit, ThresholdUnit::Absolute);
|
|
EXPECT_EQ(parsed.value, 11);
|
|
EXPECT_EQ(parsed.matchedName, thrName);
|
|
}
|
|
}
|
|
|
|
TEST(IntrinThresholdSynonymCoverageTest, AllPcSynonymsParseAsPercentage)
|
|
{
|
|
const std::array<std::string_view, 2> pcNames = {
|
|
"interest-percentage",
|
|
"interest-pc",
|
|
};
|
|
|
|
for (const std::string_view pcName : pcNames)
|
|
{
|
|
const ParamList params = makeParams({
|
|
{pcName.data(), "25"},
|
|
});
|
|
|
|
const ParsedThresholdParam parsed = parseOptionalThresholdParam(
|
|
params,
|
|
kIntrinInterestPcNames,
|
|
kIntrinInterestThrNames,
|
|
0,
|
|
ThresholdUnit::Absolute);
|
|
|
|
EXPECT_TRUE(parsed.wasSpecified);
|
|
EXPECT_EQ(parsed.unit, ThresholdUnit::Percentage);
|
|
EXPECT_EQ(parsed.value, 25);
|
|
EXPECT_EQ(parsed.matchedName, pcName);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace intrin
|
|
} // namespace smo
|