Commit 4bbccd70 authored by Dominik Charousset's avatar Dominik Charousset

Re-implement inspector_access

parent 4eae4034
......@@ -198,6 +198,7 @@ endif()
add_executable(caf-core-test
test/core-test.cpp
test/nasty.cpp
$<TARGET_OBJECTS:libcaf_core_obj>)
caf_core_set_default_properties(caf-core-test)
......
......@@ -30,10 +30,10 @@ namespace caf {
// -- 1 param templates --------------------------------------------------------
template <class> class [[nodiscard]] error_code;
template <class> class behavior_type_of;
template <class> class dictionary;
template <class> class downstream;
template <class> class [[nodiscard]] error_code;
template <class> class expected;
template <class> class intrusive_cow_ptr;
template <class> class intrusive_ptr;
......@@ -45,6 +45,7 @@ template <class> class stream_sink;
template <class> class stream_source;
template <class> class weak_intrusive_ptr;
template <class> struct inspector_access;
template <class> struct timeout_definition;
template <class> struct type_id;
......
This diff is collapsed.
This diff is collapsed.
......@@ -18,9 +18,7 @@
#pragma once
#include "caf/error.hpp"
#include "caf/inspector_access.hpp"
#include "caf/sec.hpp"
#include "caf/string_view.hpp"
namespace caf {
......@@ -31,7 +29,7 @@ namespace caf {
/// for the DSL.
class save_inspector {
public:
// -- contants ---------------------------------------------------------------
// -- constants --------------------------------------------------------------
/// Convenience constant to indicate success of a processing step.
static constexpr bool ok = true;
......@@ -49,78 +47,95 @@ public:
/// A load inspector never modifies the state of an object.
static constexpr bool writes_state = false;
/// Inspecting objects, fields and values always returns a `bool`.
using result_type = bool;
// -- DSL types for regular fields -------------------------------------------
template <class T, class U>
struct field_with_fallback_t {
string_view field_name;
T* val;
U fallback;
template <class Inspector>
bool operator()(Inspector& f) {
auto is_present = [this] { return *val != fallback; };
auto get = [this] { return *val; };
return inspector_access<T>::save_field(f, field_name, is_present, get);
}
template <class Predicate>
field_with_fallback_t&& invariant(Predicate&&) && {
return std::move(*this);
}
};
template <class T>
struct field_t {
string_view field_name;
T* val;
template <class Inspector>
bool operator()(string_view, Inspector& f) {
if constexpr (inspector_access_traits<T>::is_optional) {
auto& ref = *val;
using value_type = std::decay_t<decltype(*ref)>;
if (ref) {
return f.begin_field(field_name, true) //
&& inspector_access<value_type>::apply(f, *ref) //
&& f.end_field();
} else {
return f.begin_field(field_name, false) && f.end_field();
}
} else {
return f.begin_field(field_name) //
&& inspector_access<T>::apply(f, *val) //
&& f.end_field();
}
bool operator()(Inspector& f) {
return inspector_access<T>::save_field(f, field_name, *val);
}
template <class Unused>
field_t& fallback(Unused&&) {
return *this;
template <class U>
auto fallback(U value) && {
return field_with_fallback_t<T, U>{field_name, val, std::move(value)};
}
template <class Predicate>
field_t invariant(Predicate&&) {
return *this;
field_t&& invariant(Predicate&&) && {
return std::move(*this);
}
};
// -- DSL types for virtual fields (getter and setter access) ----------------
template <class T, class Get, class U>
struct virt_field_with_fallback_t {
string_view field_name;
Get get;
U fallback;
template <class Inspector>
bool operator()(Inspector& f) {
auto is_present = [this] { return get() != fallback; };
return inspector_access<T>::save_field(f, field_name, is_present, get);
}
template <class Predicate>
virt_field_with_fallback_t&& invariant(Predicate&&) && {
return std::move(*this);
}
};
template <class T, class Get>
struct virt_field_t {
string_view field_name;
Get get;
template <class Inspector>
bool operator()(string_view, Inspector& f) {
if (!f.begin_field(field_name))
return stop;
auto&& value = get();
using value_type = std::remove_reference_t<decltype(value)>;
if constexpr (std::is_const<value_type>::value) {
// Force a mutable reference, because the inspect API requires it. This
// const_cast is always safe, because we never actually modify the
// object.
using mutable_ref = std::remove_const_t<value_type>&;
if (!inspector_access<T>::apply(f, const_cast<mutable_ref>(value)))
return stop;
} else {
if (!inspector_access<T>::apply(f, value))
return stop;
}
return f.end_field();
bool operator()(Inspector& f) {
auto&& x = get();
return inspector_access<T>::save_field(f, field_name,
detail::as_mutable_ref(x));
}
template <class Unused>
virt_field_t& fallback(Unused&&) {
return *this;
template <class U>
auto fallback(U value) && {
return virt_field_with_fallback_t<T, Get, U>{
field_name,
std::move(get),
std::move(value),
};
}
template <class Predicate>
virt_field_t invariant(Predicate&&) {
return *this;
virt_field_t&& invariant(Predicate&&) && {
return std::move(*this);
}
};
......@@ -131,8 +146,7 @@ public:
template <class... Fields>
bool fields(Fields&&... fs) {
return f->begin_object(object_name) && (fs(object_name, *f) && ...)
&& f->end_object();
return f->begin_object(object_name) && (fs(*f) && ...) && f->end_object();
}
auto pretty_name(string_view name) && {
......
......@@ -136,7 +136,7 @@ enum class sec : uint8_t {
malformed_basp_message,
/// The middleman closed a connection because it failed to serialize or
/// deserialize a payload.
serializing_basp_payload_failed,
serializing_basp_payload_failed = 50,
/// The middleman closed a connection to itself or an already connected node.
redundant_connection,
/// Resolving a path on a remote node failed.
......@@ -145,6 +145,13 @@ enum class sec : uint8_t {
no_tracing_context,
/// No request produced a valid result.
all_requests_failed,
/// Deserialization failed, because an invariant got violated after reading
/// the content of a field.
field_invariant_check_failed = 55,
/// Deserialization failed, because a setter rejected the input.
field_value_synchronization_failed,
/// Deserialization failed, because the source announced an invalid type.
invalid_field_type,
};
/// @relates sec
......
......@@ -37,6 +37,10 @@ namespace caf {
/// Internal representation of a type ID.
using type_id_t = uint16_t;
/// Special value equal to the greatest possible value for `type_id_t`.
/// Generally indicates that no type ID for a given type exists.
constexpr type_id_t invalid_type_id = 65535;
/// Maps the type `T` to a globally unique ID.
template <class T>
struct type_id;
......
......@@ -240,8 +240,8 @@ enum dummy_enum { de_foo, de_bar };
CAF_BEGIN_TYPE_ID_BLOCK(core_test, caf::first_custom_type_id)
ADD_TYPE_ID((caf::stream<int32_t>) )
ADD_TYPE_ID((caf::stream<std::string>) )
ADD_TYPE_ID((caf::stream<std::pair<level, std::string>>) )
ADD_TYPE_ID((caf::stream<std::string>) )
ADD_TYPE_ID((dummy_enum))
ADD_TYPE_ID((dummy_enum_class))
ADD_TYPE_ID((dummy_struct))
......
......@@ -26,33 +26,11 @@
#include <string>
#include <vector>
namespace caf {
#include "caf/span.hpp"
#include "caf/type_id.hpp"
#include "caf/variant.hpp"
template <>
struct inspector_access<std::string> {
template <class Inspector>
static bool apply(Inspector& f, std::string& x) {
return f.value(x);
}
};
template <>
struct inspector_access<int32_t> {
template <class Inspector>
static bool apply(Inspector& f, int32_t& x) {
return f.value(x);
}
};
template <>
struct inspector_access<double> {
template <class Inspector>
static bool apply(Inspector& f, double& x) {
return f.value(x);
}
};
} // namespace caf
#include "nasty.hpp"
using namespace caf;
......@@ -153,6 +131,28 @@ bool inspect(Inspector& f, foobar& x) {
f.field("bar", get_bar, set_bar));
}
struct dummy_message {
static inline string_view tname = "dummy_message";
variant<std::string, double> content;
};
template <class Inspector>
bool inspect(Inspector& f, dummy_message& x) {
return f.object(x).fields(f.field("content", x.content));
}
struct fallback_dummy_message {
static inline string_view tname = "fallback_dummy_message";
variant<std::string, double> content;
};
template <class Inspector>
bool inspect(Inspector& f, fallback_dummy_message& x) {
return f.object(x).fields(f.field("content", x.content).fallback(42.0));
}
struct testee : load_inspector {
std::string log;
......@@ -162,6 +162,11 @@ struct testee : load_inspector {
err = std::move(x);
}
bool load_field_failed(string_view, sec code) {
set_error(make_error(code));
return stop;
}
size_t indent = 0;
void new_line() {
......@@ -206,6 +211,26 @@ struct testee : load_inspector {
return ok;
}
bool begin_field(string_view name, span<const type_id_t>,
size_t& type_index) {
new_line();
indent += 2;
log += "begin variant field ";
log.insert(log.end(), name.begin(), name.end());
type_index = 0;
return ok;
}
bool begin_field(string_view name, bool& is_present, span<const type_id_t>,
size_t&) {
new_line();
indent += 2;
log += "begin optional variant field ";
log.insert(log.end(), name.begin(), name.end());
is_present = false;
return ok;
}
bool end_field() {
indent -= 2;
new_line();
......@@ -213,14 +238,36 @@ struct testee : load_inspector {
return ok;
}
bool begin_tuple(size_t size) {
new_line();
indent += 2;
log += "begin tuple of size ";
log += std::to_string(size);
return ok;
}
bool end_tuple() {
indent -= 2;
new_line();
log += "end tuple";
return ok;
}
template <class T>
bool value(T& x) {
std::enable_if_t<std::is_arithmetic<T>::value, bool> value(T& x) {
new_line();
log += type_name_v<T>;
log += " value";
x = T{};
return ok;
}
bool value(std::string& x) {
new_line();
log += "std::string value";
x.clear();
return ok;
}
};
struct fixture {
......@@ -340,4 +387,134 @@ begin object foobar
end object)_");
}
CAF_TEST(load inspectors support variant fields) {
dummy_message d;
d.content = 42.0;
CAF_CHECK(inspect(f, d));
// Our dummy inspector resets variants to their first type.
CAF_CHECK(holds_alternative<std::string>(d.content));
CAF_CHECK_EQUAL(f.log, R"_(
begin object dummy_message
begin variant field content
std::string value
end field
end object)_");
}
CAF_TEST(load inspectors support variant fields with fallbacks) {
fallback_dummy_message d;
d.content = std::string{"hello world"};
CAF_CHECK(inspect(f, d));
CAF_CHECK_EQUAL(d.content, 42.0);
CAF_CHECK_EQUAL(f.log, R"_(
begin object fallback_dummy_message
begin optional variant field content
end field
end object)_");
}
CAF_TEST(load inspectors support nasty data structures) {
nasty x;
CAF_CHECK(inspect(f, x));
CAF_CHECK_EQUAL(f.log, R"_(
begin object nasty
begin field field_01
int32_t value
end field
begin optional field field_02
end field
begin field field_03
int32_t value
end field
begin optional field field_04
end field
begin optional field field_05
end field
begin optional field field_06
end field
begin optional field field_07
end field
begin optional field field_08
end field
begin variant field field_09
std::string value
end field
begin optional variant field field_10
end field
begin variant field field_11
std::string value
end field
begin optional variant field field_12
end field
begin field field_13
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_14
end field
begin field field_15
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_16
end field
begin field field_17
int32_t value
end field
begin optional field field_18
end field
begin field field_19
int32_t value
end field
begin optional field field_20
end field
begin optional field field_21
end field
begin optional field field_22
end field
begin optional field field_23
end field
begin optional field field_24
end field
begin variant field field_25
std::string value
end field
begin optional variant field field_26
end field
begin variant field field_27
std::string value
end field
begin optional variant field field_28
end field
begin field field_29
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_30
end field
begin field field_31
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_32
end field
begin optional variant field field_33
end field
begin optional field field_34
end field
begin optional variant field field_35
end field
begin optional field field_36
end field
end object)_");
}
CAF_TEST_FIXTURE_SCOPE_END()
#include "nasty.hpp"
std::string to_string(weekday x) {
switch (x) {
default:
return "???";
case weekday::monday:
return "monday";
case weekday::tuesday:
return "tuesday";
case weekday::wednesday:
return "wednesday";
case weekday::thursday:
return "thursday";
case weekday::friday:
return "friday";
case weekday::saturday:
return "saturday";
case weekday::sunday:
return "sunday";
}
}
bool parse(std::string_view input, weekday& dest) {
if (input == "monday") {
dest = weekday::monday;
return true;
}
if (input == "tuesday") {
dest = weekday::tuesday;
return true;
}
if (input == "wednesday") {
dest = weekday::wednesday;
return true;
}
if (input == "thursday") {
dest = weekday::thursday;
return true;
}
if (input == "friday") {
dest = weekday::friday;
return true;
}
if (input == "saturday") {
dest = weekday::saturday;
return true;
}
if (input == "sunday") {
dest = weekday::sunday;
return true;
}
return false;
}
#pragma once
#include <cstdint>
#include <string>
#include <tuple>
#include "caf/inspector_access.hpp"
#include "caf/optional.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
enum class weekday {
monday,
tuesday,
wednesday,
thursday,
friday,
saturday,
sunday,
};
std::string to_string(weekday x);
bool parse(std::string_view input, weekday& dest);
namespace caf {
template <>
struct inspector_access<weekday> : inspector_access_base<weekday> {
using default_impl = default_inspector_access<weekday>;
template <class Inspector>
static bool apply_object(Inspector& f, weekday& x) {
if constexpr (Inspector::has_human_readable_format) {
auto get = [&x] { return to_string(x); };
auto set = [&x](std::string str) { return parse(str, x); };
f.object(x).fields(f.field("value", get, set));
} else {
return default_impl::apply_object(f, x);
}
}
template <class Inspector>
static bool apply_value(Inspector& f, weekday& x) {
if constexpr (Inspector::has_human_readable_format) {
auto get = [&x] { return to_string(x); };
auto set = [&x](std::string str) { return parse(str, x); };
return inspect_value(f, get, set);
} else {
return default_impl::apply_value(f, x);
}
}
};
} // namespace caf
#define ADD_GET_SET_FIELD(type, name) \
private: \
type name##_ = type{}; \
\
public: \
const auto& name() const noexcept { \
return name##_; \
} \
void name(type value) { \
name##_ = std::move(value); \
}
// A mean data type designed for maximum coverage of the inspect API.
class nasty {
public:
static inline caf::string_view tname = "nasty";
using optional_type = caf::optional<int32_t>;
using variant_type = caf::variant<std::string, int32_t>;
using tuple_type = std::tuple<std::string, int32_t>;
using optional_variant_type = caf::optional<variant_type>;
using optional_tuple_type = caf::optional<tuple_type>;
// Plain, direct access.
int32_t field_01 = 0;
// Plain, direct access, fallback (0).
int32_t field_02 = 0;
// Plain, direct access, invariant (>= 0).
int32_t field_03 = 0;
// Plain, direct access, fallback (0), invariant (>= 0).
int32_t field_04 = 0;
// Optional, direct access.
optional_type field_05;
// Optional, direct access, fallback (0).
optional_type field_06;
// Optional, direct access, invariant (>= 0).
optional_type field_07;
// Optional, direct access, fallback (0), invariant (>= 0).
optional_type field_08;
// Variant, direct access.
variant_type field_09;
// Variant, direct access, fallback (0).
variant_type field_10;
// Variant, direct access, invariant (>= 0).
variant_type field_11;
// Variant, direct access, fallback (0), invariant (>= 0).
variant_type field_12;
// Tuple, direct access.
tuple_type field_13;
// Tuple, direct access, fallback ("", 0).
tuple_type field_14;
// Tuple, direct access, invariant (>= 0).
tuple_type field_15;
// Tuple, direct access, fallback ("", 0), invariant (>= 0).
tuple_type field_16;
// Plain, get/set access.
ADD_GET_SET_FIELD(int32_t, field_17)
// Plain, get/set access, fallback (0).
ADD_GET_SET_FIELD(int32_t, field_18)
// Plain, get/set access, invariant (>= 0).
ADD_GET_SET_FIELD(int32_t, field_19)
// Plain, get/set access, fallback (0), invariant (>= 0).
ADD_GET_SET_FIELD(int32_t, field_20)
// Optional, get/set access.
ADD_GET_SET_FIELD(optional_type, field_21)
// Optional, get/set access, fallback (0).
ADD_GET_SET_FIELD(optional_type, field_22)
// Optional, get/set access, invariant (>= 0).
ADD_GET_SET_FIELD(optional_type, field_23)
// Optional, get/set access, fallback (0), invariant (>= 0).
ADD_GET_SET_FIELD(optional_type, field_24)
// Variant, get/set access.
ADD_GET_SET_FIELD(variant_type, field_25)
// Variant, get/set access, fallback (0).
ADD_GET_SET_FIELD(variant_type, field_26)
// Variant, get/set access, invariant (>= 0).
ADD_GET_SET_FIELD(variant_type, field_27)
// Variant, get/set access, fallback (0), invariant (>= 0).
ADD_GET_SET_FIELD(variant_type, field_28)
// Tuple, get/set access.
ADD_GET_SET_FIELD(tuple_type, field_29)
// Tuple, get/set access, fallback ("", 0).
ADD_GET_SET_FIELD(tuple_type, field_30)
// Tuple, get/set access, invariant (>= 0).
ADD_GET_SET_FIELD(tuple_type, field_31)
// Tuple, get/set access, fallback ("", 0), invariant (>= 0).
ADD_GET_SET_FIELD(tuple_type, field_32)
// Optional variant, direct access.
optional_variant_type field_33;
// Optional tuple, direct access.
optional_tuple_type field_34;
// Optional variant, get/set access.
ADD_GET_SET_FIELD(optional_variant_type, field_35)
// Optional variant, get/set access.
ADD_GET_SET_FIELD(optional_tuple_type, field_36)
// Plain, direct access with custom inspector_access.
weekday field_37;
// Plain, get/set access with custom inspector_access.
ADD_GET_SET_FIELD(weekday, field_38)
};
#undef ADD_GET_SET_FIELD
#define DIRECT_FIELD(num) field("field_" #num, x.field_##num)
#define GET_SET_FIELD(num) \
field( \
"field_" #num, [&x]() -> decltype(auto) { return x.field_##num(); }, \
[&x](auto&& value) { \
x.field_##num(std::forward<decltype(value)>(value)); \
return true; \
})
template <class Inspector>
bool inspect(Inspector& f, nasty& x) {
using caf::get;
using caf::get_if;
struct {
bool operator()(int32_t x) {
return x >= 0;
}
bool operator()(const nasty::optional_type& x) {
return x ? *x >= 0 : true;
}
bool operator()(const nasty::variant_type& x) {
if (auto ptr = get_if<int32_t>(&x))
return *ptr >= 0;
return true;
}
bool operator()(const nasty::tuple_type& x) {
return get<1>(x) >= 0;
}
} is_positive;
nasty::variant_type default_variant{int32_t{0}};
nasty::tuple_type default_tuple{"", 0};
return f.object(x).fields( //
f.DIRECT_FIELD(01), //
f.DIRECT_FIELD(02).fallback(0), //
f.DIRECT_FIELD(03).invariant(is_positive), //
f.DIRECT_FIELD(04).fallback(0).invariant(is_positive), //
f.DIRECT_FIELD(05), //
f.DIRECT_FIELD(06).fallback(0), //
f.DIRECT_FIELD(07).invariant(is_positive), //
f.DIRECT_FIELD(08).fallback(0).invariant(is_positive), //
f.DIRECT_FIELD(09), //
f.DIRECT_FIELD(10).fallback(default_variant), //
f.DIRECT_FIELD(11).invariant(is_positive), //
f.DIRECT_FIELD(12).fallback(default_variant).invariant(is_positive), //
f.DIRECT_FIELD(13), //
f.DIRECT_FIELD(14).fallback(default_tuple), //
f.DIRECT_FIELD(15).invariant(is_positive), //
f.DIRECT_FIELD(16).fallback(default_tuple).invariant(is_positive), //
f.GET_SET_FIELD(17), //
f.GET_SET_FIELD(18).fallback(0), //
f.GET_SET_FIELD(19).invariant(is_positive), //
f.GET_SET_FIELD(20).fallback(0).invariant(is_positive), //
f.GET_SET_FIELD(21), //
f.GET_SET_FIELD(22).fallback(0), //
f.GET_SET_FIELD(23).invariant(is_positive), //
f.GET_SET_FIELD(24).fallback(0).invariant(is_positive), //
f.GET_SET_FIELD(25), //
f.GET_SET_FIELD(26).fallback(default_variant), //
f.GET_SET_FIELD(27).invariant(is_positive), //
f.GET_SET_FIELD(28).fallback(default_variant).invariant(is_positive), //
f.GET_SET_FIELD(29), //
f.GET_SET_FIELD(30).fallback(default_tuple), //
f.GET_SET_FIELD(31).invariant(is_positive), //
f.GET_SET_FIELD(32).fallback(default_tuple).invariant(is_positive), //
f.DIRECT_FIELD(33), //
f.DIRECT_FIELD(34), //
f.GET_SET_FIELD(35), //
f.GET_SET_FIELD(36));
}
#undef DIRECT_FIELD
#undef GET_SET_FIELD
......@@ -26,33 +26,7 @@
#include <string>
#include <vector>
namespace caf {
template <>
struct inspector_access<std::string> {
template <class Inspector>
static bool apply(Inspector& f, std::string& x) {
return f.value(x);
}
};
template <>
struct inspector_access<int32_t> {
template <class Inspector>
static bool apply(Inspector& f, int32_t& x) {
return f.value(x);
}
};
template <>
struct inspector_access<double> {
template <class Inspector>
static bool apply(Inspector& f, double& x) {
return f.value(x);
}
};
} // namespace caf
#include "nasty.hpp"
using namespace caf;
......@@ -174,6 +148,16 @@ struct testee : save_inspector {
return object_t<testee>{T::tname, this};
}
template <class T>
auto object(optional<T>&) {
return object_t<testee>{"optional", this};
}
template <class... Ts>
auto object(variant<Ts...>&) {
return object_t<testee>{"variant", this};
}
bool begin_object(string_view object_name) {
new_line();
indent += 2;
......@@ -205,6 +189,22 @@ struct testee : save_inspector {
return ok;
}
bool begin_field(string_view name, span<const type_id_t>, size_t) {
new_line();
indent += 2;
log += "begin variant field ";
log.insert(log.end(), name.begin(), name.end());
return ok;
}
bool begin_field(string_view name, bool, span<const type_id_t>, size_t) {
new_line();
indent += 2;
log += "begin optional variant field ";
log.insert(log.end(), name.begin(), name.end());
return ok;
}
bool end_field() {
indent -= 2;
new_line();
......@@ -212,13 +212,34 @@ struct testee : save_inspector {
return ok;
}
bool begin_tuple(size_t size) {
new_line();
indent += 2;
log += "begin tuple of size ";
log += std::to_string(size);
return ok;
}
bool end_tuple() {
indent -= 2;
new_line();
log += "end tuple";
return ok;
}
template <class T>
bool value(const T&) {
std::enable_if_t<std::is_arithmetic<T>::value, bool> value(const T&) {
new_line();
log += type_name_v<T>;
log += " value";
return ok;
}
bool value(const std::string&) {
new_line();
log += "std::string value";
return ok;
}
};
struct fixture {
......@@ -291,19 +312,38 @@ end object)_");
}
CAF_TEST(save inspectors support fields with fallbacks and invariants) {
duration d{"minutes", 42.0};
CAF_CHECK_EQUAL(inspect(f, d), true);
CAF_CHECK_EQUAL(d.unit, "minutes");
CAF_CHECK_EQUAL(d.count, 42.0);
CAF_CHECK_EQUAL(f.log, R"_(
CAF_MESSAGE("save inspectors suppress fields with their default value");
{
duration d{"seconds", 12.0};
CAF_CHECK_EQUAL(inspect(f, d), true);
CAF_CHECK_EQUAL(d.unit, "seconds");
CAF_CHECK_EQUAL(d.count, 12.0);
CAF_CHECK_EQUAL(f.log, R"_(
begin object duration
begin field unit
begin optional field unit
end field
begin field count
double value
end field
end object)_");
}
f.log.clear();
CAF_MESSAGE("save inspectors include fields with non-default value");
{
duration d{"minutes", 42.0};
CAF_CHECK_EQUAL(inspect(f, d), true);
CAF_CHECK_EQUAL(d.unit, "minutes");
CAF_CHECK_EQUAL(d.count, 42.0);
CAF_CHECK_EQUAL(f.log, R"_(
begin object duration
begin optional field unit
std::string value
end field
begin field count
double value
end field
end object)_");
}
}
CAF_TEST(save inspectors support fields with optional values) {
......@@ -335,7 +375,7 @@ CAF_TEST(save inspectors support fields with getters and setters) {
foobar fb;
fb.foo("hello");
fb.bar("world");
CAF_CHECK_EQUAL(inspect(f, fb), true);
CAF_CHECK(inspect(f, fb));
CAF_CHECK_EQUAL(fb.foo(), "hello");
CAF_CHECK_EQUAL(fb.bar(), "world");
CAF_CHECK_EQUAL(f.log, R"_(
......@@ -349,4 +389,112 @@ begin object foobar
end object)_");
}
CAF_TEST(save inspectors support nasty data structures) {
nasty x;
CAF_CHECK(inspect(f, x));
CAF_CHECK_EQUAL(f.log, R"_(
begin object nasty
begin field field_01
int32_t value
end field
begin optional field field_02
end field
begin field field_03
int32_t value
end field
begin optional field field_04
end field
begin optional field field_05
end field
begin optional field field_06
end field
begin optional field field_07
end field
begin optional field field_08
end field
begin variant field field_09
std::string value
end field
begin optional variant field field_10
std::string value
end field
begin variant field field_11
std::string value
end field
begin optional variant field field_12
std::string value
end field
begin field field_13
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_14
end field
begin field field_15
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_16
end field
begin field field_17
int32_t value
end field
begin optional field field_18
end field
begin field field_19
int32_t value
end field
begin optional field field_20
end field
begin optional field field_21
end field
begin optional field field_22
end field
begin optional field field_23
end field
begin optional field field_24
end field
begin variant field field_25
std::string value
end field
begin optional variant field field_26
std::string value
end field
begin variant field field_27
std::string value
end field
begin optional variant field field_28
std::string value
end field
begin field field_29
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_30
end field
begin field field_31
begin tuple of size 2
std::string value
int32_t value
end tuple
end field
begin optional field field_32
end field
begin optional variant field field_33
end field
begin optional field field_34
end field
begin optional variant field field_35
end field
begin optional field field_36
end field
end object)_");
}
CAF_TEST_FIXTURE_SCOPE_END()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment