| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- //
- // json_binder_polymorphic.t.h
- // json
- //
- // Created by Sam Jaffe on 11/14/18.
- // Copyright © 2018 Sam Jaffe. All rights reserved.
- //
- #include "json/json_binder.hpp"
- #include <gmock/gmock.h>
- struct Base {
- virtual ~Base() = default;
- virtual void run() const = 0;
- };
- struct Left : public Base {
- int a;
- void run() const override {}
- };
- struct Right : public Base {
- std::string a;
- void run() const override {}
- };
- struct Middle : public Base {
- std::tuple<int, std::string> a;
- void run() const override {}
- };
- bool operator==(Left const & lhs, Left const & rhs) { return lhs.a == rhs.a; }
- bool operator==(Right const & lhs, Right const & rhs) { return lhs.a == rhs.a; }
- using namespace json::binder;
- using namespace json::parser;
- class JsonBinderPolymorphicTest : public ::testing::Test {
- protected:
- using pBase = std::unique_ptr<Base>;
- polymorphic_binder<pBase> & GetBinder() {
- static polymorphic_binder<pBase> val = polymorphic_binder<pBase>()(
- "Left", object_binder<Left>()("a", &Left::a))(
- "Right", object_binder<Right>()("a", &Right::a));
- return val;
- }
- };
- template <typename T> bool instanceof (Base * ptr) {
- return dynamic_cast<T *>(ptr) != nullptr;
- }
- using namespace ::testing;
- TEST_F(JsonBinderPolymorphicTest, CanHitLeftPolymorph) {
- char data[] = "{\"@id\":\"Left\", \"@value\":{\"a\":1}}";
- pBase out;
- Left expected;
- expected.a = 1;
- EXPECT_NO_THROW(parse(json::binder::bind(out, GetBinder()), data));
- EXPECT_THAT(out, Not(IsNull()));
- EXPECT_PRED1(instanceof <Left>, out.get());
- EXPECT_THAT(dynamic_cast<Left &>(*out), expected);
- }
- TEST_F(JsonBinderPolymorphicTest, CanHitRightPolymorph) {
- char data[] = "{\"@id\":\"Right\", \"@value\":{\"a\":\"hello\"}}";
- pBase out;
- Right expected;
- expected.a = "hello";
- EXPECT_NO_THROW(parse(json::binder::bind(out, GetBinder()), data));
- EXPECT_THAT(out, Not(IsNull()));
- EXPECT_PRED1(instanceof <Right>, out.get());
- EXPECT_THAT(dynamic_cast<Right &>(*out), expected);
- }
- TEST_F(JsonBinderPolymorphicTest, ThrowsOnUnknownSubclass) {
- char data[] = "{\"@id\":\"Middle\", \"@value\":{\"a\":[]]}}";
- pBase out;
- EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
- json::malformed_json_exception);
- EXPECT_THAT(out, IsNull());
- }
- TEST_F(JsonBinderPolymorphicTest, ThrowsOnIdNotString) {
- char data[] = "{\"@id\":0, \"@value\":{\"a\":[]]}}";
- pBase out;
- EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
- json::malformed_json_exception);
- EXPECT_THAT(out, IsNull());
- }
- TEST_F(JsonBinderPolymorphicTest, ThrowsOnUnexpectedKey1) {
- char data[] = "{\"@class\":\"Left\", \"@value\":{\"a\":[]]}}";
- pBase out;
- EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
- json::malformed_json_exception);
- EXPECT_THAT(out, IsNull());
- }
- TEST_F(JsonBinderPolymorphicTest, ThrowsOnUnexpectedKey2) {
- char data[] = "{\"@id\":\"Left\", \"@impl\":null, \"@value\":{\"a\":[]]}}";
- pBase out;
- EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
- json::malformed_json_exception);
- EXPECT_THAT(out, IsNull());
- }
- TEST_F(JsonBinderPolymorphicTest, ThrowsOnUnexpectedKey3) {
- char data[] = "{\"@id\":\"Left\", \"@impl\":{\"a\":[]]}}";
- pBase out;
- EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
- json::malformed_json_exception);
- EXPECT_THAT(out, IsNull());
- }
- TEST_F(JsonBinderPolymorphicTest, ThrowsOnUnterminatedJson) {
- char data[] = "{\"@id\":\"Right\", \"@value\":{\"a\":\"hello\"}";
- pBase out;
- Right expected;
- expected.a = "hello";
- EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
- json::malformed_json_exception);
- EXPECT_THAT(out, Not(IsNull()));
- EXPECT_PRED1(instanceof <Right>, out.get());
- EXPECT_THAT(dynamic_cast<Right &>(*out), expected);
- }
- TEST_F(JsonBinderPolymorphicTest, ThrowsOnMoreData) {
- char data[] = "{\"@id\":\"Right\", \"@value\":{\"a\":\"hello\"},"
- " \"key\":null }";
- pBase out;
- Right expected;
- expected.a = "hello";
- EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
- json::malformed_json_exception);
- EXPECT_THAT(out, Not(IsNull()));
- EXPECT_PRED1(instanceof <Right>, out.get());
- EXPECT_THAT(dynamic_cast<Right &>(*out), expected);
- }
- TEST_F(JsonBinderPolymorphicTest, ThrowsOnNonObject) {
- char data[] = "[\"Right\", \"@value\":{\"a\":\"hello\"}]";
- pBase out;
- Right expected;
- expected.a = "hello";
- EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
- json::malformed_json_exception);
- EXPECT_THAT(out, IsNull());
- }
- TEST_F(JsonBinderPolymorphicTest, ThrowsMalformedObjectKey) {
- char data[] = "{@id\":\"Right\", \"@value\":{\"a\":\"hello\"}}";
- pBase out;
- Right expected;
- expected.a = "hello";
- EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
- json::malformed_json_exception);
- EXPECT_THAT(out, IsNull());
- }
- TEST_F(JsonBinderPolymorphicTest, ThrowsMalformedObjectAssoc) {
- char data[] = "{\"@id\"=\"Right\", \"@value\":{\"a\":\"hello\"}}";
- pBase out;
- Right expected;
- expected.a = "hello";
- EXPECT_THROW(parse(json::binder::bind(out, GetBinder()), data),
- json::malformed_json_exception);
- EXPECT_THAT(out, IsNull());
- }
- TEST_F(JsonBinderPolymorphicTest, WritesRightImplWithoutWhitespace) {
- std::string const expected = R"({"@id":"Right","@value":{"a":"hello"}})";
- Right in;
- in.a = "hello";
- pBase ptr(new Right(in));
- std::stringstream ss;
- EXPECT_NO_THROW(write(json::binder::bind(ptr, GetBinder()), ss));
- EXPECT_THAT(ss.str(), expected);
- }
- TEST_F(JsonBinderPolymorphicTest, WritesLeftImplWithoutWhitespace) {
- std::string const expected = R"({"@id":"Left","@value":{"a":1}})";
- Left in;
- in.a = 1;
- pBase ptr(new Left(in));
- std::stringstream ss;
- EXPECT_NO_THROW(write(json::binder::bind(ptr, GetBinder()), ss));
- EXPECT_THAT(ss.str(), expected);
- }
- TEST_F(JsonBinderPolymorphicTest, ThrowsWhenWritingUnboundImpl) {
- Middle in;
- in.a = {1, "hello"};
- pBase ptr(new Middle(in));
- std::stringstream ss;
- EXPECT_THROW(write(json::binder::bind(ptr, GetBinder()), ss),
- std::domain_error);
- }
- TEST_F(JsonBinderPolymorphicTest, ParsesNullSuccessfully) {
- char const data[] = "null";
- pBase out;
- EXPECT_NO_THROW(parse(json::binder::bind(out, GetBinder()), data));
- EXPECT_THAT(out, IsNull());
- }
- TEST_F(JsonBinderPolymorphicTest, WritesNullSuccessfully) {
- pBase ptr = nullptr;
- std::stringstream ss;
- EXPECT_NO_THROW(write(json::binder::bind(ptr, GetBinder()), ss));
- EXPECT_THAT(ss.str(), "null");
- }
|