Skip to content

Commit 7e150fb

Browse files
committed
Better checks of types and formats
Signed-off-by: David Laseca Perez <davidlaseca@eprosima.com>
1 parent ce453b1 commit 7e150fb

3 files changed

Lines changed: 142 additions & 2 deletions

File tree

ddspipe_yaml/src/cpp/YamlValidator.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ void YamlValidator::format_checker(
5050
throw std::invalid_argument(value + " is not a valid IPv6 address");
5151
}
5252
}
53+
else
54+
{
55+
EPROSIMA_LOG_WARNING(
56+
DDSPIPE_YAML,
57+
"Unsupported format '" << format << "' in JSON schema. Value '" << value << "' was not validated.");
58+
}
5359
}
5460

5561
YamlValidator::YamlValidator()
@@ -106,19 +112,26 @@ void YamlValidator::set_schema(
106112
<< e.what());
107113
}
108114
break;
115+
116+
default:
117+
throw eprosima::utils::ConfigurationException(
118+
utils::Formatter()
119+
<< "Error occured while loading JSON schema, unsupported YamlValidator::InpuType.\n");
109120
}
110121

111-
// Set the validator schema
122+
// Set the validator schema preventing deletion of the current one
123+
auto new_validator = std::make_unique<nlohmann::json_schema::json_validator>(nullptr, format_checker);
112124
try
113125
{
114-
validator->set_root_schema(schema);
126+
new_validator->set_root_schema(schema);
115127
}
116128
catch (const std::exception& e)
117129
{
118130
throw eprosima::utils::ConfigurationException(
119131
utils::Formatter() << "Error occured while setting the JSON schema in the YamlValidator:\n"
120132
<< e.what());
121133
}
134+
validator = std::move(new_validator);
122135
}
123136

124137
bool YamlValidator::validate_YAML(
@@ -161,6 +174,12 @@ bool YamlValidator::validate_YAML(
161174
// The only allowed scalar types are: boolean, integer, number (double) and string
162175
const std::string value = yml.as<std::string>();
163176

177+
// Ensure quoted numbers as well as quoted "true" and "false" are parsed to strings
178+
if (yml.Tag() == "!")
179+
{
180+
return value;
181+
}
182+
164183
if (value == "true")
165184
{
166185
return true;
@@ -176,6 +195,19 @@ bool YamlValidator::validate_YAML(
176195
} catch (...)
177196
{
178197
}
198+
try
199+
{
200+
return yml.as<long>();
201+
} catch (...)
202+
{
203+
}
204+
try
205+
{
206+
return yml.as<u_int64_t>();
207+
} catch (...)
208+
{
209+
}
210+
179211
try
180212
{
181213
return yml.as<double>();

ddspipe_yaml/test/unittest/yaml_validator/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ set(TEST_LIST
3636
validation_without_schema
3737
validation_with_invalid_yaml_file
3838
validation_is_correct
39+
validation_edge_cases
3940
)
4041

4142
set(TEST_EXTRA_LIBRARIES

ddspipe_yaml/test/unittest/yaml_validator/YamlValidatorTest.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
#include <cpp_utils/exception/ConfigurationException.hpp>
2121

22+
#include <fastdds/dds/log/Log.hpp>
23+
2224
#include <ddspipe_yaml/library/library_dll.h>
2325
#include <ddspipe_yaml/YamlManager.hpp>
2426
#include <ddspipe_yaml/YamlValidator.hpp>
@@ -79,6 +81,83 @@ std::vector<std::string> invalid_files = {
7981
"./test_yaml_files/invalid_object.yaml",
8082
"./test_yaml_files/invalid_new_property.yaml"
8183
};
84+
85+
// Test additional edge cases
86+
std::string edge_cases_schema_string =
87+
R"(
88+
{
89+
"$schema":"http://json-schema.org/draft-07/schema#",
90+
"type":"object",
91+
"additionalProperties":false,
92+
"properties":{
93+
"quoted-int":{
94+
"type":"string"
95+
},
96+
"quoted-float":{
97+
"type":"string"
98+
},
99+
"quoted-bool":{
100+
"type":"string"
101+
},
102+
"plain-int":{
103+
"type":"integer"
104+
},
105+
"plain-bool":{
106+
"type":"boolean"
107+
},
108+
"large-int-1":{
109+
"type":"integer"
110+
},
111+
"large-int-2":{
112+
"type":"integer"
113+
},
114+
"large-int-3":{
115+
"type":"integer"
116+
},
117+
"large-int-4":{
118+
"type":"integer"
119+
},
120+
"large-float-1":{
121+
"type":"number"
122+
},
123+
"large-float-2":{
124+
"type":"number"
125+
},
126+
"string-ipv4":{
127+
"type":"string",
128+
"format":"v4"
129+
},
130+
"string-ipv6":{
131+
"type":"string",
132+
"format":"v6"
133+
},
134+
"string-undefined-format":{
135+
"type":"string",
136+
"format":"undefined-format"
137+
}
138+
}
139+
}
140+
)";
141+
142+
Yaml edge_cases_types_yml = YAML::Load(
143+
"quoted-int: \"123\"\n"
144+
"quoted-float: \"123.456\"\n"
145+
"quoted-bool: \"false\"\n"
146+
"plain-int: 123\n"
147+
"plain-bool: true\n"
148+
"large-int-1: 2147483648\n" // 2^31
149+
"large-int-2: 4294967296\n" // 2^32
150+
"large-int-3: 9223372036854775808\n" // 2^63
151+
"large-int-4: 18446744073709551615\n" // 2^64 - 1
152+
"large-float-1: 18446744073709551616.0\n" // 2^64 float
153+
"large-float-2: 1.7976931348623157e308\n" // std::numeric_limits<double>::max()
154+
);
155+
156+
Yaml edge_cases_format_yml = YAML::Load(
157+
"string-ipv4: 192.168.1.1\n"
158+
"string-ipv6: 2001:db8:85a3::8a2e:370:7334\n" //001:0db8:85a3:0000:0000:8a2e:0370:7334\n"
159+
"string-undefined-format: abc.123.def.456\n"
160+
);
82161
} // namespace test
83162

84163

@@ -189,6 +268,34 @@ TEST(YamlValidatorTest, validation_is_correct)
189268
}
190269
}
191270

271+
/**
272+
* Test a set of edge cases to ensure some edge cases are processed correctly
273+
*/
274+
TEST(YamlValidatorTest, validation_edge_cases)
275+
{
276+
YamlValidator validator = YamlValidator(YamlValidator::InputType::FROM_STRING, test::edge_cases_schema_string);
277+
278+
// all the types are processed correctly
279+
{
280+
ASSERT_TRUE(validator.validate_YAML(test::edge_cases_types_yml));
281+
}
282+
283+
// all the formats are processed correctly
284+
{
285+
eprosima::fastdds::dds::Log::SetVerbosity(eprosima::fastdds::dds::Log::Kind::Warning);
286+
testing::internal::CaptureStderr();
287+
288+
ASSERT_TRUE(validator.validate_YAML(test::edge_cases_format_yml));
289+
290+
eprosima::fastdds::dds::Log::Flush();
291+
std::string output = testing::internal::GetCapturedStderr();
292+
ASSERT_NE(output.find("undefined-format"), std::string::npos); // the string is different from not found
293+
294+
eprosima::fastdds::dds::Log::SetVerbosity(eprosima::fastdds::dds::Log::Kind::Error); // restore verbosity
295+
}
296+
297+
}
298+
192299
int main(
193300
int argc,
194301
char** argv)

0 commit comments

Comments
 (0)