new unit-udt.cpp tests
This commit is contained in:
parent
1f25ec5d36
commit
3494014ba0
1 changed files with 123 additions and 58 deletions
|
@ -391,27 +391,27 @@ TEST_CASE("adl_serializer specialization", "[udt]")
|
||||||
|
|
||||||
namespace nlohmann
|
namespace nlohmann
|
||||||
{
|
{
|
||||||
// TODO provide a real example, since this works now :)
|
template <>
|
||||||
// template <typename T>
|
struct adl_serializer<std::vector<float>>
|
||||||
// struct adl_serializer<std::vector<T>>
|
{
|
||||||
// {
|
static void to_json(json& j, std::vector<float> const&)
|
||||||
// static void to_json(json& j, std::vector<T> const& opt)
|
{
|
||||||
// {
|
j = "hijacked!";
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// static void from_json(json const& j, std::vector<T>& opt)
|
|
||||||
// {
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("current supported types are preferred over specializations", "[udt]")
|
static void from_json(json const&, std::vector<float>& opt)
|
||||||
{
|
{
|
||||||
|
opt = {42.0, 42.0, 42.0};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
json j = std::vector<int> {1, 2, 3};
|
TEST_CASE("even supported types can be specialized", "[udt]")
|
||||||
auto f = j.get<std::vector<int>>();
|
{
|
||||||
CHECK((f == std::vector<int> {1, 2, 3}));
|
json j = std::vector<float> {1.0, 2.0, 3.0};
|
||||||
|
CHECK(j.dump() == R"("hijacked!")");
|
||||||
|
auto f = j.get<std::vector<float>>();
|
||||||
|
CHECK((f == std::vector<float>{42.0, 42.0, 42.0}));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace nlohmann
|
namespace nlohmann
|
||||||
|
@ -432,7 +432,6 @@ struct adl_serializer<std::unique_ptr<T>>
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is the overload needed for non-copyable types,
|
// this is the overload needed for non-copyable types,
|
||||||
// should we add a priority tag in the implementation to prefer this overload if it exists?
|
|
||||||
static std::unique_ptr<T> from_json(json const& j)
|
static std::unique_ptr<T> from_json(json const& j)
|
||||||
{
|
{
|
||||||
if (j.is_null())
|
if (j.is_null())
|
||||||
|
@ -456,7 +455,7 @@ TEST_CASE("Non-copyable types", "[udt]")
|
||||||
json j = optPerson;
|
json j = optPerson;
|
||||||
CHECK(j.is_null());
|
CHECK(j.is_null());
|
||||||
|
|
||||||
optPerson.reset(new udt::person{{42}, {"John Doe"}});
|
optPerson.reset(new udt::person{{42}, {"John Doe"}, udt::country::russia});
|
||||||
j = optPerson;
|
j = optPerson;
|
||||||
CHECK_FALSE(j.is_null());
|
CHECK_FALSE(j.is_null());
|
||||||
|
|
||||||
|
@ -465,7 +464,7 @@ TEST_CASE("Non-copyable types", "[udt]")
|
||||||
|
|
||||||
SECTION("from_json")
|
SECTION("from_json")
|
||||||
{
|
{
|
||||||
auto person = udt::person{{42}, {"John Doe"}};
|
auto person = udt::person{{42}, {"John Doe"}, udt::country::russia};
|
||||||
json j = person;
|
json j = person;
|
||||||
|
|
||||||
auto optPerson = j.get<std::unique_ptr<udt::person>>();
|
auto optPerson = j.get<std::unique_ptr<udt::person>>();
|
||||||
|
@ -478,37 +477,68 @@ TEST_CASE("Non-copyable types", "[udt]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// custom serializer
|
// custom serializer - advanced usage
|
||||||
// advanced usage (I did not have a real use case in mind)
|
// pack structs that are pod-types (but not scalar types)
|
||||||
template <typename T, typename = typename std::enable_if<std::is_pod<T>::value>::type>
|
// relies on adl for any other type
|
||||||
|
template <typename T, typename = void>
|
||||||
struct pod_serializer
|
struct pod_serializer
|
||||||
{
|
{
|
||||||
template <typename Json>
|
// use adl for non-pods, or scalar types
|
||||||
static void from_json(Json const& j , T& t)
|
template <
|
||||||
|
typename Json, typename U = T,
|
||||||
|
typename std::enable_if<
|
||||||
|
not(std::is_pod<U>::value and std::is_class<U>::value), int>::type = 0>
|
||||||
|
static void from_json(Json const &j, U &t)
|
||||||
|
{
|
||||||
|
using nlohmann::from_json;
|
||||||
|
from_json(j, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// special behaviour for pods
|
||||||
|
template <typename Json, typename U = T,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_pod<U>::value and std::is_class<U>::value, int>::type = 0>
|
||||||
|
static void from_json(Json const &j, U &t)
|
||||||
{
|
{
|
||||||
std::uint64_t value;
|
std::uint64_t value;
|
||||||
|
// TODO The following block is no longer relevant in this serializer, make another one that shows the issue
|
||||||
|
// the problem arises only when one from_json method is defined without any constraint
|
||||||
|
//
|
||||||
// Why cannot we simply use: j.get<std::uint64_t>() ?
|
// Why cannot we simply use: j.get<std::uint64_t>() ?
|
||||||
// Well, with the current experiment, the get method looks for a from_json function, which we are currently defining!
|
// Well, with the current experiment, the get method looks for a from_json
|
||||||
// This would end up in a stack overflow. Calling nlohmann::from_json is a workaround.
|
// function, which we are currently defining!
|
||||||
// I shall find a good way to avoid this once all constructors are converted to free methods
|
// This would end up in a stack overflow. Calling nlohmann::from_json is a
|
||||||
|
// workaround (is it?).
|
||||||
|
// I shall find a good way to avoid this once all constructors are converted
|
||||||
|
// to free methods
|
||||||
//
|
//
|
||||||
// In short, constructing a json by constructor calls to_json
|
// In short, constructing a json by constructor calls to_json
|
||||||
// calling get calls from_json, for now, we cannot do this in custom serializers
|
// calling get calls from_json, for now, we cannot do this in custom
|
||||||
|
// serializers
|
||||||
nlohmann::from_json(j, value);
|
nlohmann::from_json(j, value);
|
||||||
auto bytes = static_cast<char *>(static_cast<void *>(&value));
|
auto bytes = static_cast<char *>(static_cast<void *>(&value));
|
||||||
std::memcpy(&t, bytes, sizeof(value));
|
std::memcpy(&t, bytes, sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Json>
|
template <
|
||||||
|
typename Json, typename U = T,
|
||||||
|
typename std::enable_if<
|
||||||
|
not(std::is_pod<U>::value and std::is_class<U>::value), int>::type = 0>
|
||||||
static void to_json(Json &j, T const &t)
|
static void to_json(Json &j, T const &t)
|
||||||
{
|
{
|
||||||
auto bytes = static_cast<char const*>(static_cast<void const*>(&t));
|
using nlohmann::to_json;
|
||||||
|
to_json(j, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Json, typename U = T,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_pod<U>::value and std::is_class<U>::value, int>::type = 0>
|
||||||
|
static void to_json(Json &j, T const &t) noexcept
|
||||||
|
{
|
||||||
|
auto bytes = static_cast<unsigned char const *>(static_cast<void const *>(&t));
|
||||||
std::uint64_t value = bytes[0];
|
std::uint64_t value = bytes[0];
|
||||||
for (auto i = 1; i < 8; ++i)
|
for (auto i = 1; i < 8; ++i)
|
||||||
{
|
value |= std::uint64_t{bytes[i]} << 8 * i;
|
||||||
value |= bytes[i] << 8 * i;
|
|
||||||
}
|
|
||||||
// same thing here
|
|
||||||
nlohmann::to_json(j, value);
|
nlohmann::to_json(j, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -522,16 +552,46 @@ struct small_pod
|
||||||
short end;
|
short end;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(small_pod lhs, small_pod rhs)
|
struct non_pod
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Json>
|
||||||
|
void to_json(Json& j, non_pod const& np)
|
||||||
|
{
|
||||||
|
j = np.s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Json>
|
||||||
|
void from_json(Json const& j, non_pod& np)
|
||||||
|
{
|
||||||
|
np.s = j.template get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(small_pod lhs, small_pod rhs) noexcept
|
||||||
{
|
{
|
||||||
return std::tie(lhs.begin, lhs.middle, lhs.end) ==
|
return std::tie(lhs.begin, lhs.middle, lhs.end) ==
|
||||||
std::tie(lhs.begin, lhs.middle, lhs.end);
|
std::tie(rhs.begin, rhs.middle, rhs.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(non_pod const &lhs, non_pod const &rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.s == rhs.s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, small_pod l)
|
||||||
|
{
|
||||||
|
return os << "begin: " << l.begin << ", middle: " << l.middle << ", end: " << l.end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("custom serializer for pods", "[udt]")
|
TEST_CASE("custom serializer for pods", "[udt]")
|
||||||
{
|
{
|
||||||
using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, pod_serializer>;
|
using custom_json =
|
||||||
|
nlohmann::basic_json<std::map, std::vector, std::string, bool,
|
||||||
|
std::int64_t, std::uint64_t, double, std::allocator,
|
||||||
|
pod_serializer>;
|
||||||
|
|
||||||
auto p = udt::small_pod{42, '/', 42};
|
auto p = udt::small_pod{42, '/', 42};
|
||||||
custom_json j = p;
|
custom_json j = p;
|
||||||
|
@ -539,6 +599,11 @@ TEST_CASE("custom serializer for pods", "[udt]")
|
||||||
auto p2 = j.get<udt::small_pod>();
|
auto p2 = j.get<udt::small_pod>();
|
||||||
|
|
||||||
CHECK(p == p2);
|
CHECK(p == p2);
|
||||||
|
|
||||||
|
auto np = udt::non_pod{{"non-pod"}};
|
||||||
|
custom_json j2 = np;
|
||||||
|
auto np2 = j2.get<udt::non_pod>();
|
||||||
|
CHECK(np == np2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename>
|
template <typename T, typename>
|
||||||
|
|
Loading…
Reference in a new issue