#include "../reflectable.h" #include "resources/config.h" #include #include #include #include using TestUtilities::operator<<; // must be visible prior to the call site #include #include #include #include #include #include #include #include using namespace std; using namespace CPPUNIT_NS; using namespace RAPIDJSON_NAMESPACE; using namespace IoUtilities; using namespace ConversionUtilities; using namespace TestUtilities; using namespace TestUtilities::Literals; using namespace ReflectiveRapidJSON; /// \cond // define some structs for testing serialization struct TestObject : public Reflectable { int number; double number2; vector numbers; string text; bool boolean; }; struct NestingObject : public Reflectable { string name; TestObject testObj; }; struct NestingArray : public Reflectable { string name; vector testObjects; }; // pretend serialization code for structs has been generated namespace ReflectiveRapidJSON { namespace Reflector { template <> inline void push(const TestObject &reflectable, Value::Object &value, Document::AllocatorType &allocator) { push(reflectable.number, "number", value, allocator); push(reflectable.number2, "number2", value, allocator); push(reflectable.numbers, "numbers", value, allocator); push(reflectable.text, "text", value, allocator); push(reflectable.boolean, "boolean", value, allocator); } template <> inline void push(const NestingObject &reflectable, Value::Object &value, Document::AllocatorType &allocator) { push(reflectable.name, "name", value, allocator); push(reflectable.testObj, "testObj", value, allocator); } template <> inline void push(const NestingArray &reflectable, Value::Object &value, Document::AllocatorType &allocator) { push(reflectable.name, "name", value, allocator); push(reflectable.testObjects, "testObjects", value, allocator); } template <> inline void pull(TestObject &reflectable, const GenericValue>::ConstObject &value) { pull(reflectable.number, "number", value); pull(reflectable.number2, "number2", value); pull(reflectable.numbers, "numbers", value); pull(reflectable.text, "text", value); pull(reflectable.boolean, "boolean", value); } template <> inline void pull(NestingObject &reflectable, const GenericValue>::ConstObject &value) { pull(reflectable.name, "name", value); pull(reflectable.testObj, "testObj", value); } template <> inline void pull(NestingArray &reflectable, const GenericValue>::ConstObject &value) { pull(reflectable.name, "name", value); pull(reflectable.testObjects, "testObjects", value); } } // namespace Reflector } // namespace ReflectiveRapidJSON /// \endcond /*! * \brief The ReflectorTests class tests RapidJSON wrapper which is used to ease code generation. * \remarks In this tests, no reflection or code generation is involved yet. */ class ReflectorTests : public TestFixture { CPPUNIT_TEST_SUITE(ReflectorTests); CPPUNIT_TEST(experiment); CPPUNIT_TEST(testSerializePrimitives); CPPUNIT_TEST(testSerializeSimpleObjects); CPPUNIT_TEST(testSerializeNestedObjects); CPPUNIT_TEST(testDeserializePrimitives); CPPUNIT_TEST(testDeserializeSimpleObjects); CPPUNIT_TEST(testDeserializeNestedObjects); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void experiment(); void testSerializePrimitives(); void testSerializeSimpleObjects(); void testSerializeNestedObjects(); void testDeserializePrimitives(); void testDeserializeSimpleObjects(); void testDeserializeNestedObjects(); private: }; CPPUNIT_TEST_SUITE_REGISTRATION(ReflectorTests); void ReflectorTests::setUp() { } void ReflectorTests::tearDown() { } /*! * \brief Not a real test, just some assertions for experimenting with the RapidJSON library. */ void ReflectorTests::experiment() { Document doc(kArrayType); Document::AllocatorType &alloc = doc.GetAllocator(); /* doc.PushBack(25, alloc); doc.PushBack(26, alloc); doc.SetObject(); doc.AddMember(StringRef("test"), 27, alloc); StringBuffer strbuf; Writer jsonWriter(strbuf); doc.Accept(jsonWriter); */ doc.Parse("[\"a\", 5, \"test\", \"7\"]"); GenericValue>::Array a = doc.GetArray(); CPPUNIT_ASSERT_EQUAL("a"s, string(a[0].GetString())); CPPUNIT_ASSERT_EQUAL(5, a[1].GetInt()); //CPPUNIT_ASSERT_EQUAL(5, a[2].GetInt()); //CPPUNIT_ASSERT_EQUAL(7, a[3].GetInt()); } /*! * \brief Tests serializing strings, numbers, arrays and boolean. */ void ReflectorTests::testSerializePrimitives() { Document doc(kArrayType); Document::AllocatorType &alloc = doc.GetAllocator(); doc.SetArray(); Document::Array array(doc.GetArray()); // string Reflector::push("foo"s, array, alloc); Reflector::push("bar", array, alloc); // number Reflector::push(25, array, alloc); Reflector::push(12.5, array, alloc); // array Reflector::push>({ "foo1", "bar1" }, array, alloc); Reflector::push>({ "foo2", "bar2" }, array, alloc); Reflector::push>({ "foo3", "bar3" }, array, alloc); // boolean Reflector::push(true, array, alloc); Reflector::push(false, array, alloc); StringBuffer strbuf; Writer jsonWriter(strbuf); doc.Accept(jsonWriter); CPPUNIT_ASSERT_EQUAL( "[\"foo\",\"bar\",25,12.5,[\"foo1\",\"bar1\"],[\"foo2\",\"bar2\"],[\"foo3\",\"bar3\"],true,false]"s, string(strbuf.GetString())); } /*! * \brief Tests serializing objects. */ void ReflectorTests::testSerializeSimpleObjects() { TestObject testObj; testObj.number = 42; testObj.number2 = 3.141592653589793; testObj.numbers = { 1, 2, 3, 4 }; testObj.text = "test"; testObj.boolean = false; CPPUNIT_ASSERT_EQUAL("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}"s, string(testObj.toJson().GetString())); } /*! * \brief Tests serializing nested object and arrays. */ void ReflectorTests::testSerializeNestedObjects() { NestingObject nestingObj; nestingObj.name = "nesting"; TestObject &testObj = nestingObj.testObj; testObj.number = 42; testObj.number2 = 3.141592653589793; testObj.numbers = { 1, 2, 3, 4 }; testObj.text = "test"; testObj.boolean = false; CPPUNIT_ASSERT_EQUAL( "{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}"s, string(nestingObj.toJson().GetString())); NestingArray nestingArray; nestingArray.name = "nesting2"; nestingArray.testObjects.emplace_back(testObj); nestingArray.testObjects.emplace_back(testObj); nestingArray.testObjects.back().number = 43; CPPUNIT_ASSERT_EQUAL( "{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}"s, string(nestingArray.toJson().GetString())); } /*! * \brief Tests deserializing strings, numbers (int, float, double) and boolean. */ void ReflectorTests::testDeserializePrimitives() { Document doc(kArrayType); doc.Parse("[\"a\", 5, 5e6, \"test\", true, 4.125, false]"); auto array = doc.GetArray().begin(); string str1, str2; int int1 = 0; bool bool1 = false, bool2 = true; float float1 = 0.0; double double1 = 0.0; Reflector::pull(str1, array); Reflector::pull(int1, array); Reflector::pull(float1, array); Reflector::pull(str2, array); Reflector::pull(bool1, array); Reflector::pull(double1, array); Reflector::pull(bool2, array); CPPUNIT_ASSERT_EQUAL("a"s, str1); CPPUNIT_ASSERT_EQUAL(5, int1); CPPUNIT_ASSERT_EQUAL(5e6f, float1); CPPUNIT_ASSERT_EQUAL("test"s, str2); CPPUNIT_ASSERT_EQUAL(true, bool1); CPPUNIT_ASSERT_EQUAL(4.125, double1); CPPUNIT_ASSERT_EQUAL(false, bool2); } /*! * \brief Tests deserializing simple objects. */ void ReflectorTests::testDeserializeSimpleObjects() { const TestObject testObj( TestObject::fromJson("{\"number\":42,\"number2\":3.141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}")); CPPUNIT_ASSERT_EQUAL(42, testObj.number); CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2); CPPUNIT_ASSERT_EQUAL(vector({ 1, 2, 3, 4 }), testObj.numbers); CPPUNIT_ASSERT_EQUAL("test"s, testObj.text); CPPUNIT_ASSERT_EQUAL(false, testObj.boolean); } /*! * \brief Tests deserializing nested objects and arrays. */ void ReflectorTests::testDeserializeNestedObjects() { const NestingObject nestingObj(NestingObject::fromJson("{\"name\":\"nesting\",\"testObj\":{\"number\":42,\"number2\":3.141592653589793," "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}}")); const TestObject &testObj = nestingObj.testObj; CPPUNIT_ASSERT_EQUAL("nesting"s, nestingObj.name); CPPUNIT_ASSERT_EQUAL(42, testObj.number); CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2); CPPUNIT_ASSERT_EQUAL(vector({ 1, 2, 3, 4 }), testObj.numbers); CPPUNIT_ASSERT_EQUAL("test"s, testObj.text); CPPUNIT_ASSERT_EQUAL(false, testObj.boolean); const NestingArray nestingArray(NestingArray::fromJson("{\"name\":\"nesting2\",\"testObjects\":[{\"number\":42,\"number2\":3.141592653589793," "\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false},{\"number\":43,\"number2\":3." "141592653589793,\"numbers\":[1,2,3,4],\"text\":\"test\",\"boolean\":false}]}")); const vector &testObjects = nestingArray.testObjects; CPPUNIT_ASSERT_EQUAL("nesting2"s, nestingArray.name); CPPUNIT_ASSERT_EQUAL(2_st, testObjects.size()); CPPUNIT_ASSERT_EQUAL(42, testObjects[0].number); CPPUNIT_ASSERT_EQUAL(43, testObjects[1].number); for (const TestObject &testObj : testObjects) { CPPUNIT_ASSERT_EQUAL(3.141592653589793, testObj.number2); CPPUNIT_ASSERT_EQUAL(vector({ 1, 2, 3, 4 }), testObj.numbers); CPPUNIT_ASSERT_EQUAL("test"s, testObj.text); CPPUNIT_ASSERT_EQUAL(false, testObj.boolean); } }