From 9a77f9d7aebfe22df0ced995ad0678997b188bf7 Mon Sep 17 00:00:00 2001 From: Joao Paulo Magalhaes Date: Tue, 21 Oct 2025 02:29:52 +0100 Subject: [PATCH] Emitter: improve coverage --- samples/quickstart.cpp | 12 +++++---- src/c4/yml/detail/print.hpp | 2 +- test/CMakeLists.txt | 2 +- test/test_anchor.cpp | 19 ++++++++++++++ test/test_emit.cpp | 26 +++++++++++++++++++ test/test_parser.cpp | 27 +++++++++++++------- test/{test_tag_property.cpp => test_tag.cpp} | 18 +++++++++++++ 7 files changed, 90 insertions(+), 16 deletions(-) rename test/{test_tag_property.cpp => test_tag.cpp} (98%) diff --git a/samples/quickstart.cpp b/samples/quickstart.cpp index 3eb9f386..d71fa9f2 100644 --- a/samples/quickstart.cpp +++ b/samples/quickstart.cpp @@ -4560,7 +4560,6 @@ void sample_style_flow_ml_indent() { // we will be using this helper throughout this function auto tostr = [](ryml::ConstNodeRef n, ryml::EmitOptions opts) { -std::cout << "~~~" << ryml::emitrs_yaml(n, opts) << "~~~\n"; return ryml::emitrs_yaml(n, opts); }; ryml::csubstr yaml = "{map: {seq: [0, 1, 2, 3, [40, 41]]}}"; @@ -4669,16 +4668,18 @@ void sample_style_flow_ml_filter() { const ryml::Tree tree = ryml::parse_in_arena(yaml); CHECK(tree["map"].is_flow_ml()); // etc + // emitted yaml is exactly equal to parsed yaml: CHECK(ryml::emitrs_yaml(tree) == yaml); } // if you prefer to shorten the emitted yaml, you can set the - // parser to use singleline flow (FLOW_SL): + // parser to set singleline flow (FLOW_SL) on all flow containers: { const ryml::ParserOptions opts = ryml::ParserOptions{}.detect_flow_ml(false); const ryml::Tree tree = ryml::parse_in_arena(yaml, opts); CHECK(tree["map"].is_flow_sl()); // etc - // notice how this is smaller - CHECK(ryml::emitrs_yaml(tree) == R"({map: {seq: [0,1,2,3,[40,41]]}})"); + // notice how this is smaller now: + CHECK(ryml::emitrs_yaml(tree) == + R"({map: {seq: [0,1,2,3,[40,41]]}})"); } // you can also keep FLOW_ML, but control its indentation: // (see more details in @ref sample_style_flow_ml_indent()) @@ -4686,7 +4687,8 @@ void sample_style_flow_ml_filter() const ryml::EmitOptions noindent = ryml::EmitOptions{}.indent_flow_ml(false); const ryml::Tree tree = ryml::parse_in_arena(yaml); CHECK(tree["map"].is_flow_ml()); // etc - CHECK(ryml::emitrs_yaml(tree, noindent) == R"({ + CHECK(ryml::emitrs_yaml(tree, noindent) == + R"({ map: { seq: [ 0, diff --git a/src/c4/yml/detail/print.hpp b/src/c4/yml/detail/print.hpp index 5f5b4277..f5c0a2fe 100644 --- a/src/c4/yml/detail/print.hpp +++ b/src/c4/yml/detail/print.hpp @@ -133,7 +133,7 @@ inline C4_NO_INLINE id_type print_node(Tree const& p, id_type node, int level, i //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -inline void print_node(ConstNodeRef const& p, int level=0, bool print_address=false) +inline void print_node(ConstNodeRef const& p, int level=0, bool print_address=false) // LCOV_EXCL_LINE { print_node(*p.tree(), p.id(), level, 0, true, print_address); // LCOV_EXCL_LINE } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5a30f8d3..43e55060 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -127,7 +127,7 @@ ryml_add_test_case_group(scalar_dquoted) ryml_add_test_case_group(scalar_literal) ryml_add_test_case_group(scalar_folded) ryml_add_test_case_group(scalar_plain) -ryml_add_test_case_group(tag_property) +ryml_add_test_case_group(tag) ryml_add_test_case_group(explicit_key) ryml_add_test_case_group(map_nestedx2) ryml_add_test_case_group(seq_nestedx2) diff --git a/test/test_anchor.cpp b/test/test_anchor.cpp index a59f467d..f6f5db82 100644 --- a/test/test_anchor.cpp +++ b/test/test_anchor.cpp @@ -859,6 +859,25 @@ k2: } +TEST(simple_anchor, key_anchor_error_json) +{ + Tree tree = parse_in_arena("{&k key: val}"); + EXPECT_EQ(emitrs_json(tree), "{\"key\": \"val\"}"); + ExpectError::check_error_visit(&tree, [&]{ + emitrs_json(tree, EmitOptions{}.json_error_flags(EmitOptions::JSON_ERR_ON_ANCHOR)); + }); +} + +TEST(simple_anchor, val_anchor_error_json) +{ + Tree tree = parse_in_arena("{key: &v val}"); + EXPECT_EQ(emitrs_json(tree), "{\"key\": \"val\"}"); + ExpectError::check_error_visit(&tree, [&]{ + emitrs_json(tree, EmitOptions{}.json_error_flags(EmitOptions::JSON_ERR_ON_ANCHOR)); + }); +} + + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- diff --git a/test/test_emit.cpp b/test/test_emit.cpp index 2896a27a..96407c1f 100644 --- a/test/test_emit.cpp +++ b/test/test_emit.cpp @@ -232,6 +232,32 @@ TEST(emit_nested, basic) )"); } +TEST(emit_block_seq, ambiguous_plain_emitted_as_squo) +{ + Tree t; + NodeRef r = t.rootref(); + r |= SEQ|BLOCK; + r[0] = ": odd"; + r[0] |= VAL_PLAIN; + r[1] = ":\todd"; + r[1] |= VAL_PLAIN; + EXPECT_EQ(emitrs_yaml(t), "- ': odd'\n- ':\todd'\n"); +} + +TEST(emit_block_map, ambiguous_plain_emitted_as_squo) +{ + Tree t; + NodeRef r = t.rootref(); + r |= MAP|BLOCK; + r[0].set_key(": odd"); + r[0] = ": odd"; + r[0] |= KEY_PLAIN|VAL_PLAIN; + r[1].set_key(":\todd"); + r[1] = ":\todd"; + r[1] |= KEY_PLAIN|VAL_PLAIN; + EXPECT_EQ(emitrs_yaml(t), "': odd': ': odd'\n':\todd': ':\todd'\n"); +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- diff --git a/test/test_parser.cpp b/test/test_parser.cpp index ada46893..1100313a 100644 --- a/test/test_parser.cpp +++ b/test/test_parser.cpp @@ -616,32 +616,41 @@ TEST(parse_in_arena, error_without_handler) TEST(parse_flow_ml, respects_parser_options) { - csubstr yaml = R"({ + std::string yaml = R"({ foo: 0, bar: 1, map: { hell: yeah }, seq: [ - hell, yeah + hell, + yeah ] -})"; +} +)"; const ParserOptions defaults = ParserOptions{}; + const ParserOptions flow_ml = ParserOptions{}.detect_flow_ml(true); const ParserOptions no_flow_ml = ParserOptions{}.detect_flow_ml(false); { SCOPED_TRACE("default behavior: detect flow_ml"); - test_check_emit_check_with_parser(yaml, defaults, [](const Tree& t, Parser const&){ - EXPECT_TRUE(t.rootref().is_flow_ml()); - EXPECT_TRUE(t["map"].is_flow_ml()); - EXPECT_TRUE(t["seq"].is_flow_ml()); - }); + for(ParserOptions opts : {defaults, flow_ml}) + { + test_check_emit_check_with_parser(to_csubstr(yaml), opts, [&](const Tree& t, Parser const&){ + EXPECT_TRUE(t.rootref().is_flow_ml()); + EXPECT_TRUE(t["map"].is_flow_ml()); + EXPECT_TRUE(t["seq"].is_flow_ml()); + EXPECT_EQ(emitrs_yaml(t), yaml); + }); + } } { SCOPED_TRACE("custom behavior: do not detect flow_ml"); - test_check_emit_check_with_parser(yaml, no_flow_ml, [](const Tree& t, Parser const&){ + test_check_emit_check_with_parser(to_csubstr(yaml), no_flow_ml, [](const Tree& t, Parser const&){ EXPECT_FALSE(t.rootref().is_flow_ml()); EXPECT_FALSE(t["map"].is_flow_ml()); EXPECT_FALSE(t["seq"].is_flow_ml()); + EXPECT_EQ(emitrs_yaml(t), + "{foo: 0,bar: 1,map: {hell: yeah},seq: [hell,yeah]}"); }); } } diff --git a/test/test_tag_property.cpp b/test/test_tag.cpp similarity index 98% rename from test/test_tag_property.cpp rename to test/test_tag.cpp index 49f0016a..e577a968 100644 --- a/test/test_tag_property.cpp +++ b/test/test_tag.cpp @@ -1070,6 +1070,24 @@ TEST(tags, ys0) }); } +TEST(tags, key_tag_error_json) +{ + Tree tree = parse_in_arena("{!!str key: val}"); + EXPECT_EQ(emitrs_json(tree), "{\"key\": \"val\"}"); + ExpectError::check_error_visit(&tree, [&]{ + emitrs_json(tree, EmitOptions{}.json_error_flags(EmitOptions::JSON_ERR_ON_TAG)); + }); +} + +TEST(tags, val_tag_error_json) +{ + Tree tree = parse_in_arena("{key: !!str val}"); + EXPECT_EQ(emitrs_json(tree), "{\"key\": \"val\"}"); + ExpectError::check_error_visit(&tree, [&]{ + emitrs_json(tree, EmitOptions{}.json_error_flags(EmitOptions::JSON_ERR_ON_TAG)); + }); +} + //----------------------------------------------------------------------------- //-----------------------------------------------------------------------------