Files
rippled/src/test/protocol/MultiApiJson_test.cpp

922 lines
37 KiB
C++

#include <xrpl/beast/unit_test.h>
#include <xrpl/protocol/MultiApiJson.h>
#include <cstdint>
#include <limits>
#include <optional>
#include <type_traits>
#include <utility>
namespace xrpl {
namespace test {
namespace {
// This needs to be in a namespace because of deduction guide
template <typename... Ts>
struct Overload : Ts...
{
using Ts::operator()...;
};
template <typename... Ts>
Overload(Ts...) -> Overload<Ts...>;
} // namespace
struct MultiApiJson_test : beast::unit_test::suite
{
static auto
makeJson(char const* key, int val)
{
Json::Value obj1(Json::objectValue);
obj1[key] = val;
return obj1;
}
void
run() override
{
using xrpl::detail::MultiApiJson;
Json::Value const obj1 = makeJson("value", 1);
Json::Value const obj2 = makeJson("value", 2);
Json::Value const obj3 = makeJson("value", 3);
Json::Value const jsonNull{};
MultiApiJson<1, 3> subject{};
static_assert(sizeof(subject) == sizeof(subject.val));
static_assert(subject.size == subject.val.size());
static_assert(std::is_same_v<decltype(subject.val), std::array<Json::Value, 3>>);
BEAST_EXPECT(subject.val.size() == 3);
BEAST_EXPECT((subject.val == std::array<Json::Value, 3>{jsonNull, jsonNull, jsonNull}));
subject.val[0] = obj1;
subject.val[1] = obj2;
{
testcase("forApiVersions, forAllApiVersions");
// Some static data for test inputs
static int const primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
static_assert(std::size(primes) > RPC::apiMaximumValidVersion);
MultiApiJson<1, 3> s1{};
static_assert(
s1.size == RPC::apiMaximumValidVersion + 1 - RPC::apiMinimumSupportedVersion);
int productAllVersions = 1;
for (unsigned i = RPC::apiMinimumSupportedVersion; i <= RPC::apiMaximumValidVersion;
++i)
{
auto const index = i - RPC::apiMinimumSupportedVersion;
BEAST_EXPECT(index == s1.index(i));
BEAST_EXPECT(s1.valid(i));
s1.val[index] = makeJson("value", primes[i]);
productAllVersions *= primes[i];
}
BEAST_EXPECT(!s1.valid(0));
BEAST_EXPECT(!s1.valid(RPC::apiMaximumValidVersion + 1));
BEAST_EXPECT(
!s1.valid(std::numeric_limits<decltype(RPC::apiMaximumValidVersion.value)>::max()));
int result = 1;
static_assert(RPC::apiMinimumSupportedVersion + 1 <= RPC::apiMaximumValidVersion);
forApiVersions<RPC::apiMinimumSupportedVersion, RPC::apiMinimumSupportedVersion + 1>(
std::as_const(s1).visit(),
[this](Json::Value const& json, unsigned int version, int* result) {
BEAST_EXPECT(
version >= RPC::apiMinimumSupportedVersion &&
version <= RPC::apiMinimumSupportedVersion + 1);
if (BEAST_EXPECT(json.isMember("value")))
{
*result *= json["value"].asInt();
}
},
&result);
BEAST_EXPECT(
result ==
primes[RPC::apiMinimumSupportedVersion] *
primes[RPC::apiMinimumSupportedVersion + 1]);
// Check all the values with mutable data
forAllApiVersions(s1.visit(), [&s1, this](Json::Value& json, auto version) {
BEAST_EXPECT(s1.val[s1.index(version)] == json);
if (BEAST_EXPECT(json.isMember("value")))
{
BEAST_EXPECT(json["value"].asInt() == primes[version]);
}
});
result = 1;
forAllApiVersions(
std::as_const(s1).visit(),
[this](Json::Value const& json, unsigned int version, int* result) {
BEAST_EXPECT(
version >= RPC::apiMinimumSupportedVersion &&
version <= RPC::apiMaximumValidVersion);
if (BEAST_EXPECT(json.isMember("value")))
{
*result *= json["value"].asInt();
}
},
&result);
BEAST_EXPECT(result == productAllVersions);
// Several overloads we want to fail
static_assert([](auto&& v) {
return !requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](Json::Value&, auto) {}); // missing const
};
}(std::as_const(s1)));
static_assert([](auto&& v) {
return !requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](Json::Value&) {}); // missing const
};
}(std::as_const(s1)));
static_assert([](auto&& v) {
return !requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[]() {}); // missing parameters
};
}(std::as_const(s1)));
static_assert([](auto&& v) {
return !requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](auto) {},
1); // missing parameters
};
}(std::as_const(s1)));
static_assert([](auto&& v) {
return !requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](auto, auto) {},
1); // missing parameters
};
}(std::as_const(s1)));
static_assert([](auto&& v) {
return !requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](auto, auto, char const*) {},
1); // parameter type mismatch
};
}(std::as_const(s1)));
// Sanity checks
static_assert([](auto&& v) {
return requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](auto) {});
};
}(s1));
static_assert([](auto&& v) {
return requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](Json::Value const&) {});
};
}(std::as_const(s1)));
static_assert([](auto&& v) {
return requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](auto...) {});
};
}(s1));
static_assert([](auto&& v) {
return requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](Json::Value const&, auto...) {});
};
}(std::as_const(s1)));
static_assert([](auto&& v) {
return requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](Json::Value&, auto, auto, auto...) {},
0,
"");
};
}(s1));
static_assert([](auto&& v) {
return requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[]<unsigned int Version>(
Json::Value const&,
std::integral_constant<unsigned int, Version>,
int,
char const*) {},
0,
"");
};
}(std::as_const(s1)));
static_assert([](auto&& v) {
return requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](auto...) {});
};
}(std::move(s1)));
static_assert([](auto&& v) {
return requires {
forAllApiVersions(
std::forward<decltype(v)>(v).visit(), //
[](auto...) {});
};
}(std::move(std::as_const(s1)))); // NOLINT(performance-move-const-arg)
}
{
testcase("default copy construction / assignment");
MultiApiJson<1, 3> x{subject};
BEAST_EXPECT(x.val.size() == subject.val.size());
BEAST_EXPECT(x.val[0] == subject.val[0]);
BEAST_EXPECT(x.val[1] == subject.val[1]);
BEAST_EXPECT(x.val[2] == subject.val[2]);
BEAST_EXPECT(x.val == subject.val);
BEAST_EXPECT(&x.val[0] != &subject.val[0]);
BEAST_EXPECT(&x.val[1] != &subject.val[1]);
BEAST_EXPECT(&x.val[2] != &subject.val[2]);
MultiApiJson<1, 3> y;
BEAST_EXPECT((y.val == std::array<Json::Value, 3>{}));
y = subject;
BEAST_EXPECT(y.val == subject.val);
BEAST_EXPECT(&y.val[0] != &subject.val[0]);
BEAST_EXPECT(&y.val[1] != &subject.val[1]);
BEAST_EXPECT(&y.val[2] != &subject.val[2]);
y = std::move(x);
BEAST_EXPECT(y.val == subject.val);
BEAST_EXPECT(&y.val[0] != &subject.val[0]);
BEAST_EXPECT(&y.val[1] != &subject.val[1]);
BEAST_EXPECT(&y.val[2] != &subject.val[2]);
}
{
testcase("set");
auto x = MultiApiJson<1, 2>{Json::objectValue};
x.set("name1", 42);
BEAST_EXPECT(x.val[0].isMember("name1"));
BEAST_EXPECT(x.val[1].isMember("name1"));
BEAST_EXPECT(x.val[0]["name1"].isInt());
BEAST_EXPECT(x.val[1]["name1"].isInt());
BEAST_EXPECT(x.val[0]["name1"].asInt() == 42);
BEAST_EXPECT(x.val[1]["name1"].asInt() == 42);
x.set("name2", "bar");
BEAST_EXPECT(x.val[0].isMember("name2"));
BEAST_EXPECT(x.val[1].isMember("name2"));
BEAST_EXPECT(x.val[0]["name2"].isString());
BEAST_EXPECT(x.val[1]["name2"].isString());
BEAST_EXPECT(x.val[0]["name2"].asString() == "bar");
BEAST_EXPECT(x.val[1]["name2"].asString() == "bar");
// Tests of requires clause - these are expected to match
static_assert([](auto&& v) { return requires { v.set("name", Json::nullValue); }; }(x));
static_assert([](auto&& v) { return requires { v.set("name", "value"); }; }(x));
static_assert([](auto&& v) { return requires { v.set("name", true); }; }(x));
static_assert([](auto&& v) { return requires { v.set("name", 42); }; }(x));
// Tests of requires clause - these are expected NOT to match
struct foo_t final
{
};
static_assert([](auto&& v) { return !requires { v.set("name", foo_t{}); }; }(x));
static_assert([](auto&& v) { return !requires { v.set("name", std::nullopt); }; }(x));
}
{
testcase("isMember");
// Well defined behaviour even if we have different types of members
BEAST_EXPECT(subject.isMember("foo") == decltype(subject)::none);
{
// All variants have element "One", none have element "Two"
MultiApiJson<1, 2> s1{};
s1.val[0] = makeJson("One", 12);
s1.val[1] = makeJson("One", 42);
BEAST_EXPECT(s1.isMember("One") == decltype(s1)::all);
BEAST_EXPECT(s1.isMember("Two") == decltype(s1)::none);
}
{
// Some variants have element "One" and some have "Two"
MultiApiJson<1, 2> s2{};
s2.val[0] = makeJson("One", 12);
s2.val[1] = makeJson("Two", 42);
BEAST_EXPECT(s2.isMember("One") == decltype(s2)::some);
BEAST_EXPECT(s2.isMember("Two") == decltype(s2)::some);
}
{
// Not all variants have element "One", because last one is null
MultiApiJson<1, 3> s3{};
s3.val[0] = makeJson("One", 12);
s3.val[1] = makeJson("One", 42);
BEAST_EXPECT(s3.isMember("One") == decltype(s3)::some);
BEAST_EXPECT(s3.isMember("Two") == decltype(s3)::none);
}
}
{
testcase("visitor");
MultiApiJson<1, 3> s1{};
s1.val[0] = makeJson("value", 2);
s1.val[1] = makeJson("value", 3);
s1.val[2] = makeJson("value", 5);
BEAST_EXPECT(not s1.valid(0));
BEAST_EXPECT(s1.index(0) == 0);
BEAST_EXPECT(s1.valid(1));
BEAST_EXPECT(s1.index(1) == 0);
BEAST_EXPECT(not s1.valid(4));
// Test different overloads
static_assert([](auto&& v) {
return requires {
v.visitor(
v,
std::integral_constant<unsigned, 1>{},
[](Json::Value&, std::integral_constant<unsigned, 1>) {});
};
}(s1));
BEAST_EXPECT(
s1.visitor(
s1,
std::integral_constant<unsigned, 1>{},
Overload{
[](Json::Value& v, std::integral_constant<unsigned, 1>) {
return v["value"].asInt();
},
[](Json::Value const&, auto) { return 0; },
[](auto, auto) { return 0; }}) == 2);
static_assert([](auto&& v) {
return requires {
v.visitor(v, std::integral_constant<unsigned, 1>{}, [](Json::Value&) {});
};
}(s1));
BEAST_EXPECT(
s1.visitor(
s1,
std::integral_constant<unsigned, 1>{},
Overload{
[](Json::Value& v) { return v["value"].asInt(); },
[](Json::Value const&) { return 0; },
[](auto...) { return 0; }}) == 2);
static_assert([](auto&& v) {
return requires {
v.visitor(
v,
std::integral_constant<unsigned, 1>{},
[](Json::Value const&, std::integral_constant<unsigned, 1>) {});
};
}(std::as_const(s1)));
BEAST_EXPECT(
s1.visitor(
std::as_const(s1),
std::integral_constant<unsigned, 2>{},
Overload{
[](Json::Value const& v, std::integral_constant<unsigned, 2>) {
return v["value"].asInt();
},
[](Json::Value&, auto) { return 0; },
[](auto, auto) { return 0; }}) == 3);
static_assert([](auto&& v) {
return requires {
v.visitor(v, std::integral_constant<unsigned, 1>{}, [](Json::Value const&) {});
};
}(std::as_const(s1)));
BEAST_EXPECT(
s1.visitor(
std::as_const(s1),
std::integral_constant<unsigned, 2>{},
Overload{
[](Json::Value const& v) { return v["value"].asInt(); },
[](Json::Value&) { return 0; },
[](auto...) { return 0; }}) == 3);
static_assert([](auto&& v) {
return requires { v.visitor(v, 1, [](Json::Value&, unsigned) {}); };
}(s1));
BEAST_EXPECT(
s1.visitor(
s1, //
3u,
Overload{
[](Json::Value& v, unsigned) { return v["value"].asInt(); },
[](Json::Value const&, unsigned) { return 0; },
[](auto, auto) { return 0; }}) == 5);
static_assert(
[](auto&& v) { return requires { v.visitor(v, 1, [](Json::Value&) {}); }; }(s1));
BEAST_EXPECT(
s1.visitor(
s1, //
3,
Overload{
[](Json::Value& v) { return v["value"].asInt(); },
[](Json::Value const&) { return 0; },
[](auto...) { return 0; }}) == 5);
static_assert([](auto&& v) {
return requires { v.visitor(v, 1, [](Json::Value const&, unsigned) {}); };
}(std::as_const(s1)));
BEAST_EXPECT(
s1.visitor(
std::as_const(s1), //
2u,
Overload{
[](Json::Value const& v, unsigned) { return v["value"].asInt(); },
[](Json::Value const&, auto) { return 0; },
[](auto, auto) { return 0; }}) == 3);
static_assert([](auto&& v) {
return requires { v.visitor(v, 1, [](Json::Value const&) {}); };
}(std::as_const(s1)));
BEAST_EXPECT(
s1.visitor(
std::as_const(s1), //
2,
Overload{
[](Json::Value const& v) { return v["value"].asInt(); },
[](Json::Value&) { return 0; },
[](auto...) { return 0; }}) == 3);
// Test type conversions
BEAST_EXPECT(
s1.visitor(
s1,
std::integral_constant<unsigned, 1>{}, // to unsigned
[](Json::Value& v, unsigned) { return v["value"].asInt(); }) == 2);
BEAST_EXPECT(
s1.visitor(
std::as_const(s1),
std::integral_constant<unsigned, 2>{}, // to unsigned
[](Json::Value const& v, unsigned) { return v["value"].asInt(); }) == 3);
BEAST_EXPECT(
s1.visitor(
s1, // to const
std::integral_constant<unsigned, 3>{},
[](Json::Value const& v, auto) { return v["value"].asInt(); }) == 5);
BEAST_EXPECT(
s1.visitor(
s1, // to const
std::integral_constant<unsigned, 3>{},
[](Json::Value const& v) { return v["value"].asInt(); }) == 5);
BEAST_EXPECT(
s1.visitor(
s1,
3, // to long
[](Json::Value& v, long) { return v["value"].asInt(); }) == 5);
BEAST_EXPECT(
s1.visitor(
std::as_const(s1),
1, // to long
[](Json::Value const& v, long) { return v["value"].asInt(); }) == 2);
BEAST_EXPECT(
s1.visitor(
s1, // to const
2,
[](Json::Value const& v, auto) { return v["value"].asInt(); }) == 3);
BEAST_EXPECT(
s1.visitor(
s1, // type deduction
2,
[](auto& v, auto) { return v["value"].asInt(); }) == 3);
BEAST_EXPECT(
s1.visitor(
s1, // to const, type deduction
2,
[](auto const& v, auto) { return v["value"].asInt(); }) == 3);
BEAST_EXPECT(
s1.visitor(
s1, // type deduction
2,
[](auto& v) { return v["value"].asInt(); }) == 3);
BEAST_EXPECT(
s1.visitor(
s1, // to const, type deduction
2,
[](auto const& v) { return v["value"].asInt(); }) == 3);
// Test passing of additional arguments
BEAST_EXPECT(
s1.visitor(
s1,
std::integral_constant<unsigned, 2>{},
[](Json::Value& v, auto ver, auto a1, auto a2) {
return ver * a1 * a2 * v["value"].asInt();
},
5,
7) == 2 * 5 * 7 * 3);
BEAST_EXPECT(
s1.visitor(
s1,
std::integral_constant<unsigned, 2>{},
[](Json::Value& v, auto ver, auto... args) {
return ver * (1 * ... * args) * v["value"].asInt();
},
5,
7) == 2 * 5 * 7 * 3);
// Several overloads we want to fail
static_assert([](auto&& v) {
return !requires {
v.visitor(
v,
1, //
[](Json::Value&, auto) {}); // missing const
};
}(std::as_const(s1)));
static_assert([](auto&& v) {
return !requires {
v.visitor(
decltype(v){}, // cannot bind rvalue
1,
[](Json::Value&, auto) {});
};
}(s1));
static_assert([](auto&& v) {
return !requires {
v.visitor(
v,
1, //
[]() {}); // missing parameter
};
}(s1));
static_assert([](auto&& v) {
return !requires {
v.visitor(
v,
1, //
[](Json::Value&, int, int) {}); // too many parameters
};
}(s1));
// Want these to be unambiguous
static_assert([](auto&& v) { return requires { v.visitor(v, 1, [](auto) {}); }; }(s1));
static_assert(
[](auto&& v) { return requires { v.visitor(v, 1, [](Json::Value&) {}); }; }(s1));
static_assert([](auto&& v) {
return requires { v.visitor(v, 1, [](Json::Value&, auto...) {}); };
}(s1));
static_assert([](auto&& v) {
return requires { v.visitor(v, 1, [](Json::Value const&) {}); };
}(s1));
static_assert([](auto&& v) {
return requires { v.visitor(v, 1, [](Json::Value const&, auto...) {}); };
}(s1));
static_assert(
[](auto&& v) { return requires { v.visitor(v, 1, [](auto...) {}); }; }(s1));
static_assert(
[](auto&& v) { return requires { v.visitor(v, 1, [](auto, auto...) {}); }; }(s1));
static_assert([](auto&& v) {
return requires { v.visitor(v, 1, [](auto, auto, auto...) {}); };
}(s1));
static_assert([](auto&& v) {
return requires { v.visitor(v, 1, [](auto, auto, auto...) {}, ""); };
}(s1));
static_assert([](auto&& v) {
return requires { v.visitor(v, 1, [](auto, auto, auto, auto...) {}, ""); };
}(s1));
}
{
testcase("visit");
MultiApiJson<1, 3> s1{};
s1.val[0] = makeJson("value", 2);
s1.val[1] = makeJson("value", 3);
s1.val[2] = makeJson("value", 5);
// Test different overloads
static_assert([](auto&& v) {
return requires {
v.visit(
std::integral_constant<unsigned, 1>{},
[](Json::Value&, std::integral_constant<unsigned, 1>) {});
};
}(s1));
BEAST_EXPECT(
s1.visit(
std::integral_constant<unsigned, 1>{},
Overload{
[](Json::Value& v, std::integral_constant<unsigned, 1>) {
return v["value"].asInt();
},
[](Json::Value const&, auto) { return 0; },
[](auto, auto) { return 0; }}) == 2);
static_assert([](auto&& v) {
return requires {
v.visit()(
std::integral_constant<unsigned, 1>{},
[](Json::Value&, std::integral_constant<unsigned, 1>) {});
};
}(s1));
BEAST_EXPECT(
s1.visit()(
std::integral_constant<unsigned, 1>{},
Overload{
[](Json::Value& v, std::integral_constant<unsigned, 1>) {
return v["value"].asInt();
},
[](Json::Value const&, auto) { return 0; },
[](auto, auto) { return 0; }}) == 2);
static_assert([](auto&& v) {
return requires {
v.visit(std::integral_constant<unsigned, 1>{}, [](Json::Value&) {});
};
}(s1));
BEAST_EXPECT(
s1.visit(
std::integral_constant<unsigned, 1>{},
Overload{
[](Json::Value& v) { return v["value"].asInt(); },
[](Json::Value const&) { return 0; },
[](auto...) { return 0; }}) == 2);
static_assert([](auto&& v) {
return requires {
v.visit()(std::integral_constant<unsigned, 1>{}, [](Json::Value&) {});
};
}(s1));
BEAST_EXPECT(
s1.visit()(
std::integral_constant<unsigned, 1>{},
Overload{
[](Json::Value& v) { return v["value"].asInt(); },
[](Json::Value const&) { return 0; },
[](auto...) { return 0; }}) == 2);
static_assert([](auto&& v) {
return requires {
v.visit(
std::integral_constant<unsigned, 1>{},
[](Json::Value const&, std::integral_constant<unsigned, 1>) {});
};
}(std::as_const(s1)));
BEAST_EXPECT(
std::as_const(s1).visit(
std::integral_constant<unsigned, 2>{},
Overload{
[](Json::Value const& v, std::integral_constant<unsigned, 2>) {
return v["value"].asInt();
},
[](Json::Value&, auto) { return 0; },
[](auto, auto) { return 0; }}) == 3);
static_assert([](auto&& v) {
return requires {
v.visit()(
std::integral_constant<unsigned, 1>{},
[](Json::Value const&, std::integral_constant<unsigned, 1>) {});
};
}(std::as_const(s1)));
BEAST_EXPECT(
std::as_const(s1).visit()(
std::integral_constant<unsigned, 2>{},
Overload{
[](Json::Value const& v, std::integral_constant<unsigned, 2>) {
return v["value"].asInt();
},
[](Json::Value&, auto) { return 0; },
[](auto, auto) { return 0; }}) == 3);
static_assert([](auto&& v) {
return requires {
v.visit(std::integral_constant<unsigned, 1>{}, [](Json::Value const&) {});
};
}(std::as_const(s1)));
BEAST_EXPECT(
std::as_const(s1).visit(
std::integral_constant<unsigned, 2>{},
Overload{
[](Json::Value const& v) { return v["value"].asInt(); },
[](Json::Value&) { return 0; },
[](auto...) { return 0; }}) == 3);
static_assert([](auto&& v) {
return requires {
v.visit()(std::integral_constant<unsigned, 1>{}, [](Json::Value const&) {});
};
}(std::as_const(s1)));
BEAST_EXPECT(
std::as_const(s1).visit()(
std::integral_constant<unsigned, 2>{},
Overload{
[](Json::Value const& v) { return v["value"].asInt(); },
[](Json::Value&) { return 0; },
[](auto...) { return 0; }}) == 3);
static_assert([](auto&& v) {
return requires { v.visit(1, [](Json::Value&, unsigned) {}); };
}(s1));
BEAST_EXPECT(
s1.visit(
3u,
Overload{
[](Json::Value& v, unsigned) { return v["value"].asInt(); },
[](Json::Value const&, unsigned) { return 0; },
[](Json::Value&, auto) { return 0; },
[](auto, auto) { return 0; }}) == 5);
static_assert([](auto&& v) {
return requires { v.visit()(1, [](Json::Value&, unsigned) {}); };
}(s1));
BEAST_EXPECT(
s1.visit()(
3u,
Overload{
[](Json::Value& v, unsigned) { return v["value"].asInt(); },
[](Json::Value const&, unsigned) { return 0; },
[](Json::Value&, auto) { return 0; },
[](auto, auto) { return 0; }}) == 5);
static_assert(
[](auto&& v) { return requires { v.visit(1, [](Json::Value&) {}); }; }(s1));
BEAST_EXPECT(
s1.visit(
3,
Overload{
[](Json::Value& v) { return v["value"].asInt(); },
[](Json::Value const&) { return 0; },
[](auto...) { return 0; }}) == 5);
static_assert(
[](auto&& v) { return requires { v.visit()(1, [](Json::Value&) {}); }; }(s1));
BEAST_EXPECT(
s1.visit()(
3,
Overload{
[](Json::Value& v) { return v["value"].asInt(); },
[](Json::Value const&) { return 0; },
[](auto...) { return 0; }}) == 5);
static_assert([](auto&& v) {
return requires { v.visit(1, [](Json::Value const&, unsigned) {}); };
}(std::as_const(s1)));
BEAST_EXPECT(
std::as_const(s1).visit(
2u,
Overload{
[](Json::Value const& v, unsigned) { return v["value"].asInt(); },
[](Json::Value const&, auto) { return 0; },
[](Json::Value&, unsigned) { return 0; },
[](auto, auto) { return 0; }}) == 3);
static_assert([](auto&& v) {
return requires { v.visit()(1, [](Json::Value const&, unsigned) {}); };
}(std::as_const(s1)));
BEAST_EXPECT(
std::as_const(s1).visit()(
2u,
Overload{
[](Json::Value const& v, unsigned) { return v["value"].asInt(); },
[](Json::Value const&, auto) { return 0; },
[](Json::Value&, unsigned) { return 0; },
[](auto, auto) { return 0; }}) == 3);
static_assert([](auto&& v) {
return requires { v.visit(1, [](Json::Value const&) {}); };
}(std::as_const(s1)));
BEAST_EXPECT(
std::as_const(s1).visit(
2,
Overload{
[](Json::Value const& v) { return v["value"].asInt(); },
[](Json::Value&) { return 0; },
[](auto...) { return 0; }}) == 3);
static_assert([](auto&& v) {
return requires { v.visit()(1, [](Json::Value const&) {}); };
}(std::as_const(s1)));
BEAST_EXPECT(
std::as_const(s1).visit()(
2,
Overload{
[](Json::Value const& v) { return v["value"].asInt(); },
[](Json::Value&) { return 0; },
[](auto...) { return 0; }}) == 3);
// Rvalue MultivarJson visitor only binds to regular reference
static_assert([](auto&& v) {
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
return !requires { std::forward<decltype(v)>(v).visit(1, [](Json::Value&&) {}); };
}(std::move(s1)));
static_assert([](auto&& v) {
return !requires {
std::forward<decltype(v)>(v).visit(1, [](Json::Value const&&) {});
};
}(std::move(s1)));
static_assert([](auto&& v) {
return requires { std::forward<decltype(v)>(v).visit(1, [](Json::Value&) {}); };
}(std::move(s1)));
static_assert([](auto&& v) {
return requires {
std::forward<decltype(v)>(v).visit(1, [](Json::Value const&) {});
};
}(std::move(s1)));
static_assert([](auto&& v) {
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
return !requires { std::forward<decltype(v)>(v).visit()(1, [](Json::Value&&) {}); };
}(std::move(s1)));
static_assert([](auto&& v) {
return !requires {
std::forward<decltype(v)>(v).visit()(1, [](Json::Value const&&) {});
};
}(std::move(s1)));
static_assert([](auto&& v) {
return requires { std::forward<decltype(v)>(v).visit()(1, [](Json::Value&) {}); };
}(std::move(s1)));
static_assert([](auto&& v) {
return requires {
std::forward<decltype(v)>(v).visit()(1, [](Json::Value const&) {});
};
}(std::move(s1)));
static_assert([](auto&& v) {
return !requires {
std::forward<decltype(v)>(v).visit(1, [](Json::Value const&&) {});
};
}(std::move(std::as_const(s1)))); // NOLINT(performance-move-const-arg)
static_assert([](auto&& v) {
return requires {
std::forward<decltype(v)>(v).visit(1, [](Json::Value const&) {});
};
}(std::move(std::as_const(s1)))); // NOLINT(performance-move-const-arg)
static_assert([](auto&& v) {
return !requires {
std::forward<decltype(v)>(v).visit()(1, [](Json::Value const&&) {});
};
}(std::move(std::as_const(s1)))); // NOLINT(performance-move-const-arg)
static_assert([](auto&& v) {
return requires {
std::forward<decltype(v)>(v).visit()(1, [](Json::Value const&) {});
};
}(std::move(std::as_const(s1)))); // NOLINT(performance-move-const-arg)
// Missing const
static_assert([](auto&& v) {
return !requires {
std::forward<decltype(v)>(v).visit(1, [](Json::Value&, auto) {});
};
}(std::as_const(s1)));
static_assert([](auto&& v) {
return !requires {
std::forward<decltype(v)>(v).visit()(1, [](Json::Value&, auto) {});
};
}(std::as_const(s1)));
// Missing parameter
static_assert([](auto&& v) {
return !requires { std::forward<decltype(v)>(v).visit(1, []() {}); };
}(s1));
static_assert([](auto&& v) {
return !requires { std::forward<decltype(v)>(v).visit()(1, []() {}); };
}(s1));
// Sanity checks
static_assert([](auto&& v) {
return requires { std::forward<decltype(v)>(v).visit(1, [](auto...) {}); };
}(std::as_const(s1)));
static_assert([](auto&& v) {
return requires { std::forward<decltype(v)>(v).visit()(1, [](auto...) {}); };
}(std::as_const(s1)));
}
}
};
BEAST_DEFINE_TESTSUITE(MultiApiJson, protocol, xrpl);
} // namespace test
} // namespace xrpl