105 lines
3.5 KiB
C++
105 lines
3.5 KiB
C++
#include <msgpack/token.h>
|
|
|
|
#include <boost/ut.hpp>
|
|
|
|
using namespace boost::ut;
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
template <typename First, typename... Others>
|
|
constexpr bool wrong_types(auto const& obj) {
|
|
auto err = tl::make_unexpected(msgpack::error::wrong_type);
|
|
if (obj.template get<First>() != err) return false;
|
|
if constexpr (sizeof...(Others)) {
|
|
return wrong_types<Others...>(obj);
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
template <typename T, typename E>
|
|
std::ostream &operator<<(std::ostream &os, tl::expected<T, E> const &exp) {
|
|
if (exp.has_value()) {
|
|
os << "Value: '" << *exp << "'";
|
|
} else {
|
|
os << "Error";
|
|
}
|
|
return os;
|
|
}
|
|
}
|
|
|
|
suite reader = [] {
|
|
"read uint32"_test = [] {
|
|
constexpr auto payload = make_bytes(0xce, 0x01, 0x02, 0x03, 0x09);
|
|
msgpack::token_reader reader(payload);
|
|
auto token = reader.read_one();
|
|
expect(token && token->type() == msgpack::format::type::unsigned_int);
|
|
expect(token->get<std::uint8_t>() == tl::make_unexpected(msgpack::error::will_truncate));
|
|
expect(token->get<std::uint16_t>() == tl::make_unexpected(msgpack::error::will_truncate));
|
|
expect(token->get<std::uint32_t>() == 0x01020309);
|
|
expect(token->get<std::uint64_t>() == 0x01020309);
|
|
token = reader.read_one();
|
|
expect(token == tl::make_unexpected(msgpack::error::end_of_message));
|
|
};
|
|
"read str8"_test = [] {
|
|
constexpr std::string_view sv = "hello d";
|
|
constexpr auto payload =
|
|
cat(make_bytes(0xd9, sv.size()),
|
|
generate_bytes([sv] { return from_string_view(sv); }));
|
|
|
|
msgpack::token_reader reader(payload);
|
|
auto token = reader.read_one();
|
|
expect(token && token->type() == msgpack::format::type::string);
|
|
expect(token->get<std::string_view>() == sv);
|
|
token = reader.read_one();
|
|
expect(token == tl::make_unexpected(msgpack::error::end_of_message));
|
|
};
|
|
};
|