The open source OpenXR runtime
1// Copyright 2021, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief JSON C++ wrapper tests.
6 * @author Mateo de Mayo <mateo.demayo@collabora.com>
7 */
8
9
10#include "catch_amalgamated.hpp"
11#include "util/u_json.hpp"
12#include <string>
13
14using std::string;
15using xrt::auxiliary::util::json::JSONBuilder;
16using xrt::auxiliary::util::json::JSONNode;
17
18TEST_CASE("u_json")
19{
20 // This is the json data we will be dealing with
21 // {
22 // "alpha": [1, true, 3.14, {"beta" : 4, "gamma" : 5}, {"delta" : 6}, [{"epsilon": [7], "zeta": false}]],
23 // "eta": "theta",
24 // "iota": {"kappa": [{"lambda": [5.5, [4.4, 3.3], {}, 2.2, 1, 0, {}, [-1], -2.2, -3.3, -4.4, -5.5]}]},
25 // "mu" : true,
26 // "nu" : false,
27 // "xi": 42,
28 // "omicron": [],
29 // "pi": 3.141592,
30 // "rho": [{"sigma": [{ "tau": [{"upsilon": [[[]]]}]}]}]
31 // }
32
33 JSONBuilder jb{};
34 jb << "{";
35 jb << "alpha"
36 << "[" << 1 << true << 3.14 << "{"
37 << "beta" << 4 << "gamma" << 5 << "}"
38 << "{"
39 << "delta" << 6 << "}"
40 << "["
41 << "{"
42 << "epsilon"
43 << "[" << 7 << "]"
44 << "zeta" << false << "}"
45 << "]"
46 << "]";
47 jb << "eta"
48 << "theta";
49 jb << "iota"
50 << "{"
51 << "kappa"
52 << "["
53 << "{"
54 << "lambda"
55 << "[" << 5.5 << "[" << 4.4 << 3.3 << "]"
56 << "{"
57 << "}" << 2.2 << 1 << 0 << "{"
58 << "}"
59 << "[" << -1 << "]" << -2.2 << -3.3 << -4.4 << -5.5 << "]"
60 << "}"
61 << "]"
62 << "}";
63 jb << "mu" << true;
64 jb << "nu" << false;
65 jb << "xi" << 42;
66 jb << "omicron"
67 << "["
68 << "]";
69 jb << "pi" << 3.141592;
70 jb << "rho"
71 << "["
72 << "{"
73 << "sigma"
74 << "["
75 << "{"
76 << "tau"
77 << "["
78 << "{"
79 << "upsilon"
80 << "["
81 << "["
82 << "["
83 << "]"
84 << "]"
85 << "]"
86 << "}"
87 << "]"
88 << "}"
89 << "]"
90 << "}"
91 << "]";
92 jb << "}";
93
94 JSONNode json_node = *jb.getBuiltNode();
95
96 SECTION("JSONBuilder builds as expected")
97 {
98 string raw_json =
99 "{"
100 "\"alpha\": [1, true, 3.14, {\"beta\" : 4, \"gamma\" : 5}, {\"delta\" : 6}, [{\"epsilon\": [7], "
101 "\"zeta\": "
102 "false}]],"
103 "\"eta\": \"theta\","
104 "\"iota\": {\"kappa\": [{\"lambda\": [5.5, [4.4, 3.3], {}, 2.2, 1, 0, {}, [-1], -2.2, -3.3, -4.4, "
105 "-5.5]}]},"
106 "\"mu\" : true,"
107 "\"nu\" : false,"
108 "\"xi\": 42,"
109 "\"omicron\": [],"
110 "\"pi\": 3.141592,"
111 "\"rho\": [{\"sigma\": [{ \"tau\": [{\"upsilon\": [[[]]]}]}]}]"
112 "}";
113 JSONNode node_from_string{raw_json};
114 INFO("json_node=" << json_node.toString(false));
115 INFO("node_from_string=" << node_from_string.toString(false));
116 CHECK(json_node.toString(false) == node_from_string.toString(false));
117 }
118
119 SECTION("Complex JSON is preserved through save and load")
120 {
121 JSONNode loaded{jb.getBuiltNode()->toString(false)};
122 INFO("json_node=" << json_node.toString(false));
123 INFO("loaded=" << loaded.toString(false));
124 CHECK(json_node.toString(false) == loaded.toString(false));
125 }
126
127 SECTION("Read methods work")
128 {
129 CHECK(json_node["eta"].asString() == "theta");
130 CHECK(json_node["eta"].asDouble(3.14) == 3.14);
131 CHECK(json_node["mu"].asBool(false) == true);
132 CHECK(json_node["alpha"][0].canBool());
133 CHECK(json_node["alpha"][0].asBool(false) == true);
134 CHECK(json_node["alpha"][4]["delta"].asInt(-1) == 6);
135 CHECK(json_node["alpha"][4]["delta"].asDouble(-1) == 6.0);
136 CHECK(json_node["rho"][0]["sigma"][0]["tau"][0]["upsilon"].asArray().size() == 1);
137 CHECK(json_node["alpha"][3].asObject()["gamma"].asInt() == 5);
138 CHECK(json_node["iota"].hasKey("kappa"));
139 }
140
141 SECTION("Can make a double")
142 {
143 JSONNode stringToDouble("0.5");
144
145 constexpr float e = std::numeric_limits<float>::epsilon();
146
147 CHECK(stringToDouble.isDouble());
148 CHECK(stringToDouble.asDouble() == Catch::Approx(0.5).margin(e));
149 }
150
151 SECTION("Copy construction duplicates the JSON")
152 {
153 JSONNode copy{json_node};
154 CHECK(copy.getCJSON() != json_node.getCJSON());
155 CHECK(copy.toString(false) == json_node.toString(false));
156 }
157
158 SECTION("Copy assignment duplicates the JSON")
159 {
160 JSONNode copy;
161 copy = json_node;
162 CHECK(copy.getCJSON() != json_node.getCJSON());
163 CHECK(copy.toString(false) == json_node.toString(false));
164 }
165
166 SECTION("Move construction doesn't duplicate the JSON")
167 {
168 JSONNode temp{json_node};
169 const auto cjson = temp.getCJSON();
170 JSONNode moved{std::move(temp)};
171 CHECK(moved.getCJSON() == cjson);
172 CHECK(moved.toString(false) == json_node.toString(false));
173 }
174
175 SECTION("Move assignment doesn't duplicate the JSON")
176 {
177 JSONNode temp{json_node};
178 const auto cjson = temp.getCJSON();
179 JSONNode moved;
180 moved = std::move(temp);
181 CHECK(moved.getCJSON() == cjson);
182 CHECK(moved.toString(false) == json_node.toString(false));
183 }
184}