diff options
-rw-r--r-- | lib/jsonParse-persistance.cpp | 11 | ||||
-rw-r--r-- | lib/jsonParse-persistance.h | 13 | ||||
-rw-r--r-- | lib/persistance.cpp | 11 | ||||
-rw-r--r-- | lib/persistance.h | 68 | ||||
-rw-r--r-- | test/Jamfile.jam | 3 | ||||
-rw-r--r-- | test/fixtures/json/abs.json | 7 | ||||
-rw-r--r-- | test/fixtures/json/empty.json | 6 | ||||
-rw-r--r-- | test/fixtures/json/empty_abs.json | 6 | ||||
-rw-r--r-- | test/fixtures/json/implicit.json | 8 | ||||
-rw-r--r-- | test/fixtures/json/implicit_abs.json | 8 | ||||
-rw-r--r-- | test/fixtures/json/load_object.json | 55 | ||||
-rw-r--r-- | test/fixtures/json/nested.json | 21 | ||||
-rw-r--r-- | test/fixtures/json/vector_ptr.json | 13 | ||||
-rw-r--r-- | test/test-persistance.cpp | 144 |
14 files changed, 311 insertions, 63 deletions
diff --git a/lib/jsonParse-persistance.cpp b/lib/jsonParse-persistance.cpp index 89887da..ad9fc2a 100644 --- a/lib/jsonParse-persistance.cpp +++ b/lib/jsonParse-persistance.cpp @@ -1,11 +1,10 @@ #include "jsonParse-persistance.h" namespace Persistanace { - JsonParsePersistance::JsonParsePersistance(std::istream & in) : json::jsonParser {&in} { } - void - JsonParsePersistance::loadState() + JsonParsePersistance::loadState(std::istream & in) { + this->switch_streams(&in, nullptr); yy_push_state(0); yylex(); } @@ -13,7 +12,8 @@ namespace Persistanace { void JsonParsePersistance::BeginObject() { - stk.push(current()->BeginObject()); + current()->beforeValue(stk); + current()->BeginObject(stk); } void @@ -61,7 +61,8 @@ namespace Persistanace { void JsonParsePersistance::EndObject() { - stk.pop(); + current()->EndObject(stk); + current()->EndObject(stk); } template<typename T> diff --git a/lib/jsonParse-persistance.h b/lib/jsonParse-persistance.h index d5c76ed..bea93e0 100644 --- a/lib/jsonParse-persistance.h +++ b/lib/jsonParse-persistance.h @@ -11,18 +11,18 @@ namespace Persistanace { class JsonParsePersistance : public json::jsonParser { public: - explicit JsonParsePersistance(std::istream & in); - template<typename T> - void - loadState(T & t) + inline T + loadState(std::istream & in) { + T t {}; stk.push(std::make_unique<SelectionT<T>>(std::ref(t))); - loadState(); + loadState(in); + return t; } protected: - void loadState(); + void loadState(std::istream & in); void BeginObject() override; void BeginArray() override; @@ -34,7 +34,6 @@ namespace Persistanace { void EndArray() override; void EndObject() override; - private: Stack stk; template<typename T> inline void PushValue(T && value); diff --git a/lib/persistance.cpp b/lib/persistance.cpp index 7539b44..bdcbe9f 100644 --- a/lib/persistance.cpp +++ b/lib/persistance.cpp @@ -47,8 +47,8 @@ namespace Persistanace { throw std::runtime_error("Unexpected array"); } - SelectionPtr - Selection::BeginObject() + void + Selection::BeginObject(Stack &) { throw std::runtime_error("Unexpected object"); } @@ -62,7 +62,12 @@ namespace Persistanace { SelectionPtr Selection::select(const std::string &) { - throw std::runtime_error("Unexpected persist"); + throw std::runtime_error("Unexpected select"); + } + + void + Selection::EndObject(Stack &) + { } static_assert(!SelectionT<float>::ArrayLike); diff --git a/lib/persistance.h b/lib/persistance.h index 92366f2..7f28ad1 100644 --- a/lib/persistance.h +++ b/lib/persistance.h @@ -32,7 +32,8 @@ namespace Persistanace { virtual void operator()(const std::nullptr_t &); virtual void operator()(std::string &); virtual void BeginArray(Stack &); - virtual SelectionPtr BeginObject(); + virtual void BeginObject(Stack &); + virtual void EndObject(Stack &); virtual void beforeValue(Stack &); virtual SelectionPtr select(const std::string &); }; @@ -94,28 +95,13 @@ namespace Persistanace { explicit SelectionT(std::vector<T> & value) : v {value} { } void - BeginArray(Stack &) override - { - } - - void - beforeValue(Stack & stk) override + BeginArray(Stack & stk) override { stk.push(std::make_unique<SelectionT<T>>(std::ref(v.emplace_back()))); } - static constexpr bool ArrayLike {true}; - std::vector<T> & v; - }; - - template<typename T> - concept ArrayLike = SelectionT<T>::ArrayLike; - - template<ArrayLike T> struct SelectionT<std::vector<T>> : public Selection { - explicit SelectionT(std::vector<T> & value) : v {value} { } - void - BeginArray(Stack & stk) override + beforeValue(Stack & stk) override { stk.push(std::make_unique<SelectionT<T>>(std::ref(v.emplace_back()))); } @@ -172,10 +158,12 @@ namespace Persistanace { } else { if (!v) { - if constexpr (!std::is_abstract_v<T>) { + if constexpr (std::is_abstract_v<T>) { + throw std::runtime_error("cannot select member of null object"); + } + else { v = std::make_unique<T>(); } - throw std::runtime_error("cannot select member of null object"); } PersistanceStore ps {mbr}; v->persist(ps); @@ -183,18 +171,48 @@ namespace Persistanace { } } + void + EndObject(Stack & stk) override + { + if (!v) { + if constexpr (std::is_abstract_v<T>) { + throw std::runtime_error("cannot default create abstract object"); + } + else { + v = std::make_unique<T>(); + } + } + stk.pop(); + } + Ptr & v; }; - explicit SelectionT(std::unique_ptr<T> & o) : v {o} { } + explicit SelectionT(Ptr & o) : v {o} { } + + void + beforeValue(Stack &) override + { + } + + void + operator()(const std::nullptr_t &) override + { + v.reset(); + } - SelectionPtr - BeginObject() override + void + BeginObject(Stack & stk) override + { + stk.push(std::make_unique<SelectionObj>(v)); + } + void + EndObject(Stack & stk) override { - return std::make_unique<SelectionObj>(v); + stk.pop(); } - std::unique_ptr<T> & v; + Ptr & v; }; } diff --git a/test/Jamfile.jam b/test/Jamfile.jam index c065dd8..cfa1f21 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -1,4 +1,5 @@ import testing ; +import sequence ; lib boost_unit_test_framework ; @@ -18,4 +19,4 @@ run test-collection.cpp ; run test-obj.cpp ; run test-maths.cpp ; run test-network.cpp ; -run test-persistance.cpp ; +run test-persistance.cpp : -- : [ sequence.insertion-sort [ glob fixtures/json/*.json ] ] ; diff --git a/test/fixtures/json/abs.json b/test/fixtures/json/abs.json new file mode 100644 index 0000000..8492df3 --- /dev/null +++ b/test/fixtures/json/abs.json @@ -0,0 +1,7 @@ +{ + "aptr": { + "@typeid": "SubObject", + "base": "set base", + "sub": "set sub" + } +} diff --git a/test/fixtures/json/empty.json b/test/fixtures/json/empty.json new file mode 100644 index 0000000..a9193a3 --- /dev/null +++ b/test/fixtures/json/empty.json @@ -0,0 +1,6 @@ +{ + "@typeid": "TestObject", + "flt": 1, + "ptr": {}, + "str": "after" +} diff --git a/test/fixtures/json/empty_abs.json b/test/fixtures/json/empty_abs.json new file mode 100644 index 0000000..7d22001 --- /dev/null +++ b/test/fixtures/json/empty_abs.json @@ -0,0 +1,6 @@ +{ + "@typeid": "TestObject", + "flt": 1, + "aptr": {}, + "str": "after" +} diff --git a/test/fixtures/json/implicit.json b/test/fixtures/json/implicit.json new file mode 100644 index 0000000..03dec4b --- /dev/null +++ b/test/fixtures/json/implicit.json @@ -0,0 +1,8 @@ +{ + "@typeid": "TestObject", + "flt": 1, + "ptr": { + "str": "trigger" + }, + "str": "after" +} diff --git a/test/fixtures/json/implicit_abs.json b/test/fixtures/json/implicit_abs.json new file mode 100644 index 0000000..573b323 --- /dev/null +++ b/test/fixtures/json/implicit_abs.json @@ -0,0 +1,8 @@ +{ + "@typeid": "TestObject", + "flt": 1, + "aptr": { + "str": "trigger" + }, + "str": "after" +} diff --git a/test/fixtures/json/load_object.json b/test/fixtures/json/load_object.json new file mode 100644 index 0000000..bb32298 --- /dev/null +++ b/test/fixtures/json/load_object.json @@ -0,0 +1,55 @@ +{ + "@typeid": "TestObject", + "flt": 3.14, + "str": "Lovely string", + "bl": true, + "pos": [ + 3.14, + 6.28, + 1.57 + ], + "flts": [ + 3.14, + 6.28, + 1.57, + 0, + -1, + -3.14 + ], + "poss": [ + [ + 3.14, + 6.28, + 1.57 + ], + [ + 0, + -1, + -3.14 + ] + ], + "nest": [ + [ + [ + "a", + "b" + ], + [ + "c", + "d", + "e" + ] + ], + [ + [ + "f" + ] + ], + [] + ], + "ptr": { + "@typeid": "TestObject", + "flt": 3.14, + "str": "Lovely string" + } +} diff --git a/test/fixtures/json/nested.json b/test/fixtures/json/nested.json new file mode 100644 index 0000000..98951fc --- /dev/null +++ b/test/fixtures/json/nested.json @@ -0,0 +1,21 @@ +{ + "@typeid": "TestObject", + "flt": 1, + "ptr": { + "@typeid": "TestObject", + "flt": 2, + "ptr": { + "@typeid": "TestObject", + "flt": 3, + "ptr": { + "@typeid": "TestObject", + "flt": 4, + "ptr": null, + "str": "four" + }, + "str": "three" + }, + "str": "two" + }, + "str": "one" +} diff --git a/test/fixtures/json/vector_ptr.json b/test/fixtures/json/vector_ptr.json new file mode 100644 index 0000000..8a07a2e --- /dev/null +++ b/test/fixtures/json/vector_ptr.json @@ -0,0 +1,13 @@ +{ + "vptr": [ + { + "@typeid": "TestObject", + "str": "type" + }, + { + "flt": 3.14 + }, + null, + {} + ] +} diff --git a/test/test-persistance.cpp b/test/test-persistance.cpp index 101c2d2..fb90de2 100644 --- a/test/test-persistance.cpp +++ b/test/test-persistance.cpp @@ -6,9 +6,38 @@ #include <iosfwd> #include <jsonParse-persistance.h> #include <memory> +#include <stdexcept> #include <string> #include <vector> +struct AbsObject : public Persistanace::Persistable { + std::string base; + + void + persist(Persistanace::PersistanceStore & store) override + { + STORE_MEMBER(base); + } + + virtual void dummy() const = 0; +}; + +struct SubObject : public AbsObject { + std::string sub; + + void + persist(Persistanace::PersistanceStore & store) override + { + AbsObject::persist(store); + STORE_MEMBER(sub); + } + + void + dummy() const override + { + } +}; + struct TestObject : public Persistanace::Persistable { TestObject() = default; @@ -20,39 +49,44 @@ struct TestObject : public Persistanace::Persistable { std::vector<glm::vec3> poss; std::vector<std::vector<std::vector<std::string>>> nest; std::unique_ptr<TestObject> ptr; + std::unique_ptr<AbsObject> aptr; + std::vector<std::unique_ptr<TestObject>> vptr; void persist(Persistanace::PersistanceStore & store) override { STORE_MEMBER(flt) && STORE_MEMBER(str) && STORE_MEMBER(bl) && STORE_MEMBER(pos) && STORE_MEMBER(flts) - && STORE_MEMBER(poss) && STORE_MEMBER(nest) && STORE_MEMBER(ptr); + && STORE_MEMBER(poss) && STORE_MEMBER(nest) && STORE_MEMBER(ptr) && STORE_MEMBER(aptr) + && STORE_MEMBER(vptr); } }; -const std::string input(R"J({ - "@typeid": "TestObject", - "flt": 3.14, - "str": "Lovely string", - "bl": true, - "pos": [3.14, 6.28, 1.57], - "flts": [3.14, 6.28, 1.57, 0, -1, -3.14], - "poss": [[3.14, 6.28, 1.57], [0, -1, -3.14]], - "nest": [[["a","b"],["c","d","e"]],[["f"]],[]], - "ptr": { - "@typeid": "TestObject", - "flt": 3.14, - "str": "Lovely string", - }, -})J"); - -BOOST_AUTO_TEST_CASE(load_object) +BOOST_AUTO_TEST_CASE(setup) { Persistanace::Persistable::addFactory("TestObject", std::make_unique<TestObject>); - std::stringstream ss {input}; - Persistanace::JsonParsePersistance jlps {ss}; - std::unique_ptr<TestObject> to; - jlps.loadState(to); + Persistanace::Persistable::addFactory("SubObject", std::make_unique<SubObject>); +} + +struct JPP : public Persistanace::JsonParsePersistance { + template<typename T> + T + load_json(const char * path) + { + BOOST_TEST_CONTEXT(path) { + std::ifstream ss {path}; + auto to = loadState<T>(ss); + BOOST_CHECK(stk.empty()); + BOOST_REQUIRE(to); + return to; + } + // Presumably BOOST_TEST_CONTEXT is implemented as an if (...) { } + throw std::logic_error("We shouldn't ever get here, but apparently we can!"); + } +}; +BOOST_FIXTURE_TEST_CASE(load_object, JPP) +{ + auto to = load_json<std::unique_ptr<TestObject>>(FIXTURESDIR "json/load_object.json"); BOOST_CHECK_CLOSE(to->flt, 3.14, 0.01); BOOST_CHECK_EQUAL(to->str, "Lovely string"); BOOST_CHECK_EQUAL(to->bl, true); @@ -84,3 +118,69 @@ BOOST_AUTO_TEST_CASE(load_object) BOOST_CHECK_CLOSE(to->ptr->flt, 3.14, 0.01); BOOST_CHECK_EQUAL(to->ptr->str, "Lovely string"); } + +BOOST_FIXTURE_TEST_CASE(load_nested_object, JPP) +{ + auto to = load_json<std::unique_ptr<TestObject>>(FIXTURESDIR "json/nested.json"); + BOOST_CHECK_EQUAL(to->flt, 1.F); + BOOST_CHECK_EQUAL(to->str, "one"); + BOOST_REQUIRE(to->ptr); + BOOST_CHECK_EQUAL(to->ptr->flt, 2.F); + BOOST_CHECK_EQUAL(to->ptr->str, "two"); + BOOST_REQUIRE(to->ptr->ptr); + BOOST_CHECK_EQUAL(to->ptr->ptr->flt, 3.F); + BOOST_CHECK_EQUAL(to->ptr->ptr->str, "three"); + BOOST_REQUIRE(to->ptr->ptr->ptr); + BOOST_CHECK_EQUAL(to->ptr->ptr->ptr->flt, 4.F); + BOOST_CHECK_EQUAL(to->ptr->ptr->ptr->str, "four"); + BOOST_REQUIRE(!to->ptr->ptr->ptr->ptr); +} + +BOOST_FIXTURE_TEST_CASE(load_implicit_object, JPP) +{ + auto to = load_json<std::unique_ptr<TestObject>>(FIXTURESDIR "json/implicit.json"); + BOOST_CHECK(to->ptr); + BOOST_CHECK_EQUAL(to->flt, 1.F); + BOOST_CHECK_EQUAL(to->ptr->str, "trigger"); + BOOST_CHECK_EQUAL(to->str, "after"); +} + +BOOST_FIXTURE_TEST_CASE(load_empty_object, JPP) +{ + auto to = load_json<std::unique_ptr<TestObject>>(FIXTURESDIR "json/empty.json"); + BOOST_CHECK_EQUAL(to->flt, 1.F); + BOOST_CHECK(to->ptr); + BOOST_CHECK_EQUAL(to->str, "after"); +} + +BOOST_FIXTURE_TEST_CASE(fail_implicit_abs_object, JPP) +{ + BOOST_CHECK_THROW(load_json<std::unique_ptr<TestObject>>(FIXTURESDIR "json/implicit_abs.json"), std::runtime_error); +} + +BOOST_FIXTURE_TEST_CASE(fail_empty_abs_object, JPP) +{ + BOOST_CHECK_THROW(load_json<std::unique_ptr<TestObject>>(FIXTURESDIR "json/empty_abs.json"), std::runtime_error); +} + +BOOST_FIXTURE_TEST_CASE(load_abs_object, JPP) +{ + auto to = load_json<std::unique_ptr<TestObject>>(FIXTURESDIR "json/abs.json"); + BOOST_REQUIRE(to->aptr); + BOOST_CHECK_NO_THROW(to->aptr->dummy()); + BOOST_CHECK_EQUAL(to->aptr->base, "set base"); + auto s = dynamic_cast<SubObject *>(to->aptr.get()); + BOOST_REQUIRE(s); + BOOST_CHECK_EQUAL(s->sub, "set sub"); +} + +BOOST_FIXTURE_TEST_CASE(load_vector_ptr, JPP) +{ + auto to = load_json<std::unique_ptr<TestObject>>(FIXTURESDIR "json/vector_ptr.json"); + BOOST_CHECK(to->str.empty()); + BOOST_CHECK_EQUAL(to->vptr.size(), 4); + BOOST_CHECK_EQUAL(to->vptr.at(0)->str, "type"); + BOOST_CHECK_CLOSE(to->vptr.at(1)->flt, 3.14, .01); + BOOST_CHECK(!to->vptr.at(2)); + BOOST_CHECK(to->vptr.at(3)->str.empty()); +} |