diff --git a/tests/unit/libutil/local.mk b/tests/unit/libutil/local.mk index 6de96c0dc..bf18a9da7 100644 --- a/tests/unit/libutil/local.mk +++ b/tests/unit/libutil/local.mk @@ -18,6 +18,7 @@ libutil-tests_EXTRA_INCLUDES = \ libutil-tests_CXXFLAGS += $(libutil-tests_EXTRA_INCLUDES) -libutil-tests_LIBS = libutil-test-support libutil +# libexpr is needed for exception serialization tests. sigh. +libutil-tests_LIBS = libutil-test-support libutil libexpr libutil-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS) diff --git a/tests/unit/libutil/serialise.cc b/tests/unit/libutil/serialise.cc index 71d99b9a7..b3bbdd33e 100644 --- a/tests/unit/libutil/serialise.cc +++ b/tests/unit/libutil/serialise.cc @@ -1,5 +1,10 @@ #include "serialise.hh" +#include "error.hh" +#include "fmt.hh" +#include "libexpr/pos-table.hh" +#include "ref.hh" #include "types.hh" +#include "util.hh" #include #include @@ -53,4 +58,155 @@ TEST(ChainSource, move) ASSERT_EQ(buf, "33"); } +TEST(Sink, uint64_t) +{ + StringSink s; + s << 42; + ASSERT_EQ(s.s, std::string({42, 0, 0, 0, 0, 0, 0, 0})); +} + +TEST(Sink, string_view) +{ + StringSink s; + s << ""; + // clang-format off + ASSERT_EQ( + s.s, + std::string({ + // length + 0, 0, 0, 0, 0, 0, 0, 0, + // data (omitted) + }) + ); + // clang-format on + + s = {}; + s << "test"; + // clang-format off + ASSERT_EQ( + s.s, + std::string({ + // length + 4, 0, 0, 0, 0, 0, 0, 0, + // data + 't', 'e', 's', 't', + // padding + 0, 0, 0, 0, + }) + ); + // clang-format on + + s = {}; + s << "longer string"; + // clang-format off + ASSERT_EQ( + s.s, + std::string({ + // length + 13, 0, 0, 0, 0, 0, 0, 0, + // data + 'l', 'o', 'n', 'g', 'e', 'r', ' ', 's', 't', 'r', 'i', 'n', 'g', + // padding + 0, 0, 0, + }) + ); + // clang-format on +} + +TEST(Sink, StringSet) +{ + StringSink s; + s << StringSet{}; + // clang-format off + ASSERT_EQ( + s.s, + std::string({ + // length + 0, 0, 0, 0, 0, 0, 0, 0, + // data (omitted) + }) + ); + // clang-format on + + s = {}; + s << StringSet{"a", ""}; + // clang-format off + ASSERT_EQ( + s.s, + std::string({ + // length + 2, 0, 0, 0, 0, 0, 0, 0, + // data "" + 0, 0, 0, 0, 0, 0, 0, 0, + // data "a" + 1, 0, 0, 0, 0, 0, 0, 0, 'a', 0, 0, 0, 0, 0, 0, 0, + }) + ); + // clang-format on +} + +TEST(Sink, Strings) +{ + StringSink s; + s << Strings{}; + // clang-format off + ASSERT_EQ( + s.s, + std::string({ + // length + 0, 0, 0, 0, 0, 0, 0, 0, + // data (omitted) + }) + ); + // clang-format on + + s = {}; + s << Strings{"a", ""}; + // clang-format off + ASSERT_EQ( + s.s, + std::string({ + // length + 2, 0, 0, 0, 0, 0, 0, 0, + // data "a" + 1, 0, 0, 0, 0, 0, 0, 0, 'a', 0, 0, 0, 0, 0, 0, 0, + // data "" + 0, 0, 0, 0, 0, 0, 0, 0, + }) + ); + // clang-format on +} + +TEST(Sink, Error) +{ + PosTable pt; + auto o = pt.addOrigin(Pos::String{make_ref("test")}, 4); + + StringSink s; + s << Error{{ + .level = lvlInfo, + .msg = HintFmt("foo"), + .pos = pt[pt.add(o, 1)], + .traces = {{.pos = pt[pt.add(o, 2)], .hint = HintFmt("b %1%", "foo")}}, + }}; + // NOTE position of the error and all traces are ignored + // by the wire format + // clang-format off + ASSERT_EQ( + s.s, + std::string({ + 5, 0, 0, 0, 0, 0, 0, 0, 'E', 'r', 'r', 'o', 'r', 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 0, 0, 0, 0, 'E', 'r', 'r', 'o', 'r', 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 0, + 'b', ' ', '\x1b', '[', '3', '5', ';', '1', 'm', 'f', 'o', 'o', '\x1b', '[', '0', 'm', + }) + ); + // clang-format on +} + }