From ba955e3300a0db0842475f08281b30e2c5617e31 Mon Sep 17 00:00:00 2001 From: Alexandru Farcasanu Date: Fri, 28 Aug 2026 11:51:26 +0200 Subject: [PATCH] Reject externally tagged variants with more than one field Reading an rfl::Variant, ...> from an object with several keys silently kept the last recognized tag, and an unknown key followed by a valid tag overwrote the error. Serde, which this format models, rejects such objects. The reader now returns an error whenever a second field is encountered, mirroring the existing 'found none' error. --- include/rfl/parsing/FieldVariantReader.hpp | 6 +++ .../test_field_variant_multiple_fields.cpp | 42 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/json/test_field_variant_multiple_fields.cpp diff --git a/include/rfl/parsing/FieldVariantReader.hpp b/include/rfl/parsing/FieldVariantReader.hpp index ec045e5aa..b7454b1a7 100644 --- a/include/rfl/parsing/FieldVariantReader.hpp +++ b/include/rfl/parsing/FieldVariantReader.hpp @@ -43,6 +43,12 @@ class FieldVariantReader { */ void read(const std::string_view& _disc_value, const InputVarType& _var) const noexcept { + if (*field_variant_) { + *field_variant_ = error( + "Could not parse rfl::Variant: Expected the object to have " + "exactly one field, but found more than one."); + return; + } try_matching_fields( _disc_value, _var, std::make_integer_sequence()); diff --git a/tests/json/test_field_variant_multiple_fields.cpp b/tests/json/test_field_variant_multiple_fields.cpp new file mode 100644 index 000000000..db6ee5e66 --- /dev/null +++ b/tests/json/test_field_variant_multiple_fields.cpp @@ -0,0 +1,42 @@ +#include + +#include +#include +#include + +namespace test_field_variant_multiple_fields { + +struct Circle { + double radius; +}; + +struct Rectangle { + double height; + double width; +}; + +using Shapes = + rfl::Variant, rfl::Field<"rectangle", Rectangle>>; + +TEST(json, test_field_variant_multiple_fields) { + const std::string faulty_string = + R"({"circle":{"radius":2.0},"rectangle":{"height":10.0,"width":5.0}})"; + + const auto result = rfl::json::read(faulty_string); + + EXPECT_TRUE(!result.has_value() && true); + EXPECT_EQ(result.error().what(), + "Could not parse rfl::Variant: Expected the object to have " + "exactly one field, but found more than one."); +} + +TEST(json, test_field_variant_unknown_then_known_field) { + const std::string faulty_string = + R"({"triangle":{"base":3.0},"circle":{"radius":2.0}})"; + + const auto result = rfl::json::read(faulty_string); + + EXPECT_TRUE(!result.has_value() && true); +} + +} // namespace test_field_variant_multiple_fields