#include #include #include #include #include #include #include namespace xrpl { namespace test { namespace { // This needs to be in a namespace because of deduction guide template struct Overload : Ts... { using Ts::operator()...; }; template Overload(Ts...) -> Overload; } // 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>); BEAST_EXPECT(subject.val.size() == 3); BEAST_EXPECT((subject.val == std::array{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::max())); int result = 1; static_assert(RPC::apiMinimumSupportedVersion + 1 <= RPC::apiMaximumValidVersion); forApiVersions( 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(v).visit(), // [](Json::Value&, auto) {}); // missing const }; }(std::as_const(s1))); static_assert([](auto&& v) { return !requires { forAllApiVersions( std::forward(v).visit(), // [](Json::Value&) {}); // missing const }; }(std::as_const(s1))); static_assert([](auto&& v) { return !requires { forAllApiVersions( std::forward(v).visit(), // []() {}); // missing parameters }; }(std::as_const(s1))); static_assert([](auto&& v) { return !requires { forAllApiVersions( std::forward(v).visit(), // [](auto) {}, 1); // missing parameters }; }(std::as_const(s1))); static_assert([](auto&& v) { return !requires { forAllApiVersions( std::forward(v).visit(), // [](auto, auto) {}, 1); // missing parameters }; }(std::as_const(s1))); static_assert([](auto&& v) { return !requires { forAllApiVersions( std::forward(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(v).visit(), // [](auto) {}); }; }(s1)); static_assert([](auto&& v) { return requires { forAllApiVersions( std::forward(v).visit(), // [](Json::Value const&) {}); }; }(std::as_const(s1))); static_assert([](auto&& v) { return requires { forAllApiVersions( std::forward(v).visit(), // [](auto...) {}); }; }(s1)); static_assert([](auto&& v) { return requires { forAllApiVersions( std::forward(v).visit(), // [](Json::Value const&, auto...) {}); }; }(std::as_const(s1))); static_assert([](auto&& v) { return requires { forAllApiVersions( std::forward(v).visit(), // [](Json::Value&, auto, auto, auto...) {}, 0, ""); }; }(s1)); static_assert([](auto&& v) { return requires { forAllApiVersions( std::forward(v).visit(), // []( Json::Value const&, std::integral_constant, int, char const*) {}, 0, ""); }; }(std::as_const(s1))); static_assert([](auto&& v) { return requires { forAllApiVersions( std::forward(v).visit(), // [](auto...) {}); }; }(std::move(s1))); static_assert([](auto&& v) { return requires { forAllApiVersions( std::forward(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{})); 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{}, [](Json::Value&, std::integral_constant) {}); }; }(s1)); BEAST_EXPECT( s1.visitor( s1, std::integral_constant{}, Overload{ [](Json::Value& v, std::integral_constant) { 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{}, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visitor( s1, std::integral_constant{}, 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{}, [](Json::Value const&, std::integral_constant) {}); }; }(std::as_const(s1))); BEAST_EXPECT( s1.visitor( std::as_const(s1), std::integral_constant{}, Overload{ [](Json::Value const& v, std::integral_constant) { 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{}, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( s1.visitor( std::as_const(s1), std::integral_constant{}, 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{}, // to unsigned [](Json::Value& v, unsigned) { return v["value"].asInt(); }) == 2); BEAST_EXPECT( s1.visitor( std::as_const(s1), std::integral_constant{}, // to unsigned [](Json::Value const& v, unsigned) { return v["value"].asInt(); }) == 3); BEAST_EXPECT( s1.visitor( s1, // to const std::integral_constant{}, [](Json::Value const& v, auto) { return v["value"].asInt(); }) == 5); BEAST_EXPECT( s1.visitor( s1, // to const std::integral_constant{}, [](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{}, [](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{}, [](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{}, [](Json::Value&, std::integral_constant) {}); }; }(s1)); BEAST_EXPECT( s1.visit( std::integral_constant{}, Overload{ [](Json::Value& v, std::integral_constant) { 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{}, [](Json::Value&, std::integral_constant) {}); }; }(s1)); BEAST_EXPECT( s1.visit()( std::integral_constant{}, Overload{ [](Json::Value& v, std::integral_constant) { 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{}, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visit( std::integral_constant{}, 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{}, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visit()( std::integral_constant{}, 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{}, [](Json::Value const&, std::integral_constant) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit( std::integral_constant{}, Overload{ [](Json::Value const& v, std::integral_constant) { 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{}, [](Json::Value const&, std::integral_constant) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit()( std::integral_constant{}, Overload{ [](Json::Value const& v, std::integral_constant) { 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{}, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit( std::integral_constant{}, 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{}, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit()( std::integral_constant{}, 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(v).visit(1, [](Json::Value&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { return !requires { std::forward(v).visit(1, [](Json::Value const&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { return requires { std::forward(v).visit(1, [](Json::Value&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { return requires { std::forward(v).visit(1, [](Json::Value const&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) return !requires { std::forward(v).visit()(1, [](Json::Value&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { return !requires { std::forward(v).visit()(1, [](Json::Value const&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { return requires { std::forward(v).visit()(1, [](Json::Value&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { return requires { std::forward(v).visit()(1, [](Json::Value const&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { return !requires { std::forward(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(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(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(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(v).visit(1, [](Json::Value&, auto) {}); }; }(std::as_const(s1))); static_assert([](auto&& v) { return !requires { std::forward(v).visit()(1, [](Json::Value&, auto) {}); }; }(std::as_const(s1))); // Missing parameter static_assert([](auto&& v) { return !requires { std::forward(v).visit(1, []() {}); }; }(s1)); static_assert([](auto&& v) { return !requires { std::forward(v).visit()(1, []() {}); }; }(s1)); // Sanity checks static_assert([](auto&& v) { return requires { std::forward(v).visit(1, [](auto...) {}); }; }(std::as_const(s1))); static_assert([](auto&& v) { return requires { std::forward(v).visit()(1, [](auto...) {}); }; }(std::as_const(s1))); } } }; BEAST_DEFINE_TESTSUITE(MultiApiJson, protocol, xrpl); } // namespace test } // namespace xrpl