88 lines
2.8 KiB
C++
88 lines
2.8 KiB
C++
|
|
#include "test_harness.h"
|
||
|
|
#include <TestProject/RNG/model/ModelRegistry.h>
|
||
|
|
using json = nlohmann::json;
|
||
|
|
|
||
|
|
static const char* testJsonPath() {
|
||
|
|
// TEST_DATA_DIR is defined via CMake target_compile_definitions
|
||
|
|
return TEST_DATA_DIR "/test_models.json";
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(registry_singleton_is_same) {
|
||
|
|
CHECK_EQ(&ModelRegistry::instance(), &ModelRegistry::instance());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(registry_load_models_and_get_builtin) {
|
||
|
|
auto& reg = ModelRegistry::instance();
|
||
|
|
reg.loadModels(testJsonPath());
|
||
|
|
|
||
|
|
IModel* m = reg.getOrCreate("const_100", 0.0f, "builtin_1");
|
||
|
|
CHECK(m != nullptr);
|
||
|
|
CHECK_FLOAT_EQ(m->evaluate(0), 100.0f, 0.001f);
|
||
|
|
CHECK_FLOAT_EQ(m->evaluate(999), 100.0f, 0.001f);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(registry_linear_model_via_template) {
|
||
|
|
auto& reg = ModelRegistry::instance();
|
||
|
|
IModel* m = reg.getOrCreate("linear_k1", 5.0f, "linear_1");
|
||
|
|
CHECK(m != nullptr);
|
||
|
|
CHECK_FLOAT_EQ(m->evaluate(0), 5.0f, 0.001f);
|
||
|
|
CHECK_FLOAT_EQ(m->evaluate(3), 8.0f, 0.001f);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(registry_same_key_returns_same_instance) {
|
||
|
|
auto& reg = ModelRegistry::instance();
|
||
|
|
IModel* a = reg.getOrCreate("const_100", 10.0f, "same_key");
|
||
|
|
IModel* b = reg.getOrCreate("linear_k1", 20.0f, "same_key");
|
||
|
|
// same instanceKey → returns cached instance, not a new one
|
||
|
|
CHECK_EQ(a, b);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(registry_different_keys_different_instances) {
|
||
|
|
auto& reg = ModelRegistry::instance();
|
||
|
|
IModel* a = reg.getOrCreate("const_100", 0.0f, "key_a");
|
||
|
|
IModel* b = reg.getOrCreate("const_100", 0.0f, "key_b");
|
||
|
|
CHECK(a != b);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(registry_empty_spec_falls_back_to_normal_tiny) {
|
||
|
|
auto& reg = ModelRegistry::instance();
|
||
|
|
IModel* m = reg.getOrCreate("", 0.0f, "empty_spec_test");
|
||
|
|
CHECK(m != nullptr);
|
||
|
|
// normal_tiny → NormalModel with sigma=0.01, returns near-default
|
||
|
|
float v = m->evaluate(0);
|
||
|
|
(void)v;
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(registry_find_by_model_name) {
|
||
|
|
auto& reg = ModelRegistry::instance();
|
||
|
|
// "const_100" was created via getOrCreate above; should be tracked
|
||
|
|
auto found = reg.findByModelName("const_100");
|
||
|
|
CHECK(!found.empty());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(registry_find_nonexistent) {
|
||
|
|
auto& reg = ModelRegistry::instance();
|
||
|
|
auto found = reg.findByModelName("no_such_model_xyz");
|
||
|
|
CHECK(found.empty());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(registry_composite_syntax) {
|
||
|
|
auto& reg = ModelRegistry::instance();
|
||
|
|
// const_100 + linear_k1: evaluate(0) = 100 + 0 = 100, evaluate(3) = 100 + 8 = 108
|
||
|
|
IModel* m = reg.getOrCreate("const_100+linear_k1", 0.0f, "composite_1");
|
||
|
|
CHECK(m != nullptr);
|
||
|
|
CHECK_FLOAT_EQ(m->evaluate(0), 100.0f, 0.001f);
|
||
|
|
CHECK_FLOAT_EQ(m->evaluate(3), 108.0f, 0.001f);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(registry_not_syntax) {
|
||
|
|
auto& reg = ModelRegistry::instance();
|
||
|
|
// !toggle_1s: negates the bool toggle
|
||
|
|
IModel* m = reg.getOrCreate("!toggle_1s", 0.0f, "not_1");
|
||
|
|
CHECK(m != nullptr);
|
||
|
|
// toggle_1s period_ms=1000 → 50 ticks, first 25 true.
|
||
|
|
// !toggle_1s at t=0 should be false
|
||
|
|
CHECK_EQ(m->evaluateBool(0), false);
|
||
|
|
CHECK_EQ(m->evaluateBool(26), true); // toggle is false at 26, so ! is true
|
||
|
|
}
|