summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/jsonParse-persistance.cpp11
-rw-r--r--lib/jsonParse-persistance.h13
-rw-r--r--lib/persistance.cpp11
-rw-r--r--lib/persistance.h68
-rw-r--r--test/Jamfile.jam3
-rw-r--r--test/fixtures/json/abs.json7
-rw-r--r--test/fixtures/json/empty.json6
-rw-r--r--test/fixtures/json/empty_abs.json6
-rw-r--r--test/fixtures/json/implicit.json8
-rw-r--r--test/fixtures/json/implicit_abs.json8
-rw-r--r--test/fixtures/json/load_object.json55
-rw-r--r--test/fixtures/json/nested.json21
-rw-r--r--test/fixtures/json/vector_ptr.json13
-rw-r--r--test/test-persistance.cpp144
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());
+}