+#include <typeinfo>
+#include <msp/debug/demangle.h>
+#include <msp/io/print.h>
+#include <msp/strings/utils.h>
+#include "runner.h"
+#include "test.h"
+
+using namespace std;
+
+namespace {
+
+/* This makes the linker pull in the Runner class when linking msptest as a
+static library */
+void *dummy()
+{ return new Msp::Test::Runner(0, 0); }
+
+}
+
+
+namespace Msp {
+namespace Test {
+
+Test::Test(const string &n):
+ name(n)
+{ }
+
+Test::~Test()
+{
+ for(list<Function *>::iterator i=functions.begin(); i!=functions.end(); ++i)
+ delete *i;
+}
+
+list<Test::Factory *> &Test::get_factories()
+{
+ static list<Factory *> factories;
+ return factories;
+}
+
+void Test::run_single(const string &name, bool verbose)
+{
+ const list<Factory *> &factories = get_factories();
+ for(list<Factory *>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
+ if((*i)->get_name()==name)
+ {
+ Test *test = (*i)->create();
+ test->run(verbose);
+ delete test;
+ }
+}
+
+void Test::run_all(bool verbose)
+{
+ const list<Factory *> &factories = get_factories();
+ IO::print("Running %d test suites\n", factories.size());
+ for(list<Factory *>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
+ {
+ Test *test = (*i)->create();
+ test->run(verbose);
+ delete test;
+ }
+}
+
+void Test::run(bool verbose)
+{
+ IO::print("Running tests for %s\n", name);
+
+ unsigned n_passed = 0;
+ unsigned total = 0;
+ for(list<Function *>::const_iterator i=functions.begin(); i!=functions.end(); ++i)
+ {
+ detail_info = string();
+ detail_debug = string();
+ passed = false;
+ start_test((*i)->get_description());
+ const ExceptionCheck *exc_check = (*i)->get_exception_check();
+ try
+ {
+ (*i)->run(*this);
+ if(exc_check)
+ fail_test("Exception expected but none thrown");
+ else
+ pass_test();
+ }
+ catch(const test_failed &e)
+ {
+ fail_test(e.what());
+ }
+ catch(const exception &e)
+ {
+ if(exc_check && exc_check->check(e))
+ {
+ pass_test();
+ debug(Debug::demangle(typeid(e).name()));
+ debug(e.what());
+ }
+ else
+ fail_test(e.what());
+ }
+ catch(...)
+ {
+ fail_test("Unknown object thrown");
+ }
+
+ if(verbose)
+ detail_info += detail_debug;
+ if(!detail_info.empty())
+ {
+ vector<string> lines = split(detail_info, '\n');
+ for(vector<string>::const_iterator j=lines.begin(); j!=lines.end(); ++j)
+ IO::print(" %s\n", *j);
+ }
+
+ ++total;
+ if(passed)
+ ++n_passed;
+ }
+
+ IO::print(" %d/%d passed\n", n_passed, total);
+}
+
+void Test::start_test(const string &descr)
+{
+ IO::print(" %s: ", descr);
+}
+
+void Test::pass_test()
+{
+ IO::print("\033[32mok\033[0m\n");
+ ++passed;
+}
+
+void Test::fail_test(const string &why)
+{
+ IO::print("\033[31mfailed\033[0m\n");
+ IO::print(" %s\n", why);
+}
+
+void Test::expect(bool cond, const string &expr)
+{
+ if(!cond)
+ throw test_failed(format("!(%s)", expr));
+ debug(expr);
+}
+
+void Test::info(const string &str)
+{
+ detail_info += format("%s\n", str);
+}
+
+void Test::debug(const string &str)
+{
+ detail_debug += format("%s\n", str);
+}
+
+
+Test::Factory::Factory()
+{
+ get_factories().push_back(this);
+}
+
+} // namespace Test
+} // namespace Msp