323 lines
12 KiB
C++
323 lines
12 KiB
C++
//-----------------------------------------------------------------------------
|
|
// ___ __ _ _
|
|
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
|
|
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
|
|
// / ___/ (_| | | \__ \ __/ /__| | | | | <
|
|
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
// Author: Kurt Sassenrath
|
|
// Module: msgpack
|
|
//
|
|
// Default packer tests.
|
|
//
|
|
// Copyright (c) 2023 Kurt Sassenrath.
|
|
//
|
|
// License TBD.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "parselink/msgpack/core/packer.h"
|
|
|
|
#include <fmt/format.h>
|
|
#include <fmt/ranges.h>
|
|
|
|
#include "rng.h"
|
|
#include <algorithm>
|
|
#include <boost/ut.hpp>
|
|
#include <chrono>
|
|
|
|
using namespace boost::ut;
|
|
|
|
template <>
|
|
struct fmt::formatter<msgpack::invalid> : fmt::formatter<std::string_view> {
|
|
template <typename FormatContext>
|
|
auto format(msgpack::nil const&, FormatContext& ctx) const {
|
|
return fmt::format_to(ctx.out(), "{{msgpack::invalid}}");
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct fmt::formatter<msgpack::nil> : fmt::formatter<std::string_view> {
|
|
template <typename FormatContext>
|
|
auto format(msgpack::nil const&, FormatContext& ctx) const {
|
|
return fmt::format_to(ctx.out(), "{{msgpack::nil}}");
|
|
}
|
|
};
|
|
|
|
namespace {
|
|
|
|
template <typename... Bytes>
|
|
constexpr std::array<std::byte, sizeof...(Bytes)> make_bytes(Bytes&&... bytes) {
|
|
return {static_cast<std::byte>(std::forward<Bytes>(bytes))...};
|
|
}
|
|
|
|
constexpr auto equal(auto a, auto b) {
|
|
return std::equal(std::begin(a), std::end(a), std::begin(b), std::end(b));
|
|
}
|
|
|
|
template <typename T>
|
|
struct test_data {};
|
|
|
|
template <>
|
|
struct test_data<msgpack::nil> {
|
|
static constexpr msgpack::nil values[] = {{}};
|
|
static constexpr auto payload = make_bytes(0xc0);
|
|
};
|
|
|
|
template <>
|
|
struct test_data<msgpack::invalid> {
|
|
static constexpr msgpack::invalid values[] = {{}};
|
|
static constexpr auto payload = make_bytes(0xc1);
|
|
};
|
|
|
|
template <>
|
|
struct test_data<bool> {
|
|
static constexpr auto values = std::to_array<bool>({false, true});
|
|
static constexpr auto payload = make_bytes(0xc2, 0xc3);
|
|
};
|
|
|
|
template <>
|
|
struct test_data<std::uint64_t> {
|
|
static constexpr auto values = std::to_array<std::uint64_t>({
|
|
0x00, // positive fixint
|
|
0x79, // positive fixint
|
|
0x80, // uint8
|
|
0xff, // uint8
|
|
0x100, // uint16
|
|
0xffff, // uint16
|
|
0x10000, // uint32
|
|
0xffffffff, // uint32
|
|
0x100000000, // uint64
|
|
0xffffffffffffffff // uint64
|
|
});
|
|
|
|
static constexpr auto payload = make_bytes(0x00, // positive fixint
|
|
0x79, // positive fixint
|
|
0xcc, 0x80, // uint8
|
|
0xcc, 0xff, // uint8
|
|
0xcd, 0x01, 0x00, // uint16
|
|
0xcd, 0xff, 0xff, // uint16
|
|
0xce, 0x00, 0x01, 0x00, 0x00, // uint32
|
|
0xce, 0xff, 0xff, 0xff, 0xff, // uint32
|
|
0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // uint64
|
|
0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // uint64
|
|
);
|
|
|
|
static constexpr auto valid(auto value) noexcept {
|
|
return value <= std::numeric_limits<std::uint64_t>::max();
|
|
}
|
|
};
|
|
|
|
template <std::unsigned_integral T>
|
|
struct test_data<T> : test_data<std::uint64_t> {
|
|
static constexpr auto valid(auto value) noexcept {
|
|
return value <= std::numeric_limits<T>::max();
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct test_data<std::int64_t> {
|
|
static constexpr auto values = std::to_array<std::int64_t>({
|
|
-1, // negative fixint
|
|
-32, // negative fixint
|
|
-33, // int8
|
|
-128, // int8
|
|
0, // int8
|
|
127, // int8
|
|
128, // int16
|
|
-129, // int16
|
|
-32768, // int16
|
|
32767, // int16
|
|
-32769, // int32
|
|
32768, // int32
|
|
-2147483648, // int32
|
|
2147483647, // int32
|
|
-2147483649, // int64
|
|
2147483648, // int64
|
|
std::numeric_limits<std::int64_t>::lowest(), // int64
|
|
std::numeric_limits<std::int64_t>::max(), // int64
|
|
});
|
|
|
|
static constexpr auto payload = make_bytes(0xff, // negative fixint
|
|
0xe0, // negative fixint
|
|
0xd0, 0xdf, // int8
|
|
0xd0, 0x80, // int8
|
|
0xd0, 0x0, // int8
|
|
0xd0, 0x7f, // int8
|
|
0xd1, 0x00, 0x80, // int16
|
|
0xd1, 0xff, 0x7f, // int16
|
|
0xd1, 0x80, 0x00, // int16
|
|
0xd1, 0x7f, 0xff, // int16
|
|
0xd2, 0xff, 0xff, 0x7f, 0xff, // int32
|
|
0xd2, 0x00, 0x00, 0x80, 0x00, // int32
|
|
0xd2, 0x80, 0x00, 0x00, 0x00, // int32
|
|
0xd2, 0x7f, 0xff, 0xff, 0xff, // int32
|
|
0xd3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, // int64
|
|
0xd3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, // int64
|
|
0xd3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // int64
|
|
0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // int64
|
|
);
|
|
|
|
static constexpr auto valid(auto value) noexcept {
|
|
return value <= std::numeric_limits<std::int64_t>::max()
|
|
&& value >= std::numeric_limits<std::int64_t>::lowest();
|
|
}
|
|
};
|
|
|
|
template <std::convertible_to<std::string_view> T>
|
|
struct test_data<T> {
|
|
static constexpr auto values = std::to_array<T>({
|
|
"", // fixstr
|
|
"0", // fixstr
|
|
"0123456789abcdef0123456789abcde", // fixstr
|
|
"0123456789abcdef0123456789abcdef", // str8
|
|
});
|
|
|
|
static constexpr auto payload = make_bytes(0xa0, // fixstr
|
|
0xa1, 0x30, // fixstr
|
|
|
|
// fixstr
|
|
0xbf, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
|
|
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x30, 0x31, 0x32, 0x33, 0x34,
|
|
0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65,
|
|
|
|
// str8
|
|
0xd9, 0x20, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
|
0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x30, 0x31, 0x32, 0x33,
|
|
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65,
|
|
0x66);
|
|
|
|
static constexpr auto valid(T value) noexcept {
|
|
return std::string_view(value).size()
|
|
<= std::numeric_limits<std::uint32_t>::max();
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct test_data<std::span<std::byte const>> {
|
|
static constexpr auto test1 = make_bytes(0x02, 0x03);
|
|
static constexpr auto values =
|
|
std::to_array<std::span<std::byte const>>({test1});
|
|
static constexpr auto payload = make_bytes(0xc4, 0x02, 0x02, 0x03);
|
|
|
|
static constexpr auto valid(auto value) noexcept {
|
|
return value.size() <= std::numeric_limits<std::uint32_t>::max();
|
|
}
|
|
};
|
|
|
|
template <std::signed_integral T>
|
|
struct test_data<T> : test_data<std::int64_t> {
|
|
static constexpr auto valid(auto value) noexcept {
|
|
return value <= std::numeric_limits<T>::max()
|
|
&& value >= std::numeric_limits<T>::lowest();
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
bool test_deduced() noexcept {
|
|
constexpr auto const& expected_payload = test_data<T>::payload;
|
|
std::array<std::byte, expected_payload.size()> payload;
|
|
|
|
msgpack::packer packer(payload);
|
|
for (auto const& value : test_data<T>::values) {
|
|
if constexpr (requires { test_data<T>::valid(value); }) {
|
|
if (!test_data<T>::valid(value)) break;
|
|
}
|
|
expect(!!packer.pack(T(value)));
|
|
auto expect = std::span(expected_payload.begin(), packer.tell());
|
|
auto correct = equal(packer.subspan(), expect);
|
|
if (!correct) {
|
|
fmt::print("Deduction failed for '{}'\n", T(value));
|
|
fmt::print("\tActual: {::#04x}\n", packer.subspan());
|
|
fmt::print("\tExpect: {::#04x}\n", expect);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
suite packer = [] {
|
|
"packer::pack<bool>"_test = [] { expect(test_deduced<bool>()); };
|
|
"packer::pack<nil>"_test = [] { expect(test_deduced<msgpack::nil>()); };
|
|
"packer::pack<invalid>"_test = [] {
|
|
expect(test_deduced<msgpack::invalid>());
|
|
};
|
|
|
|
// Unsigned ints
|
|
"packer::pack<std::uint8_t>"_test = [] {
|
|
expect(test_deduced<std::uint8_t>());
|
|
};
|
|
"packer::pack<std::uint16_t>"_test = [] {
|
|
expect(test_deduced<std::uint16_t>());
|
|
};
|
|
"packer::pack<std::uint32_t>"_test = [] {
|
|
expect(test_deduced<std::uint32_t>());
|
|
};
|
|
"packer::pack<std::uint64_t>"_test = [] {
|
|
expect(test_deduced<std::uint64_t>());
|
|
};
|
|
|
|
// Signed ints
|
|
"packer::pack<std::int8_t>"_test = [] {
|
|
expect(test_deduced<std::int8_t>());
|
|
};
|
|
"packer::pack<std::int16_t>"_test = [] {
|
|
expect(test_deduced<std::int16_t>());
|
|
};
|
|
"packer::pack<std::int32_t>"_test = [] {
|
|
expect(test_deduced<std::int32_t>());
|
|
};
|
|
"packer::pack<std::int64_t>"_test = [] {
|
|
expect(test_deduced<std::int64_t>());
|
|
};
|
|
|
|
// Strings
|
|
"packer::pack<std::string_view>"_test = [] {
|
|
expect(test_deduced<std::string_view>());
|
|
};
|
|
#if 0
|
|
"packer::pack<char const*>"_test = [] {
|
|
expect(test_deduced<char const*>());
|
|
};
|
|
#endif
|
|
"packer::pack<std::span<std::byte>>"_test = [] {
|
|
expect(test_deduced<std::span<std::byte const>>());
|
|
};
|
|
|
|
"packer::pack<std::array<std::byte, N>>"_test = [] {
|
|
{
|
|
constexpr auto data = make_bytes(0x01, 0x02, 0x03, 0x04);
|
|
constexpr auto expected =
|
|
make_bytes(0xc4, 0x04, 0x01, 0x02, 0x03, 0x04);
|
|
std::array<std::byte, std::size(expected)> payload;
|
|
|
|
msgpack::packer packer(payload);
|
|
expect(!!packer.pack(data));
|
|
expect(std::ranges::equal(payload, expected));
|
|
}
|
|
{
|
|
constexpr std::array<std::byte, 256> data{};
|
|
constexpr std::array<std::byte, 259> expected{
|
|
std::byte(0xc5), std::byte(0x01), std::byte(0x00)};
|
|
std::array<std::byte, std::size(expected)> payload;
|
|
|
|
msgpack::packer packer(payload);
|
|
expect(!!packer.pack(data));
|
|
expect(std::ranges::equal(payload, expected));
|
|
}
|
|
{
|
|
constexpr std::array<std::byte, 65536> data{};
|
|
constexpr std::array<std::byte, std::size(data) + 5> expected{
|
|
std::byte(0xc6), std::byte(0x00), std::byte(0x01),
|
|
std::byte(0x00), std::byte(0x00)};
|
|
std::array<std::byte, std::size(expected)> payload;
|
|
|
|
msgpack::packer packer(payload);
|
|
expect(!!packer.pack(data));
|
|
expect(std::ranges::equal(payload, expected));
|
|
}
|
|
};
|
|
};
|