1 /*
2 __ _____ _____ _____
3 __| | __| | | | JSON for Modern C++ (test suite)
4 | | |__ | | | | | | version 3.9.1
5 |_____|_____|_____|_|___| https://github.com/nlohmann/json
6
7 Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8 SPDX-License-Identifier: MIT
9 Copyright (c) 2018 Vitaliy Manushkin <agri@akamo.info>.
10
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 SOFTWARE.
28 */
29
30 #include "doctest_compatibility.h"
31
32 #include <nlohmann/json.hpp>
33
34 #include <string>
35 #include <utility>
36
37
38 /* forward declarations */
39 class alt_string;
40 bool operator<(const char* op1, const alt_string& op2);
41 void int_to_string(alt_string& target, std::size_t value);
42
43 /*
44 * This is virtually a string class.
45 * It covers std::string under the hood.
46 */
47 class alt_string
48 {
49 public:
50 using value_type = std::string::value_type;
51
alt_string(const char * str)52 alt_string(const char* str): str_impl(str) {}
alt_string(const char * str,std::size_t count)53 alt_string(const char* str, std::size_t count): str_impl(str, count) {}
alt_string(size_t count,char chr)54 alt_string(size_t count, char chr): str_impl(count, chr) {}
55 alt_string() = default;
56
57 template <typename...TParams>
append(TParams &&...params)58 alt_string& append(TParams&& ...params)
59 {
60 str_impl.append(std::forward<TParams>(params)...);
61 return *this;
62 }
63
push_back(char c)64 void push_back(char c)
65 {
66 str_impl.push_back(c);
67 }
68
69 template <typename op_type>
operator ==(const op_type & op) const70 bool operator==(const op_type& op) const
71 {
72 return str_impl == op;
73 }
74
operator ==(const alt_string & op) const75 bool operator==(const alt_string& op) const
76 {
77 return str_impl == op.str_impl;
78 }
79
80 template <typename op_type>
operator !=(const op_type & op) const81 bool operator!=(const op_type& op) const
82 {
83 return str_impl != op;
84 }
85
operator !=(const alt_string & op) const86 bool operator!=(const alt_string& op) const
87 {
88 return str_impl != op.str_impl;
89 }
90
size() const91 std::size_t size() const noexcept
92 {
93 return str_impl.size();
94 }
95
resize(std::size_t n)96 void resize (std::size_t n)
97 {
98 str_impl.resize(n);
99 }
100
resize(std::size_t n,char c)101 void resize (std::size_t n, char c)
102 {
103 str_impl.resize(n, c);
104 }
105
106 template <typename op_type>
operator <(const op_type & op) const107 bool operator<(const op_type& op) const
108 {
109 return str_impl < op;
110 }
111
operator <(const alt_string & op) const112 bool operator<(const alt_string& op) const
113 {
114 return str_impl < op.str_impl;
115 }
116
c_str() const117 const char* c_str() const
118 {
119 return str_impl.c_str();
120 }
121
operator [](std::size_t index)122 char& operator[](std::size_t index)
123 {
124 return str_impl[index];
125 }
126
operator [](std::size_t index) const127 const char& operator[](std::size_t index) const
128 {
129 return str_impl[index];
130 }
131
back()132 char& back()
133 {
134 return str_impl.back();
135 }
136
back() const137 const char& back() const
138 {
139 return str_impl.back();
140 }
141
clear()142 void clear()
143 {
144 str_impl.clear();
145 }
146
data()147 const value_type* data()
148 {
149 return str_impl.data();
150 }
151
152 private:
153 std::string str_impl {};
154
155 friend bool ::operator<(const char*, const alt_string&);
156 };
157
int_to_string(alt_string & target,std::size_t value)158 void int_to_string(alt_string& target, std::size_t value)
159 {
160 target = std::to_string(value).c_str();
161 }
162
163 using alt_json = nlohmann::basic_json <
164 std::map,
165 std::vector,
166 alt_string,
167 bool,
168 std::int64_t,
169 std::uint64_t,
170 double,
171 std::allocator,
172 nlohmann::adl_serializer >;
173
174
operator <(const char * op1,const alt_string & op2)175 bool operator<(const char* op1, const alt_string& op2)
176 {
177 return op1 < op2.str_impl;
178 }
179
180 TEST_CASE("alternative string type")
181 {
182 SECTION("dump")
183 {
184 {
185 alt_json doc;
186 doc["pi"] = 3.141;
187 alt_string dump = doc.dump();
188 CHECK(dump == R"({"pi":3.141})");
189 }
190
191 {
192 alt_json doc;
193 doc["happy"] = true;
194 alt_string dump = doc.dump();
195 CHECK(dump == R"({"happy":true})");
196 }
197
198 {
199 alt_json doc;
200 doc["name"] = "I'm Batman";
201 alt_string dump = doc.dump();
202 CHECK(dump == R"({"name":"I'm Batman"})");
203 }
204
205 {
206 alt_json doc;
207 doc["nothing"] = nullptr;
208 alt_string dump = doc.dump();
209 CHECK(dump == R"({"nothing":null})");
210 }
211
212 {
213 alt_json doc;
214 doc["answer"]["everything"] = 42;
215 alt_string dump = doc.dump();
216 CHECK(dump == R"({"answer":{"everything":42}})");
217 }
218
219 {
220 alt_json doc;
221 doc["list"] = { 1, 0, 2 };
222 alt_string dump = doc.dump();
223 CHECK(dump == R"({"list":[1,0,2]})");
224 }
225
226 {
227 alt_json doc;
228 doc["object"] = { {"currency", "USD"}, {"value", 42.99} };
229 alt_string dump = doc.dump();
230 CHECK(dump == R"({"object":{"currency":"USD","value":42.99}})");
231 }
232 }
233
234 SECTION("parse")
235 {
236 auto doc = alt_json::parse("{\"foo\": \"bar\"}");
237 alt_string dump = doc.dump();
238 CHECK(dump == R"({"foo":"bar"})");
239 }
240
241 SECTION("items")
242 {
243 auto doc = alt_json::parse("{\"foo\": \"bar\"}");
244
245 for ( auto item : doc.items() )
246 {
247 CHECK( item.key() == "foo" );
248 CHECK( item.value() == "bar" );
249 }
250
251 auto doc_array = alt_json::parse("[\"foo\", \"bar\"]");
252
253 for ( auto item : doc_array.items() )
254 {
255 if (item.key() == "0" )
256 {
257 CHECK( item.value() == "foo" );
258 }
259 else if (item.key() == "1" )
260 {
261 CHECK( item.value() == "bar" );
262 }
263 else
264 {
265 CHECK( false );
266 }
267 }
268 }
269
270 SECTION("equality")
271 {
272 alt_json doc;
273 doc["Who are you?"] = "I'm Batman";
274
275 CHECK("I'm Batman" == doc["Who are you?"]);
276 CHECK(doc["Who are you?"] == "I'm Batman");
277 CHECK_FALSE("I'm Batman" != doc["Who are you?"]);
278 CHECK_FALSE(doc["Who are you?"] != "I'm Batman");
279
280 CHECK("I'm Bruce Wayne" != doc["Who are you?"]);
281 CHECK(doc["Who are you?"] != "I'm Bruce Wayne");
282 CHECK_FALSE("I'm Bruce Wayne" == doc["Who are you?"]);
283 CHECK_FALSE(doc["Who are you?"] == "I'm Bruce Wayne");
284
285 {
286 const alt_json& const_doc = doc;
287
288 CHECK("I'm Batman" == const_doc["Who are you?"]);
289 CHECK(const_doc["Who are you?"] == "I'm Batman");
290 CHECK_FALSE("I'm Batman" != const_doc["Who are you?"]);
291 CHECK_FALSE(const_doc["Who are you?"] != "I'm Batman");
292
293 CHECK("I'm Bruce Wayne" != const_doc["Who are you?"]);
294 CHECK(const_doc["Who are you?"] != "I'm Bruce Wayne");
295 CHECK_FALSE("I'm Bruce Wayne" == const_doc["Who are you?"]);
296 CHECK_FALSE(const_doc["Who are you?"] == "I'm Bruce Wayne");
297 }
298 }
299 }
300