--- /dev/null
+#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));
+}