156 lines
5.7 KiB
C++
156 lines
5.7 KiB
C++
#include "source/include/parselink/msgpack/object.h"
|
|
#include <string>
|
|
#include <tl/expected.hpp>
|
|
#include <msgpack/object.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 First, typename... Others>
|
|
constexpr bool wrong_types(auto const& obj) {
|
|
auto err = tl::make_unexpected(msgpack::object_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;
|
|
}
|
|
}
|
|
|
|
enum class foo : std::uint8_t {
|
|
a, b, c, d, e
|
|
};
|
|
|
|
suite size_and_enum = [] {
|
|
"expected use case"_test = [] {
|
|
msgpack::size_and_enum<std::uint32_t, foo> value;
|
|
expect(sizeof(value) == 8);
|
|
expect(value.rep() == uintptr_t{});
|
|
expect(value.get_size() == std::uint32_t{});
|
|
expect(value.get_enum() == foo::a);
|
|
value.set_size(std::uint32_t(-1));
|
|
expect(value.get_size() == std::uint32_t(-1));
|
|
expect(value.get_enum() == foo::a);
|
|
expect(value.rep() == 0xffffffff00000000);
|
|
value.set_enum(foo::c);
|
|
expect(value.get_size() == std::uint32_t(-1));
|
|
expect(value.get_enum() == foo::c);
|
|
expect(value.rep() == 0xffffffff00000002);
|
|
value.set_both(0xaa, foo::e);
|
|
expect(value.get_size() == 0xaa);
|
|
expect(value.get_enum() == foo::e);
|
|
expect(value.rep() == 0x000000aa00000004);
|
|
};
|
|
};
|
|
|
|
suite assignment_and_access = [] {
|
|
"object::object()"_test = [] {
|
|
msgpack::object obj;
|
|
expect(obj.type() == msgpack::object_type::invalid);
|
|
};
|
|
"object::object(bool)"_test = [] {
|
|
msgpack::object obj(true);
|
|
expect(obj.type() == msgpack::object_type::boolean);
|
|
auto retrieved = obj.get<bool>();
|
|
expect(retrieved && *retrieved);
|
|
expect(wrong_types<int, unsigned, char, std::string_view>(obj));
|
|
};
|
|
"object::object(std::int8_t)"_test = [] {
|
|
std::int8_t val = 0x32;
|
|
msgpack::object obj(val);
|
|
expect(obj.type() == msgpack::object_type::signed_int);
|
|
auto retrieved = obj.get<std::int8_t>();
|
|
expect(retrieved && *retrieved == val);
|
|
expect(wrong_types<bool, unsigned, std::string_view>(obj));
|
|
};
|
|
"object::object(std::uint8_t)"_test = [] {
|
|
std::uint8_t val = 0xaa;
|
|
msgpack::object obj(val);
|
|
expect(obj.type() == msgpack::object_type::unsigned_int);
|
|
auto retrieved = obj.get<std::uint8_t>();
|
|
expect(retrieved && *retrieved == val);
|
|
expect(wrong_types<bool, int, std::string_view>(obj));
|
|
};
|
|
"object::object(char const*)"_test = [] {
|
|
std::string extracted_val;
|
|
{
|
|
char const* val = "hello world";
|
|
msgpack::object obj(val);
|
|
expect(obj.type() == msgpack::object_type::string);
|
|
auto retrieved = obj.get<std::string_view>();
|
|
expect(bool(retrieved));
|
|
if (*retrieved != std::string_view(val)) {
|
|
expect(false);
|
|
}
|
|
expect(wrong_types<bool, int, unsigned>(obj));
|
|
auto string_retrieved = obj.get<std::string>();
|
|
expect(bool(string_retrieved));
|
|
extracted_val = std::move(*string_retrieved);
|
|
}
|
|
expect(extracted_val == "hello world");
|
|
};
|
|
"object::object(std::string)"_test = [] {
|
|
std::string val = "std::string";
|
|
msgpack::object obj(val);
|
|
expect(obj.type() == msgpack::object_type::string);
|
|
auto retrieved = obj.get<std::string_view>();
|
|
expect(bool(retrieved));
|
|
expect(*retrieved == val);
|
|
expect(wrong_types<bool, int, unsigned>(obj));
|
|
};
|
|
"object::object(std::span<byte const>)"_test = [] {
|
|
auto expected_val = make_bytes(0x32, 0xff, 0xaa, 0xce);
|
|
std::vector<std::byte> extracted_val;
|
|
{
|
|
auto val = make_bytes(0x32, 0xff, 0xaa, 0xce);
|
|
msgpack::object obj(val);
|
|
expect(obj.type() == msgpack::object_type::bytes);
|
|
auto retrieved = obj.get<std::span<std::byte const>>();
|
|
expect(bool(retrieved));
|
|
expect(std::equal(retrieved->begin(), retrieved->end(),
|
|
val.begin(), val.end()));
|
|
expect(wrong_types<bool, int, unsigned, std::string_view>(obj));
|
|
auto bytes_retrieved = obj.get<std::vector<std::byte>>();
|
|
expect(bool(bytes_retrieved));
|
|
extracted_val = std::move(*bytes_retrieved);
|
|
}
|
|
expect(std::equal(expected_val.begin(), expected_val.end(),
|
|
extracted_val.begin(), extracted_val.end()));
|
|
};
|
|
};
|
|
|
|
suite int_truncation = [] {
|
|
"unsigned truncation"_test = [] {
|
|
msgpack::object obj(0xffffffffu);
|
|
expect(obj.type() == msgpack::object_type::unsigned_int);
|
|
auto retrieved = obj.get<std::uint8_t>();
|
|
auto err = tl::make_unexpected(msgpack::object_error::will_truncate);
|
|
expect(retrieved == err);
|
|
};
|
|
"signed truncation"_test = [] {
|
|
msgpack::object obj(-0xffff);
|
|
expect(obj.type() == msgpack::object_type::signed_int);
|
|
auto retrieved = obj.get<std::int8_t>();
|
|
auto err = tl::make_unexpected(msgpack::object_error::will_truncate);
|
|
expect(retrieved == err);
|
|
};
|
|
};
|