// // json_binder_object.t.h // json // // Created by Sam Jaffe on 2/27/17. // #include "json/json_binder.hpp" #include using namespace json::binder; using namespace json::parser; using vec_t = std::vector; using map_t = std::map; struct TestObject { int count; double average; map_t data; }; bool operator==(TestObject const & lhs, TestObject const & rhs) { return lhs.count == rhs.count && lhs.average == rhs.average && lhs.data == rhs.data; } class JsonBinderObjectTest : public ::testing::Test { protected: static object_binder & GetBinder() { static object_binder val = object_binder()( "count", &TestObject::count)("average", &TestObject::average)( "data", direct_binder(&TestObject::data)); return val; } }; TEST_F(JsonBinderObjectTest, ParsesSuccessfully) { char data[] = "{ \"count\":10, \"average\":1.0, " "\"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }}"; TestObject out = {0, 0.0, {}}; TestObject expected = {10, 1.0, {{"key1", {1, 2}}, {"key2", {3, 4}}}}; EXPECT_NO_THROW(parse(json::binder::bind(out, GetBinder()), data, allow_all)); EXPECT_THAT(out, expected); } TEST_F(JsonBinderObjectTest, IgnoresUnknownKeysByDefault) { char data[] = "{ \"count\":10, \"average\":1.0, " "\"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }, " "\"lemon\":true}"; TestObject out = {0, 0.0, {}}; TestObject expected = {10, 1.0, {{"key1", {1, 2}}, {"key2", {3, 4}}}}; EXPECT_NO_THROW(parse(json::binder::bind(out, GetBinder()), data, allow_all)); EXPECT_THAT(out, expected); } TEST_F(JsonBinderObjectTest, ThrowsOnUnknownKeyWithSetting) { char data[] = "{ \"count\":10, \"average\":1.0, " "\"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }, " "\"lemon\":true}"; TestObject out = {0, 0.0, {}}; EXPECT_THROW( parse(json::binder::bind(out, GetBinder()), data, disable_unknown_keys), json::malformed_json_exception); } TEST_F(JsonBinderObjectTest, AllowsMissingExpectedKeysByDefault) { char data[] = "{ \"count\":10, \"average\":1.0 }"; TestObject out = {0, 0.0, {}}; TestObject expected = {10, 1.0, {}}; EXPECT_NO_THROW(parse(json::binder::bind(out, GetBinder()), data, allow_all)); EXPECT_THAT(out, expected); } TEST_F(JsonBinderObjectTest, ThrowsOnMissingExpectedKeyWithSetting) { char data[] = "{ \"count\":10, \"average\":1.0 }"; TestObject out = {0, 0.0, {}}; EXPECT_THROW( parse(json::binder::bind(out, GetBinder()), data, disable_missing_keys), json::malformed_json_exception); } TEST_F(JsonBinderObjectTest, ThrowsMalformedObjectKey) { char data[] = "{ count\":10, \"average\":1.0 }"; TestObject out = {0, 0.0, {}}; EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data, allow_all), json::malformed_json_exception); } TEST_F(JsonBinderObjectTest, ThrowsMalformedObjectAssoc) { char data[] = "{ \"count\"=10, \"average\":1.0 }"; TestObject out = {0, 0.0, {}}; EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data, allow_all), json::malformed_json_exception); } TEST_F(JsonBinderObjectTest, ThrowsOnMissingStartToken) { char data[] = "\"count\":10, \"average\":1.0, " "\"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] } }"; TestObject out = {0, 0.0, {}}; EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data, allow_all), json::malformed_json_exception); } TEST_F(JsonBinderObjectTest, ThrowsIfMissingValueForKey) { char data[] = "{ \"count\":10, \"average\":1.0, \"data\": }"; TestObject out = {0, 0.0, {}}; EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data, allow_all), json::malformed_json_exception); } TEST_F(JsonBinderObjectTest, ThrowsOnMissingEndToken) { char data[] = "{ \"count\":10, \"average\":1.0, " "\"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }"; TestObject out = {0, 0.0, {}}; EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data, allow_all), json::unterminated_json_exception); } TEST_F(JsonBinderObjectTest, ThrowsOnMissingEndTokenAfterUnknownKey) { char data[] = "{ \"count\":10, \"average\":1.0, " "\"data\":{ \"key1\":[1, 2], \"key2\":[3, 4] }, " "\"lemon\":{\"key\":false }"; TestObject out = {0, 0.0, {}}; EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data, allow_all), json::unterminated_json_exception); } std::string ify(double value) { std::stringstream ss; ss << std::fixed << value; return ss.str(); } TEST_F(JsonBinderObjectTest, WritesBackOriginalObject) { std::string const dbl = ify(1.0); std::string const expected = "{\"average\":1.000000,\"count\":10," "\"data\":{\"key1\":[1,2],\"key2\":[3,4]}}"; std::stringstream ss; TestObject const in = {10, 1.0, {{"key1", {1, 2}}, {"key2", {3, 4}}}}; EXPECT_NO_THROW(write(json::binder::bind(in, GetBinder()), ss)); EXPECT_THAT(ss.str(), expected); }