]> git.tdb.fi Git - libs/game.git/commitdiff
Add unit tests for reflection
authorMikko Rasa <tdb@tdb.fi>
Sat, 3 Dec 2022 11:18:11 +0000 (13:18 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sat, 3 Dec 2022 16:18:15 +0000 (18:18 +0200)
tests/.gitignore [new file with mode: 0644]
tests/Build [new file with mode: 0644]
tests/reflection.cpp [new file with mode: 0644]

diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644 (file)
index 0000000..ee4c926
--- /dev/null
@@ -0,0 +1 @@
+/test
diff --git a/tests/Build b/tests/Build
new file mode 100644 (file)
index 0000000..db50340
--- /dev/null
@@ -0,0 +1,17 @@
+package "mspgame-tests"
+{
+       require "mspcore";
+       require "mspgame";
+       require "msptest";
+
+       program "test"
+       {
+               source ".";
+               build_info
+               {
+                       /* XXX Shouldn't be needed, but builder has a bug and doesn't
+                       correctly propagate the standard from required packages. */
+                       standard CXX "c++20";
+               };
+       };
+};
diff --git a/tests/reflection.cpp b/tests/reflection.cpp
new file mode 100644 (file)
index 0000000..a40ada3
--- /dev/null
@@ -0,0 +1,156 @@
+#include <msp/game/reflection.h>
+#include <msp/test/test.h>
+
+using namespace std;
+using namespace Msp;
+
+class ReflectionTests: public Test::RegisteredTest<ReflectionTests>
+{
+public:
+       ReflectionTests();
+
+       static const char *get_name() { return "Reflection"; }
+
+private:
+       void find_class();
+       void basic_polymorphism();
+       void polymorphism_conflict();
+       void deep_polymorphism();
+       void branching_polymorphism();
+};
+
+struct A { virtual ~A() = default; };
+struct B: A { };
+struct C: B { };
+struct D: C { };
+struct C2: B { };
+
+
+ReflectionTests::ReflectionTests()
+{
+       add(&ReflectionTests::find_class, "find_class");
+       add(&ReflectionTests::basic_polymorphism, "Basic polymorphism");
+       add(&ReflectionTests::polymorphism_conflict, "Polymorphism conflict").expect_throw<std::logic_error>();
+       add(&ReflectionTests::deep_polymorphism, "Deep polymorphism");
+       add(&ReflectionTests::branching_polymorphism, "Branching polymorphism");
+}
+
+
+void ReflectionTests::find_class()
+{
+       Game::Reflection::Reflector reflector;
+       Game::Reflection::Class<A> *a_class = reflector.find_class<A>();
+       EXPECT_EQUAL(a_class, nullptr);
+       Game::Reflection::Class<A> &a_reg = reflector.get_or_create_class<A>();
+       a_class = reflector.find_class<A>();
+       EXPECT(a_class!=nullptr);
+       EXPECT_EQUAL(a_class, &a_reg);
+}
+
+void ReflectionTests::basic_polymorphism()
+{
+       Game::Reflection::Reflector reflector;
+
+       Game::Reflection::Class<A> &a_class = reflector.get_or_create_class<A>();
+       a_class.set_polymorphic_base<A>();
+       Game::Reflection::Class<B> &b_class = reflector.get_or_create_class<B>();
+       b_class.set_polymorphic_base<A>(B());
+
+       EXPECT(a_class.is_direct_base_of(b_class));
+       EXPECT(!b_class.is_direct_base_of(a_class));
+
+       A a_obj;
+       EXPECT(a_class.is_instance(a_obj));
+       EXPECT(!b_class.is_instance(a_obj));
+
+       B b_obj;
+       EXPECT(a_class.is_instance(b_obj));
+       EXPECT(b_class.is_instance(b_obj));
+
+       A &a_ref_to_b = b_obj;
+       EXPECT(a_class.is_instance(a_ref_to_b));
+       EXPECT(b_class.is_instance(a_ref_to_b));
+}
+
+void ReflectionTests::polymorphism_conflict()
+{
+       Game::Reflection::Reflector reflector;
+       Game::Reflection::Class<B> &b_class = reflector.get_or_create_class<B>();
+       b_class.set_polymorphic_base<A>();
+       b_class.set_polymorphic_base<B>();
+}
+
+void ReflectionTests::deep_polymorphism()
+{
+       Game::Reflection::Reflector reflector;
+
+       Game::Reflection::Class<A> &a_class = reflector.get_or_create_class<A>();
+       a_class.set_polymorphic_base<A>();
+       Game::Reflection::Class<B> &b_class = reflector.get_or_create_class<B>();
+       b_class.set_polymorphic_base<A>(B());
+       Game::Reflection::Class<C> &c_class = reflector.get_or_create_class<C>();
+       c_class.set_polymorphic_base<A>(C());
+       Game::Reflection::Class<D> &d_class = reflector.get_or_create_class<D>();
+       d_class.set_polymorphic_base<A>(D());
+
+       EXPECT(a_class.is_direct_base_of(b_class));
+       EXPECT(!a_class.is_direct_base_of(c_class));
+       EXPECT(!a_class.is_direct_base_of(d_class));
+       EXPECT(a_class.is_base_of(c_class));
+       EXPECT(a_class.is_base_of(d_class));
+       EXPECT(b_class.is_direct_base_of(c_class));
+       EXPECT(!b_class.is_direct_base_of(d_class));
+       EXPECT(b_class.is_base_of(d_class));
+       EXPECT(c_class.is_direct_base_of(d_class));
+
+       D d_obj;
+       EXPECT(a_class.is_instance(d_obj));
+       EXPECT(b_class.is_instance(d_obj));
+       EXPECT(c_class.is_instance(d_obj));
+       EXPECT(d_class.is_instance(d_obj));
+
+       B &b_ref_to_d = d_obj;
+       EXPECT(a_class.is_instance(b_ref_to_d));
+       EXPECT(b_class.is_instance(b_ref_to_d));
+       EXPECT(c_class.is_instance(b_ref_to_d));
+       EXPECT(d_class.is_instance(b_ref_to_d));
+
+       C &c_ref_to_d = d_obj;
+       EXPECT(a_class.is_instance(c_ref_to_d));
+       EXPECT(b_class.is_instance(c_ref_to_d));
+       EXPECT(c_class.is_instance(c_ref_to_d));
+       EXPECT(d_class.is_instance(c_ref_to_d));
+}
+
+void ReflectionTests::branching_polymorphism()
+{
+       Game::Reflection::Reflector reflector;
+
+       Game::Reflection::Class<A> &a_class = reflector.get_or_create_class<A>();
+       a_class.set_polymorphic_base<A>();
+       Game::Reflection::Class<B> &b_class = reflector.get_or_create_class<B>();
+       b_class.set_polymorphic_base<A>(B());
+       Game::Reflection::Class<C> &c_class = reflector.get_or_create_class<C>();
+       c_class.set_polymorphic_base<A>(C());
+       Game::Reflection::Class<C2> &c2_class = reflector.get_or_create_class<C2>();
+       c2_class.set_polymorphic_base<A>(C2());
+
+       EXPECT(a_class.is_direct_base_of(b_class));
+       EXPECT(a_class.is_base_of(c_class));
+       EXPECT(a_class.is_base_of(c2_class));
+       EXPECT(b_class.is_direct_base_of(c_class));
+       EXPECT(b_class.is_direct_base_of(c2_class));
+       EXPECT(!c_class.is_base_of(c2_class));
+       EXPECT(!c2_class.is_base_of(c_class));
+
+       C c_obj;
+       C2 c2_obj;
+       EXPECT(a_class.is_instance(c_obj));
+       EXPECT(a_class.is_instance(c2_obj));
+       EXPECT(b_class.is_instance(c_obj));
+       EXPECT(b_class.is_instance(c2_obj));
+       EXPECT(c_class.is_instance(c_obj));
+       EXPECT(!c_class.is_instance(c2_obj));
+       EXPECT(c2_class.is_instance(c2_obj));
+       EXPECT(!c2_class.is_instance(c_obj));
+}