refactor: finish constraint builder and its testbench
This commit is contained in:
@ -34,32 +34,61 @@ namespace yycc::constraint::builder {
|
||||
* @brief Get constraint for enum values by enumerating all possible values.
|
||||
* @tparam T An enum type (except bool) of underlying stored value.
|
||||
* @param[in] il An initializer list storing all possible values.
|
||||
* @param[in] default_index The index of default value in given list.
|
||||
* @return The generated constraint instance which can be directly applied.
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
|
||||
Constraint<T> enum_constraint(const std::initializer_list<T>& il) {
|
||||
std::set<T> data(il);
|
||||
Constraint<T> enum_constraint(const std::initializer_list<T>& il, size_t default_index = 0u) {
|
||||
if (default_index >= il.size())
|
||||
throw std::invalid_argument("the default index must be a valid index in given list");
|
||||
|
||||
auto fn_check = [data](const T& val) -> bool { return data.find(val) != data.end(); };
|
||||
return Constraint<T>(std::move(fn_check), nullptr);
|
||||
T default_entry = il.begin()[default_index];
|
||||
std::set<T> entries(il);
|
||||
|
||||
// TODO: modify it as `contain` once we finish patch namespace.
|
||||
auto fn_check = [entries](const T& val) -> bool {
|
||||
return entries.find(val) != entries.end();
|
||||
};
|
||||
auto fn_clamp = [entries, default_entry](const T& val) -> T {
|
||||
if (entries.find(val) != entries.end()) {
|
||||
return val;
|
||||
} else {
|
||||
return default_entry;
|
||||
}
|
||||
};
|
||||
return Constraint<T>(std::move(fn_check), fn_clamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get constraint for string values by enumerating all possible values.
|
||||
* @param[in] il An initializer list storing all possible values.
|
||||
* @param[in] default_index The index of default value in given list.
|
||||
* @return The generated constraint instance which can be directly applied.
|
||||
* @remarks
|
||||
* Caller must make sure that the string view passed in initializer list is valid until this Constraint life time gone.
|
||||
* Becasue this generator will not copy your given string view into string.
|
||||
*/
|
||||
inline Constraint<NS_YYCC_STRING::u8string> GetStringEnumerationConstraint(
|
||||
const std::initializer_list<NS_YYCC_STRING::u8string_view>& il) {
|
||||
std::set<NS_YYCC_STRING::u8string_view> data(il);
|
||||
inline Constraint<NS_YYCC_STRING::u8string> strenum_constraint(
|
||||
const std::initializer_list<NS_YYCC_STRING::u8string_view>& il, size_t default_index = 0u) {
|
||||
if (default_index >= il.size())
|
||||
throw std::invalid_argument("the default index must be a valid index in given list");
|
||||
|
||||
auto fn_check = [data](const NS_YYCC_STRING::u8string& val) -> bool {
|
||||
return data.find(NS_YYCC_STRING::u8string_view(val)) != data.end();
|
||||
NS_YYCC_STRING::u8string default_entry = NS_YYCC_STRING::u8string(il.begin()[default_index]);
|
||||
std::set<NS_YYCC_STRING::u8string> entries;
|
||||
for (const auto& i : il) {
|
||||
entries.emplace(i);
|
||||
}
|
||||
|
||||
// TODO: modify it as `contain` once we finish patch namespace.
|
||||
auto fn_check = [entries](const NS_YYCC_STRING::u8string& val) -> bool {
|
||||
return entries.find(val) != entries.end();
|
||||
};
|
||||
return Constraint<NS_YYCC_STRING::u8string>(std::move(fn_check), nullptr);
|
||||
auto fn_clamp = [entries, default_entry](
|
||||
const NS_YYCC_STRING::u8string& val) -> NS_YYCC_STRING::u8string {
|
||||
if (entries.find(val) != entries.end()) {
|
||||
return val;
|
||||
} else {
|
||||
return default_entry;
|
||||
}
|
||||
};
|
||||
return Constraint<NS_YYCC_STRING::u8string>(std::move(fn_check), fn_clamp);
|
||||
}
|
||||
|
||||
} // namespace yycc::constraint::builder
|
||||
|
@ -1,5 +1,83 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <yycc.hpp>
|
||||
#include <yycc/constraint/builder.hpp>
|
||||
#include <yycc/string/reinterpret.hpp>
|
||||
|
||||
#include <yycc/prelude/rust.hpp>
|
||||
|
||||
#define BUILDER ::yycc::constraint::builder
|
||||
|
||||
namespace yycctest::constraint::builder {
|
||||
|
||||
#define TEST_SUCCESS(constraint, value) \
|
||||
EXPECT_TRUE(constraint.check(value)); \
|
||||
EXPECT_EQ(constraint.clamp(value), value);
|
||||
|
||||
#define TEST_FAIL(constraint, value, clamped_value) \
|
||||
EXPECT_FALSE(constraint.check(value)); \
|
||||
EXPECT_EQ(constraint.clamp(value), clamped_value);
|
||||
|
||||
TEST(ConstraintBuilder, MinMaxConstraint) {
|
||||
// Integral type
|
||||
{
|
||||
auto c = BUILDER::min_max_constraint<i32>(5, 61);
|
||||
ASSERT_TRUE(c.support_check());
|
||||
ASSERT_TRUE(c.support_clamp());
|
||||
TEST_SUCCESS(c, 5);
|
||||
TEST_SUCCESS(c, 6);
|
||||
TEST_SUCCESS(c, 61);
|
||||
TEST_FAIL(c, -2, 5);
|
||||
TEST_FAIL(c, 0, 5);
|
||||
TEST_FAIL(c, 66, 61);
|
||||
}
|
||||
// Unisgned integral type
|
||||
{
|
||||
auto c = BUILDER::min_max_constraint<u32>(5, 61);
|
||||
ASSERT_TRUE(c.support_check());
|
||||
ASSERT_TRUE(c.support_clamp());
|
||||
TEST_SUCCESS(c, 5);
|
||||
TEST_SUCCESS(c, 6);
|
||||
TEST_SUCCESS(c, 61);
|
||||
TEST_FAIL(c, 0, 5);
|
||||
TEST_FAIL(c, 66, 61);
|
||||
}
|
||||
// Float point type
|
||||
{
|
||||
auto c = BUILDER::min_max_constraint<f32>(5.0f, 61.0f);
|
||||
ASSERT_TRUE(c.support_check());
|
||||
ASSERT_TRUE(c.support_clamp());
|
||||
TEST_SUCCESS(c, 5.0f);
|
||||
TEST_SUCCESS(c, 6.0f);
|
||||
TEST_SUCCESS(c, 61.0f);
|
||||
TEST_FAIL(c, 0.0f, 5.0f);
|
||||
TEST_FAIL(c, 66.0f, 61.0f);
|
||||
}
|
||||
}
|
||||
|
||||
enum class TestEnum : u8 { Entry1 = 0, Entry2 = 1, Entry3 = 2 };
|
||||
|
||||
TEST(ConstraintBuilder, EnumConstraint) {
|
||||
auto c = BUILDER::enum_constraint({TestEnum::Entry1, TestEnum::Entry2, TestEnum::Entry3},
|
||||
1u);
|
||||
ASSERT_TRUE(c.support_check());
|
||||
ASSERT_TRUE(c.support_clamp());
|
||||
TEST_SUCCESS(c, TestEnum::Entry1);
|
||||
TEST_SUCCESS(c, TestEnum::Entry2);
|
||||
TEST_SUCCESS(c, TestEnum::Entry3);
|
||||
TEST_FAIL(c, static_cast<TestEnum>(UINT8_C(61)), TestEnum::Entry2);
|
||||
}
|
||||
|
||||
TEST(ConstraintBuilder, StrEnumConstraint) {
|
||||
auto c = BUILDER::strenum_constraint({YYCC_U8("first-entry"),
|
||||
YYCC_U8("second-entry"),
|
||||
YYCC_U8("third-entry")},
|
||||
1u);
|
||||
ASSERT_TRUE(c.support_check());
|
||||
ASSERT_TRUE(c.support_clamp());
|
||||
TEST_SUCCESS(c, YYCC_U8("first-entry"));
|
||||
TEST_SUCCESS(c, YYCC_U8("second-entry"));
|
||||
TEST_SUCCESS(c, YYCC_U8("third-entry"));
|
||||
TEST_FAIL(c, YYCC_U8("wtf?"), YYCC_U8("second-entry"));
|
||||
}
|
||||
|
||||
} // namespace yycctest::constraint::builder
|
||||
|
Reference in New Issue
Block a user