]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/common/test_json_formattable.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / test / common / test_json_formattable.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2018 Red Hat Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 */
14
15 #include <errno.h>
16 #include <gtest/gtest.h>
17
18 #include "common/ceph_json.h"
19
20 #include <sstream>
21
22 using namespace std;
23
24
25 static void get_jf(const string& s, JSONFormattable *f)
26 {
27 JSONParser p;
28 bool result = p.parse(s.c_str(), s.size());
29 if (!result) {
30 cout << "Failed to parse: '" << s << "'" << std::endl;
31 }
32 ASSERT_EQ(true, result);
33 try {
34 decode_json_obj(*f, &p);
35 } catch (JSONDecoder::err& e) {
36 ASSERT_TRUE(0 == "Failed to decode JSON object");
37 }
38 }
39
40 TEST(formatable, str) {
41 JSONFormattable f;
42 get_jf("{ \"foo\": \"bar\" }", &f);
43 ASSERT_EQ((string)f["foo"], "bar");
44 ASSERT_EQ((string)f["fooz"], "");
45 ASSERT_EQ((string)f["fooz"]("lala"), "lala");
46 }
47
48 TEST(formatable, str2) {
49 JSONFormattable f;
50 get_jf("{ \"foo\": \"bar\" }", &f);
51 ASSERT_EQ((string)f["foo"], "bar");
52 ASSERT_EQ((string)f["fooz"], "");
53 ASSERT_EQ((string)f["fooz"]("lala"), "lala");
54
55 JSONFormattable f2;
56 get_jf("{ \"foo\": \"bar\", \"fooz\": \"zzz\" }", &f2);
57 ASSERT_EQ((string)f2["foo"], "bar");
58 ASSERT_NE((string)f2["fooz"], "");
59 ASSERT_EQ((string)f2["fooz"], "zzz");
60 ASSERT_EQ((string)f2["fooz"]("lala"), "zzz");
61
62 }
63
64 TEST(formatable, int) {
65 JSONFormattable f;
66 get_jf("{ \"foo\": 1 }", &f);
67 ASSERT_EQ((int)f["foo"], 1);
68 ASSERT_EQ((int)f["fooz"], 0);
69 ASSERT_EQ((int)f["fooz"](3), 3);
70
71 JSONFormattable f2;
72 get_jf("{ \"foo\": \"bar\", \"fooz\": \"123\" }", &f2);
73 ASSERT_EQ((string)f2["foo"], "bar");
74 ASSERT_NE((int)f2["fooz"], 0);
75 ASSERT_EQ((int)f2["fooz"], 123);
76 ASSERT_EQ((int)f2["fooz"](111), 123);
77 }
78
79 TEST(formatable, bool) {
80 JSONFormattable f;
81 get_jf("{ \"foo\": \"true\" }", &f);
82 ASSERT_EQ((bool)f["foo"], true);
83 ASSERT_EQ((bool)f["fooz"], false);
84 ASSERT_EQ((bool)f["fooz"](true), true);
85
86 JSONFormattable f2;
87 get_jf("{ \"foo\": \"false\" }", &f);
88 ASSERT_EQ((bool)f["foo"], false);
89 }
90
91 TEST(formatable, nested) {
92 JSONFormattable f;
93 get_jf("{ \"obj\": { \"foo\": 1, \"inobj\": { \"foo\": 2 } } }", &f);
94 ASSERT_EQ((int)f["foo"], 0);
95 ASSERT_EQ((int)f["obj"]["foo"], 1);
96 ASSERT_EQ((int)f["obj"]["inobj"]["foo"], 2);
97 }
98
99 TEST(formatable, array) {
100 JSONFormattable f;
101 get_jf("{ \"arr\": [ { \"foo\": 1, \"inobj\": { \"foo\": 2 } },"
102 "{ \"foo\": 2 } ] }", &f);
103
104 int i = 1;
105 for (auto a : f.array()) {
106 ASSERT_EQ((int)a["foo"], i);
107 ++i;
108 }
109
110 JSONFormattable f2;
111 get_jf("{ \"arr\": [ 0, 1, 2, 3, 4 ]}", &f2);
112
113 i = 0;
114 for (auto a : f2.array()) {
115 ASSERT_EQ((int)a, i);
116 ++i;
117 }
118 }
119
120 TEST(formatable, bin_encode) {
121 JSONFormattable f, f2;
122 get_jf("{ \"arr\": [ { \"foo\": 1, \"bar\": \"aaa\", \"inobj\": { \"foo\": 2 } },"
123 "{ \"foo\": 2, \"inobj\": { \"foo\": 3 } } ] }", &f);
124
125 int i = 1;
126 for (auto a : f.array()) {
127 ASSERT_EQ((int)a["foo"], i);
128 ASSERT_EQ((int)a["foo"]["inobj"], i + 1);
129 ASSERT_EQ((string)a["bar"], "aaa");
130 ++i;
131 }
132
133 bufferlist bl;
134 ::encode(f, bl);
135 auto iter = bl.cbegin();
136 try {
137 ::decode(f2, iter);
138 } catch (buffer::error& err) {
139 ASSERT_TRUE(0 == "Failed to decode object");
140 }
141
142 i = 1;
143 for (auto a : f2.array()) {
144 ASSERT_EQ((int)a["foo"], i);
145 ASSERT_EQ((int)a["foo"]["inobj"], i + 1);
146 ASSERT_EQ((string)a["bar"], "aaa");
147 ++i;
148 }
149
150 }
151
152 TEST(formatable, json_encode) {
153 JSONFormattable f, f2;
154 get_jf("{ \"arr\": [ { \"foo\": 1, \"bar\": \"aaa\", \"inobj\": { \"foo\": 2 } },"
155 "{ \"foo\": 2, \"inobj\": { \"foo\": 3 } } ] }", &f);
156
157 JSONFormatter formatter;
158 formatter.open_object_section("bla");
159 ::encode_json("f", f, &formatter);
160 formatter.close_section();
161
162 stringstream ss;
163 formatter.flush(ss);
164
165 get_jf(ss.str(), &f2);
166
167 int i = 1;
168 for (auto a : f2.array()) {
169 ASSERT_EQ((int)a["foo"], i);
170 ASSERT_EQ((int)a["foo"]["inobj"], i + 1);
171 ASSERT_EQ((string)a["bar"], "aaa");
172 ++i;
173 }
174
175 }
176
177 TEST(formatable, set) {
178 JSONFormattable f, f2;
179
180 f.set("", "{ \"abc\": \"xyz\"}");
181 ASSERT_EQ((string)f["abc"], "xyz");
182
183 f.set("aaa", "111");
184 ASSERT_EQ((string)f["abc"], "xyz");
185 ASSERT_EQ((int)f["aaa"], 111);
186
187 f.set("obj", "{ \"a\": \"10\", \"b\": \"20\"}");
188 ASSERT_EQ((int)f["obj"]["a"], 10);
189 ASSERT_EQ((int)f["obj"]["b"], 20);
190
191 f.set("obj.c", "30");
192
193 ASSERT_EQ((int)f["obj"]["c"], 30);
194 }
195
196 TEST(formatable, erase) {
197 JSONFormattable f, f2;
198
199 f.set("", "{ \"abc\": \"xyz\"}");
200 ASSERT_EQ((string)f["abc"], "xyz");
201
202 f.set("aaa", "111");
203 ASSERT_EQ((string)f["abc"], "xyz");
204 ASSERT_EQ((int)f["aaa"], 111);
205 f.erase("aaa");
206 ASSERT_EQ((int)f["aaa"], 0);
207
208 f.set("obj", "{ \"a\": \"10\", \"b\": \"20\"}");
209 ASSERT_EQ((int)f["obj"]["a"], 10);
210 ASSERT_EQ((int)f["obj"]["b"], 20);
211 f.erase("obj.a");
212 ASSERT_EQ((int)f["obj"]["a"], 0);
213 ASSERT_EQ((int)f["obj"]["b"], 20);
214 }
215
216 template <class T>
217 static void dumpt(const T& t, const char *n)
218 {
219 JSONFormatter formatter;
220 formatter.open_object_section("bla");
221 ::encode_json(n, t, &formatter);
222 formatter.close_section();
223 formatter.flush(cout);
224 }
225
226 static void dumpf(const JSONFormattable& f) {
227 dumpt(f, "f");
228 }
229
230 TEST(formatable, set_array) {
231 JSONFormattable f, f2;
232
233 f.set("asd[0]", "\"xyz\"");
234 ASSERT_EQ(1u, f["asd"].array().size());
235 ASSERT_EQ((string)f["asd"][0], "xyz");
236
237 f.set("bbb[0][0]", "10");
238 f.set("bbb[0][1]", "20");
239 ASSERT_EQ(1u, f["bbb"].array().size());
240 ASSERT_EQ(2u, f["bbb"][0].array().size());
241 ASSERT_EQ("10", (string)f["bbb"][0][0]);
242 ASSERT_EQ(20, (int)f["bbb"][0][1]);
243 f.set("bbb[0][1]", "25");
244 ASSERT_EQ(2u, f["bbb"][0].array().size());
245 ASSERT_EQ(25, (int)f["bbb"][0][1]);
246
247 f.set("bbb[0][]", "26"); /* append operation */
248 ASSERT_EQ(26, (int)f["bbb"][0][2]);
249 f.set("bbb[0][-1]", "27"); /* replace last */
250 ASSERT_EQ(27, (int)f["bbb"][0][2]);
251 ASSERT_EQ(3u, f["bbb"][0].array().size());
252
253 f.set("foo.asd[0][0]", "{ \"field\": \"xyz\"}");
254 ASSERT_EQ((string)f["foo"]["asd"][0][0]["field"], "xyz");
255
256 ASSERT_EQ(f.set("foo[0]", "\"zzz\""), -EINVAL); /* can't assign array to an obj entity */
257
258 f2.set("[0]", "{ \"field\": \"xyz\"}");
259 ASSERT_EQ((string)f2[0]["field"], "xyz");
260 }
261
262 TEST(formatable, erase_array) {
263 JSONFormattable f;
264
265 f.set("asd[0]", "\"xyz\"");
266 ASSERT_EQ(1u, f["asd"].array().size());
267 ASSERT_EQ("xyz", (string)f["asd"][0]);
268 ASSERT_TRUE(f["asd"].exists(0));
269 f.erase("asd[0]");
270 ASSERT_FALSE(f["asd"].exists(0));
271 f.set("asd[0]", "\"xyz\"");
272 ASSERT_TRUE(f["asd"].exists(0));
273 f["asd"].erase("[0]");
274 ASSERT_FALSE(f["asd"].exists(0));
275 f.set("asd[0]", "\"xyz\"");
276 ASSERT_TRUE(f["asd"].exists(0));
277 f.erase("asd");
278 ASSERT_FALSE(f["asd"].exists(0));
279 ASSERT_FALSE(f.exists("asd"));
280
281 f.set("bbb[]", "10");
282 f.set("bbb[]", "20");
283 f.set("bbb[]", "30");
284 ASSERT_EQ((int)f["bbb"][0], 10);
285 ASSERT_EQ((int)f["bbb"][1], 20);
286 ASSERT_EQ((int)f["bbb"][2], 30);
287 f.erase("bbb[-2]");
288 ASSERT_FALSE(f.exists("bbb[2]"));
289
290 ASSERT_EQ((int)f["bbb"][0], 10);
291 ASSERT_EQ((int)f["bbb"][1], 30);
292
293 if (0) { /* for debugging when needed */
294 dumpf(f);
295 }
296 }
297
298 void formatter_convert(JSONFormatter& formatter, JSONFormattable *dest)
299 {
300 stringstream ss;
301 formatter.flush(ss);
302 get_jf(ss.str(), dest);
303 }
304
305 TEST(formatable, encode_simple) {
306 JSONFormattable f;
307
308 encode_json("foo", "bar", &f);
309
310 ASSERT_EQ((string)f["foo"], "bar");
311
312
313 JSONFormatter formatter;
314 {
315 Formatter::ObjectSection s(formatter, "os");
316 encode_json("f", f, &formatter);
317 }
318
319 JSONFormattable jf2;
320 formatter_convert(formatter, &jf2);
321
322 ASSERT_EQ((string)jf2["f"]["foo"], "bar");
323 }
324
325
326 struct struct1 {
327 long i;
328 string s;
329 bool b;
330
331 struct1() {
332 void *p = (void *)this;
333 i = (long)p;
334 char buf[32];
335 snprintf(buf, sizeof(buf), "%p", p);
336 s = buf;
337 b = (bool)(i % 2);
338 }
339
340 void dump(Formatter *f) const {
341 encode_json("i", i, f);
342 encode_json("s", s, f);
343 encode_json("b", b, f);
344 }
345
346 void decode_json(JSONObj *obj) {
347 JSONDecoder::decode_json("i", i, obj);
348 JSONDecoder::decode_json("s", s, obj);
349 JSONDecoder::decode_json("b", b, obj);
350 }
351
352 bool compare(const JSONFormattable& jf) const {
353 bool ret = (s == (string)jf["s"] &&
354 i == (long)jf["i"] &&
355 b == (bool)jf["b"]);
356
357 if (!ret) {
358 cout << "failed comparison: s=" << s << " jf[s]=" << (string)jf["s"] <<
359 " i=" << i << " jf[i]=" << (long)jf["i"] << " b=" << b << " jf[b]=" << (bool)jf["b"] << std::endl;
360 dumpf(jf);
361 }
362
363 return ret;
364 }
365 };
366
367
368 struct struct2 {
369 struct1 s1;
370 vector<struct1> v;
371
372 struct2() {
373 void *p = (void *)this;
374 long i = (long)p;
375 v.resize((i >> 16) % 16 + 1);
376 }
377
378 void dump(Formatter *f) const {
379 encode_json("s1", s1, f);
380 encode_json("v", v, f);
381 }
382
383 void decode_json(JSONObj *obj) {
384 JSONDecoder::decode_json("s1", s1, obj);
385 JSONDecoder::decode_json("v", v, obj);
386 }
387
388 bool compare(const JSONFormattable& jf) const {
389 if (!s1.compare(jf["s1"])) {
390 cout << "s1.compare(jf[s1] failed" << std::endl;
391 return false;
392 }
393
394 if (v.size() != jf["v"].array().size()) {
395 cout << "v.size()=" << v.size() << " jf[v].array().size()=" << jf["v"].array().size() << std::endl;
396 return false;
397 }
398
399 auto viter = v.begin();
400 auto jiter = jf["v"].array().begin();
401
402 for (; viter != v.end(); ++viter, ++jiter) {
403 if (!viter->compare(*jiter)) {
404 return false;
405 }
406 }
407 return true;
408 }
409 };
410
411
412 TEST(formatable, encode_struct) {
413 JSONFormattable f;
414
415 struct2 s2;
416
417 {
418 Formatter::ObjectSection s(f, "section");
419 encode_json("foo", "bar", &f);
420 encode_json("s2", s2, &f);
421 }
422
423 dumpt(s2, "s2");
424 cout << std::endl;
425 cout << std::endl;
426
427 ASSERT_EQ((string)f["foo"], "bar");
428 ASSERT_TRUE(s2.compare(f["s2"]));
429
430
431 JSONFormatter formatter;
432 encode_json("f", f, &formatter);
433
434 JSONFormattable jf2;
435
436 formatter_convert(formatter, &jf2);
437
438 ASSERT_EQ((string)jf2["foo"], "bar");
439 ASSERT_TRUE(s2.compare(jf2["s2"]));
440 }
441