aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/ryml/test/test_serialize.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-11-07 14:49:13 +0100
committerGitHub Enterprise <[email protected]>2025-11-07 14:49:13 +0100
commit24e43a913f29ac3b314354e8ce5175f135bcc64f (patch)
treeca442937ceeb63461012b33a4576e9835099f106 /thirdparty/ryml/test/test_serialize.cpp
parentget oplog attachments (#622) (diff)
downloadzen-24e43a913f29ac3b314354e8ce5175f135bcc64f.tar.xz
zen-24e43a913f29ac3b314354e8ce5175f135bcc64f.zip
switch to xmake for package management (#611)
This change removes our dependency on vcpkg for package management, in favour of bringing some code in-tree in the `thirdparty` folder as well as using the xmake build-in package management feature. For the latter, all the package definitions are maintained in the zen repo itself, in the `repo` folder. It should now also be easier to build the project as it will no longer depend on having the right version of vcpkg installed, which has been a common problem for new people coming in to the codebase. Now you should only need xmake to build. * Bumps xmake requirement on github runners to 2.9.9 to resolve an issue where xmake on Windows invokes cmake with `v144` toolchain which does not exist * BLAKE3 is now in-tree at `thirdparty/blake3` * cpr is now in-tree at `thirdparty/cpr` * cxxopts is now in-tree at `thirdparty/cxxopts` * fmt is now in-tree at `thirdparty/fmt` * robin-map is now in-tree at `thirdparty/robin-map` * ryml is now in-tree at `thirdparty/ryml` * sol2 is now in-tree at `thirdparty/sol2` * spdlog is now in-tree at `thirdparty/spdlog` * utfcpp is now in-tree at `thirdparty/utfcpp` * xmake package repo definitions is in `repo` * implemented support for sanitizers. ASAN is supported on windows, TSAN, UBSAN, MSAN etc are supported on Linux/MacOS though I have not yet tested it extensively on MacOS * the zencore encryption implementation also now supports using mbedTLS which is used on MacOS, though for now we still use openssl on Linux * crashpad * bumps libcurl to 8.11.0 (from 8.8.0) which should address a rare build upload bug
Diffstat (limited to 'thirdparty/ryml/test/test_serialize.cpp')
-rw-r--r--thirdparty/ryml/test/test_serialize.cpp499
1 files changed, 499 insertions, 0 deletions
diff --git a/thirdparty/ryml/test/test_serialize.cpp b/thirdparty/ryml/test/test_serialize.cpp
new file mode 100644
index 000000000..979de7c79
--- /dev/null
+++ b/thirdparty/ryml/test/test_serialize.cpp
@@ -0,0 +1,499 @@
+#ifndef RYML_SINGLE_HEADER
+#include "c4/yml/std/std.hpp"
+#include "c4/yml/parse.hpp"
+#include "c4/yml/emit.hpp"
+#include <c4/format.hpp>
+#include <c4/yml/detail/checks.hpp>
+#include <c4/yml/detail/print.hpp>
+#endif
+
+#include "./test_case.hpp"
+
+#include <gtest/gtest.h>
+
+#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<class T>
+struct vec2
+{
+ T x, y;
+};
+template<class T>
+struct vec3
+{
+ T x, y, z;
+};
+template<class T>
+struct vec4
+{
+ T x, y, z, w;
+};
+
+template<class T> size_t to_chars(c4::substr buf, vec2<T> v) { return c4::format(buf, "({},{})", v.x, v.y); }
+template<class T> size_t to_chars(c4::substr buf, vec3<T> v) { return c4::format(buf, "({},{},{})", v.x, v.y, v.z); }
+template<class T> size_t to_chars(c4::substr buf, vec4<T> v) { return c4::format(buf, "({},{},{},{})", v.x, v.y, v.z, v.w); }
+
+template<class T> bool from_chars(c4::csubstr buf, vec2<T> *v) { size_t ret = c4::unformat(buf, "({},{})", v->x, v->y); return ret != c4::yml::npos; }
+template<class T> bool from_chars(c4::csubstr buf, vec3<T> *v) { size_t ret = c4::unformat(buf, "({},{},{})", v->x, v->y, v->z); return ret != c4::yml::npos; }
+template<class T> bool from_chars(c4::csubstr buf, vec4<T> *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<int> v2in{10, 11};
+ vec2<int> v2out{1, 2};
+ r["v2"] << v2in;
+ r["v2"] >> v2out;
+ EXPECT_EQ(v2in.x, v2out.x);
+ EXPECT_EQ(v2in.y, v2out.y);
+
+ vec3<int> v3in{100, 101, 102};
+ vec3<int> 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<int> v4in{1000, 1001, 1002, 1003};
+ vec4<int> 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<class Container, class... Args>
+void do_test_serialize(Args&& ...args)
+{
+ using namespace c4::yml;
+ Container s(std::forward<Args>(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<T>;
+ do_test_serialize<std::vector<T>>(L{1, 2, 3, 4, 5});
+}
+TEST(serialize, std_vector_bool)
+{
+ using T = bool;
+ using L = std::initializer_list<T>;
+ do_test_serialize<std::vector<T>>(L{true, false, true, false, true, true});
+}
+TEST(serialize, std_vector_string)
+{
+ using T = std::string;
+ using L = std::initializer_list<T>;
+ do_test_serialize<std::vector<T>>(L{"0asdadk0", "1sdfkjdfgu1", "2fdfdjkhdfgkjhdfi2", "3e987dfgnfdg83", "4'd0fgºçdfg«4"});
+}
+TEST(serialize, std_vector_std_vector_int)
+{
+ using T = std::vector<int>;
+ using L = std::initializer_list<T>;
+ do_test_serialize<std::vector<T>>(L{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 0}});
+}
+
+
+TEST(serialize, std_map__int_int)
+{
+ using M = std::map<int, int>;
+ using L = std::initializer_list<typename M::value_type>;
+ do_test_serialize<M>(L{{10, 0}, {11, 1}, {22, 2}, {10001, 1000}, {20002, 2000}, {30003, 3000}});
+}
+TEST(serialize, std_map__std_string_int)
+{
+ using M = std::map<std::string, int>;
+ using L = std::initializer_list<typename M::value_type>;
+ do_test_serialize<M>(L{{"asdsdf", 0}, {"dfgdfgdfg", 1}, {"dfgjdfgkjh", 2}});
+}
+TEST(serialize, std_map__string_vectori)
+{
+ using M = std::map<std::string, std::vector<int>>;
+ using L = std::initializer_list<typename M::value_type>;
+ do_test_serialize<M>(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<std::string, int>>;
+ using M = typename V::value_type;
+ using L = std::initializer_list<M>;
+ do_test_serialize<V>(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<float>::quiet_NaN();
+ t["set"][1] << std::numeric_limits<double>::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<float>::infinity();
+ double dinf = std::numeric_limits<double>::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