425 lines
15 KiB
C++
425 lines
15 KiB
C++
#include <msgpack/core/writer.h>
|
|
|
|
#include <boost/ut.hpp>
|
|
|
|
#include <string>
|
|
|
|
using namespace boost::ut;
|
|
namespace format = msgpack::format;
|
|
|
|
namespace {
|
|
|
|
template <typename... Bytes>
|
|
constexpr std::array<std::byte, sizeof...(Bytes)> make_bytes(Bytes &&...bytes) {
|
|
return {std::byte(std::forward<Bytes>(bytes))...};
|
|
}
|
|
|
|
template <typename T, std::size_t C = 1024> struct oversized_array {
|
|
std::array<T, C> data;
|
|
std::size_t size;
|
|
};
|
|
|
|
constexpr auto to_bytes_array_oversized(auto const &container) {
|
|
oversized_array<std::byte> 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<std::byte, oversized.size> out;
|
|
std::copy(std::begin(oversized.data),
|
|
std::next(std::begin(oversized.data), oversized.size),
|
|
std::begin(out));
|
|
return out;
|
|
}
|
|
|
|
template <std::size_t A, std::size_t B>
|
|
consteval auto cat(std::array<std::byte, A> const &a,
|
|
std::array<std::byte, B> const &b) {
|
|
std::array<std::byte, A + B> 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 <typename T, typename Itr>
|
|
constexpr auto zip(T val, Itr begin, Itr end) {
|
|
std::vector<T> output;
|
|
for (auto itr = begin; itr != end; ++itr) {
|
|
output.emplace_back(val);
|
|
output.emplace_back(*itr);
|
|
}
|
|
return output;
|
|
}
|
|
|
|
template <typename T, typename Iterable>
|
|
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<std::byte> 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<std::byte> 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<std::byte, 16> payload;
|
|
|
|
msgpack::writer writer(payload);
|
|
expect(writer.tell() == 0);
|
|
};
|
|
|
|
"writer::write<format::positive_fixint>"_test = [] {
|
|
using fmt = format::positive_fixint;
|
|
using error = msgpack::writer_error;
|
|
|
|
std::array<std::byte, 2> payload;
|
|
auto constexpr expected = make_bytes(0x32, 0x55);
|
|
msgpack::writer writer(payload);
|
|
auto result = writer.write<fmt>(std::uint8_t{0x32});
|
|
expect(!!result);
|
|
expect(writer.tell() == 1);
|
|
expect(*writer.subspan().begin() == std::byte{0x32});
|
|
expect(writer.write<fmt>(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<format::uint8>"_test = [] {
|
|
using fmt = format::uint8;
|
|
using error = msgpack::writer_error;
|
|
|
|
std::array<std::byte, 4> payload;
|
|
auto constexpr expected = make_bytes(0xcc, 0x32, 0xcc, 0x82);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(std::uint8_t{0x32}));
|
|
expect(writer.tell() == 2);
|
|
expect(equal(writer.subspan(), std::span{expected.begin(), 2}));
|
|
expect(!!writer.write<fmt>(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<format::uint16>"_test = [] {
|
|
using fmt = format::uint16;
|
|
using error = msgpack::writer_error;
|
|
|
|
std::array<std::byte, 6> payload;
|
|
auto constexpr expected = make_bytes(0xcd, 0x32, 0xcc, 0xcd, 0xaa, 0xff);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(std::uint16_t{0x32cc}));
|
|
expect(writer.tell() == 3);
|
|
expect(equal(writer.subspan(), std::span{expected.begin(), 3}));
|
|
expect(!!writer.write<fmt>(0xaaff));
|
|
expect(equal(writer.subspan(), expected));
|
|
expect(writer.write<fmt>(0x01) == tl::make_unexpected(error::out_of_space));
|
|
};
|
|
|
|
"writer::write<format::uint32>"_test = [] {
|
|
using fmt = format::uint32;
|
|
using error = msgpack::writer_error;
|
|
|
|
std::array<std::byte, 5> payload;
|
|
auto constexpr expected = make_bytes(0xce, 0x01, 0x02, 0x03, 0x04);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(0x01020304));
|
|
expect(writer.tell() == 5);
|
|
expect(equal(writer.subspan(), expected));
|
|
expect(writer.write<fmt>(0x01) == tl::make_unexpected(error::out_of_space));
|
|
};
|
|
|
|
"writer::write<format::uint64>"_test = [] {
|
|
using fmt = format::uint64;
|
|
using error = msgpack::writer_error;
|
|
|
|
std::array<std::byte, 9> payload;
|
|
auto constexpr expected = make_bytes(
|
|
0xcf, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(0x0102030405060708));
|
|
expect(writer.tell() == 9);
|
|
expect(equal(writer.subspan(), expected));
|
|
expect(writer.write<fmt>(0x01) == tl::make_unexpected(error::out_of_space));
|
|
};
|
|
|
|
"writer::write<format::negative_fixint>"_test = [] {
|
|
using fmt = format::negative_fixint;
|
|
using error = msgpack::writer_error;
|
|
|
|
std::array<std::byte, 2> payload;
|
|
auto constexpr expected = make_bytes(0xff, 0xe0);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(-1));
|
|
expect(writer.tell() == 1);
|
|
expect(*writer.subspan().begin() == std::byte{0xff});
|
|
expect(writer.write<fmt>(-33) == tl::make_unexpected(error::bad_value));
|
|
expect(!!writer.write<fmt>(-32));
|
|
expect(writer.tell() == 2);
|
|
expect(equal(writer.subspan(), expected));
|
|
expect(writer.write<fmt>(-5) == tl::make_unexpected(error::out_of_space));
|
|
};
|
|
|
|
"writer::write<format::int8>"_test = [] {
|
|
using fmt = format::int8;
|
|
using error = msgpack::writer_error;
|
|
|
|
std::array<std::byte, 4> payload;
|
|
auto constexpr expected = make_bytes(0xd0, 0x32, 0xd0, 0xfb);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(std::int8_t{0x32}));
|
|
expect(writer.tell() == 2);
|
|
expect(equal(writer.subspan(), std::span{expected.begin(), 2}));
|
|
expect(!!writer.write<fmt>(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<format::int16>"_test = [] {
|
|
using fmt = format::int16;
|
|
using error = msgpack::writer_error;
|
|
|
|
std::array<std::byte, 6> payload;
|
|
auto constexpr expected = make_bytes(0xd1, 0x32, 0xcc, 0xd1, 0xff, 0xfa);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(std::int16_t{0x32cc}));
|
|
expect(writer.tell() == 3);
|
|
expect(equal(writer.subspan(), std::span{expected.begin(), 3}));
|
|
expect(!!writer.write<fmt>(-6));
|
|
expect(equal(writer.subspan(), expected));
|
|
expect(writer.write<fmt>(0x01) == tl::make_unexpected(error::out_of_space));
|
|
};
|
|
|
|
"writer::write<format::int32>"_test = [] {
|
|
using fmt = format::int32;
|
|
using error = msgpack::writer_error;
|
|
|
|
std::array<std::byte, 5> payload;
|
|
auto constexpr expected = make_bytes(0xd2, 0x01, 0x02, 0x03, 0x04);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(0x01020304));
|
|
expect(writer.tell() == 5);
|
|
expect(equal(writer.subspan(), expected));
|
|
expect(writer.write<fmt>(0x01) == tl::make_unexpected(error::out_of_space));
|
|
};
|
|
|
|
"writer::write<format::int64>"_test = [] {
|
|
using fmt = format::int64;
|
|
using error = msgpack::writer_error;
|
|
|
|
std::array<std::byte, 9> payload;
|
|
auto constexpr expected = make_bytes(
|
|
0xd3, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(std::int64_t{0x0102030405060708}));
|
|
expect(writer.tell() == 9);
|
|
expect(equal(writer.subspan(), expected));
|
|
expect(writer.write<fmt>(0x01) == tl::make_unexpected(error::out_of_space));
|
|
};
|
|
|
|
"writer::write<format::fixstr>"_test = [] {
|
|
using fmt = format::fixstr;
|
|
|
|
std::array<std::byte, 4> payload;
|
|
auto constexpr expected = make_bytes(0xa2, 'o', 'h');
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>("oh"));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::str8>"_test = [] {
|
|
using fmt = format::str8;
|
|
std::array<std::byte, 46> 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<fmt>(std::move(txt)));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::str16>"_test = [] {
|
|
using fmt = format::str16;
|
|
std::array<std::byte, 47> 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<fmt>(std::move(txt)));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::str32>"_test = [] {
|
|
using fmt = format::str32;
|
|
std::array<std::byte, 49> 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<fmt>(std::move(txt)));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::bin8>"_test = [] {
|
|
using fmt = format::bin8;
|
|
std::array<std::byte, 12> payload;
|
|
auto constexpr expected = make_bytes(0xc4, 0x07, 0x01, 0x02, 0x03, 0x04,
|
|
0xf8, 0xf9, 0xfa);
|
|
|
|
msgpack::writer writer(payload);
|
|
std::span<std::byte const> bv(expected.begin() + 2, expected.end());
|
|
expect(!!writer.write<fmt>(std::move(bv)));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::bin16>"_test = [] {
|
|
using fmt = format::bin16;
|
|
std::array<std::byte, 12> payload;
|
|
auto constexpr expected = make_bytes(0xc5, 0x0, 0x07, 0x01, 0x02, 0x03,
|
|
0x04, 0xf8, 0xf9, 0xfa);
|
|
|
|
msgpack::writer writer(payload);
|
|
std::span<std::byte const> bv(expected.begin() + 3, expected.end());
|
|
expect(!!writer.write<fmt>(std::move(bv)));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::bin32>"_test = [] {
|
|
using fmt = format::bin32;
|
|
std::array<std::byte, 12> payload;
|
|
auto constexpr expected = make_bytes(0xc6, 0x0, 0x0, 0x0, 0x07, 0x01,
|
|
0x02, 0x03, 0x04, 0xf8, 0xf9, 0xfa);
|
|
|
|
msgpack::writer writer(payload);
|
|
std::span<std::byte const> bv(expected.begin() + 5, expected.end());
|
|
expect(!!writer.write<fmt>(std::move(bv)));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::fixmap>"_test = [] {
|
|
using fmt = format::fixmap;
|
|
std::array<std::byte, 1> payload;
|
|
auto constexpr expected = make_bytes(0x83);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(msgpack::map_desc{3}));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::map16>"_test = [] {
|
|
using fmt = format::map16;
|
|
std::array<std::byte, 3> payload;
|
|
auto constexpr expected = make_bytes(0xde, 0x01, 0x00);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(msgpack::map_desc{256}));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::map32>"_test = [] {
|
|
using fmt = format::map32;
|
|
std::array<std::byte, 5> payload;
|
|
auto constexpr expected = make_bytes(0xdf, 0x00, 0x01, 0x00, 0x00);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(msgpack::map_desc{0x10000}));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::fixarray>"_test = [] {
|
|
using fmt = format::fixarray;
|
|
std::array<std::byte, 1> payload;
|
|
auto constexpr expected = make_bytes(0x93);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(msgpack::array_desc{3}));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::array16>"_test = [] {
|
|
using fmt = format::array16;
|
|
std::array<std::byte, 3> payload;
|
|
auto constexpr expected = make_bytes(0xdc, 0x01, 0x00);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(msgpack::array_desc{256}));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::array32>"_test = [] {
|
|
using fmt = format::array32;
|
|
std::array<std::byte, 5> payload;
|
|
auto constexpr expected = make_bytes(0xdd, 0x00, 0x01, 0x00, 0x00);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(msgpack::array_desc{0x10000}));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::nil>"_test = [] {
|
|
using fmt = format::nil;
|
|
std::array<std::byte, 1> payload;
|
|
auto constexpr expected = make_bytes(0xc0);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>({}));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::invalid>"_test = [] {
|
|
using fmt = format::invalid;
|
|
std::array<std::byte, 1> payload;
|
|
auto constexpr expected = make_bytes(0xc1);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>({}));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
|
|
"writer::write<format::boolean>"_test = [] {
|
|
using fmt = format::boolean;
|
|
std::array<std::byte, 2> payload;
|
|
auto constexpr expected = make_bytes(0xc2, 0xc3);
|
|
msgpack::writer writer(payload);
|
|
expect(!!writer.write<fmt>(false));
|
|
expect(!!writer.write<fmt>(true));
|
|
expect(equal(writer.subspan(), expected));
|
|
};
|
|
};
|