From c08c8d2dc0205fc22626931437286b503045f28b Mon Sep 17 00:00:00 2001 From: Markus Weber Date: Sun, 26 Apr 2026 09:16:14 +0200 Subject: [PATCH 1/3] Enhance null handling in YAML reader and add corresponding test case --- include/rfl/yaml/Reader.hpp | 2 +- tests/yaml/test_read_null.cpp | 39 +++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/yaml/test_read_null.cpp diff --git a/include/rfl/yaml/Reader.hpp b/include/rfl/yaml/Reader.hpp index 505339e2..12664522 100644 --- a/include/rfl/yaml/Reader.hpp +++ b/include/rfl/yaml/Reader.hpp @@ -67,7 +67,7 @@ struct Reader { } bool is_empty(const InputVarType& _var) const noexcept { - return !_var.node_ && true; + return !_var.node_ || _var.node_.IsNull(); } template diff --git a/tests/yaml/test_read_null.cpp b/tests/yaml/test_read_null.cpp new file mode 100644 index 00000000..dca71c2b --- /dev/null +++ b/tests/yaml/test_read_null.cpp @@ -0,0 +1,39 @@ +#include + +#include +#include +#include +#include + +namespace test_read_null { + +struct Person { + std::string first_name; + std::optional last_name; + std::optional age; + std::string city; + float weight; + double height; +}; + +TEST(yaml, test_read_null) { + const std::string yaml_str = + "first_name: Homer\n" + "last_name: null\n" + "age: ~\n" + "city: null\n" + "weight: null\n" + "height: null\n"; + + const auto res = rfl::yaml::read(yaml_str); + + ASSERT_TRUE(res && true) << "Test failed on read. Error: " + << res.error().what(); + EXPECT_EQ(res.value().first_name, "Homer"); + EXPECT_FALSE(res.value().last_name.has_value()); + EXPECT_FALSE(res.value().age.has_value()); + EXPECT_EQ(std::numeric_limits::quiet_NaN(), res.value().weight); + EXPECT_EQ(std::numeric_limits::quiet_NaN(), res.value().height); +} + +} // namespace test_read_null From c1be1cdb0e3df527f342c11af18dddc063bf2cdd Mon Sep 17 00:00:00 2001 From: Markus Weber Date: Sun, 26 Apr 2026 09:21:25 +0200 Subject: [PATCH 2/3] Update test for null handling to use NaN for weight and height --- tests/yaml/test_read_null.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/yaml/test_read_null.cpp b/tests/yaml/test_read_null.cpp index dca71c2b..b1f2a7da 100644 --- a/tests/yaml/test_read_null.cpp +++ b/tests/yaml/test_read_null.cpp @@ -22,8 +22,8 @@ TEST(yaml, test_read_null) { "last_name: null\n" "age: ~\n" "city: null\n" - "weight: null\n" - "height: null\n"; + "weight: .nan\n" + "height: .nan\n"; const auto res = rfl::yaml::read(yaml_str); @@ -32,8 +32,8 @@ TEST(yaml, test_read_null) { EXPECT_EQ(res.value().first_name, "Homer"); EXPECT_FALSE(res.value().last_name.has_value()); EXPECT_FALSE(res.value().age.has_value()); - EXPECT_EQ(std::numeric_limits::quiet_NaN(), res.value().weight); - EXPECT_EQ(std::numeric_limits::quiet_NaN(), res.value().height); + EXPECT_TRUE(std::isnan(res.value().weight)); + EXPECT_TRUE(std::isnan(res.value().height)); } } // namespace test_read_null From aceec385e9ab8443fdb399761f8fa1f51070da7e Mon Sep 17 00:00:00 2001 From: Markus Weber Date: Sun, 26 Apr 2026 09:32:36 +0200 Subject: [PATCH 3/3] Add tests for null handling in YAML parser for various types --- tests/yaml/test_read_null.cpp | 106 +++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/tests/yaml/test_read_null.cpp b/tests/yaml/test_read_null.cpp index b1f2a7da..b03fd1db 100644 --- a/tests/yaml/test_read_null.cpp +++ b/tests/yaml/test_read_null.cpp @@ -1,9 +1,11 @@ #include #include +#include #include #include #include +#include namespace test_read_null { @@ -13,7 +15,7 @@ struct Person { std::optional age; std::string city; float weight; - double height; + double height; }; TEST(yaml, test_read_null) { @@ -36,4 +38,106 @@ TEST(yaml, test_read_null) { EXPECT_TRUE(std::isnan(res.value().height)); } +TEST(yaml, test_null_for_required_field_fails) { + const std::string yaml_str = + "first_name: Homer\n" + "last_name: null\n" + "age: ~\n" + "city: Springfield\n" + "weight: null\n" + "height: null\n"; + + const auto res = rfl::yaml::read(yaml_str); + EXPECT_FALSE(res.has_value()); +} + +// One struct per primitive type — each tested with a null value below. + +struct IntHolder { int value; }; +struct Int8Holder { int8_t value; }; +struct Int16Holder { int16_t value; }; +struct Int32Holder { int32_t value; }; +struct Int64Holder { int64_t value; }; +struct UInt8Holder { uint8_t value; }; +struct UInt16Holder { uint16_t value; }; +struct UInt32Holder { uint32_t value; }; +struct UInt64Holder { uint64_t value; }; +struct FloatHolder { float value; }; +struct DoubleHolder { double value; }; +struct BoolHolder { bool value; }; + +struct OptionalIntHolder { std::optional value; }; +struct OptionalStringHolder { std::optional value; }; + +static constexpr std::string_view kNullYaml = "value: null\n"; +static constexpr std::string_view kNaNYaml = "value: .nan\n"; + +TEST(yaml, test_null_for_int_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_null_for_int8_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_null_for_int16_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_null_for_int32_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_null_for_int64_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_null_for_uint8_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_null_for_uint16_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_null_for_uint32_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_null_for_uint64_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_null_for_float_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_nan_for_float_succeeds) { + EXPECT_TRUE(std::isnan(rfl::yaml::read(kNaNYaml).value().value)); +} + +TEST(yaml, test_null_for_double_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_nan_for_double_succeeds) { + EXPECT_TRUE(std::isnan(rfl::yaml::read(kNaNYaml).value().value)); +} + +TEST(yaml, test_null_for_bool_fails) { + EXPECT_FALSE(rfl::yaml::read(kNullYaml).has_value()); +} + +TEST(yaml, test_null_for_optional_int_is_nullopt) { + const auto res = rfl::yaml::read(kNullYaml); + ASSERT_TRUE(res.has_value()); + EXPECT_FALSE(res.value().value.has_value()); +} + +TEST(yaml, test_null_for_optional_string_is_nullopt) { + const auto res = rfl::yaml::read(kNullYaml); + ASSERT_TRUE(res.has_value()); + EXPECT_FALSE(res.value().value.has_value()); +} + } // namespace test_read_null