#include #include #include using namespace boost::ut; namespace format = msgpack::format; namespace { template constexpr std::array make_bytes(Bytes &&...bytes) { return {std::byte(std::forward(bytes))...}; } template struct oversized_array { std::array data; std::size_t size; }; constexpr auto to_bytes_array_oversized(auto const &container) { oversized_array arr; std::copy(std::begin(container), std::end(container), std::begin(arr.data)); arr.size = std::distance(std::begin(container), std::end(container)); return arr; } consteval auto generate_bytes(auto callable) { constexpr auto oversized = to_bytes_array_oversized(callable()); std::array out; std::copy(std::begin(oversized.data), std::next(std::begin(oversized.data), oversized.size), std::begin(out)); return out; } template consteval auto cat(std::array const &a, std::array const &b) { std::array out; std::copy(std::begin(a), std::next(std::begin(a), std::size(a)), std::begin(out)); std::copy(std::begin(b), std::next(std::begin(b), std::size(b)), std::next(std::begin(out), std::size(a))); return out; } template constexpr auto zip(T val, Itr begin, Itr end) { std::vector output; for (auto itr = begin; itr != end; ++itr) { output.emplace_back(val); output.emplace_back(*itr); } return output; } template constexpr auto zip(T val, Iterable const &itr) { return zip(val, std::begin(itr), std::end(itr)); } constexpr auto from_string_view(std::string_view sv) { std::vector range; range.resize(sv.size()); auto itr = range.begin(); for (auto c : sv) { *itr = std::byte(c); ++itr; } return range; } constexpr auto make_contiguous_range(std::uint8_t start, std::uint8_t end) { auto count = std::size_t(end) - std::size_t(start) + 1; std::vector range; range.resize(count); for (auto i = std::size_t(start); i <= std::size_t(end); ++i) { range[i - std::size_t(start)] = std::byte(i); } return range; } constexpr auto equal(auto a, auto b) { return std::equal(std::begin(a), std::end(a), std::begin(b), std::end(b)); } } // namespace suite writer = [] { "writer empty span"_test = [] { std::array payload; msgpack::writer writer(payload); expect(writer.tell() == 0); }; "writer::write"_test = [] { using fmt = format::positive_fixint; using error = msgpack::writer_error; std::array payload; auto constexpr expected = make_bytes(0x32, 0x55); msgpack::writer writer(payload); auto result = writer.write(std::uint8_t{0x32}); expect(!!result); expect(writer.tell() == 1); expect(*writer.subspan().begin() == std::byte{0x32}); expect(writer.write(std::uint8_t{0x82}) == tl::make_unexpected(error::bad_value)); writer.write(std::uint8_t{0x55}); expect(writer.tell() == 2); expect(equal(writer.subspan(), expected)); expect(writer.write(std::uint8_t{0x01}) == tl::make_unexpected(error::out_of_space)); }; "writer::write"_test = [] { using fmt = format::uint8; using error = msgpack::writer_error; std::array payload; auto constexpr expected = make_bytes(0xcc, 0x32, 0xcc, 0x82); msgpack::writer writer(payload); expect(!!writer.write(std::uint8_t{0x32})); expect(writer.tell() == 2); expect(equal(writer.subspan(), std::span{expected.begin(), 2})); expect(!!writer.write(std::uint8_t{0x82})); expect(equal(writer.subspan(), expected)); expect(writer.write(std::uint8_t{0x01}) == tl::make_unexpected(error::out_of_space)); }; "writer::write"_test = [] { using fmt = format::uint16; using error = msgpack::writer_error; std::array payload; auto constexpr expected = make_bytes(0xcd, 0x32, 0xcc, 0xcd, 0xaa, 0xff); msgpack::writer writer(payload); expect(!!writer.write(std::uint16_t{0x32cc})); expect(writer.tell() == 3); expect(equal(writer.subspan(), std::span{expected.begin(), 3})); expect(!!writer.write(0xaaff)); expect(equal(writer.subspan(), expected)); expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); }; "writer::write"_test = [] { using fmt = format::uint32; using error = msgpack::writer_error; std::array payload; auto constexpr expected = make_bytes(0xce, 0x01, 0x02, 0x03, 0x04); msgpack::writer writer(payload); expect(!!writer.write(0x01020304)); expect(writer.tell() == 5); expect(equal(writer.subspan(), expected)); expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); }; "writer::write"_test = [] { using fmt = format::uint64; using error = msgpack::writer_error; std::array payload; auto constexpr expected = make_bytes( 0xcf, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08); msgpack::writer writer(payload); expect(!!writer.write(0x0102030405060708)); expect(writer.tell() == 9); expect(equal(writer.subspan(), expected)); expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); }; "writer::write"_test = [] { using fmt = format::negative_fixint; using error = msgpack::writer_error; std::array payload; auto constexpr expected = make_bytes(0xff, 0xe0); msgpack::writer writer(payload); expect(!!writer.write(-1)); expect(writer.tell() == 1); expect(*writer.subspan().begin() == std::byte{0xff}); expect(writer.write(-33) == tl::make_unexpected(error::bad_value)); expect(!!writer.write(-32)); expect(writer.tell() == 2); expect(equal(writer.subspan(), expected)); expect(writer.write(-5) == tl::make_unexpected(error::out_of_space)); }; "writer::write"_test = [] { using fmt = format::int8; using error = msgpack::writer_error; std::array payload; auto constexpr expected = make_bytes(0xd0, 0x32, 0xd0, 0xfb); msgpack::writer writer(payload); expect(!!writer.write(std::int8_t{0x32})); expect(writer.tell() == 2); expect(equal(writer.subspan(), std::span{expected.begin(), 2})); expect(!!writer.write(std::int8_t{-5})); expect(equal(writer.subspan(), expected)); expect(writer.write(std::uint8_t{0x01}) == tl::make_unexpected(error::out_of_space)); }; "writer::write"_test = [] { using fmt = format::int16; using error = msgpack::writer_error; std::array payload; auto constexpr expected = make_bytes(0xd1, 0x32, 0xcc, 0xd1, 0xff, 0xfa); msgpack::writer writer(payload); expect(!!writer.write(std::int16_t{0x32cc})); expect(writer.tell() == 3); expect(equal(writer.subspan(), std::span{expected.begin(), 3})); expect(!!writer.write(-6)); expect(equal(writer.subspan(), expected)); expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); }; "writer::write"_test = [] { using fmt = format::int32; using error = msgpack::writer_error; std::array payload; auto constexpr expected = make_bytes(0xd2, 0x01, 0x02, 0x03, 0x04); msgpack::writer writer(payload); expect(!!writer.write(0x01020304)); expect(writer.tell() == 5); expect(equal(writer.subspan(), expected)); expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); }; "writer::write"_test = [] { using fmt = format::int64; using error = msgpack::writer_error; std::array payload; auto constexpr expected = make_bytes( 0xd3, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08); msgpack::writer writer(payload); expect(!!writer.write(std::int64_t{0x0102030405060708})); expect(writer.tell() == 9); expect(equal(writer.subspan(), expected)); expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); }; "writer::write"_test = [] { using fmt = format::fixstr; std::array payload; auto constexpr expected = make_bytes(0xa2, 'o', 'h'); msgpack::writer writer(payload); expect(!!writer.write("oh")); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::str8; std::array payload; auto constexpr expected = make_bytes(0xd9, 44, 't', 'h', 'e', ' ', 'q', 'u', 'i', 'c', 'k', ' ', 'b', 'r', 'o', 'w', 'n', ' ', 'f', 'o', 'x', ' ', 'j', 'u', 'm', 'p', 'e', 'd', ' ', 'o', 'v', 'e', 'r', ' ', 't', 'h', 'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', 'o', 'g'); msgpack::writer writer(payload); std::string_view txt = "the quick brown fox jumped over the lazy dog"; expect(!!writer.write(std::move(txt))); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::str16; std::array payload; auto constexpr expected = make_bytes(0xda, 0, 44, 't', 'h', 'e', ' ', 'q', 'u', 'i', 'c', 'k', ' ', 'b', 'r', 'o', 'w', 'n', ' ', 'f', 'o', 'x', ' ', 'j', 'u', 'm', 'p', 'e', 'd', ' ', 'o', 'v', 'e', 'r', ' ', 't', 'h', 'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', 'o', 'g'); msgpack::writer writer(payload); std::string_view txt = "the quick brown fox jumped over the lazy dog"; expect(!!writer.write(std::move(txt))); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::str32; std::array payload; auto constexpr expected = make_bytes(0xdb, 0, 0, 0, 44, 't', 'h', 'e', ' ', 'q', 'u', 'i', 'c', 'k', ' ', 'b', 'r', 'o', 'w', 'n', ' ', 'f', 'o', 'x', ' ', 'j', 'u', 'm', 'p', 'e', 'd', ' ', 'o', 'v', 'e', 'r', ' ', 't', 'h', 'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', 'o', 'g'); msgpack::writer writer(payload); std::string_view txt = "the quick brown fox jumped over the lazy dog"; expect(!!writer.write(std::move(txt))); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::bin8; std::array payload; auto constexpr expected = make_bytes(0xc4, 0x07, 0x01, 0x02, 0x03, 0x04, 0xf8, 0xf9, 0xfa); msgpack::writer writer(payload); std::span bv(expected.begin() + 2, expected.end()); expect(!!writer.write(std::move(bv))); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::bin16; std::array payload; auto constexpr expected = make_bytes(0xc5, 0x0, 0x07, 0x01, 0x02, 0x03, 0x04, 0xf8, 0xf9, 0xfa); msgpack::writer writer(payload); std::span bv(expected.begin() + 3, expected.end()); expect(!!writer.write(std::move(bv))); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::bin32; std::array payload; auto constexpr expected = make_bytes(0xc6, 0x0, 0x0, 0x0, 0x07, 0x01, 0x02, 0x03, 0x04, 0xf8, 0xf9, 0xfa); msgpack::writer writer(payload); std::span bv(expected.begin() + 5, expected.end()); expect(!!writer.write(std::move(bv))); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::fixmap; std::array payload; auto constexpr expected = make_bytes(0x83); msgpack::writer writer(payload); expect(!!writer.write(msgpack::map_desc{3})); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::map16; std::array payload; auto constexpr expected = make_bytes(0xde, 0x01, 0x00); msgpack::writer writer(payload); expect(!!writer.write(msgpack::map_desc{256})); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::map32; std::array payload; auto constexpr expected = make_bytes(0xdf, 0x00, 0x01, 0x00, 0x00); msgpack::writer writer(payload); expect(!!writer.write(msgpack::map_desc{0x10000})); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::fixarray; std::array payload; auto constexpr expected = make_bytes(0x93); msgpack::writer writer(payload); expect(!!writer.write(msgpack::array_desc{3})); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::array16; std::array payload; auto constexpr expected = make_bytes(0xdc, 0x01, 0x00); msgpack::writer writer(payload); expect(!!writer.write(msgpack::array_desc{256})); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::array32; std::array payload; auto constexpr expected = make_bytes(0xdd, 0x00, 0x01, 0x00, 0x00); msgpack::writer writer(payload); expect(!!writer.write(msgpack::array_desc{0x10000})); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::nil; std::array payload; auto constexpr expected = make_bytes(0xc0); msgpack::writer writer(payload); expect(!!writer.write({})); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::invalid; std::array payload; auto constexpr expected = make_bytes(0xc1); msgpack::writer writer(payload); expect(!!writer.write({})); expect(equal(writer.subspan(), expected)); }; "writer::write"_test = [] { using fmt = format::boolean; std::array payload; auto constexpr expected = make_bytes(0xc2, 0xc3); msgpack::writer writer(payload); expect(!!writer.write(false)); expect(!!writer.write(true)); expect(equal(writer.subspan(), expected)); }; };