#ifndef RYML_SINGLE_HEADER #include "c4/yml/std/std.hpp" #include "c4/yml/parse.hpp" #include "c4/yml/emit.hpp" #include #include #include #endif #include "./test_case.hpp" #include #if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable: 4389) // signed/unsigned mismatch #elif defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" #elif defined(__GNUC__) # pragma GCC diagnostic push #endif namespace foo { template struct vec2 { T x, y; }; template struct vec3 { T x, y, z; }; template struct vec4 { T x, y, z, w; }; template size_t to_chars(c4::substr buf, vec2 v) { return c4::format(buf, "({},{})", v.x, v.y); } template size_t to_chars(c4::substr buf, vec3 v) { return c4::format(buf, "({},{},{})", v.x, v.y, v.z); } template size_t to_chars(c4::substr buf, vec4 v) { return c4::format(buf, "({},{},{},{})", v.x, v.y, v.z, v.w); } template bool from_chars(c4::csubstr buf, vec2 *v) { size_t ret = c4::unformat(buf, "({},{})", v->x, v->y); return ret != c4::yml::npos; } template bool from_chars(c4::csubstr buf, vec3 *v) { size_t ret = c4::unformat(buf, "({},{},{})", v->x, v->y, v->z); return ret != c4::yml::npos; } template bool from_chars(c4::csubstr buf, vec4 *v) { size_t ret = c4::unformat(buf, "({},{},{},{})", v->x, v->y, v->z, v->w); return ret != c4::yml::npos; } TEST(serialize, type_as_str) { c4::yml::Tree t; auto r = t.rootref(); r |= c4::yml::MAP; vec2 v2in{10, 11}; vec2 v2out{1, 2}; r["v2"] << v2in; r["v2"] >> v2out; EXPECT_EQ(v2in.x, v2out.x); EXPECT_EQ(v2in.y, v2out.y); vec3 v3in{100, 101, 102}; vec3 v3out{1, 2, 3}; r["v3"] << v3in; r["v3"] >> v3out; EXPECT_EQ(v3in.x, v3out.x); EXPECT_EQ(v3in.y, v3out.y); EXPECT_EQ(v3in.z, v3out.z); vec4 v4in{1000, 1001, 1002, 1003}; vec4 v4out{1, 2, 3, 4}; r["v4"] << v4in; r["v4"] >> v4out; EXPECT_EQ(v4in.x, v4out.x); EXPECT_EQ(v4in.y, v4out.y); EXPECT_EQ(v4in.z, v4out.z); EXPECT_EQ(v4in.w, v4out.w); char buf[256]; c4::csubstr ret = c4::yml::emit_yaml(t, buf); EXPECT_EQ(ret, R"(v2: '(10,11)' v3: '(100,101,102)' v4: '(1000,1001,1002,1003)' )"); } } // namespace foo namespace c4 { namespace yml { //------------------------------------------- template void do_test_serialize(Args&& ...args) { using namespace c4::yml; Container s(std::forward(args)...); Container out; Tree t; NodeRef n(&t); n << s; //print_tree(t); emit_yaml(t); c4::yml::check_invariants(t); n >> out; EXPECT_EQ(s, out); } TEST(serialize, std_vector_int) { using T = int; using L = std::initializer_list; do_test_serialize>(L{1, 2, 3, 4, 5}); } TEST(serialize, std_vector_bool) { using T = bool; using L = std::initializer_list; do_test_serialize>(L{true, false, true, false, true, true}); } TEST(serialize, std_vector_string) { using T = std::string; using L = std::initializer_list; do_test_serialize>(L{"0asdadk0", "1sdfkjdfgu1", "2fdfdjkhdfgkjhdfi2", "3e987dfgnfdg83", "4'd0fgºçdfg«4"}); } TEST(serialize, std_vector_std_vector_int) { using T = std::vector; using L = std::initializer_list; do_test_serialize>(L{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 0}}); } TEST(serialize, std_map__int_int) { using M = std::map; using L = std::initializer_list; do_test_serialize(L{{10, 0}, {11, 1}, {22, 2}, {10001, 1000}, {20002, 2000}, {30003, 3000}}); } TEST(serialize, std_map__std_string_int) { using M = std::map; using L = std::initializer_list; do_test_serialize(L{{"asdsdf", 0}, {"dfgdfgdfg", 1}, {"dfgjdfgkjh", 2}}); } TEST(serialize, std_map__string_vectori) { using M = std::map>; using L = std::initializer_list; do_test_serialize(L{{"asdsdf", {0, 1, 2, 3}}, {"dfgdfgdfg", {4, 5, 6, 7}}, {"dfgjdfgkjh", {8, 9, 10, 11}}}); } TEST(serialize, std_vector__map_string_int) { using V = std::vector< std::map>; using M = typename V::value_type; using L = std::initializer_list; do_test_serialize(L{ M{{"asdasf", 0}, {"dfgkjhdfg", 1}, {"fghffg", 2}, {"r5656kjnh9b'dfgwg+*", 3}}, M{{"asdasf", 10}, {"dfgkjhdfg", 11}, {"fghffg", 12}, {"r5656kjnh9b'dfgwg+*", 13}}, M{{"asdasf", 20}, {"dfgkjhdfg", 21}, {"fghffg", 22}, {"r5656kjnh9b'dfgwg+*", 23}}, M{{"asdasf", 30}, {"dfgkjhdfg", 31}, {"fghffg", 32}, {"r5656kjnh9b'dfgwg+*", 33}}, }); } TEST(serialize, bool) { Tree t = parse_in_arena("{a: 0, b: false, c: 1, d: true}"); bool v, w; t["a"] >> v; EXPECT_EQ(v, false); t["b"] >> v; EXPECT_EQ(v, false); t["c"] >> v; EXPECT_EQ(v, true); t["d"] >> v; EXPECT_EQ(v, true); t["e"] << true; EXPECT_EQ(t["e"].val(), "1"); t["e"] >> w; EXPECT_EQ(w, true); t["e"] << false; EXPECT_EQ(t["e"].val(), "0"); t["e"] >> w; EXPECT_EQ(w, false); t["e"] << fmt::boolalpha(true); EXPECT_EQ(t["e"].val(), "true"); t["e"] >> w; EXPECT_EQ(w, true); t["e"] << fmt::boolalpha(false); EXPECT_EQ(t["e"].val(), "false"); t["e"] >> w; EXPECT_EQ(w, false); } TEST(serialize, nan) { Tree t = parse_in_arena(R"( good: - .nan - .nan - .NaN - .NAN - nan - .nan set: - nothing - nothing })"); t["set"][0] << std::numeric_limits::quiet_NaN(); t["set"][1] << std::numeric_limits::quiet_NaN(); EXPECT_EQ(t["set"][0].val(), ".nan"); EXPECT_EQ(t["set"][1].val(), ".nan"); EXPECT_EQ(t["good"][0].val(), ".nan"); EXPECT_EQ(t["good"][1].val(), ".nan"); EXPECT_EQ(t["good"][2].val(), ".NaN"); EXPECT_EQ(t["good"][3].val(), ".NAN"); EXPECT_EQ(t["good"][4].val(), "nan"); EXPECT_EQ(t["good"][5].val(), ".nan"); float f; double d; f = 0.f; d = 0.; t["good"][0] >> f; t["good"][0] >> d; EXPECT_TRUE(std::isnan(f)); EXPECT_TRUE(std::isnan(d)); f = 0.f; d = 0.; t["good"][1] >> f; t["good"][1] >> d; EXPECT_TRUE(std::isnan(f)); EXPECT_TRUE(std::isnan(d)); f = 0.f; d = 0.; t["good"][2] >> f; t["good"][2] >> d; EXPECT_TRUE(std::isnan(f)); EXPECT_TRUE(std::isnan(d)); f = 0.f; d = 0.; t["good"][3] >> f; t["good"][3] >> d; EXPECT_TRUE(std::isnan(f)); EXPECT_TRUE(std::isnan(d)); f = 0.f; d = 0.; t["good"][4] >> f; t["good"][4] >> d; EXPECT_TRUE(std::isnan(f)); EXPECT_TRUE(std::isnan(d)); f = 0.f; d = 0.; t["good"][5] >> f; t["good"][5] >> d; EXPECT_TRUE(std::isnan(f)); EXPECT_TRUE(std::isnan(d)); } TEST(serialize, inf) { C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wfloat-equal"); Tree t = parse_in_arena(R"( good: - .inf - .inf - .Inf - .INF - inf - infinity - .inf set: - nothing - nothing })"); float finf = std::numeric_limits::infinity(); double dinf = std::numeric_limits::infinity(); t["set"][0] << finf; t["set"][1] << dinf; EXPECT_EQ(t["set"][0].val(), ".inf"); EXPECT_EQ(t["set"][1].val(), ".inf"); EXPECT_EQ(t["good"][0].val(), ".inf"); EXPECT_EQ(t["good"][1].val(), ".inf"); EXPECT_EQ(t["good"][2].val(), ".Inf"); EXPECT_EQ(t["good"][3].val(), ".INF"); EXPECT_EQ(t["good"][4].val(), "inf"); EXPECT_EQ(t["good"][5].val(), "infinity"); EXPECT_EQ(t["good"][6].val(), ".inf"); float f; double d; f = 0.f; d = 0.; t["good"][0] >> f; t["good"][0] >> d; EXPECT_TRUE(f == finf); EXPECT_TRUE(d == dinf); f = 0.f; d = 0.; t["good"][1] >> f; t["good"][1] >> d; EXPECT_TRUE(f == finf); EXPECT_TRUE(d == dinf); f = 0.f; d = 0.; t["good"][2] >> f; t["good"][2] >> d; EXPECT_TRUE(f == finf); EXPECT_TRUE(d == dinf); f = 0.f; d = 0.; t["good"][3] >> f; t["good"][3] >> d; EXPECT_TRUE(f == finf); EXPECT_TRUE(d == dinf); f = 0.f; d = 0.; t["good"][4] >> f; t["good"][4] >> d; EXPECT_TRUE(f == finf); EXPECT_TRUE(d == dinf); f = 0.f; d = 0.; t["good"][5] >> f; t["good"][5] >> d; EXPECT_TRUE(f == finf); EXPECT_TRUE(d == dinf); f = 0.f; d = 0.; t["good"][6] >> f; t["good"][6] >> d; EXPECT_TRUE(f == finf); EXPECT_TRUE(d == dinf); t = parse_in_arena(R"( good: - -.inf - -.inf - -.Inf - -.INF - -inf - -infinity - -.inf set: - nothing - nothing })"); t["set"][0] << -finf; t["set"][1] << -dinf; EXPECT_EQ(t["set"][0].val(), "-.inf"); EXPECT_EQ(t["set"][1].val(), "-.inf"); EXPECT_EQ(t["good"][0].val(), "-.inf"); EXPECT_EQ(t["good"][1].val(), "-.inf"); EXPECT_EQ(t["good"][2].val(), "-.Inf"); EXPECT_EQ(t["good"][3].val(), "-.INF"); EXPECT_EQ(t["good"][4].val(), "-inf"); EXPECT_EQ(t["good"][5].val(), "-infinity"); EXPECT_EQ(t["good"][6].val(), "-.inf"); f = 0.f; d = 0.; t["good"][0] >> f; t["good"][0] >> d; EXPECT_TRUE(f == -finf); EXPECT_TRUE(d == -dinf); f = 0.f; d = 0.; t["good"][1] >> f; t["good"][1] >> d; EXPECT_TRUE(f == -finf); EXPECT_TRUE(d == -dinf); f = 0.f; d = 0.; t["good"][2] >> f; t["good"][2] >> d; EXPECT_TRUE(f == -finf); EXPECT_TRUE(d == -dinf); f = 0.f; d = 0.; t["good"][3] >> f; t["good"][3] >> d; EXPECT_TRUE(f == -finf); EXPECT_TRUE(d == -dinf); f = 0.f; d = 0.; t["good"][4] >> f; t["good"][4] >> d; EXPECT_TRUE(f == -finf); EXPECT_TRUE(d == -dinf); f = 0.f; d = 0.; t["good"][5] >> f; t["good"][5] >> d; EXPECT_TRUE(f == -finf); EXPECT_TRUE(d == -dinf); f = 0.f; d = 0.; t["good"][6] >> f; t["good"][6] >> d; EXPECT_TRUE(f == -finf); EXPECT_TRUE(d == -dinf); C4_SUPPRESS_WARNING_GCC_CLANG_POP } TEST(serialize, std_string) { auto t = parse_in_arena("{foo: bar}"); std::string s; EXPECT_NE(s, "bar"); t["foo"] >> s; EXPECT_EQ(s, "bar"); } TEST(serialize, anchor_and_ref_round_trip) { const char yaml[] = R"(anchor_objects: - &id001 name: id001 - &id002 name: id002 - name: id003 - &id004 name: id004 references: reference_key: *id001 reference_list: - *id002 - *id004 )"; Tree t = parse_in_arena(yaml); std::string cmpbuf; emitrs_yaml(t, &cmpbuf); EXPECT_EQ(cmpbuf, yaml); } TEST(serialize, create_anchor_ref_trip) { const char expected_yaml[] = R"(anchor_objects: - &id001 name: a_name reference_list: - *id001 )"; Tree tree; auto root_id = tree.root_id(); tree.to_map(root_id); auto anchor_list_id = tree.append_child(root_id); tree.to_seq(anchor_list_id, "anchor_objects"); auto anchor_map0 = tree.append_child(anchor_list_id); tree.to_map(anchor_map0); tree.set_val_anchor(anchor_map0, "id001"); auto anchor_elem0 = tree.append_child(anchor_map0); tree.to_keyval(anchor_elem0, "name", "a_name"); auto ref_list_id = tree.append_child(root_id); tree.to_seq(ref_list_id, "reference_list"); auto elem0_id = tree.append_child(ref_list_id); tree.set_val_ref(elem0_id, "id001"); std::string cmpbuf; emitrs_yaml(tree, &cmpbuf); EXPECT_EQ(cmpbuf, expected_yaml); } //------------------------------------------- // this is needed to use the test case library Case const* get_case(csubstr /*name*/) { return nullptr; } } // namespace yml } // namespace c4 #if defined(_MSC_VER) # pragma warning(pop) #elif defined(__clang__) # pragma clang diagnostic pop #elif defined(__GNUC__) # pragma GCC diagnostic pop #endif