mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-04 09:16:47 +00:00
added few more tests and doc
This commit is contained in:
171
src/doctest/MIGRATION.md
Normal file
171
src/doctest/MIGRATION.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Doctest Migration Documentation
|
||||
|
||||
This document describes the migration of unit tests from the beast `unit_test` framework to the doctest framework.
|
||||
|
||||
## Overview
|
||||
|
||||
Tests were migrated from `src/test/` (beast unit_test format) to `src/doctest/` (doctest format), following the pattern established in `src/tests/libxrpl/`.
|
||||
|
||||
## Build Configuration
|
||||
|
||||
### CMakeLists.txt Structure
|
||||
|
||||
Created `src/doctest/CMakeLists.txt` with:
|
||||
- Helper function `xrpl_add_doctest(name)` that creates per-module executables
|
||||
- Compiler flags: `-m64 -g -std=c++20 -fPIE -Wno-unknown-warning-option -Wall -Wdeprecated -Wno-deprecated-declarations -Wextra -Wno-unused-parameter -Werror -fstack-protector -Wno-sign-compare -Wno-unused-but-set-variable -MD -MT -MF`
|
||||
- Six module targets: `xrpl.doctest.basics`, `xrpl.doctest.beast`, `xrpl.doctest.core`, `xrpl.doctest.csf`, `xrpl.doctest.nodestore`, `xrpl.doctest.protocol`
|
||||
|
||||
### Module Structure
|
||||
|
||||
Each module has its own `main.cpp` following the pre-migrated test pattern:
|
||||
```
|
||||
src/doctest/
|
||||
├── basics/main.cpp
|
||||
├── beast/main.cpp
|
||||
├── core/main.cpp
|
||||
├── csf/main.cpp
|
||||
├── nodestore/main.cpp
|
||||
└── protocol/main.cpp
|
||||
```
|
||||
|
||||
## Framework Conversion Patterns
|
||||
|
||||
| Beast Unit Test | Doctest Equivalent |
|
||||
|-----------------|-------------------|
|
||||
| `#include <xrpl/beast/unit_test.h>` | `#include <doctest/doctest.h>` |
|
||||
| `BEAST_EXPECT(expr)` | `CHECK(expr)` |
|
||||
| `BEAST_EXPECTS(expr, msg)` | `CHECK_MESSAGE(expr, msg)` |
|
||||
| `testcase("name")` | `SUBCASE("name")` |
|
||||
| `class X : public unit_test::suite { ... }` | Free functions with `TEST_CASE` |
|
||||
| `BEAST_DEFINE_TESTSUITE(Name, Module, Lib)` | `TEST_CASE("Name")` |
|
||||
| `pass()` / `fail()` | `CHECK(true)` / `CHECK(false)` |
|
||||
|
||||
## Namespace Changes
|
||||
|
||||
- Changed from `namespace ripple` to `namespace xrpl` where applicable
|
||||
- Header paths changed from `xrpld/` to `xrpl/` (e.g., `xrpld/app/` → `xrpl/protocol/`)
|
||||
|
||||
## Common Migration Issues and Solutions
|
||||
|
||||
### 1. CHECK Macro with Complex Expressions
|
||||
|
||||
**Problem**: Doctest's CHECK macro doesn't support `&&` or `||` in expressions.
|
||||
|
||||
```cpp
|
||||
// Doesn't work
|
||||
CHECK(a && b);
|
||||
|
||||
// Solution: Split into separate checks
|
||||
CHECK(a);
|
||||
CHECK(b);
|
||||
```
|
||||
|
||||
### 2. CHECK Macro with Custom Iterator Comparisons
|
||||
|
||||
**Problem**: CHECK wraps expressions in `Expression_lhs<>` which breaks template argument deduction for custom comparison operators (especially boost::intrusive iterators).
|
||||
|
||||
```cpp
|
||||
// Doesn't compile
|
||||
CHECK(iter != container.end());
|
||||
|
||||
// Solution: Store result in bool first
|
||||
bool notEnd = (iter != container.end());
|
||||
CHECK(notEnd);
|
||||
```
|
||||
|
||||
### 3. Constructor Argument Order
|
||||
|
||||
Some container constructors have different argument order than initially assumed:
|
||||
|
||||
```cpp
|
||||
// Wrong order
|
||||
Container c(clock, first, last);
|
||||
|
||||
// Correct order (iterators before clock)
|
||||
Container c(first, last, clock);
|
||||
```
|
||||
|
||||
### 4. Return Type Differences
|
||||
|
||||
For map types with `P&&` insert overloads, return types differ:
|
||||
|
||||
```cpp
|
||||
// Use if constexpr to handle both cases
|
||||
if constexpr (!IsMulti && IsMap)
|
||||
{
|
||||
auto result = c.insert(c.end(), value); // returns pair<iterator, bool>
|
||||
CHECK(result.first != c.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = c.insert(c.end(), value); // returns iterator
|
||||
CHECK(it != c.end());
|
||||
}
|
||||
```
|
||||
|
||||
## Files Migrated
|
||||
|
||||
### basics/ (13 files)
|
||||
- Buffer.cpp, Expected.cpp, IOUAmount.cpp, KeyCache.cpp, Number.cpp
|
||||
- StringUtilities.cpp, TaggedCache.cpp, Units.cpp, XRPAmount.cpp
|
||||
- base58.cpp, base_uint.cpp, hardened_hash.cpp, join.cpp
|
||||
|
||||
### beast/ (11 files)
|
||||
- CurrentThreadName.cpp, IPEndpoint.cpp, Journal.cpp, LexicalCast.cpp
|
||||
- PropertyStream.cpp, SemanticVersion.cpp, aged_associative_container.cpp
|
||||
- basic_seconds_clock.cpp, beast_Zero.cpp, xxhasher.cpp
|
||||
|
||||
### core/ (1 file)
|
||||
- Workers.cpp
|
||||
|
||||
### csf/ (4 files)
|
||||
- BasicNetwork.cpp, Digraph.cpp, Histogram.cpp, Scheduler.cpp
|
||||
|
||||
### nodestore/ (1 file)
|
||||
- varint.cpp
|
||||
|
||||
### protocol/ (14 files)
|
||||
- ApiVersion.cpp, BuildInfo.cpp, Issue.cpp, MultiApiJson.cpp
|
||||
- PublicKey.cpp, Quality.cpp, STAccount.cpp, STInteger.cpp
|
||||
- STNumber.cpp, SecretKey.cpp, Seed.cpp, SeqProxy.cpp
|
||||
- Serializer.cpp, TER.cpp
|
||||
|
||||
## Test Results Summary
|
||||
|
||||
| Module | Test Cases | Assertions |
|
||||
|--------|------------|------------|
|
||||
| basics | 61 | 2,638,582 |
|
||||
| beast | 48 | 162,715 |
|
||||
| core | 6 | 66 |
|
||||
| csf | 8 | 101 |
|
||||
| nodestore | 1 | 68 |
|
||||
| protocol | 73 | 20,372 |
|
||||
| **Total** | **197** | **2,821,904** |
|
||||
|
||||
## Running Tests
|
||||
|
||||
```bash
|
||||
# Build all doctest targets
|
||||
cd .build
|
||||
cmake --build . --target xrpl.doctests
|
||||
|
||||
# Run individual module
|
||||
./src/doctest/xrpl.doctest.basics
|
||||
./src/doctest/xrpl.doctest.beast
|
||||
./src/doctest/xrpl.doctest.core
|
||||
./src/doctest/xrpl.doctest.csf
|
||||
./src/doctest/xrpl.doctest.nodestore
|
||||
./src/doctest/xrpl.doctest.protocol
|
||||
|
||||
# Run all tests
|
||||
for test in src/doctest/xrpl.doctest.*; do ./$test; done
|
||||
```
|
||||
|
||||
## Tests Not Migrated
|
||||
|
||||
Some tests were not migrated due to dependencies:
|
||||
- **Manual tests** requiring user interaction (e.g., `DetectCrash_test`)
|
||||
- **Tests using xrpld infrastructure** (`test/jtx.h`, `unit_test/SuiteJournal.h`)
|
||||
- **Complex async tests** using boost coroutines
|
||||
- **Tests with FileDirGuard** or other test-specific utilities
|
||||
|
||||
1168
src/doctest/beast/aged_associative_container.cpp
Normal file
1168
src/doctest/beast/aged_associative_container.cpp
Normal file
File diff suppressed because it is too large
Load Diff
989
src/doctest/protocol/MultiApiJson.cpp
Normal file
989
src/doctest/protocol/MultiApiJson.cpp
Normal file
@@ -0,0 +1,989 @@
|
||||
#include <xrpl/protocol/MultiApiJson.h>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
using namespace xrpl;
|
||||
|
||||
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...>;
|
||||
|
||||
auto
|
||||
makeJson(char const* key, int val)
|
||||
{
|
||||
Json::Value obj1(Json::objectValue);
|
||||
obj1[key] = val;
|
||||
return obj1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_SUITE_BEGIN("MultiApiJson");
|
||||
|
||||
TEST_CASE("forApiVersions, forAllApiVersions")
|
||||
{
|
||||
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>>);
|
||||
|
||||
CHECK(subject.val.size() == 3);
|
||||
CHECK(
|
||||
(subject.val ==
|
||||
std::array<Json::Value, 3>{jsonNull, jsonNull, jsonNull}));
|
||||
|
||||
subject.val[0] = obj1;
|
||||
subject.val[1] = obj2;
|
||||
|
||||
// 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;
|
||||
CHECK(index == s1.index(i));
|
||||
CHECK(s1.valid(i));
|
||||
s1.val[index] = makeJson("value", primes[i]);
|
||||
productAllVersions *= primes[i];
|
||||
}
|
||||
CHECK(!s1.valid(0));
|
||||
CHECK(!s1.valid(RPC::apiMaximumValidVersion + 1));
|
||||
CHECK(!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(),
|
||||
[](Json::Value const& json, unsigned int version, int* result) {
|
||||
CHECK(version >= RPC::apiMinimumSupportedVersion);
|
||||
CHECK(version <= RPC::apiMinimumSupportedVersion + 1);
|
||||
if (json.isMember("value"))
|
||||
{
|
||||
*result *= json["value"].asInt();
|
||||
}
|
||||
},
|
||||
&result);
|
||||
CHECK(
|
||||
result ==
|
||||
primes[RPC::apiMinimumSupportedVersion] *
|
||||
primes[RPC::apiMinimumSupportedVersion + 1]);
|
||||
|
||||
// Check all the values with mutable data
|
||||
forAllApiVersions(s1.visit(), [&s1](Json::Value& json, auto version) {
|
||||
CHECK(s1.val[s1.index(version)] == json);
|
||||
if (json.isMember("value"))
|
||||
{
|
||||
CHECK(json["value"].asInt() == primes[version]);
|
||||
}
|
||||
});
|
||||
|
||||
result = 1;
|
||||
forAllApiVersions(
|
||||
std::as_const(s1).visit(),
|
||||
[](Json::Value const& json, unsigned int version, int* result) {
|
||||
CHECK(version >= RPC::apiMinimumSupportedVersion);
|
||||
CHECK(version <= RPC::apiMaximumValidVersion);
|
||||
if (json.isMember("value"))
|
||||
{
|
||||
*result *= json["value"].asInt();
|
||||
}
|
||||
},
|
||||
&result);
|
||||
|
||||
CHECK(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))));
|
||||
}
|
||||
|
||||
TEST_CASE("default copy construction / assignment")
|
||||
{
|
||||
using xrpl::detail::MultiApiJson;
|
||||
|
||||
Json::Value const obj1 = makeJson("value", 1);
|
||||
Json::Value const obj2 = makeJson("value", 2);
|
||||
Json::Value const jsonNull{};
|
||||
|
||||
MultiApiJson<1, 3> subject{};
|
||||
subject.val[0] = obj1;
|
||||
subject.val[1] = obj2;
|
||||
|
||||
MultiApiJson<1, 3> x{subject};
|
||||
|
||||
CHECK(x.val.size() == subject.val.size());
|
||||
CHECK(x.val[0] == subject.val[0]);
|
||||
CHECK(x.val[1] == subject.val[1]);
|
||||
CHECK(x.val[2] == subject.val[2]);
|
||||
CHECK(x.val == subject.val);
|
||||
CHECK(&x.val[0] != &subject.val[0]);
|
||||
CHECK(&x.val[1] != &subject.val[1]);
|
||||
CHECK(&x.val[2] != &subject.val[2]);
|
||||
|
||||
MultiApiJson<1, 3> y;
|
||||
CHECK((y.val == std::array<Json::Value, 3>{}));
|
||||
y = subject;
|
||||
CHECK(y.val == subject.val);
|
||||
CHECK(&y.val[0] != &subject.val[0]);
|
||||
CHECK(&y.val[1] != &subject.val[1]);
|
||||
CHECK(&y.val[2] != &subject.val[2]);
|
||||
|
||||
y = std::move(x);
|
||||
CHECK(y.val == subject.val);
|
||||
CHECK(&y.val[0] != &subject.val[0]);
|
||||
CHECK(&y.val[1] != &subject.val[1]);
|
||||
CHECK(&y.val[2] != &subject.val[2]);
|
||||
}
|
||||
|
||||
TEST_CASE("set")
|
||||
{
|
||||
using xrpl::detail::MultiApiJson;
|
||||
|
||||
auto x = MultiApiJson<1, 2>{Json::objectValue};
|
||||
x.set("name1", 42);
|
||||
CHECK(x.val[0].isMember("name1"));
|
||||
CHECK(x.val[1].isMember("name1"));
|
||||
CHECK(x.val[0]["name1"].isInt());
|
||||
CHECK(x.val[1]["name1"].isInt());
|
||||
CHECK(x.val[0]["name1"].asInt() == 42);
|
||||
CHECK(x.val[1]["name1"].asInt() == 42);
|
||||
|
||||
x.set("name2", "bar");
|
||||
CHECK(x.val[0].isMember("name2"));
|
||||
CHECK(x.val[1].isMember("name2"));
|
||||
CHECK(x.val[0]["name2"].isString());
|
||||
CHECK(x.val[1]["name2"].isString());
|
||||
CHECK(x.val[0]["name2"].asString() == "bar");
|
||||
CHECK(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));
|
||||
}
|
||||
|
||||
TEST_CASE("isMember")
|
||||
{
|
||||
using xrpl::detail::MultiApiJson;
|
||||
|
||||
Json::Value const obj1 = makeJson("value", 1);
|
||||
Json::Value const obj2 = makeJson("value", 2);
|
||||
|
||||
MultiApiJson<1, 3> subject{};
|
||||
subject.val[0] = obj1;
|
||||
subject.val[1] = obj2;
|
||||
|
||||
// Well defined behaviour even if we have different types of members
|
||||
CHECK(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);
|
||||
CHECK(s1.isMember("One") == decltype(s1)::all);
|
||||
CHECK(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);
|
||||
CHECK(s2.isMember("One") == decltype(s2)::some);
|
||||
CHECK(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);
|
||||
CHECK(s3.isMember("One") == decltype(s3)::some);
|
||||
CHECK(s3.isMember("Two") == decltype(s3)::none);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("visitor")
|
||||
{
|
||||
using xrpl::detail::MultiApiJson;
|
||||
|
||||
MultiApiJson<1, 3> s1{};
|
||||
s1.val[0] = makeJson("value", 2);
|
||||
s1.val[1] = makeJson("value", 3);
|
||||
s1.val[2] = makeJson("value", 5);
|
||||
|
||||
CHECK(not s1.valid(0));
|
||||
CHECK(s1.index(0) == 0);
|
||||
|
||||
CHECK(s1.valid(1));
|
||||
CHECK(s1.index(1) == 0);
|
||||
|
||||
CHECK(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));
|
||||
CHECK(
|
||||
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));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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));
|
||||
CHECK(
|
||||
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));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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
|
||||
CHECK(
|
||||
s1.visitor(
|
||||
s1,
|
||||
std::integral_constant<unsigned, 1>{}, // to unsigned
|
||||
[](Json::Value& v, unsigned) { return v["value"].asInt(); }) == 2);
|
||||
CHECK(
|
||||
s1.visitor(
|
||||
std::as_const(s1),
|
||||
std::integral_constant<unsigned, 2>{}, // to unsigned
|
||||
[](Json::Value const& v, unsigned) {
|
||||
return v["value"].asInt();
|
||||
}) == 3);
|
||||
CHECK(
|
||||
s1.visitor(
|
||||
s1, // to const
|
||||
std::integral_constant<unsigned, 3>{},
|
||||
[](Json::Value const& v, auto) { return v["value"].asInt(); }) ==
|
||||
5);
|
||||
CHECK(
|
||||
s1.visitor(
|
||||
s1, // to const
|
||||
std::integral_constant<unsigned, 3>{},
|
||||
[](Json::Value const& v) { return v["value"].asInt(); }) == 5);
|
||||
CHECK(
|
||||
s1.visitor(
|
||||
s1,
|
||||
3, // to long
|
||||
[](Json::Value& v, long) { return v["value"].asInt(); }) == 5);
|
||||
CHECK(
|
||||
s1.visitor(
|
||||
std::as_const(s1),
|
||||
1, // to long
|
||||
[](Json::Value const& v, long) { return v["value"].asInt(); }) ==
|
||||
2);
|
||||
CHECK(
|
||||
s1.visitor(
|
||||
s1, // to const
|
||||
2,
|
||||
[](Json::Value const& v, auto) { return v["value"].asInt(); }) ==
|
||||
3);
|
||||
CHECK(
|
||||
s1.visitor(
|
||||
s1, // type deduction
|
||||
2,
|
||||
[](auto& v, auto) { return v["value"].asInt(); }) == 3);
|
||||
CHECK(
|
||||
s1.visitor(
|
||||
s1, // to const, type deduction
|
||||
2,
|
||||
[](auto const& v, auto) { return v["value"].asInt(); }) == 3);
|
||||
CHECK(
|
||||
s1.visitor(
|
||||
s1, // type deduction
|
||||
2,
|
||||
[](auto& v) { return v["value"].asInt(); }) == 3);
|
||||
CHECK(
|
||||
s1.visitor(
|
||||
s1, // to const, type deduction
|
||||
2,
|
||||
[](auto const& v) { return v["value"].asInt(); }) == 3);
|
||||
|
||||
// Test passing of additional arguments
|
||||
CHECK(
|
||||
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);
|
||||
CHECK(
|
||||
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(
|
||||
std::move(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));
|
||||
}
|
||||
|
||||
TEST_CASE("visit")
|
||||
{
|
||||
using xrpl::detail::MultiApiJson;
|
||||
|
||||
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));
|
||||
CHECK(
|
||||
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));
|
||||
CHECK(
|
||||
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));
|
||||
CHECK(
|
||||
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));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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));
|
||||
CHECK(
|
||||
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));
|
||||
CHECK(
|
||||
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));
|
||||
CHECK(
|
||||
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));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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)));
|
||||
CHECK(
|
||||
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) {
|
||||
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&&) {});
|
||||
};
|
||||
}(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))));
|
||||
static_assert([](auto&& v) {
|
||||
return requires {
|
||||
std::forward<decltype(v)>(v).visit(1, [](Json::Value const&) {});
|
||||
};
|
||||
}(std::move(std::as_const(s1))));
|
||||
static_assert([](auto&& v) {
|
||||
return !requires {
|
||||
std::forward<decltype(v)>(v).visit()(1, [](Json::Value const&&) {});
|
||||
};
|
||||
}(std::move(std::as_const(s1))));
|
||||
static_assert([](auto&& v) {
|
||||
return requires {
|
||||
std::forward<decltype(v)>(v).visit()(1, [](Json::Value const&) {});
|
||||
};
|
||||
}(std::move(std::as_const(s1))));
|
||||
|
||||
// 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)));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
@@ -158,3 +158,100 @@ testSigning(KeyType type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("secp256k1: signing & verification")
|
||||
{
|
||||
testSigning(KeyType::secp256k1);
|
||||
}
|
||||
|
||||
TEST_CASE("ed25519: signing & verification")
|
||||
{
|
||||
testSigning(KeyType::ed25519);
|
||||
}
|
||||
|
||||
TEST_CASE("secp256k1: key derivation")
|
||||
{
|
||||
// clang-format off
|
||||
static TestKeyData const secp256k1TestVectors[] = {
|
||||
{{0xDE,0xDC,0xE9,0xCE,0x67,0xB4,0x51,0xD8,0x52,0xFD,0x4E,0x84,0x6F,0xCD,0xE3,0x1C},
|
||||
{0x03,0x30,0xE7,0xFC,0x9D,0x56,0xBB,0x25,0xD6,0x89,0x3B,0xA3,0xF3,0x17,0xAE,0x5B,
|
||||
0xCF,0x33,0xB3,0x29,0x1B,0xD6,0x3D,0xB3,0x26,0x54,0xA3,0x13,0x22,0x2F,0x7F,0xD0,0x20},
|
||||
{0x1A,0xCA,0xAE,0xDE,0xCE,0x40,0x5B,0x2A,0x95,0x82,0x12,0x62,0x9E,0x16,0xF2,0xEB,
|
||||
0x46,0xB1,0x53,0xEE,0xE9,0x4C,0xDD,0x35,0x0F,0xDE,0xFF,0x52,0x79,0x55,0x25,0xB7},
|
||||
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"},
|
||||
{{0xF7,0x5C,0x48,0xFE,0xC4,0x6D,0x4D,0x64,0x92,0x8B,0x79,0x5F,0x3F,0xBA,0xBB,0xA0},
|
||||
{0x03,0xAF,0x53,0xE8,0x01,0x1E,0x85,0xB3,0x66,0x64,0xF1,0x71,0x08,0x90,0x50,0x1C,
|
||||
0x3E,0x86,0xFC,0x2C,0x66,0x58,0xC2,0xEE,0x83,0xCA,0x58,0x0D,0xC9,0x97,0x25,0x41,0xB1},
|
||||
{0x5B,0x8A,0xB0,0xE7,0xCD,0xAF,0x48,0x87,0x4D,0x5D,0x99,0x34,0xBF,0x3E,0x7B,0x2C,
|
||||
0xB0,0x6B,0xC4,0xC7,0xEA,0xAA,0xF7,0x62,0x68,0x2E,0xD8,0xD0,0xA3,0x1E,0x3C,0x70},
|
||||
"r9ZERztesFu3ZBs7zsWTeCvBg14GQ9zWF7"}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
for (auto const& v : secp256k1TestVectors)
|
||||
{
|
||||
auto const id = parseBase58<AccountID>(v.addr);
|
||||
CHECK(id);
|
||||
|
||||
auto kp = generateKeyPair(KeyType::secp256k1, Seed{makeSlice(v.seed)});
|
||||
|
||||
CHECK(kp.first == PublicKey{makeSlice(v.pubkey)});
|
||||
CHECK(kp.second == SecretKey{makeSlice(v.seckey)});
|
||||
CHECK(calcAccountID(kp.first) == *id);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("ed25519: key derivation")
|
||||
{
|
||||
// clang-format off
|
||||
static TestKeyData const ed25519TestVectors[] = {
|
||||
{{0xAF,0x41,0xFF,0x66,0xF7,0x5E,0xBD,0x3A,0x6B,0x18,0xFB,0x7A,0x1D,0xF6,0x1C,0x97},
|
||||
{0xED,0x48,0xCB,0xBB,0xE0,0xEE,0x7B,0x86,0x86,0xA7,0xDE,0x9F,0x0A,0x01,0x59,0x73,
|
||||
0x4E,0x65,0xF9,0xC3,0x69,0x94,0x7F,0x2E,0x26,0x96,0x23,0x2B,0x46,0x1E,0x55,0x32,0x13},
|
||||
{0x1A,0x10,0x97,0xFC,0xD9,0xCE,0x4E,0x1D,0xA2,0x46,0x66,0xB6,0x98,0x87,0x97,0x66,
|
||||
0xE1,0x75,0x75,0x47,0xD1,0xD4,0xE3,0x64,0xB6,0x43,0x55,0xF7,0xC8,0x4B,0xA0,0xF3},
|
||||
"rVAEQBhWT6nZ4woEifdN3TMMdUZaxeXnR"},
|
||||
{{0x14,0x0C,0x1D,0x08,0x13,0x19,0x33,0x9C,0x79,0x9D,0xC6,0xA1,0x65,0x95,0x1B,0xE1},
|
||||
{0xED,0x3B,0xC8,0x2E,0xF4,0x5F,0x89,0x09,0xCC,0x00,0xF8,0xB7,0xAA,0xF0,0x59,0x31,
|
||||
0x68,0x14,0x11,0x75,0x8C,0x11,0x71,0x24,0x87,0x50,0x66,0xC2,0x83,0x98,0xFE,0x15,0x6D},
|
||||
{0xFE,0x3E,0x5A,0x82,0xB8,0x0D,0xD8,0x2E,0x91,0x5F,0x76,0x38,0x94,0x2A,0x33,0x2C,
|
||||
0xE3,0x06,0x88,0x79,0x74,0x0C,0x7E,0x90,0xE2,0x20,0xA4,0xFB,0x0B,0x37,0xCE,0xC8},
|
||||
"rK57dJ9533WtoY8NNwVWGY7ffuAc8WCcPE"}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
for (auto const& v : ed25519TestVectors)
|
||||
{
|
||||
auto const id = parseBase58<AccountID>(v.addr);
|
||||
CHECK(id);
|
||||
|
||||
auto kp = generateKeyPair(KeyType::ed25519, Seed{makeSlice(v.seed)});
|
||||
|
||||
CHECK(kp.first == PublicKey{makeSlice(v.pubkey)});
|
||||
CHECK(kp.second == SecretKey{makeSlice(v.seckey)});
|
||||
CHECK(calcAccountID(kp.first) == *id);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("secp256k1: cross-type key mismatch")
|
||||
{
|
||||
auto const [pk1, sk1] = randomKeyPair(KeyType::secp256k1);
|
||||
auto const [pk2, sk2] = randomKeyPair(KeyType::secp256k1);
|
||||
|
||||
CHECK(pk1 != pk2);
|
||||
CHECK(sk1 != sk2);
|
||||
|
||||
auto const [pk3, sk3] = randomKeyPair(KeyType::ed25519);
|
||||
auto const [pk4, sk4] = randomKeyPair(KeyType::ed25519);
|
||||
|
||||
CHECK(pk3 != pk4);
|
||||
CHECK(sk3 != sk4);
|
||||
|
||||
// Cross-type comparisons
|
||||
CHECK(pk1 != pk3);
|
||||
CHECK(pk2 != pk4);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
Reference in New Issue
Block a user