new unit-udt.cpp tests

This commit is contained in:
Théo DELRIEU 2017-01-09 00:29:00 +01:00
parent 1f25ec5d36
commit 3494014ba0

View file

@ -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>