json_binder_object.t.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. //
  2. // json_binder_object.t.h
  3. // json
  4. //
  5. // Created by Sam Jaffe on 2/27/17.
  6. //
  7. #pragma once
  8. #include <cxxtest/TestSuite.h>
  9. #include "json/json_binder.hpp"
  10. using namespace json::binder;
  11. using namespace json::parser;
  12. class json_binder_object_TestSuite : public CxxTest::TestSuite {
  13. public:
  14. using vec_t = std::vector<int>;
  15. using map_t = std::map<std::string, vec_t>;
  16. struct TestObject {
  17. int count;
  18. double average;
  19. std::map<std::string, std::vector<int>> data;
  20. bool operator==(TestObject const & other) const {
  21. return count == other.count && average == other.average && data == other.data;
  22. }
  23. };
  24. static object_binder<TestObject> GetImpl() {
  25. return object_binder<TestObject>()
  26. ("count", &TestObject::count)
  27. ("average", &TestObject::average)
  28. ("data", direct_binder<TestObject, map_t>(&TestObject::data));
  29. }
  30. static object_binder<TestObject> & Get() {
  31. static object_binder<TestObject> val = GetImpl();
  32. return val;
  33. }
  34. void test_construct_object_from_json() {
  35. char data[] = "{ \"count\":10, \"average\":1.0, \"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }}";
  36. TestObject out = { 0, 0.0, {} };
  37. TestObject expected = { 10, 1.0, {{"key1", {1, 2}},{"key2", {3, 4}}} };
  38. TS_ASSERT_THROWS_NOTHING(parse(json::binder::bind(out, Get()), data, allow_all));
  39. TS_ASSERT_EQUALS(out, expected);
  40. }
  41. void test_permits_extra_keys() {
  42. char data[] = "{ \"count\":10, \"average\":1.0, \"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }, \"lemon\":true}";
  43. TestObject out = { 0, 0.0, {} };
  44. TestObject expected = { 10, 1.0, {{"key1", {1, 2}},{"key2", {3, 4}}} };
  45. TS_ASSERT_THROWS_NOTHING(parse(json::binder::bind(out, Get()), data, allow_all));
  46. TS_ASSERT_EQUALS(out, expected);
  47. }
  48. void test_throws_on_extra_keys_with_flag() {
  49. char data[] = "{ \"count\":10, \"average\":1.0, \"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }, \"lemon\":true}";
  50. TestObject out = { 0, 0.0, {} };
  51. TS_ASSERT_THROWS(parse(json::binder::bind(out, Get()), data,
  52. disable_unknown_keys),
  53. json::malformed_json_exception);
  54. }
  55. void test_permits_missing_keys() {
  56. char data[] = "{ \"count\":10, \"average\":1.0 }";
  57. TestObject out = { 0, 0.0, {} };
  58. TestObject expected = { 10, 1.0, {} };
  59. TS_ASSERT_THROWS_NOTHING(parse(json::binder::bind(out, Get()), data, allow_all));
  60. TS_ASSERT_EQUALS(out, expected);
  61. }
  62. void test_throws_if_missing_keys_with_flag() {
  63. char data[] = "{ \"count\":10, \"average\":1.0 }";
  64. TestObject out = { 0, 0.0, {} };
  65. TS_ASSERT_THROWS(parse(json::binder::bind(out, Get()), data,
  66. disable_missing_keys),
  67. json::malformed_json_exception);
  68. }
  69. void test_throws_if_object_unstarted() {
  70. char data[] = "\"count\":10, \"average\":1.0, \"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] } }";
  71. TestObject out = { 0, 0.0, {} };
  72. TS_ASSERT_THROWS(parse(json::binder::bind(out, Get()), data, allow_all),
  73. json::malformed_json_exception);
  74. }
  75. void test_throws_if_object_missing_associative_token() {
  76. char data[] = "{ \"count\":10, \"average\":1.0, \"data\": }";
  77. TestObject out = { 0, 0.0, {} };
  78. TS_ASSERT_THROWS(parse(json::binder::bind(out, Get()), data, allow_all),
  79. json::malformed_json_exception);
  80. }
  81. void test_throws_if_object_unterminated() {
  82. char data[] = "{ \"count\":10, \"average\":1.0, \"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }";
  83. TestObject out = { 0, 0.0, {} };
  84. TS_ASSERT_THROWS(parse(json::binder::bind(out, Get()), data, allow_all),
  85. json::unterminated_json_exception);
  86. }
  87. void test_throws_if_object_missing_associative_token_discard_t() {
  88. char data[] = "{ \"count\":10, \"average\":1.0, \"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }, \"lemon\":{\"key\": } }";
  89. TestObject out = { 0, 0.0, {} };
  90. TS_ASSERT_THROWS(parse(json::binder::bind(out, Get()), data, allow_all),
  91. json::malformed_json_exception);
  92. }
  93. void test_throws_if_object_unterminated_array_discard_t() {
  94. char data[] = "{ \"count\":10, \"average\":1.0, \"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }, \"lemon\":[1.0 }";
  95. TestObject out = { 0, 0.0, {} };
  96. TS_ASSERT_THROWS(parse(json::binder::bind(out, Get()), data, allow_all),
  97. json::unterminated_json_exception);
  98. }
  99. void test_throws_if_object_unterminated_object_discard_t() {
  100. char data[] = "{ \"count\":10, \"average\":1.0, \"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }, \"lemon\":{\"key\":false }";
  101. TestObject out = { 0, 0.0, {} };
  102. TS_ASSERT_THROWS(parse(json::binder::bind(out, Get()), data, allow_all),
  103. json::unterminated_json_exception);
  104. }
  105. std::string ify(double value) {
  106. std::stringstream ss;
  107. ss << std::fixed << value;
  108. return ss.str();
  109. }
  110. void test_write_object_is_composed_of_correct_data() {
  111. std::string const dbl = ify(1.0);
  112. std::string const expected = "{\"average\":"+dbl+",\"count\":10,\"data\":{\"key1\":[1,2],\"key2\":[3,4]}}";
  113. std::stringstream ss;
  114. TestObject const in = { 10, 1.0, { { "key1", {1, 2} }, { "key2", {3, 4} } } };
  115. TS_ASSERT_THROWS_NOTHING(write(json::binder::bind(in, Get()), ss));
  116. TS_ASSERT_EQUALS(ss.str(), expected);
  117. }
  118. };