unit-readme.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /*
  2. __ _____ _____ _____
  3. __| | __| | | | JSON for Modern C++ (test suite)
  4. | | |__ | | | | | | version 3.7.3
  5. |_____|_____|_____|_|___| https://github.com/nlohmann/json
  6. Licensed under the MIT License <http://opensource.org/licenses/MIT>.
  7. SPDX-License-Identifier: MIT
  8. Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
  9. Permission is hereby granted, free of charge, to any person obtaining a copy
  10. of this software and associated documentation files (the "Software"), to deal
  11. in the Software without restriction, including without limitation the rights
  12. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. copies of the Software, and to permit persons to whom the Software is
  14. furnished to do so, subject to the following conditions:
  15. The above copyright notice and this permission notice shall be included in all
  16. copies or substantial portions of the Software.
  17. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. SOFTWARE.
  24. */
  25. #include "doctest_compatibility.h"
  26. DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal")
  27. #include <nlohmann/json.hpp>
  28. using nlohmann::json;
  29. #include <deque>
  30. #include <forward_list>
  31. #include <list>
  32. #include <set>
  33. #include <unordered_map>
  34. #include <unordered_set>
  35. #include <iostream>
  36. #include <sstream>
  37. #include <iomanip>
  38. #if defined(_MSC_VER)
  39. #pragma warning (push)
  40. #pragma warning (disable : 4189) // local variable is initialized but not referenced
  41. #endif
  42. TEST_CASE("README" * doctest::skip())
  43. {
  44. {
  45. // redirect std::cout for the README file
  46. auto old_cout_buffer = std::cout.rdbuf();
  47. std::ostringstream new_stream;
  48. std::cout.rdbuf(new_stream.rdbuf());
  49. {
  50. // create an empty structure (null)
  51. json j;
  52. // add a number that is stored as double (note the implicit conversion of j to an object)
  53. j["pi"] = 3.141;
  54. // add a Boolean that is stored as bool
  55. j["happy"] = true;
  56. // add a string that is stored as std::string
  57. j["name"] = "Niels";
  58. // add another null object by passing nullptr
  59. j["nothing"] = nullptr;
  60. // add an object inside the object
  61. j["answer"]["everything"] = 42;
  62. // add an array that is stored as std::vector (using an initializer list)
  63. j["list"] = { 1, 0, 2 };
  64. // add another object (using an initializer list of pairs)
  65. j["object"] = { {"currency", "USD"}, {"value", 42.99} };
  66. // instead, you could also write (which looks very similar to the JSON above)
  67. json j2 =
  68. {
  69. {"pi", 3.141},
  70. {"happy", true},
  71. {"name", "Niels"},
  72. {"nothing", nullptr},
  73. {
  74. "answer", {
  75. {"everything", 42}
  76. }
  77. },
  78. {"list", {1, 0, 2}},
  79. {
  80. "object", {
  81. {"currency", "USD"},
  82. {"value", 42.99}
  83. }
  84. }
  85. };
  86. }
  87. {
  88. // ways to express the empty array []
  89. json empty_array_implicit = {{}};
  90. CHECK(empty_array_implicit.is_array());
  91. json empty_array_explicit = json::array();
  92. CHECK(empty_array_explicit.is_array());
  93. // a way to express the empty object {}
  94. json empty_object_explicit = json::object();
  95. CHECK(empty_object_explicit.is_object());
  96. // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
  97. json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} });
  98. CHECK(array_not_object.is_array());
  99. CHECK(array_not_object.size() == 2);
  100. CHECK(array_not_object[0].is_array());
  101. CHECK(array_not_object[1].is_array());
  102. }
  103. {
  104. // create object from string literal
  105. json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
  106. // or even nicer with a raw string literal
  107. auto j2 = R"(
  108. {
  109. "happy": true,
  110. "pi": 3.141
  111. }
  112. )"_json;
  113. // or explicitly
  114. auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
  115. // explicit conversion to string
  116. std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141}
  117. // serialization with pretty printing
  118. // pass in the amount of spaces to indent
  119. std::cout << j.dump(4) << std::endl;
  120. // {
  121. // "happy": true,
  122. // "pi": 3.141
  123. // }
  124. std::cout << std::setw(2) << j << std::endl;
  125. }
  126. {
  127. // create an array using push_back
  128. json j;
  129. j.push_back("foo");
  130. j.push_back(1);
  131. j.push_back(true);
  132. // comparison
  133. bool x = (j == "[\"foo\", 1, true]"_json); // true
  134. CHECK(x == true);
  135. // iterate the array
  136. for (json::iterator it = j.begin(); it != j.end(); ++it)
  137. {
  138. std::cout << *it << '\n';
  139. }
  140. // range-based for
  141. for (auto element : j)
  142. {
  143. std::cout << element << '\n';
  144. }
  145. // getter/setter
  146. const std::string tmp = j[0];
  147. j[1] = 42;
  148. bool foo = j.at(2);
  149. CHECK(foo == true);
  150. // other stuff
  151. j.size(); // 3 entries
  152. j.empty(); // false
  153. j.type(); // json::value_t::array
  154. j.clear(); // the array is empty again
  155. // create an object
  156. json o;
  157. o["foo"] = 23;
  158. o["bar"] = false;
  159. o["baz"] = 3.141;
  160. // find an entry
  161. if (o.find("foo") != o.end())
  162. {
  163. // there is an entry with key "foo"
  164. }
  165. }
  166. {
  167. std::vector<int> c_vector {1, 2, 3, 4};
  168. json j_vec(c_vector);
  169. // [1, 2, 3, 4]
  170. std::deque<float> c_deque {1.2f, 2.3f, 3.4f, 5.6f};
  171. json j_deque(c_deque);
  172. // [1.2, 2.3, 3.4, 5.6]
  173. std::list<bool> c_list {true, true, false, true};
  174. json j_list(c_list);
  175. // [true, true, false, true]
  176. std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
  177. json j_flist(c_flist);
  178. // [12345678909876, 23456789098765, 34567890987654, 45678909876543]
  179. std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
  180. json j_array(c_array);
  181. // [1, 2, 3, 4]
  182. std::set<std::string> c_set {"one", "two", "three", "four", "one"};
  183. json j_set(c_set); // only one entry for "one" is used
  184. // ["four", "one", "three", "two"]
  185. std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
  186. json j_uset(c_uset); // only one entry for "one" is used
  187. // maybe ["two", "three", "four", "one"]
  188. std::multiset<std::string> c_mset {"one", "two", "one", "four"};
  189. json j_mset(c_mset); // both entries for "one" are used
  190. // maybe ["one", "two", "one", "four"]
  191. std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"};
  192. json j_umset(c_umset); // both entries for "one" are used
  193. // maybe ["one", "two", "one", "four"]
  194. }
  195. {
  196. std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
  197. json j_map(c_map);
  198. // {"one": 1, "two": 2, "three": 3}
  199. std::unordered_map<const char*, float> c_umap { {"one", 1.2f}, {"two", 2.3f}, {"three", 3.4f} };
  200. json j_umap(c_umap);
  201. // {"one": 1.2, "two": 2.3, "three": 3.4}
  202. std::multimap<std::string, bool> c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
  203. json j_mmap(c_mmap); // only one entry for key "three" is used
  204. // maybe {"one": true, "two": true, "three": true}
  205. std::unordered_multimap<std::string, bool> c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
  206. json j_ummap(c_ummap); // only one entry for key "three" is used
  207. // maybe {"one": true, "two": true, "three": true}
  208. }
  209. {
  210. // strings
  211. std::string s1 = "Hello, world!";
  212. json js = s1;
  213. std::string s2 = js;
  214. // Booleans
  215. bool b1 = true;
  216. json jb = b1;
  217. bool b2 = jb;
  218. CHECK(b2 == true);
  219. // numbers
  220. int i = 42;
  221. json jn = i;
  222. double f = jn;
  223. CHECK(f == 42);
  224. // etc.
  225. std::string vs = js.get<std::string>();
  226. bool vb = jb.get<bool>();
  227. CHECK(vb == true);
  228. int vi = jn.get<int>();
  229. CHECK(vi == 42);
  230. // etc.
  231. }
  232. {
  233. // a JSON value
  234. json j_original = R"({
  235. "baz": ["one", "two", "three"],
  236. "foo": "bar"
  237. })"_json;
  238. // access members with a JSON pointer (RFC 6901)
  239. j_original["/baz/1"_json_pointer];
  240. // "two"
  241. // a JSON patch (RFC 6902)
  242. json j_patch = R"([
  243. { "op": "replace", "path": "/baz", "value": "boo" },
  244. { "op": "add", "path": "/hello", "value": ["world"] },
  245. { "op": "remove", "path": "/foo"}
  246. ])"_json;
  247. // apply the patch
  248. json j_result = j_original.patch(j_patch);
  249. // {
  250. // "baz": "boo",
  251. // "hello": ["world"]
  252. // }
  253. // calculate a JSON patch from two JSON values
  254. auto res = json::diff(j_result, j_original);
  255. // [
  256. // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
  257. // { "op":"remove","path":"/hello" },
  258. // { "op":"add","path":"/foo","value":"bar" }
  259. // ]
  260. }
  261. // restore old std::cout
  262. std::cout.rdbuf(old_cout_buffer);
  263. }
  264. }
  265. #if defined(_MSC_VER)
  266. #pragma warning (pop)
  267. #endif