Skip to content

Commit b7f2b09

Browse files
committed
test(ui): Add test_parameter_validator.cpp
Split from monolithic test_parameter_validation.cpp into focused validator tests covering: - Required vs optional parameter handling - Default value application and override - Range validation integration - Special floating-point values (NaN, infinity) - Nested parameter paths (dot notation: "model.temperature") - Deeply nested JSON structures (a.b.c.d.value) Tests the ParameterValidator orchestration logic that coordinates multiple ParameterMetadata instances. Validates error collection, ValidationResult construction, and validated_params tracking. Part of UI parameter validation refactoring to improve test clarity and maintainability.
1 parent b27365b commit b7f2b09

File tree

1 file changed

+151
-0
lines changed

1 file changed

+151
-0
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// SPDX-FileCopyrightText: 2025 VTT Technical Research Centre of Finland Ltd
2+
// SPDX-License-Identifier: AGPL-3.0-or-later
3+
4+
#include "openpfc/ui/parameter_validator.hpp"
5+
#include <catch2/catch_all.hpp>
6+
7+
using namespace pfc::ui;
8+
9+
TEST_CASE("ParameterValidator with required parameter",
10+
"[parameter_validator][unit]") {
11+
ParameterValidator validator;
12+
validator.add_metadata(ParameterMetadata<double>::builder()
13+
.name("temperature")
14+
.required(true)
15+
.range(0.0, 10000.0)
16+
.build());
17+
18+
SECTION("Valid configuration with required parameter") {
19+
nlohmann::json config = {{"temperature", 3300.0}};
20+
auto result = validator.validate(config);
21+
REQUIRE(result.is_valid());
22+
}
23+
24+
SECTION("Missing required parameter") {
25+
nlohmann::json config = {};
26+
auto result = validator.validate(config);
27+
REQUIRE_FALSE(result.is_valid());
28+
REQUIRE_FALSE(result.errors.empty());
29+
auto errors_str = result.format_errors();
30+
REQUIRE(errors_str.find("temperature") != std::string::npos);
31+
}
32+
33+
SECTION("Required parameter out of range") {
34+
nlohmann::json config = {{"temperature", -100.0}};
35+
auto result = validator.validate(config);
36+
REQUIRE_FALSE(result.is_valid());
37+
auto errors_str = result.format_errors();
38+
REQUIRE(errors_str.find("below minimum") != std::string::npos);
39+
}
40+
}
41+
42+
TEST_CASE("ParameterValidator with optional parameter",
43+
"[parameter_validator][unit]") {
44+
ParameterValidator validator;
45+
validator.add_metadata(ParameterMetadata<double>::builder()
46+
.name("mobility")
47+
.required(false)
48+
.range(0.0, 100.0)
49+
.build());
50+
51+
SECTION("Valid configuration without optional parameter") {
52+
nlohmann::json config = {};
53+
auto result = validator.validate(config);
54+
REQUIRE(result.is_valid());
55+
}
56+
57+
SECTION("Valid configuration with optional parameter") {
58+
nlohmann::json config = {{"mobility", 50.0}};
59+
auto result = validator.validate(config);
60+
REQUIRE(result.is_valid());
61+
}
62+
63+
SECTION("Optional parameter out of range") {
64+
nlohmann::json config = {{"mobility", 150.0}};
65+
auto result = validator.validate(config);
66+
REQUIRE_FALSE(result.is_valid());
67+
}
68+
}
69+
70+
TEST_CASE("ParameterValidator with default value", "[parameter_validator][unit]") {
71+
ParameterValidator validator;
72+
validator.add_metadata(ParameterMetadata<double>::builder()
73+
.name("tolerance")
74+
.default_val(1e-6)
75+
.range(1e-12, 1e-3)
76+
.build());
77+
78+
SECTION("Missing parameter uses default") {
79+
nlohmann::json config = {};
80+
auto result = validator.validate(config);
81+
REQUIRE(result.is_valid());
82+
// Default value handling is internal to validator
83+
REQUIRE(result.validated_params.find("tolerance") !=
84+
result.validated_params.end());
85+
}
86+
87+
SECTION("Explicit value overrides default") {
88+
nlohmann::json config = {{"tolerance", 1e-8}};
89+
auto result = validator.validate(config);
90+
REQUIRE(result.is_valid());
91+
REQUIRE(result.validated_params.find("tolerance") !=
92+
result.validated_params.end());
93+
}
94+
}
95+
96+
TEST_CASE("Special floating point values", "[parameter_validator][unit]") {
97+
ParameterValidator validator;
98+
validator.add_metadata(ParameterMetadata<double>::builder()
99+
.name("temperature")
100+
.range(0.0, 10000.0)
101+
.build());
102+
103+
SECTION("NaN is rejected") {
104+
nlohmann::json config = {
105+
{"temperature", std::numeric_limits<double>::quiet_NaN()}};
106+
auto result = validator.validate(config);
107+
REQUIRE_FALSE(result.is_valid());
108+
}
109+
110+
SECTION("Infinity is rejected") {
111+
nlohmann::json config = {
112+
{"temperature", std::numeric_limits<double>::infinity()}};
113+
auto result = validator.validate(config);
114+
REQUIRE_FALSE(result.is_valid());
115+
}
116+
}
117+
118+
TEST_CASE("Nested parameter validation", "[parameter_validator][unit]") {
119+
ParameterValidator validator;
120+
validator.add_metadata(ParameterMetadata<double>::builder()
121+
.name("model.temperature")
122+
.required(true)
123+
.range(0.0, 10000.0)
124+
.build());
125+
126+
SECTION("Valid nested parameter") {
127+
nlohmann::json config = {{"model", {{"temperature", 3300.0}}}};
128+
auto result = validator.validate(config);
129+
REQUIRE(result.is_valid());
130+
}
131+
132+
SECTION("Missing nested parameter") {
133+
nlohmann::json config = {{"model", {}}};
134+
auto result = validator.validate(config);
135+
REQUIRE_FALSE(result.is_valid());
136+
auto errors_str = result.format_errors();
137+
REQUIRE(errors_str.find("model.temperature") != std::string::npos);
138+
}
139+
140+
SECTION("Deeply nested parameters") {
141+
ParameterValidator deep_validator;
142+
deep_validator.add_metadata(ParameterMetadata<double>::builder()
143+
.name("a.b.c.d.value")
144+
.required(true)
145+
.build());
146+
147+
nlohmann::json config = {{"a", {{"b", {{"c", {{"d", {{"value", 42.0}}}}}}}}}};
148+
auto result = deep_validator.validate(config);
149+
REQUIRE(result.is_valid());
150+
}
151+
}

0 commit comments

Comments
 (0)