//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // //----------------------------------------------------------------------------- // 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 auto within(auto value) noexcept { return value >= std::numeric_limits::min() && value <= std::numeric_limits::max(); } template std::byte marker_for; template constexpr auto verify_packed(auto const& packer, auto value) noexcept { std::array::digits + 7) / 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_signed() { return rc::check([](T value) { std::array payload; msgpack::packer packer(payload); if (!packer.pack(value)) return false; if (value < 128 && value >= -32) { // positive_fixint/negative_fixint return packer.tell() == 1 && payload[0] == static_cast(value); } else if (within(value)) { return payload[0] == msgpack::format::int8::marker && verify_packed(packer, value); } else if (within(value)) { return payload[0] == msgpack::format::int16::marker && verify_packed(packer, value); } else if (within(value)) { return payload[0] == msgpack::format::int32::marker && verify_packed(packer, value); } else { return payload[0] == msgpack::format::int64::marker && verify_packed(packer, value); } }); } template auto check_unsigned() { return rc::check([](T value) { std::array payload; msgpack::packer packer(payload); if (!packer.pack(value)) return false; if (value < 128) { // positive_fixint return packer.tell() == 1 && payload[0] == static_cast(value); } else if (within(value)) { return payload[0] == msgpack::format::uint8::marker && verify_packed(packer, value); } else if (within(value)) { return payload[0] == msgpack::format::uint16::marker && verify_packed(packer, value); } else if (within(value)) { return payload[0] == msgpack::format::uint32::marker && verify_packed(packer, value); } else { return payload[0] == msgpack::format::uint64::marker && verify_packed(packer, value); } }); } template auto check_string() { return rc::check([](LenType value) { auto str = *rc::gen::container( value, rc::gen::character()); std::vector payload; payload.resize(value + 32); msgpack::packer packer(payload); if (!packer.pack(str)) return false; return true; }); } } // 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()); }; "packer::pack"_test = [] { expect(check_signed()); }; "packer::pack"_test = [] { expect(check_signed()); }; "packer::pack"_test = [] { expect(check_signed()); }; "packer::pack"_test = [] { expect(check_signed()); }; "packer::pack"_test = [] { expect(check_string()); expect(check_string()); }; }; #if 0 // 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