From c2c65aed24c4a236c842df45099ec84166685a3a Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Mon, 8 Jun 2026 21:23:58 +0200 Subject: [PATCH 1/3] WIP: respects DefaultVal in schema and adds default value to schema. fixes #679, #396 --- include/rfl/json/schema/Type.hpp | 1 + include/rfl/parsing/NamedTupleParser.hpp | 32 ++++++++++++--- include/rfl/parsing/ParserDefaultVal.hpp | 4 +- include/rfl/parsing/ParserRflVariant.hpp | 2 +- include/rfl/parsing/Parser_default.hpp | 16 ++++++-- include/rfl/parsing/schema/Type.hpp | 7 +++- src/rfl/json/to_schema.cpp | 14 ++++++- tests/json/test_json_schema_default_vals.cpp | 41 ++++++++++++++++++++ 8 files changed, 103 insertions(+), 14 deletions(-) create mode 100644 tests/json/test_json_schema_default_vals.cpp diff --git a/include/rfl/json/schema/Type.hpp b/include/rfl/json/schema/Type.hpp index 8ed247928..a17f3ce18 100644 --- a/include/rfl/json/schema/Type.hpp +++ b/include/rfl/json/schema/Type.hpp @@ -21,6 +21,7 @@ struct Type { std::optional description{}; std::optional deprecated{}; std::optional deprecationMessage{}; + rfl::Rename<"default", std::optional> defaultValue{}; }; struct Boolean { diff --git a/include/rfl/parsing/NamedTupleParser.hpp b/include/rfl/parsing/NamedTupleParser.hpp index de6153e46..995409f8f 100644 --- a/include/rfl/parsing/NamedTupleParser.hpp +++ b/include/rfl/parsing/NamedTupleParser.hpp @@ -30,6 +30,7 @@ #include "is_required.hpp" #include "schema/Type.hpp" #include "to_single_error_message.hpp" +#include "../json/write.hpp" namespace rfl::parsing { @@ -180,10 +181,12 @@ struct NamedTupleParser { * @param _definitions The map of definitions to add to. * @return The schema type. */ + template static schema::Type to_schema( - std::map* _definitions) noexcept { + std::map* _definitions, View* _view = (void*) nullptr) noexcept { + SchemaType schema; - build_schema(_definitions, &schema, + build_schema(_definitions, &schema, _view, std::make_integer_sequence()); return schema::Type{schema}; } @@ -226,14 +229,30 @@ struct NamedTupleParser { } } - template + template static void add_field_to_schema( std::map* _definitions, - SchemaType* _schema) noexcept { + SchemaType* _schema, + View* _view) noexcept { using F = internal::nth_element_t<_i, FieldTypes...>; using U = std::remove_cvref_t; if constexpr (!internal::is_skip_v && !internal::is_extra_fields_v) { + // Add default value here auto s = Parser::to_schema(_definitions); + static_assert(std::is_same_v, "was sonst?"); + if constexpr (!std::is_same_v) { + + if constexpr (std::is_same_v) { + // s.default_value_ = Parser::write(_w, *rfl::get<_i>(_view), new_parent);; + s.variant_.visit([&](auto& value) { + if constexpr (std::is_same_v, schema::Type::WithDefault>) { + // TODO we have to pass a writer here for other serialization formats + // and we would need something like glaze::raw or make default_value_ a template (or std::any, but then we don't know how to serialize + value.default_value_ = rfl::json::write((*rfl::get<_i>(*_view)).get()); + } + }); + } + } if constexpr (_no_field_names) { _schema->types_.emplace_back(std::move(s)); } else { @@ -249,11 +268,12 @@ struct NamedTupleParser { (add_field_to_object<_is>(_w, _tup, _ptr), ...); } - template + template static void build_schema(std::map* _definitions, SchemaType* _schema, + View* _view, std::integer_sequence) noexcept { - (add_field_to_schema<_is>(_definitions, _schema), ...); + (add_field_to_schema(_definitions, _schema, _view), ...); if constexpr (NamedTupleType::pos_extra_fields() != -1) { using F = internal::nth_element_t* _definitions) { using U = std::remove_cvref_t; - return schema::Type{ - Parser::to_schema(_definitions)}; + return schema::Type{schema::Type::WithDefault{Ref::make( + Parser::to_schema(_definitions)), "default"}}; } }; diff --git a/include/rfl/parsing/ParserRflVariant.hpp b/include/rfl/parsing/ParserRflVariant.hpp index 744764ff4..42096cec8 100644 --- a/include/rfl/parsing/ParserRflVariant.hpp +++ b/include/rfl/parsing/ParserRflVariant.hpp @@ -216,7 +216,7 @@ class ParserRflVariant, using AltType = std::remove_cvref_t>; _types->push_back( - Parser::to_schema(_definitions)); + Parser::to_schema(_definitions, (void*)nullptr)); } template diff --git a/include/rfl/parsing/Parser_default.hpp b/include/rfl/parsing/Parser_default.hpp index 466054344..b05ac79e0 100644 --- a/include/rfl/parsing/Parser_default.hpp +++ b/include/rfl/parsing/Parser_default.hpp @@ -572,6 +572,7 @@ struct Parser { } else if constexpr (rfl::internal::is_deprecated_v) { return make_deprecated(_definitions); + } else if constexpr (std::is_class_v && std::is_aggregate_v) { return make_reference(_definitions); @@ -637,9 +638,18 @@ struct Parser { } else { using NamedTupleType = internal::processed_t; - (*_definitions)[name] = - Parser::to_schema( - _definitions); + if constexpr (internal::has_default_val_v) { + auto t = U{}; + auto view = ProcessorsType::template process(to_view(t)); + using ViewType = decltype(view); + (*_definitions)[name] = + Parser::to_schema( + _definitions, &view); + }else { + (*_definitions)[name] = + Parser::to_schema( + _definitions, (void*)nullptr); + } } } return Type{Type::Reference{name}}; diff --git a/include/rfl/parsing/schema/Type.hpp b/include/rfl/parsing/schema/Type.hpp index ba2a1acf0..67d7ea9e5 100644 --- a/include/rfl/parsing/schema/Type.hpp +++ b/include/rfl/parsing/schema/Type.hpp @@ -80,6 +80,11 @@ struct RFL_API Type { Ref type_; }; + struct WithDefault { + Ref type_; + std::string default_value_; + }; + /// The is necessary to resolve circular definitions. Refers to something in /// Definitions. struct Reference { @@ -108,7 +113,7 @@ struct RFL_API Type { rfl::Variant; /** diff --git a/src/rfl/json/to_schema.cpp b/src/rfl/json/to_schema.cpp index 47c3868a7..91193d739 100644 --- a/src/rfl/json/to_schema.cpp +++ b/src/rfl/json/to_schema.cpp @@ -34,6 +34,7 @@ namespace rfl::json { schema::Type type_to_json_schema_type(const parsing::schema::Type& _type, const bool _no_required); +template bool is_optional(const parsing::schema::Type& _t) { return _t.variant_.visit([&](const auto& _v) -> bool { using T = std::remove_cvref_t; @@ -47,6 +48,9 @@ bool is_optional(const parsing::schema::Type& _t) { } else if constexpr (std::is_same_v) { return is_optional(*_v.type_); + } else if constexpr (std::is_same_v) { + return WithDefaultAsOptional ? true : is_optional(*_v.type_); + } else { return std::is_same_v; } @@ -239,6 +243,14 @@ schema::Type type_to_json_schema_type(const parsing::schema::Type& _type, }; return rfl::visit(update_prediction, res.value); + } else if constexpr (std::is_same()) { + auto res = type_to_json_schema_type(*_t.type_, _no_required); + const auto update_prediction = [&](auto _v) -> schema::Type { + _v.annotations.value_.defaultValue = _t.default_value_; + return schema::Type{_v}; + }; + return rfl::visit(update_prediction, res.value); + } else if constexpr (std::is_same()) { return schema::Type{ .value = schema::Type::FixedSizeTypedArray{ @@ -272,7 +284,7 @@ schema::Type type_to_json_schema_type(const parsing::schema::Type& _type, auto required = std::vector(); for (const auto& [k, v] : _t.types_) { properties[k] = type_to_json_schema_type(v, _no_required); - if (!is_optional(v) && !_no_required) { + if (!is_optional(v) && !_no_required) { required.push_back(k); } } diff --git a/tests/json/test_json_schema_default_vals.cpp b/tests/json/test_json_schema_default_vals.cpp new file mode 100644 index 000000000..4a9e6b9e3 --- /dev/null +++ b/tests/json/test_json_schema_default_vals.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +#include "write_and_read.hpp" + +namespace test_schema_default { + +struct Config { + int port = 80; + bool autostart = true; +}; + +struct DefaultValField { + rfl::DefaultVal with_default = 10; +}; + + +struct DefaultWithConfig { + rfl::DefaultVal with_default = Config{443, true}; +}; + +TEST(json, test_with_default) { + auto json_schema = rfl::json::to_schema(); + + std::string expected = R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_schema_default__DefaultValField","$defs":{"test_schema_default__DefaultValField":{"type":"object","properties":{"with_default":{"type":"integer","default":"10"}},"required":[]}}})"; + + EXPECT_EQ(json_schema, expected) << json_schema ; + + json_schema = rfl::json::to_schema(); + expected = R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_schema_default__DefaultWithConfig","$defs":{"test_schema_default__Config":{"type":"object","properties":{"port":{"type":"integer"},"autostart":{"type":"boolean"}},"required":["port","autostart"]},"test_schema_default__DefaultWithConfig":{"type":"object","properties":{"with_default":{"$ref":"#/$defs/test_schema_default__Config","default":"{\"port\":443,\"autostart\":true}"}},"required":[]}}})"; + + EXPECT_EQ(json_schema, expected) << "is " << json_schema ; + +} + + + +} // namespace test_schema_default From a8cf35b39d5099e263ce9d0cd47dbf6fe460a678 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 9 Jun 2026 14:59:37 +0200 Subject: [PATCH 2/3] use generic --- include/rfl/json/schema/Type.hpp | 2 +- include/rfl/parsing/NamedTupleParser.hpp | 13 +++++++++---- include/rfl/parsing/schema/Type.hpp | 2 +- tests/json/test_json_schema_default_vals.cpp | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/rfl/json/schema/Type.hpp b/include/rfl/json/schema/Type.hpp index a17f3ce18..0ae023f5e 100644 --- a/include/rfl/json/schema/Type.hpp +++ b/include/rfl/json/schema/Type.hpp @@ -21,7 +21,7 @@ struct Type { std::optional description{}; std::optional deprecated{}; std::optional deprecationMessage{}; - rfl::Rename<"default", std::optional> defaultValue{}; + rfl::Rename<"default", std::optional> defaultValue{}; }; struct Boolean { diff --git a/include/rfl/parsing/NamedTupleParser.hpp b/include/rfl/parsing/NamedTupleParser.hpp index 995409f8f..f1ab8867b 100644 --- a/include/rfl/parsing/NamedTupleParser.hpp +++ b/include/rfl/parsing/NamedTupleParser.hpp @@ -30,7 +30,14 @@ #include "is_required.hpp" #include "schema/Type.hpp" #include "to_single_error_message.hpp" -#include "../json/write.hpp" + +namespace rfl { + +/// forward declaration +template +Generic to_generic(const auto& _t); + +} // namespace rfl namespace rfl::parsing { @@ -246,9 +253,7 @@ struct NamedTupleParser { // s.default_value_ = Parser::write(_w, *rfl::get<_i>(_view), new_parent);; s.variant_.visit([&](auto& value) { if constexpr (std::is_same_v, schema::Type::WithDefault>) { - // TODO we have to pass a writer here for other serialization formats - // and we would need something like glaze::raw or make default_value_ a template (or std::any, but then we don't know how to serialize - value.default_value_ = rfl::json::write((*rfl::get<_i>(*_view)).get()); + value.default_value_ = rfl::to_generic((*rfl::get<_i>(*_view)).get()); } }); } diff --git a/include/rfl/parsing/schema/Type.hpp b/include/rfl/parsing/schema/Type.hpp index 67d7ea9e5..9578e2d66 100644 --- a/include/rfl/parsing/schema/Type.hpp +++ b/include/rfl/parsing/schema/Type.hpp @@ -82,7 +82,7 @@ struct RFL_API Type { struct WithDefault { Ref type_; - std::string default_value_; + Generic default_value_; }; /// The is necessary to resolve circular definitions. Refers to something in diff --git a/tests/json/test_json_schema_default_vals.cpp b/tests/json/test_json_schema_default_vals.cpp index 4a9e6b9e3..c9144f0c9 100644 --- a/tests/json/test_json_schema_default_vals.cpp +++ b/tests/json/test_json_schema_default_vals.cpp @@ -25,12 +25,12 @@ struct DefaultWithConfig { TEST(json, test_with_default) { auto json_schema = rfl::json::to_schema(); - std::string expected = R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_schema_default__DefaultValField","$defs":{"test_schema_default__DefaultValField":{"type":"object","properties":{"with_default":{"type":"integer","default":"10"}},"required":[]}}})"; + std::string expected = R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_schema_default__DefaultValField","$defs":{"test_schema_default__DefaultValField":{"type":"object","properties":{"with_default":{"type":"integer","default":10}},"required":[]}}})"; EXPECT_EQ(json_schema, expected) << json_schema ; json_schema = rfl::json::to_schema(); - expected = R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_schema_default__DefaultWithConfig","$defs":{"test_schema_default__Config":{"type":"object","properties":{"port":{"type":"integer"},"autostart":{"type":"boolean"}},"required":["port","autostart"]},"test_schema_default__DefaultWithConfig":{"type":"object","properties":{"with_default":{"$ref":"#/$defs/test_schema_default__Config","default":"{\"port\":443,\"autostart\":true}"}},"required":[]}}})"; + expected = R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_schema_default__DefaultWithConfig","$defs":{"test_schema_default__Config":{"type":"object","properties":{"port":{"type":"integer"},"autostart":{"type":"boolean"}},"required":["port","autostart"]},"test_schema_default__DefaultWithConfig":{"type":"object","properties":{"with_default":{"$ref":"#/$defs/test_schema_default__Config","default":{"port":443,"autostart":true}}},"required":[]}}})"; EXPECT_EQ(json_schema, expected) << "is " << json_schema ; From 1290a7709bf79e2642f010aa935974f63dcf84d4 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 10 Jun 2026 16:59:37 +0200 Subject: [PATCH 3/3] adapt changes --- include/rfl/parsing/NamedTupleParser.hpp | 23 +++++++++----------- include/rfl/parsing/Parser_default.hpp | 4 +--- src/rfl/json/to_schema.cpp | 21 ++++++------------ tests/json/test_json_schema5.cpp | 7 +++--- tests/json/test_json_schema_default_vals.cpp | 20 +++++++---------- 5 files changed, 29 insertions(+), 46 deletions(-) diff --git a/include/rfl/parsing/NamedTupleParser.hpp b/include/rfl/parsing/NamedTupleParser.hpp index f1ab8867b..8542cdb7b 100644 --- a/include/rfl/parsing/NamedTupleParser.hpp +++ b/include/rfl/parsing/NamedTupleParser.hpp @@ -188,10 +188,10 @@ struct NamedTupleParser { * @param _definitions The map of definitions to add to. * @return The schema type. */ - template + template static schema::Type to_schema( - std::map* _definitions, View* _view = (void*) nullptr) noexcept { - + std::map* _definitions, + View* _view = nullptr) noexcept { SchemaType schema; build_schema(_definitions, &schema, _view, std::make_integer_sequence()); @@ -246,17 +246,14 @@ struct NamedTupleParser { if constexpr (!internal::is_skip_v && !internal::is_extra_fields_v) { // Add default value here auto s = Parser::to_schema(_definitions); - static_assert(std::is_same_v, "was sonst?"); if constexpr (!std::is_same_v) { - - if constexpr (std::is_same_v) { - // s.default_value_ = Parser::write(_w, *rfl::get<_i>(_view), new_parent);; - s.variant_.visit([&](auto& value) { - if constexpr (std::is_same_v, schema::Type::WithDefault>) { - value.default_value_ = rfl::to_generic((*rfl::get<_i>(*_view)).get()); - } - }); - } + s.variant_.visit([&](auto& value) { + if constexpr (std::is_same_v, + schema::Type::DefaultVal>) { + value.default_value_ = + rfl::to_generic((*rfl::get<_i>(*_view)).get()); + } + }); } if constexpr (_no_field_names) { _schema->types_.emplace_back(std::move(s)); diff --git a/include/rfl/parsing/Parser_default.hpp b/include/rfl/parsing/Parser_default.hpp index b05ac79e0..ecab78c74 100644 --- a/include/rfl/parsing/Parser_default.hpp +++ b/include/rfl/parsing/Parser_default.hpp @@ -641,14 +641,12 @@ struct Parser { if constexpr (internal::has_default_val_v) { auto t = U{}; auto view = ProcessorsType::template process(to_view(t)); - using ViewType = decltype(view); (*_definitions)[name] = Parser::to_schema( _definitions, &view); }else { (*_definitions)[name] = - Parser::to_schema( - _definitions, (void*)nullptr); + Parser::to_schema(_definitions); } } } diff --git a/src/rfl/json/to_schema.cpp b/src/rfl/json/to_schema.cpp index 686113061..b6ed76cd6 100644 --- a/src/rfl/json/to_schema.cpp +++ b/src/rfl/json/to_schema.cpp @@ -34,7 +34,6 @@ namespace rfl::json { schema::Type type_to_json_schema_type(const parsing::schema::Type& _type, const bool _no_required); -template bool is_optional(const parsing::schema::Type& _t) { return _t.variant_.visit([&](const auto& _v) -> bool { using T = std::remove_cvref_t; @@ -48,9 +47,6 @@ bool is_optional(const parsing::schema::Type& _t) { } else if constexpr (std::is_same_v) { return is_optional(*_v.type_); - } else if constexpr (std::is_same_v) { - return WithDefaultAsOptional ? true : is_optional(*_v.type_); - } else { return std::is_same_v || std::is_same_v; @@ -227,30 +223,27 @@ schema::Type type_to_json_schema_type(const parsing::schema::Type& _type, return schema::Type{.value = schema::Type::AnyOf{.anyOf = any_of}}; } else if constexpr (std::is_same()) { - return type_to_json_schema_type(*_t.type_, _no_required); - - } else if constexpr (std::is_same()) { auto res = type_to_json_schema_type(*_t.type_, _no_required); const auto update_prediction = [&](auto _v) -> schema::Type { - _v.annotations.value_.description = _t.description_; - _v.annotations.value_.deprecated = true; - _v.annotations.value_.deprecationMessage = _t.deprecation_message_; + _v.annotations.value_.defaultValue = _t.default_value_; return schema::Type{_v}; }; return rfl::visit(update_prediction, res.value); - } else if constexpr (std::is_same()) { + } else if constexpr (std::is_same()) { auto res = type_to_json_schema_type(*_t.type_, _no_required); const auto update_prediction = [&](auto _v) -> schema::Type { _v.annotations.value_.description = _t.description_; + _v.annotations.value_.deprecated = true; + _v.annotations.value_.deprecationMessage = _t.deprecation_message_; return schema::Type{_v}; }; return rfl::visit(update_prediction, res.value); - } else if constexpr (std::is_same()) { + } else if constexpr (std::is_same()) { auto res = type_to_json_schema_type(*_t.type_, _no_required); const auto update_prediction = [&](auto _v) -> schema::Type { - _v.annotations.value_.defaultValue = _t.default_value_; + _v.annotations.value_.description = _t.description_; return schema::Type{_v}; }; return rfl::visit(update_prediction, res.value); @@ -288,7 +281,7 @@ schema::Type type_to_json_schema_type(const parsing::schema::Type& _type, auto required = std::vector(); for (const auto& [k, v] : _t.types_) { properties[k] = type_to_json_schema_type(v, _no_required); - if (!is_optional(v) && !_no_required) { + if (!is_optional(v) && !_no_required) { required.push_back(k); } } diff --git a/tests/json/test_json_schema5.cpp b/tests/json/test_json_schema5.cpp index f6196a141..28e432ff7 100644 --- a/tests/json/test_json_schema5.cpp +++ b/tests/json/test_json_schema5.cpp @@ -5,8 +5,7 @@ namespace test_json_schema5 { -using Age = rfl::Validator, rfl::Minimum<0>, - rfl::Maximum<130>>; +using Age = rfl::Validator, rfl::Maximum<130>>; struct Person { rfl::Description<"Given name of this person", std::string> first_name; @@ -14,14 +13,14 @@ struct Person { std::optional> last_name; Age age; - rfl::DefaultVal nickname; + rfl::DefaultVal nickname = "peter"; }; TEST(json, test_json_schema5) { const auto json_schema = rfl::json::to_schema(); const std::string expected = - R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_json_schema5__Person","$defs":{"test_json_schema5__Person":{"type":"object","properties":{"first_name":{"type":"string","description":"Given name of this person"},"last_name":{"description":"Optional family name of this person","anyOf":[{"type":"string"},{"type":"null"}]},"age":{"allOf":[{"minimum":0,"type":"number"},{"maximum":130,"type":"number"}]},"nickname":{"type":"string"}},"required":["first_name"]}}})"; + R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_json_schema5__Person","$defs":{"test_json_schema5__Person":{"type":"object","properties":{"first_name":{"type":"string","description":"Given name of this person"},"last_name":{"description":"Optional family name of this person","anyOf":[{"type":"string"},{"type":"null"}]},"age":{"allOf":[{"minimum":0,"type":"integer"},{"maximum":130,"type":"integer"}]},"nickname":{"type":"string","default":"peter"}},"required":["first_name","age"]}}})"; EXPECT_EQ(json_schema, expected); } diff --git a/tests/json/test_json_schema_default_vals.cpp b/tests/json/test_json_schema_default_vals.cpp index c9144f0c9..9236a329e 100644 --- a/tests/json/test_json_schema_default_vals.cpp +++ b/tests/json/test_json_schema_default_vals.cpp @@ -4,8 +4,6 @@ #include #include -#include "write_and_read.hpp" - namespace test_schema_default { struct Config { @@ -17,25 +15,23 @@ struct DefaultValField { rfl::DefaultVal with_default = 10; }; - struct DefaultWithConfig { rfl::DefaultVal with_default = Config{443, true}; }; TEST(json, test_with_default) { - auto json_schema = rfl::json::to_schema(); - - std::string expected = R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_schema_default__DefaultValField","$defs":{"test_schema_default__DefaultValField":{"type":"object","properties":{"with_default":{"type":"integer","default":10}},"required":[]}}})"; + auto json_schema = rfl::json::to_schema(); - EXPECT_EQ(json_schema, expected) << json_schema ; + std::string expected = + R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_schema_default__DefaultValField","$defs":{"test_schema_default__DefaultValField":{"type":"object","properties":{"with_default":{"type":"integer","default":10}},"required":[]}}})"; - json_schema = rfl::json::to_schema(); - expected = R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_schema_default__DefaultWithConfig","$defs":{"test_schema_default__Config":{"type":"object","properties":{"port":{"type":"integer"},"autostart":{"type":"boolean"}},"required":["port","autostart"]},"test_schema_default__DefaultWithConfig":{"type":"object","properties":{"with_default":{"$ref":"#/$defs/test_schema_default__Config","default":{"port":443,"autostart":true}}},"required":[]}}})"; + EXPECT_EQ(json_schema, expected) << json_schema; - EXPECT_EQ(json_schema, expected) << "is " << json_schema ; + json_schema = rfl::json::to_schema(); + expected = + R"({"$schema":"https://json-schema.org/draft/2020-12/schema","$ref":"#/$defs/test_schema_default__DefaultWithConfig","$defs":{"test_schema_default__Config":{"type":"object","properties":{"port":{"type":"integer"},"autostart":{"type":"boolean"}},"required":["port","autostart"]},"test_schema_default__DefaultWithConfig":{"type":"object","properties":{"with_default":{"$ref":"#/$defs/test_schema_default__Config","default":{"port":443,"autostart":true}}},"required":[]}}})"; + EXPECT_EQ(json_schema, expected) << "is " << json_schema; } - - } // namespace test_schema_default