diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/test/common/test_json_formattable.cc | |
parent | Initial commit. (diff) | |
download | ceph-upstream/16.2.11+ds.tar.xz ceph-upstream/16.2.11+ds.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/common/test_json_formattable.cc')
-rw-r--r-- | src/test/common/test_json_formattable.cc | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/src/test/common/test_json_formattable.cc b/src/test/common/test_json_formattable.cc new file mode 100644 index 000000000..90327127c --- /dev/null +++ b/src/test/common/test_json_formattable.cc @@ -0,0 +1,441 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2018 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + */ + +#include <errno.h> +#include <gtest/gtest.h> + +#include "common/ceph_json.h" + +#include <sstream> + +using namespace std; + + +static void get_jf(const string& s, JSONFormattable *f) +{ + JSONParser p; + bool result = p.parse(s.c_str(), s.size()); + if (!result) { + cout << "Failed to parse: '" << s << "'" << std::endl; + } + ASSERT_EQ(true, result); + try { + decode_json_obj(*f, &p); + } catch (JSONDecoder::err& e) { + ASSERT_TRUE(0 == "Failed to decode JSON object"); + } +} + +TEST(formatable, str) { + JSONFormattable f; + get_jf("{ \"foo\": \"bar\" }", &f); + ASSERT_EQ((string)f["foo"], "bar"); + ASSERT_EQ((string)f["fooz"], ""); + ASSERT_EQ((string)f["fooz"]("lala"), "lala"); +} + +TEST(formatable, str2) { + JSONFormattable f; + get_jf("{ \"foo\": \"bar\" }", &f); + ASSERT_EQ((string)f["foo"], "bar"); + ASSERT_EQ((string)f["fooz"], ""); + ASSERT_EQ((string)f["fooz"]("lala"), "lala"); + + JSONFormattable f2; + get_jf("{ \"foo\": \"bar\", \"fooz\": \"zzz\" }", &f2); + ASSERT_EQ((string)f2["foo"], "bar"); + ASSERT_NE((string)f2["fooz"], ""); + ASSERT_EQ((string)f2["fooz"], "zzz"); + ASSERT_EQ((string)f2["fooz"]("lala"), "zzz"); + +} + +TEST(formatable, int) { + JSONFormattable f; + get_jf("{ \"foo\": 1 }", &f); + ASSERT_EQ((int)f["foo"], 1); + ASSERT_EQ((int)f["fooz"], 0); + ASSERT_EQ((int)f["fooz"](3), 3); + + JSONFormattable f2; + get_jf("{ \"foo\": \"bar\", \"fooz\": \"123\" }", &f2); + ASSERT_EQ((string)f2["foo"], "bar"); + ASSERT_NE((int)f2["fooz"], 0); + ASSERT_EQ((int)f2["fooz"], 123); + ASSERT_EQ((int)f2["fooz"](111), 123); +} + +TEST(formatable, bool) { + JSONFormattable f; + get_jf("{ \"foo\": \"true\" }", &f); + ASSERT_EQ((bool)f["foo"], true); + ASSERT_EQ((bool)f["fooz"], false); + ASSERT_EQ((bool)f["fooz"](true), true); + + JSONFormattable f2; + get_jf("{ \"foo\": \"false\" }", &f); + ASSERT_EQ((bool)f["foo"], false); +} + +TEST(formatable, nested) { + JSONFormattable f; + get_jf("{ \"obj\": { \"foo\": 1, \"inobj\": { \"foo\": 2 } } }", &f); + ASSERT_EQ((int)f["foo"], 0); + ASSERT_EQ((int)f["obj"]["foo"], 1); + ASSERT_EQ((int)f["obj"]["inobj"]["foo"], 2); +} + +TEST(formatable, array) { + JSONFormattable f; + get_jf("{ \"arr\": [ { \"foo\": 1, \"inobj\": { \"foo\": 2 } }," + "{ \"foo\": 2 } ] }", &f); + + int i = 1; + for (auto a : f.array()) { + ASSERT_EQ((int)a["foo"], i); + ++i; + } + + JSONFormattable f2; + get_jf("{ \"arr\": [ 0, 1, 2, 3, 4 ]}", &f2); + + i = 0; + for (auto a : f2.array()) { + ASSERT_EQ((int)a, i); + ++i; + } +} + +TEST(formatable, bin_encode) { + JSONFormattable f, f2; + get_jf("{ \"arr\": [ { \"foo\": 1, \"bar\": \"aaa\", \"inobj\": { \"foo\": 2 } }," + "{ \"foo\": 2, \"inobj\": { \"foo\": 3 } } ] }", &f); + + int i = 1; + for (auto a : f.array()) { + ASSERT_EQ((int)a["foo"], i); + ASSERT_EQ((int)a["foo"]["inobj"], i + 1); + ASSERT_EQ((string)a["bar"], "aaa"); + ++i; + } + + bufferlist bl; + ::encode(f, bl); + auto iter = bl.cbegin(); + try { + ::decode(f2, iter); + } catch (buffer::error& err) { + ASSERT_TRUE(0 == "Failed to decode object"); + } + + i = 1; + for (auto a : f2.array()) { + ASSERT_EQ((int)a["foo"], i); + ASSERT_EQ((int)a["foo"]["inobj"], i + 1); + ASSERT_EQ((string)a["bar"], "aaa"); + ++i; + } + +} + +TEST(formatable, json_encode) { + JSONFormattable f, f2; + get_jf("{ \"arr\": [ { \"foo\": 1, \"bar\": \"aaa\", \"inobj\": { \"foo\": 2 } }," + "{ \"foo\": 2, \"inobj\": { \"foo\": 3 } } ] }", &f); + + JSONFormatter formatter; + formatter.open_object_section("bla"); + ::encode_json("f", f, &formatter); + formatter.close_section(); + + stringstream ss; + formatter.flush(ss); + + get_jf(ss.str(), &f2); + + int i = 1; + for (auto a : f2.array()) { + ASSERT_EQ((int)a["foo"], i); + ASSERT_EQ((int)a["foo"]["inobj"], i + 1); + ASSERT_EQ((string)a["bar"], "aaa"); + ++i; + } + +} + +TEST(formatable, set) { + JSONFormattable f, f2; + + f.set("", "{ \"abc\": \"xyz\"}"); + ASSERT_EQ((string)f["abc"], "xyz"); + + f.set("aaa", "111"); + ASSERT_EQ((string)f["abc"], "xyz"); + ASSERT_EQ((int)f["aaa"], 111); + + f.set("obj", "{ \"a\": \"10\", \"b\": \"20\"}"); + ASSERT_EQ((int)f["obj"]["a"], 10); + ASSERT_EQ((int)f["obj"]["b"], 20); + + f.set("obj.c", "30"); + + ASSERT_EQ((int)f["obj"]["c"], 30); +} + +TEST(formatable, erase) { + JSONFormattable f, f2; + + f.set("", "{ \"abc\": \"xyz\"}"); + ASSERT_EQ((string)f["abc"], "xyz"); + + f.set("aaa", "111"); + ASSERT_EQ((string)f["abc"], "xyz"); + ASSERT_EQ((int)f["aaa"], 111); + f.erase("aaa"); + ASSERT_EQ((int)f["aaa"], 0); + + f.set("obj", "{ \"a\": \"10\", \"b\": \"20\"}"); + ASSERT_EQ((int)f["obj"]["a"], 10); + ASSERT_EQ((int)f["obj"]["b"], 20); + f.erase("obj.a"); + ASSERT_EQ((int)f["obj"]["a"], 0); + ASSERT_EQ((int)f["obj"]["b"], 20); +} + +template <class T> +static void dumpt(const T& t, const char *n) +{ + JSONFormatter formatter; + formatter.open_object_section("bla"); + ::encode_json(n, t, &formatter); + formatter.close_section(); + formatter.flush(cout); +} + +static void dumpf(const JSONFormattable& f) { + dumpt(f, "f"); +} + +TEST(formatable, set_array) { + JSONFormattable f, f2; + + f.set("asd[0]", "\"xyz\""); + ASSERT_EQ(1u, f["asd"].array().size()); + ASSERT_EQ((string)f["asd"][0], "xyz"); + + f.set("bbb[0][0]", "10"); + f.set("bbb[0][1]", "20"); + ASSERT_EQ(1u, f["bbb"].array().size()); + ASSERT_EQ(2u, f["bbb"][0].array().size()); + ASSERT_EQ("10", (string)f["bbb"][0][0]); + ASSERT_EQ(20, (int)f["bbb"][0][1]); + f.set("bbb[0][1]", "25"); + ASSERT_EQ(2u, f["bbb"][0].array().size()); + ASSERT_EQ(25, (int)f["bbb"][0][1]); + + f.set("bbb[0][]", "26"); /* append operation */ + ASSERT_EQ(26, (int)f["bbb"][0][2]); + f.set("bbb[0][-1]", "27"); /* replace last */ + ASSERT_EQ(27, (int)f["bbb"][0][2]); + ASSERT_EQ(3u, f["bbb"][0].array().size()); + + f.set("foo.asd[0][0]", "{ \"field\": \"xyz\"}"); + ASSERT_EQ((string)f["foo"]["asd"][0][0]["field"], "xyz"); + + ASSERT_EQ(f.set("foo[0]", "\"zzz\""), -EINVAL); /* can't assign array to an obj entity */ + + f2.set("[0]", "{ \"field\": \"xyz\"}"); + ASSERT_EQ((string)f2[0]["field"], "xyz"); +} + +TEST(formatable, erase_array) { + JSONFormattable f; + + f.set("asd[0]", "\"xyz\""); + ASSERT_EQ(1u, f["asd"].array().size()); + ASSERT_EQ("xyz", (string)f["asd"][0]); + ASSERT_TRUE(f["asd"].exists(0)); + f.erase("asd[0]"); + ASSERT_FALSE(f["asd"].exists(0)); + f.set("asd[0]", "\"xyz\""); + ASSERT_TRUE(f["asd"].exists(0)); + f["asd"].erase("[0]"); + ASSERT_FALSE(f["asd"].exists(0)); + f.set("asd[0]", "\"xyz\""); + ASSERT_TRUE(f["asd"].exists(0)); + f.erase("asd"); + ASSERT_FALSE(f["asd"].exists(0)); + ASSERT_FALSE(f.exists("asd")); + + f.set("bbb[]", "10"); + f.set("bbb[]", "20"); + f.set("bbb[]", "30"); + ASSERT_EQ((int)f["bbb"][0], 10); + ASSERT_EQ((int)f["bbb"][1], 20); + ASSERT_EQ((int)f["bbb"][2], 30); + f.erase("bbb[-2]"); + ASSERT_FALSE(f.exists("bbb[2]")); + + ASSERT_EQ((int)f["bbb"][0], 10); + ASSERT_EQ((int)f["bbb"][1], 30); + + if (0) { /* for debugging when needed */ + dumpf(f); + } +} + +void formatter_convert(JSONFormatter& formatter, JSONFormattable *dest) +{ + stringstream ss; + formatter.flush(ss); + get_jf(ss.str(), dest); +} + +TEST(formatable, encode_simple) { + JSONFormattable f; + + encode_json("foo", "bar", &f); + + ASSERT_EQ((string)f["foo"], "bar"); + + + JSONFormatter formatter; + { + Formatter::ObjectSection s(formatter, "os"); + encode_json("f", f, &formatter); + } + + JSONFormattable jf2; + formatter_convert(formatter, &jf2); + + ASSERT_EQ((string)jf2["f"]["foo"], "bar"); +} + + +struct struct1 { + long i; + string s; + bool b; + + struct1() { + void *p = (void *)this; + i = (long)p; + char buf[32]; + snprintf(buf, sizeof(buf), "%p", p); + s = buf; + b = (bool)(i % 2); + } + + void dump(Formatter *f) const { + encode_json("i", i, f); + encode_json("s", s, f); + encode_json("b", b, f); + } + + void decode_json(JSONObj *obj) { + JSONDecoder::decode_json("i", i, obj); + JSONDecoder::decode_json("s", s, obj); + JSONDecoder::decode_json("b", b, obj); + } + + bool compare(const JSONFormattable& jf) const { + bool ret = (s == (string)jf["s"] && + i == (long)jf["i"] && + b == (bool)jf["b"]); + + if (!ret) { + cout << "failed comparison: s=" << s << " jf[s]=" << (string)jf["s"] << + " i=" << i << " jf[i]=" << (long)jf["i"] << " b=" << b << " jf[b]=" << (bool)jf["b"] << std::endl; + dumpf(jf); + } + + return ret; + } +}; + + +struct struct2 { + struct1 s1; + vector<struct1> v; + + struct2() { + void *p = (void *)this; + long i = (long)p; + v.resize((i >> 16) % 16 + 1); + } + + void dump(Formatter *f) const { + encode_json("s1", s1, f); + encode_json("v", v, f); + } + + void decode_json(JSONObj *obj) { + JSONDecoder::decode_json("s1", s1, obj); + JSONDecoder::decode_json("v", v, obj); + } + + bool compare(const JSONFormattable& jf) const { + if (!s1.compare(jf["s1"])) { + cout << "s1.compare(jf[s1] failed" << std::endl; + return false; + } + + if (v.size() != jf["v"].array().size()) { + cout << "v.size()=" << v.size() << " jf[v].array().size()=" << jf["v"].array().size() << std::endl; + return false; + } + + auto viter = v.begin(); + auto jiter = jf["v"].array().begin(); + + for (; viter != v.end(); ++viter, ++jiter) { + if (!viter->compare(*jiter)) { + return false; + } + } + return true; + } +}; + + +TEST(formatable, encode_struct) { + JSONFormattable f; + + struct2 s2; + + { + Formatter::ObjectSection s(f, "section"); + encode_json("foo", "bar", &f); + encode_json("s2", s2, &f); + } + + dumpt(s2, "s2"); + cout << std::endl; + cout << std::endl; + + ASSERT_EQ((string)f["foo"], "bar"); + ASSERT_TRUE(s2.compare(f["s2"])); + + + JSONFormatter formatter; + encode_json("f", f, &formatter); + + JSONFormattable jf2; + + formatter_convert(formatter, &jf2); + + ASSERT_EQ((string)jf2["foo"], "bar"); + ASSERT_TRUE(s2.compare(jf2["s2"])); +} + |