rippled
MultivarJson_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/XRPLF/rippled/
4  Copyright (c) 2023 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/json/MultivarJson.h>
21 #include <ripple/rpc/impl/RPCHelpers.h>
22 
23 #include <ripple/beast/unit_test.h>
24 #include "ripple/beast/unit_test/suite.hpp"
25 #include "ripple/json/json_value.h"
26 #include <cstdint>
27 #include <limits>
28 #include <optional>
29 #include <type_traits>
30 
31 namespace ripple {
32 namespace test {
33 
34 struct MultivarJson_test : beast::unit_test::suite
35 {
36  void
37  run() override
38  {
39  constexpr static Json::StaticString string1("string1");
40  static Json::Value const str1{string1};
41 
42  static Json::Value const obj1{[]() {
44  obj1["one"] = 1;
45  return obj1;
46  }()};
47 
48  static Json::Value const jsonNull{};
49 
50  MultivarJson<3> const subject({str1, obj1});
51  static_assert(sizeof(subject) == sizeof(subject.val));
52  static_assert(subject.size == subject.val.size());
53  static_assert(
54  std::is_same_v<decltype(subject.val), std::array<Json::Value, 3>>);
55 
56  BEAST_EXPECT(subject.val.size() == 3);
57  BEAST_EXPECT(
58  (subject.val == std::array<Json::Value, 3>{str1, obj1, jsonNull}));
59  BEAST_EXPECT(
60  (MultivarJson<3>({obj1, str1}).val ==
61  std::array<Json::Value, 3>{obj1, str1, jsonNull}));
62  BEAST_EXPECT(
63  (MultivarJson<3>({jsonNull, obj1, str1}).val ==
64  std::array<Json::Value, 3>{jsonNull, obj1, str1}));
65 
66  {
67  testcase("default copy construction / assignment");
68 
69  MultivarJson<3> x{subject};
70 
71  BEAST_EXPECT(x.val.size() == subject.val.size());
72  BEAST_EXPECT(x.val[0] == subject.val[0]);
73  BEAST_EXPECT(x.val[1] == subject.val[1]);
74  BEAST_EXPECT(x.val[2] == subject.val[2]);
75  BEAST_EXPECT(x.val == subject.val);
76  BEAST_EXPECT(&x.val[0] != &subject.val[0]);
77  BEAST_EXPECT(&x.val[1] != &subject.val[1]);
78  BEAST_EXPECT(&x.val[2] != &subject.val[2]);
79 
81  BEAST_EXPECT((y.val == std::array<Json::Value, 3>{}));
82  y = subject;
83  BEAST_EXPECT(y.val == subject.val);
84  BEAST_EXPECT(&y.val[0] != &subject.val[0]);
85  BEAST_EXPECT(&y.val[1] != &subject.val[1]);
86  BEAST_EXPECT(&y.val[2] != &subject.val[2]);
87 
88  y = std::move(x);
89  BEAST_EXPECT(y.val == subject.val);
90  BEAST_EXPECT(&y.val[0] != &subject.val[0]);
91  BEAST_EXPECT(&y.val[1] != &subject.val[1]);
92  BEAST_EXPECT(&y.val[2] != &subject.val[2]);
93  }
94 
95  {
96  testcase("select");
97 
98  BEAST_EXPECT(
99  subject.select([]() -> std::size_t { return 0; }) == str1);
100  BEAST_EXPECT(
101  subject.select([]() -> std::size_t { return 1; }) == obj1);
102  BEAST_EXPECT(
103  subject.select([]() -> std::size_t { return 2; }) == jsonNull);
104 
105  // Tests of requires clause - these are expected to match
106  static_assert([](auto&& v) {
107  return requires
108  {
109  v.select([]() -> std::size_t { return 0; });
110  };
111  }(subject));
112  static_assert([](auto&& v) {
113  return requires
114  {
115  v.select([]() constexpr->std::size_t { return 0; });
116  };
117  }(subject));
118  static_assert([](auto&& v) {
119  return requires
120  {
121  v.select([]() mutable -> std::size_t { return 0; });
122  };
123  }(subject));
124 
125  // Tests of requires clause - these are expected NOT to match
126  static_assert([](auto&& a) {
127  return !requires
128  {
129  subject.select([]() -> int { return 0; });
130  };
131  }(subject));
132  static_assert([](auto&& v) {
133  return !requires
134  {
135  v.select([]() -> void {});
136  };
137  }(subject));
138  static_assert([](auto&& v) {
139  return !requires
140  {
141  v.select([]() -> bool { return false; });
142  };
143  }(subject));
144  }
145 
146  {
147  struct foo_t final
148  {
149  };
150  testcase("set");
151 
153  x.set("name1", 42);
154  BEAST_EXPECT(x.val[0].isMember("name1"));
155  BEAST_EXPECT(x.val[1].isMember("name1"));
156  BEAST_EXPECT(x.val[0]["name1"].isInt());
157  BEAST_EXPECT(x.val[1]["name1"].isInt());
158  BEAST_EXPECT(x.val[0]["name1"].asInt() == 42);
159  BEAST_EXPECT(x.val[1]["name1"].asInt() == 42);
160 
161  x.set("name2", "bar");
162  BEAST_EXPECT(x.val[0].isMember("name2"));
163  BEAST_EXPECT(x.val[1].isMember("name2"));
164  BEAST_EXPECT(x.val[0]["name2"].isString());
165  BEAST_EXPECT(x.val[1]["name2"].isString());
166  BEAST_EXPECT(x.val[0]["name2"].asString() == "bar");
167  BEAST_EXPECT(x.val[1]["name2"].asString() == "bar");
168 
169  // Tests of requires clause - these are expected to match
170  static_assert([](auto&& v) {
171  return requires
172  {
173  v.set("name", Json::nullValue);
174  };
175  }(x));
176  static_assert([](auto&& v) {
177  return requires
178  {
179  v.set("name", "value");
180  };
181  }(x));
182  static_assert([](auto&& v) {
183  return requires
184  {
185  v.set("name", true);
186  };
187  }(x));
188  static_assert([](auto&& v) {
189  return requires
190  {
191  v.set("name", 42);
192  };
193  }(x));
194 
195  // Tests of requires clause - these are expected NOT to match
196  static_assert([](auto&& v) {
197  return !requires
198  {
199  v.set("name", foo_t{});
200  };
201  }(x));
202  static_assert([](auto&& v) {
203  return !requires
204  {
205  v.set("name", std::nullopt);
206  };
207  }(x));
208  }
209 
210  {
211  testcase("isMember");
212 
213  // Well defined behaviour even if we have different types of members
214  BEAST_EXPECT(subject.isMember("foo") == decltype(subject)::none);
215 
216  auto const makeJson = [](const char* key, int val) {
218  obj1[key] = val;
219  return obj1;
220  };
221 
222  {
223  // All variants have element "One", none have element "Two"
224  MultivarJson<2> const s1{
225  {makeJson("One", 12), makeJson("One", 42)}};
226  BEAST_EXPECT(s1.isMember("One") == decltype(s1)::all);
227  BEAST_EXPECT(s1.isMember("Two") == decltype(s1)::none);
228  }
229 
230  {
231  // Some variants have element "One" and some have "Two"
232  MultivarJson<2> const s2{
233  {makeJson("One", 12), makeJson("Two", 42)}};
234  BEAST_EXPECT(s2.isMember("One") == decltype(s2)::some);
235  BEAST_EXPECT(s2.isMember("Two") == decltype(s2)::some);
236  }
237 
238  {
239  // Not all variants have element "One", because last one is null
240  MultivarJson<3> const s3{
241  {makeJson("One", 12), makeJson("One", 42), {}}};
242  BEAST_EXPECT(s3.isMember("One") == decltype(s3)::some);
243  BEAST_EXPECT(s3.isMember("Two") == decltype(s3)::none);
244  }
245  }
246 
247  {
248  // NOTE It's fine to change this test when we change API versions
249  testcase("apiVersionSelector");
250 
251  static_assert(MultiApiJson::size == 2);
252  static MultiApiJson x{{obj1, str1}};
253 
254  static_assert(
256  static_assert([](auto&& v) {
257  return requires
258  {
259  v.select(apiVersionSelector(1));
260  };
261  }(x));
262 
263  BEAST_EXPECT(x.select(apiVersionSelector(0)) == obj1);
264  BEAST_EXPECT(x.select(apiVersionSelector(2)) == str1);
265 
266  static_assert(apiVersionSelector(0)() == 0);
267  static_assert(apiVersionSelector(1)() == 0);
268  static_assert(apiVersionSelector(2)() == 1);
269  static_assert(apiVersionSelector(3)() == 1);
270  static_assert(
273  }
274 
275  {
276  // There should be no reson to change this test
277  testcase("apiVersionSelector invariants");
278 
279  static_assert(
281  static_assert(
283  == MultiApiJson::size);
284 
285  BEAST_EXPECT(MultiApiJson::size >= 1);
286  }
287  }
288 };
289 
291 
292 } // namespace test
293 } // namespace ripple
std::is_same_v
T is_same_v
ripple::MultivarJson::size
constexpr static std::size_t size
Definition: MultivarJson.h:35
ripple::MultivarJson::val
std::array< Json::Value, Size > val
Definition: MultivarJson.h:34
ripple::TxSearched::all
@ all
ripple::RPC::apiBetaVersion
constexpr unsigned int apiBetaVersion
Definition: RPCHelpers.h:239
ripple::test::MultivarJson_test::run
void run() override
Definition: MultivarJson_test.cpp:37
ripple::requires
requires(T::ConsequencesFactory==Transactor::Normal) TxConsequences consequences_helper(PreflightContext const &ctx)
Definition: applySteps.cpp:181
ripple::test::MultivarJson_test
Definition: MultivarJson_test.cpp:34
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
std::array
STL class.
cstdint
ripple::apiVersionSelector
constexpr auto apiVersionSelector(unsigned int apiVersion) noexcept
Definition: MultivarJson.h:100
ripple::RPC::apiMinimumSupportedVersion
constexpr unsigned int apiMinimumSupportedVersion
Definition: RPCHelpers.h:236
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
limits
Json::StaticString
Lightweight wrapper to tag static string.
Definition: json_value.h:60
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
optional
std::size_t
ripple::MultivarJson
Definition: MultivarJson.h:32
std::numeric_limits
type_traits
ripple::TxSearched::some
@ some
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)