//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // //----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: msgpack // // Default packer tests. // // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. //----------------------------------------------------------------------------- #include "parselink/msgpack/core/packer.h" #include #include #include "rng.h" #include #include #include #include using namespace boost::ut; template <> struct fmt::formatter : fmt::formatter { template auto format(msgpack::nil const&, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "{{msgpack::invalid}}"); } }; template <> struct fmt::formatter : fmt::formatter { template auto format(msgpack::nil const&, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "{{msgpack::nil}}"); } }; template <> struct fmt::formatter : fmt::formatter { template auto format(msgpack::map_desc const& value, FormatContext& ctx) const { return fmt::format_to( ctx.out(), "{{msgpack::map_desc: {}}}", value.count); } }; template <> struct fmt::formatter : fmt::formatter { template auto format(msgpack::array_desc const& value, FormatContext& ctx) const { return fmt::format_to( ctx.out(), "{{msgpack::array_desc: {}}}", value.count); } }; namespace { template constexpr std::array make_bytes(Bytes&&... bytes) { return {static_cast(std::forward(bytes))...}; } constexpr auto equal(auto a, auto b) { return std::equal(std::begin(a), std::end(a), std::begin(b), std::end(b)); } template consteval auto within() noexcept { return std::numeric_limits::max() <= std::numeric_limits::max(); } template constexpr auto verify_packed(auto const& packer, auto value) { std::array::digits / 8> raw; if (packer.tell() != 1 + raw.size()) return false; auto packed = packer.subspan().subspan(1); be_to_host(packed.begin(), packed.end(), raw.begin()); auto actual = std::bit_cast(raw); return actual == value; } template auto check_unsigned() { return rc::check([] { std::array payload; msgpack::packer packer(payload); const auto value = *rc::gen::positive(); if (!packer.pack(value)) return false; if (value < 0x80) { // positive_fixint return packer.tell() == 1 && payload[0] == static_cast(value); } else if (value <= std::numeric_limits::max()) { // uint8 return packer.tell() == 2 && payload[0] == std::byte{0xcc} && T(payload[1]) == value; } else if (value <= std::numeric_limits::max()) { // uint16 return payload[0] == std::byte{0xcd} && verify_packed(packer, value); } else if (value <= std::numeric_limits::max()) { // uint32 return payload[0] == std::byte{0xce} && verify_packed(packer, value); } else { // uint64 return payload[0] == std::byte{0xcf} && verify_packed(packer, value); } }); } } // anonymous namespace suite packer_single_format = [] { "packer::pack"_test = [] { std::array payload; msgpack::packer packer(payload); expect(!!packer.pack(msgpack::nil{})); expect(packer.tell() == 1); expect(payload[0] == std::byte{0xc0}); }; "packer::pack"_test = [] { std::array payload; msgpack::packer packer(payload); expect(!!packer.pack(msgpack::invalid{})); expect(packer.tell() == 1); expect(payload[0] == std::byte{0xc1}); }; "packer::pack"_test = [] { std::array payload; msgpack::packer packer(payload); expect(!!packer.pack(false)); expect(packer.tell() == 1); expect(payload[0] == std::byte{0xc2}); expect(!!packer.pack(true)); expect(packer.tell() == 2); expect(payload[1] == std::byte{0xc3}); }; "packer::pack"_test = [] { expect(check_unsigned()); }; "packer::pack"_test = [] { expect(check_unsigned()); }; "packer::pack"_test = [] { expect(check_unsigned()); }; "packer::pack"_test = [] { expect(check_unsigned()); }; }; #if 0 "packer::pack"_test = [] { expect(test_deduced()); }; "packer::pack"_test = [] { expect(test_deduced()); }; "packer::pack"_test = [] { expect(test_deduced()); }; // Unsigned ints "packer::pack"_test = [] { expect(test_deduced()); }; "packer::pack"_test = [] { expect(test_deduced()); }; "packer::pack"_test = [] { expect(test_deduced()); }; "packer::pack"_test = [] { expect(test_deduced()); }; // Signed ints "packer::pack"_test = [] { expect(test_deduced()); }; "packer::pack"_test = [] { expect(test_deduced()); }; "packer::pack"_test = [] { expect(test_deduced()); }; "packer::pack"_test = [] { expect(test_deduced()); }; // Strings "packer::pack"_test = [] { expect(test_deduced()); }; #if 0 "packer::pack"_test = [] { expect(test_deduced()); }; #endif // Byte ranges -> Binary "packer::pack>"_test = [] { expect(test_deduced>()); }; "packer::pack>"_test = [] { { constexpr auto data = make_bytes(0x01, 0x02, 0x03, 0x04); constexpr auto expected = make_bytes(0xc4, 0x04, 0x01, 0x02, 0x03, 0x04); std::array payload; msgpack::packer packer(payload); expect(!!packer.pack(data)); expect(std::ranges::equal(payload, expected)); } { constexpr std::array data{}; constexpr std::array expected{ std::byte(0xc5), std::byte(0x01), std::byte(0x00)}; std::array payload; msgpack::packer packer(payload); expect(!!packer.pack(data)); expect(std::ranges::equal(payload, expected)); } { constexpr std::array data{}; constexpr std::array expected{ std::byte(0xc6), std::byte(0x00), std::byte(0x01), std::byte(0x00), std::byte(0x00)}; std::array payload; msgpack::packer packer(payload); expect(!!packer.pack(data)); expect(std::ranges::equal(payload, expected)); } }; // array_desc - Just the header of the array. "packer::pack"_test = [] { expect(test_deduced()); }; // map_desc - Just the header of the map. "packer::pack"_test = [] { expect(test_deduced()); }; }; suite packer_ranges = [] { "packer::pack>"_test = [] { constexpr auto data_array = std::to_array({5, 10, 15, 20}); constexpr auto expected = make_bytes(0x94, 0xd0, 0x05, 0xd0, 0xa, 0xd0, 0xf, 0xd0, 0x14); { std::array payload; msgpack::packer packer(payload); expect(!!packer.pack(data_array)); expect(std::ranges::equal(payload, expected)); } { std::span data_span{data_array}; std::array payload; msgpack::packer packer(payload); expect(!!packer.pack(data_span)); expect(std::ranges::equal(payload, expected)); } }; }; #endif