diff --git a/include/test/mtl/test.hpp b/include/test/mtl/test.hpp new file mode 100644 index 0000000..a4107bc --- /dev/null +++ b/include/test/mtl/test.hpp @@ -0,0 +1,101 @@ +#ifdef __GBA__ +#define REG_TM2D *(volatile uint32_t*)(0x04000108) +#define REG_TM2CNT *(volatile uint32_t*)(0x0400010A) +#define TM_ENABLE 0x80 +#endif + +#include "mtl/log.hpp" +#include "mtl/string_view.hpp" +#include "mtl/vector.hpp" + +namespace mtl { + +namespace test { + +class isuite { +public: + virtual string_view name() const = 0; + virtual bool run_tests() = 0; +}; + +extern mtl::vector suites; + +template +struct suite : public isuite { +private: + template + friend void run_test_suite(); + + using TEST_TYPE = int32_t (SUITE_TYPE::*)(); + + static SUITE_TYPE s_instance; + + SUITE_TYPE* m_suite; + vector m_tests; + vector m_test_names; + +protected: + suite() { + suites.push_back(&s_instance); + } + +public: + void add_test(TEST_TYPE test, string_view name) { + m_tests.push_back(test); + m_test_names.push_back(name); + } + + bool run_tests() override { + log::info << "=========================" << endl; + log::info << "Running suite \"" << name() << '\"' << endl; + log::info << endl; + + int32_t num_ok = 0; + int32_t num_fail = 0; + + for (size_t i = 0; i < m_tests.size(); ++i) { + log::info << "Running \"" << m_test_names[i] + << "\"..." << endl; + + TEST_TYPE test = m_tests[i]; + uint16_t time = 0; + +#ifdef __GBA__ + REG_TM2D = 0; + REG_TM2CNT = TM_ENABLE; +#endif + int32_t result = (s_instance.*test)(); +#ifdef __GBA__ + time = REG_TM2D; + REG_TM2CNT = ~TM_ENABLE; +#endif + + log::info << (result == 0 ? "OK (" : "FAILED (") << result << "), TIME: " << time << endl; + + if (result == 0) { ++num_ok; } + else { ++num_fail; } + } + + + log::info << endl; + log::info << "Finished. Tests OK: " << num_ok << '/' << m_tests.size() << endl; + log::info << "=========================" << endl; + + return num_fail == 0; + } +}; + +template +SUITE_TYPE suite::s_instance; + +template +void run_test_suite() { + suite::s_instance->run_tests(); +} + +void run_all_suites(); +isuite* get_suite(const string_view& name); + +} // namespace test + +} // namespace mtl diff --git a/src/test/test.cpp b/src/test/test.cpp new file mode 100644 index 0000000..515ff13 --- /dev/null +++ b/src/test/test.cpp @@ -0,0 +1,35 @@ +#include "mtl/test.hpp" + +#include "mtl/log.hpp" + +namespace mtl { + +namespace test { + +vector suites; + +void run_all_suites() { + log::info << "=========================" << endl; + log::info << "RUNNING " << suites.size() << " TEST SUITES" << endl; + log::info << "=========================" << endl; + log::info << endl; + + for (isuite* suite : suites) { + suite->run_tests(); + } +} + +isuite* get_suite(const string_view& name) { + for (isuite* suite : suites) { + if (suite->name() == name) { + return suite; + } + } + + return nullptr; +} + +} // namespace test + +} // namespace mtl +