testJSONHelpers.cxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. #include <functional>
  2. #include <iostream>
  3. #include <map>
  4. #include <string>
  5. #include <vector>
  6. #include <cm/optional>
  7. #include <cmext/string_view>
  8. #include <cm3p/json/value.h>
  9. #include "cmJSONHelpers.h"
  10. #include "cmJSONState.h"
  11. #define ASSERT_TRUE(x) \
  12. do { \
  13. if (!(x)) { \
  14. std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
  15. return false; \
  16. } \
  17. } while (false)
  18. namespace {
  19. struct ObjectStruct
  20. {
  21. std::string Field1;
  22. int Field2;
  23. };
  24. struct InheritedStruct : public ObjectStruct
  25. {
  26. std::string Field3;
  27. };
  28. namespace ErrorMessages {
  29. using ErrorGenerator =
  30. std::function<void(const Json::Value*, cmJSONState* state)>;
  31. ErrorGenerator ErrorGeneratorBuilder(std::string errorMessage)
  32. {
  33. return [errorMessage](const Json::Value* value, cmJSONState* state) -> void {
  34. state->AddErrorAtValue(errorMessage, value);
  35. };
  36. };
  37. ErrorGenerator InvalidArray = ErrorGeneratorBuilder("Invalid Array");
  38. ErrorGenerator MissingRequired = ErrorGeneratorBuilder("Missing Required");
  39. ErrorGenerator InvalidMap = ErrorGeneratorBuilder("Invalid Map");
  40. ErrorGenerator InvalidObject(JsonErrors::ObjectError /*errorType*/,
  41. const Json::Value::Members& extraFields)
  42. {
  43. return [extraFields](const Json::Value* value, cmJSONState* state) -> void {
  44. state->AddErrorAtValue("Invalid Object", value);
  45. };
  46. };
  47. };
  48. using JSONHelperBuilder = cmJSONHelperBuilder;
  49. auto const IntHelper = JSONHelperBuilder::Int(1);
  50. auto const RequiredIntHelper =
  51. JSONHelperBuilder::Required<int>(ErrorMessages::MissingRequired, IntHelper);
  52. auto const UIntHelper = JSONHelperBuilder::UInt(1);
  53. auto const BoolHelper = JSONHelperBuilder::Bool(false);
  54. auto const StringHelper = JSONHelperBuilder::String("default");
  55. auto const RequiredStringHelper = JSONHelperBuilder::Required<std::string>(
  56. ErrorMessages::MissingRequired, StringHelper);
  57. auto const StringVectorHelper = JSONHelperBuilder::Vector<std::string>(
  58. ErrorMessages::InvalidArray, StringHelper);
  59. auto const StringVectorFilterHelper =
  60. JSONHelperBuilder::VectorFilter<std::string>(
  61. ErrorMessages::InvalidArray, StringHelper,
  62. [](const std::string& value) { return value != "ignore"; });
  63. auto const StringMapHelper =
  64. JSONHelperBuilder::Map<std::string>(ErrorMessages::InvalidMap, StringHelper);
  65. auto const StringMapFilterHelper = JSONHelperBuilder::MapFilter<std::string>(
  66. ErrorMessages::InvalidMap, StringHelper,
  67. [](const std::string& key) { return key != "ignore"; });
  68. auto const OptionalStringHelper =
  69. JSONHelperBuilder::Optional<std::string>(StringHelper);
  70. bool testInt()
  71. {
  72. Json::Value v(2);
  73. cmJSONState state;
  74. int i = 0;
  75. ASSERT_TRUE(IntHelper(i, &v, &state));
  76. ASSERT_TRUE(i == 2);
  77. i = 0;
  78. v = Json::nullValue;
  79. ASSERT_TRUE(!IntHelper(i, &v, &state));
  80. i = 0;
  81. ASSERT_TRUE(IntHelper(i, nullptr, &state));
  82. ASSERT_TRUE(i == 1);
  83. return true;
  84. }
  85. bool testUInt()
  86. {
  87. Json::Value v(2);
  88. cmJSONState state;
  89. unsigned int i = 0;
  90. ASSERT_TRUE(UIntHelper(i, &v, &state));
  91. ASSERT_TRUE(i == 2);
  92. i = 0;
  93. v = Json::nullValue;
  94. ASSERT_TRUE(!UIntHelper(i, &v, &state));
  95. i = 0;
  96. ASSERT_TRUE(UIntHelper(i, nullptr, &state));
  97. ASSERT_TRUE(i == 1);
  98. return true;
  99. }
  100. bool testBool()
  101. {
  102. Json::Value v(true);
  103. cmJSONState state;
  104. bool b = false;
  105. ASSERT_TRUE(BoolHelper(b, &v, &state));
  106. ASSERT_TRUE(b);
  107. b = false;
  108. v = false;
  109. ASSERT_TRUE(BoolHelper(b, &v, &state));
  110. ASSERT_TRUE(!b);
  111. b = false;
  112. v = 4;
  113. ASSERT_TRUE(!BoolHelper(b, &v, &state));
  114. b = true;
  115. ASSERT_TRUE(BoolHelper(b, nullptr, &state));
  116. ASSERT_TRUE(!b);
  117. return true;
  118. }
  119. bool testString()
  120. {
  121. Json::Value v("str");
  122. cmJSONState state;
  123. std::string str = "";
  124. ASSERT_TRUE(StringHelper(str, &v, &state));
  125. ASSERT_TRUE(str == "str");
  126. str = "";
  127. v = Json::nullValue;
  128. ASSERT_TRUE(!StringHelper(str, &v, &state));
  129. str = "";
  130. ASSERT_TRUE(StringHelper(str, nullptr, &state));
  131. ASSERT_TRUE(str == "default");
  132. return true;
  133. }
  134. bool testObject()
  135. {
  136. auto const subhelper = JSONHelperBuilder::Object<ObjectStruct>().Bind(
  137. "subfield"_s, &ObjectStruct::Field2, IntHelper);
  138. auto const helper = JSONHelperBuilder::Object<ObjectStruct>()
  139. .Bind("field1"_s, &ObjectStruct::Field1, StringHelper)
  140. .Bind("field2"_s, subhelper)
  141. .Bind<std::string>("field3"_s, nullptr, StringHelper);
  142. Json::Value v(Json::objectValue);
  143. cmJSONState state;
  144. v["field1"] = "Hello";
  145. v["field2"] = Json::objectValue;
  146. v["field2"]["subfield"] = 2;
  147. v["field3"] = "world!";
  148. v["extra"] = "extra";
  149. ObjectStruct s1;
  150. ASSERT_TRUE(helper(s1, &v, &state));
  151. ASSERT_TRUE(s1.Field1 == "Hello");
  152. ASSERT_TRUE(s1.Field2 == 2);
  153. v["field2"]["subfield"] = "wrong";
  154. ObjectStruct s2;
  155. ASSERT_TRUE(!helper(s2, &v, &state));
  156. v["field2"].removeMember("subfield");
  157. ObjectStruct s3;
  158. ASSERT_TRUE(!helper(s3, &v, &state));
  159. v.removeMember("field2");
  160. ObjectStruct s4;
  161. ASSERT_TRUE(!helper(s4, &v, &state));
  162. v["field2"] = Json::objectValue;
  163. v["field2"]["subfield"] = 2;
  164. v["field3"] = 3;
  165. ObjectStruct s5;
  166. ASSERT_TRUE(!helper(s5, &v, &state));
  167. v.removeMember("field3");
  168. ObjectStruct s6;
  169. ASSERT_TRUE(!helper(s6, &v, &state));
  170. v = "Hello";
  171. ObjectStruct s7;
  172. ASSERT_TRUE(!helper(s7, &v, &state));
  173. ObjectStruct s8;
  174. ASSERT_TRUE(!helper(s8, nullptr, &state));
  175. return true;
  176. }
  177. bool testObjectInherited()
  178. {
  179. auto const helper =
  180. JSONHelperBuilder::Object<InheritedStruct>(ErrorMessages::InvalidObject,
  181. true)
  182. .Bind("field1"_s, &InheritedStruct::Field1, StringHelper)
  183. .Bind("field2"_s, &InheritedStruct::Field2, IntHelper)
  184. .Bind("field3"_s, &InheritedStruct::Field3, StringHelper);
  185. Json::Value v(Json::objectValue);
  186. cmJSONState state;
  187. v["field1"] = "Hello";
  188. v["field2"] = 2;
  189. v["field3"] = "world!";
  190. v["extra"] = "extra";
  191. InheritedStruct s1;
  192. ASSERT_TRUE(helper(s1, &v, &state));
  193. ASSERT_TRUE(s1.Field1 == "Hello");
  194. ASSERT_TRUE(s1.Field2 == 2);
  195. ASSERT_TRUE(s1.Field3 == "world!");
  196. v["field2"] = "wrong";
  197. InheritedStruct s2;
  198. ASSERT_TRUE(!helper(s2, &v, &state));
  199. v.removeMember("field2");
  200. InheritedStruct s3;
  201. ASSERT_TRUE(!helper(s3, &v, &state));
  202. v["field2"] = 2;
  203. v["field3"] = 3;
  204. InheritedStruct s4;
  205. ASSERT_TRUE(!helper(s4, &v, &state));
  206. v.removeMember("field3");
  207. InheritedStruct s5;
  208. ASSERT_TRUE(!helper(s5, &v, &state));
  209. v = "Hello";
  210. InheritedStruct s6;
  211. ASSERT_TRUE(!helper(s6, &v, &state));
  212. InheritedStruct s7;
  213. ASSERT_TRUE(!helper(s7, nullptr, &state));
  214. return true;
  215. }
  216. bool testObjectNoExtra()
  217. {
  218. auto const helper = JSONHelperBuilder::Object<ObjectStruct>(
  219. ErrorMessages::InvalidObject, false)
  220. .Bind("field1"_s, &ObjectStruct::Field1, StringHelper)
  221. .Bind("field2"_s, &ObjectStruct::Field2, IntHelper);
  222. Json::Value v(Json::objectValue);
  223. cmJSONState state;
  224. v["field1"] = "Hello";
  225. v["field2"] = 2;
  226. ObjectStruct s1;
  227. ASSERT_TRUE(helper(s1, &v, &state));
  228. ASSERT_TRUE(s1.Field1 == "Hello");
  229. ASSERT_TRUE(s1.Field2 == 2);
  230. v["extra"] = "world!";
  231. ObjectStruct s2;
  232. ASSERT_TRUE(!helper(s2, &v, &state));
  233. return true;
  234. }
  235. bool testObjectOptional()
  236. {
  237. auto const helper =
  238. JSONHelperBuilder::Object<ObjectStruct>(ErrorMessages::InvalidObject, true)
  239. .Bind("field1"_s, &ObjectStruct::Field1, StringHelper, false)
  240. .Bind("field2"_s, &ObjectStruct::Field2, IntHelper, false)
  241. .Bind<std::string>("field3_s", nullptr, StringHelper, false);
  242. Json::Value v(Json::objectValue);
  243. cmJSONState state;
  244. v["field1"] = "Hello";
  245. v["field2"] = 2;
  246. v["field3"] = "world!";
  247. v["extra"] = "extra";
  248. ObjectStruct s1;
  249. ASSERT_TRUE(helper(s1, &v, &state));
  250. ASSERT_TRUE(s1.Field1 == "Hello");
  251. ASSERT_TRUE(s1.Field2 == 2);
  252. v = Json::objectValue;
  253. ObjectStruct s2;
  254. ASSERT_TRUE(helper(s2, &v, &state));
  255. ASSERT_TRUE(s2.Field1 == "default");
  256. ASSERT_TRUE(s2.Field2 == 1);
  257. ObjectStruct s3;
  258. ASSERT_TRUE(helper(s3, nullptr, &state));
  259. ASSERT_TRUE(s3.Field1 == "default");
  260. ASSERT_TRUE(s3.Field2 == 1);
  261. return true;
  262. }
  263. bool testVector()
  264. {
  265. Json::Value v(Json::arrayValue);
  266. cmJSONState state;
  267. v.append("Hello");
  268. v.append("world!");
  269. v.append("ignore");
  270. std::vector<std::string> l{ "default" };
  271. std::vector<std::string> expected{ "Hello", "world!", "ignore" };
  272. ASSERT_TRUE(StringVectorHelper(l, &v, &state));
  273. ASSERT_TRUE(l == expected);
  274. v[1] = 2;
  275. l = { "default" };
  276. ASSERT_TRUE(!StringVectorHelper(l, &v, &state));
  277. v = "Hello";
  278. l = { "default" };
  279. ASSERT_TRUE(!StringVectorHelper(l, &v, &state));
  280. l = { "default" };
  281. ASSERT_TRUE(StringVectorHelper(l, nullptr, &state));
  282. ASSERT_TRUE(l.empty());
  283. return true;
  284. }
  285. bool testVectorFilter()
  286. {
  287. Json::Value v(Json::arrayValue);
  288. cmJSONState state;
  289. v.append("Hello");
  290. v.append("world!");
  291. v.append("ignore");
  292. std::vector<std::string> l{ "default" };
  293. std::vector<std::string> expected{
  294. "Hello",
  295. "world!",
  296. };
  297. ASSERT_TRUE(StringVectorFilterHelper(l, &v, &state));
  298. ASSERT_TRUE(l == expected);
  299. v[1] = 2;
  300. l = { "default" };
  301. ASSERT_TRUE(!StringVectorFilterHelper(l, &v, &state));
  302. v = "Hello";
  303. l = { "default" };
  304. ASSERT_TRUE(!StringVectorFilterHelper(l, &v, &state));
  305. l = { "default" };
  306. ASSERT_TRUE(StringVectorFilterHelper(l, nullptr, &state));
  307. ASSERT_TRUE(l.empty());
  308. return true;
  309. }
  310. bool testMap()
  311. {
  312. Json::Value v(Json::objectValue);
  313. v["field1"] = "Hello";
  314. v["field2"] = "world!";
  315. v["ignore"] = "ignore";
  316. cmJSONState state;
  317. std::map<std::string, std::string> m{ { "key", "default" } };
  318. std::map<std::string, std::string> expected{ { "field1", "Hello" },
  319. { "field2", "world!" },
  320. { "ignore", "ignore" } };
  321. ASSERT_TRUE(StringMapHelper(m, &v, &state));
  322. ASSERT_TRUE(m == expected);
  323. v = Json::arrayValue;
  324. m = { { "key", "default" } };
  325. ASSERT_TRUE(!StringMapHelper(m, &v, &state));
  326. m = { { "key", "default" } };
  327. ASSERT_TRUE(StringMapHelper(m, nullptr, &state));
  328. ASSERT_TRUE(m.empty());
  329. return true;
  330. }
  331. bool testMapFilter()
  332. {
  333. Json::Value v(Json::objectValue);
  334. cmJSONState state;
  335. v["field1"] = "Hello";
  336. v["field2"] = "world!";
  337. v["ignore"] = "ignore";
  338. std::map<std::string, std::string> m{ { "key", "default" } };
  339. std::map<std::string, std::string> expected{ { "field1", "Hello" },
  340. { "field2", "world!" } };
  341. ASSERT_TRUE(StringMapFilterHelper(m, &v, &state));
  342. ASSERT_TRUE(m == expected);
  343. v = Json::arrayValue;
  344. m = { { "key", "default" } };
  345. ASSERT_TRUE(!StringMapFilterHelper(m, &v, &state));
  346. m = { { "key", "default" } };
  347. ASSERT_TRUE(StringMapFilterHelper(m, nullptr, &state));
  348. ASSERT_TRUE(m.empty());
  349. return true;
  350. }
  351. bool testOptional()
  352. {
  353. Json::Value v = "Hello";
  354. cmJSONState state;
  355. cm::optional<std::string> str{ "default" };
  356. ASSERT_TRUE(OptionalStringHelper(str, &v, &state));
  357. ASSERT_TRUE(str == "Hello");
  358. str.emplace("default");
  359. ASSERT_TRUE(OptionalStringHelper(str, nullptr, &state));
  360. ASSERT_TRUE(str == cm::nullopt);
  361. return true;
  362. }
  363. bool testRequired()
  364. {
  365. Json::Value v = "Hello";
  366. std::string str = "default";
  367. int i = 1;
  368. cmJSONState state;
  369. ASSERT_TRUE(RequiredStringHelper(str, &v, &state));
  370. ASSERT_TRUE(str == "Hello");
  371. ASSERT_TRUE(!RequiredIntHelper(i, &v, &state));
  372. v = 2;
  373. str = "default";
  374. i = 1;
  375. ASSERT_TRUE(!RequiredStringHelper(str, &v, &state));
  376. ASSERT_TRUE(RequiredIntHelper(i, &v, &state));
  377. ASSERT_TRUE(i == 2);
  378. str = "default";
  379. i = 1;
  380. ASSERT_TRUE(!RequiredStringHelper(str, nullptr, &state));
  381. ASSERT_TRUE(!RequiredIntHelper(i, nullptr, &state));
  382. return true;
  383. }
  384. }
  385. int testJSONHelpers(int /*unused*/, char* /*unused*/[])
  386. {
  387. if (!testInt()) {
  388. return 1;
  389. }
  390. if (!testUInt()) {
  391. return 1;
  392. }
  393. if (!testBool()) {
  394. return 1;
  395. }
  396. if (!testString()) {
  397. return 1;
  398. }
  399. if (!testObject()) {
  400. return 1;
  401. }
  402. if (!testObjectInherited()) {
  403. return 1;
  404. }
  405. if (!testObjectNoExtra()) {
  406. return 1;
  407. }
  408. if (!testObjectOptional()) {
  409. return 1;
  410. }
  411. if (!testVector()) {
  412. return 1;
  413. }
  414. if (!testVectorFilter()) {
  415. return 1;
  416. }
  417. if (!testMap()) {
  418. return 1;
  419. }
  420. if (!testMapFilter()) {
  421. return 1;
  422. }
  423. if (!testOptional()) {
  424. return 1;
  425. }
  426. if (!testRequired()) {
  427. return 1;
  428. }
  429. return 0;
  430. }