@@ -29,13 +29,16 @@ using namespace eprosima;
2929using namespace eprosima ::ddspipe::yaml;
3030
3131namespace test {
32- // Paths and files to test the constructors
32+ // Valid schema file used by the happy-path constructor and validation tests
3333std::string valid_schema_path = " ./valid_draft07_schema.json" ;
3434
35+ // Invalid constructor inputs:
36+ // 1) wrong relative path, 2) malformed JSON file, 3) valid JSON but invalid draft-07 schema
3537std::string invalid_schema_path_1 = " ./test_yaml_files/valid_draft07_schema.json" ;
3638std::string invalid_schema_path_2 = " ./invalid_json_schema.json" ;
3739std::string invalid_schema_path_3 = " ./invalid_draft07_schema.json" ;
3840
41+ // Minimal valid draft-07 schema used when the validator is constructed from a raw string
3942std::string valid_schema_string =
4043 R"(
4144{
@@ -57,6 +60,7 @@ std::string valid_schema_string =
5760}
5861)" ;
5962
63+ // Structurally invalid draft-07 schema: "properties" must be an object, not an array
6064std::string invalid_schema_string =
6165 R"(
6266{
@@ -65,15 +69,27 @@ std::string invalid_schema_string =
6569}
6670)" ;
6771
68- // Invalid yaml file/node
72+ // Malformed JSON string used to trigger the parsing-error path in set_schema(FROM_STRING, ...)
73+ std::string malformed_schema_string =
74+ R"(
75+ {
76+ "$schema":"http://json-schema.org/draft-07/schema#",
77+ "type":"object",
78+ )" ;
79+
80+ // Valid YAML instance used as the main schema-validation input.
6981Yaml valid_yml = YamlManager::load_file(" ./test_yaml_files/valid_test.yaml" );
82+
83+ // Missing child node extracted from a valid file to exercise the YAML-to-JSON conversion failure path
7084Yaml invalid_yml = valid_yml[" missing_key" ];
7185
72- // Vectors with the valid and invalid YAML files
86+ // Files expected to pass validation with valid_draft07_schema.json
7387std::vector<std::string> valid_files = {
7488 " ./test_yaml_files/valid_test.yaml"
7589};
7690
91+ // Files expected to fail validation for different reasons: wrong version, negative integer,
92+ // wrong array type, invalid object contents, and unexpected additional property
7793std::vector<std::string> invalid_files = {
7894 " ./test_yaml_files/invalid_version.yaml" ,
7995 " ./test_yaml_files/invalid_uint.yaml" ,
@@ -82,7 +98,8 @@ std::vector<std::string> invalid_files = {
8298 " ./test_yaml_files/invalid_new_property.yaml"
8399};
84100
85- // Test additional edge cases
101+ // Schema used to exercise scalar conversion edge cases:
102+ // quoted values that must remain strings, large numeric values, and custom format checks
86103std::string edge_cases_schema_string =
87104 R"(
88105{
@@ -139,6 +156,52 @@ std::string edge_cases_schema_string =
139156}
140157)" ;
141158
159+ // Schema restricted to the custom IPv4 and IPv6 format validators
160+ std::string ip_format_schema_string =
161+ R"(
162+ {
163+ "$schema":"http://json-schema.org/draft-07/schema#",
164+ "type":"object",
165+ "additionalProperties":false,
166+ "properties":{
167+ "string-ipv4":{
168+ "type":"string",
169+ "format":"v4"
170+ },
171+ "string-ipv6":{
172+ "type":"string",
173+ "format":"v6"
174+ }
175+ }
176+ }
177+ )" ;
178+
179+ // Schema used to verify YAML null nodes are converted to JSON null values
180+ std::string nullable_schema_string =
181+ R"(
182+ {
183+ "$schema":"http://json-schema.org/draft-07/schema#",
184+ "type":"object",
185+ "additionalProperties":false,
186+ "properties":{
187+ "nullable":{
188+ "type":"null"
189+ }
190+ }
191+ }
192+ )" ;
193+
194+ // Root-level integer schema used to trigger validation errors on the YAML root itself
195+ std::string root_integer_schema_string =
196+ R"(
197+ {
198+ "$schema":"http://json-schema.org/draft-07/schema#",
199+ "type":"integer"
200+ }
201+ )" ;
202+
203+ // YAML fixture covering scalar conversion edge cases:
204+ // quoted scalars, large integers, and large floating-point values
142205Yaml edge_cases_types_yml = YAML ::Load(
143206 " quoted-int: \" 123\"\n "
144207 " quoted-float: \" 123.456\"\n "
@@ -153,11 +216,27 @@ Yaml edge_cases_types_yml = YAML::Load(
153216 " large-float-2: 1.7976931348623157e308\n " // std::numeric_limits<double>::max()
154217 );
155218
219+ // YAML fixture with valid IPv4/IPv6 values plus an unsupported custom format,
220+ // which should validate successfully while emitting a warning
156221Yaml edge_cases_format_yml = YAML ::Load(
157222 " string-ipv4: 192.168.1.1\n "
158223 " string-ipv6: 2001:db8:85a3::8a2e:370:7334\n " // 001:0db8:85a3:0000:0000:8a2e:0370:7334\n"
159224 " string-undefined-format: abc.123.def.456\n "
160225 );
226+
227+ // YAML fixture with invalid IPv4/IPv6 values to exercise format-validation failures
228+ Yaml invalid_ip_format_yml = YAML ::Load(
229+ " string-ipv4: 999.999.999.999\n "
230+ " string-ipv6: not-an-ipv6\n "
231+ );
232+
233+ // YAML fixture containing an explicit null value.
234+ Yaml nullable_yml = YAML ::Load(
235+ " nullable: ~\n "
236+ );
237+
238+ // Root scalar that violates root_integer_schema_string and produces a root-level validation error
239+ Yaml root_scalar_string_yml = YAML ::Load(" not-an-integer" );
161240} // namespace test
162241
163242
@@ -296,6 +375,67 @@ TEST(YamlValidatorTest, validation_edge_cases)
296375
297376}
298377
378+ /* *
379+ * Test invalid IPv4 and IPv6 values are reported as validation errors
380+ */
381+ TEST (YamlValidatorTest, validation_reports_invalid_ip_formats)
382+ {
383+ YamlValidator validator = YamlValidator (YamlValidator::InputType::FROM_STRING , test::ip_format_schema_string);
384+
385+ testing::internal::CaptureStderr ();
386+ ASSERT_FALSE (validator.validate_YAML (test::invalid_ip_format_yml));
387+ std::string output = testing::internal::GetCapturedStderr ();
388+
389+ ASSERT_NE (output.find (" /string-ipv4" ), std::string::npos);
390+ ASSERT_NE (output.find (" /string-ipv6" ), std::string::npos);
391+ ASSERT_NE (output.find (" valid IPv4 address" ), std::string::npos);
392+ ASSERT_NE (output.find (" valid IPv6 address" ), std::string::npos);
393+ }
394+
395+ /* *
396+ * Test additional schema-loading error paths and ensure a failed schema update
397+ * does not replace the current valid schema
398+ */
399+ TEST (YamlValidatorTest, schema_loading_error_paths_preserve_previous_schema)
400+ {
401+ YamlValidator validator = YamlValidator (YamlValidator::InputType::FROM_FILE , test::valid_schema_path);
402+
403+ ASSERT_TRUE (validator.validate_YAML (test::valid_yml, false ));
404+
405+ ASSERT_THROW (
406+ validator.set_schema (YamlValidator::InputType::FROM_STRING , test::malformed_schema_string),
407+ utils::ConfigurationException);
408+
409+ ASSERT_THROW (
410+ validator.set_schema (static_cast <YamlValidator::InputType>(99 ), test::valid_schema_string),
411+ utils::ConfigurationException);
412+
413+ ASSERT_TRUE (validator.validate_YAML (test::valid_yml, false ));
414+ }
415+
416+ /* *
417+ * Test null YAML values are converted correctly and root-level validation
418+ * errors are displayed with the root marker
419+ */
420+ TEST (YamlValidatorTest, validation_supports_nulls_and_root_level_error_output)
421+ {
422+ {
423+ YamlValidator validator = YamlValidator (YamlValidator::InputType::FROM_STRING , test::nullable_schema_string);
424+ ASSERT_TRUE (validator.validate_YAML (test::nullable_yml, false ));
425+ }
426+
427+ {
428+ YamlValidator validator = YamlValidator (YamlValidator::InputType::FROM_STRING , test::root_integer_schema_string);
429+
430+ testing::internal::CaptureStderr ();
431+ ASSERT_FALSE (validator.validate_YAML (test::root_scalar_string_yml));
432+ std::string output = testing::internal::GetCapturedStderr ();
433+
434+ ASSERT_NE (output.find (" YAML VALIDATION FAILED" ), std::string::npos);
435+ ASSERT_NE (output.find (" / (root of the YAML file)" ), std::string::npos);
436+ }
437+ }
438+
299439int main (
300440 int argc,
301441 char ** argv)
0 commit comments