Skip to content

Instantly share code, notes, and snippets.

@greatwolf
Last active August 29, 2015 14:24
Show Gist options
  • Save greatwolf/4bb61e08374a7c931ddc to your computer and use it in GitHub Desktop.
Save greatwolf/4bb61e08374a7c931ddc to your computer and use it in GitHub Desktop.
BDD test implementation
#include <iostream>
#include <vector>
using namespace std;
#define Describe(unitgroup) \
struct unitgroup; \
register_harness<unitgroup> unitgroup ## _registered; \
struct unitgroup : public testharness<unitgroup> \
#define It(unittest) \
struct wrap_ ## unittest \
{ \
wrap_ ## unittest() \
{ \
static bool added = add_unittest(&testharness::class_t::unittest); \
static_cast<void> (added); \
} \
} makewrap_ ## unittest; \
void unittest()
struct baseharness
{
virtual void SetUp() {}
virtual void TearDown() {}
virtual void run_unittest() = 0;
};
struct TestRunner
{
static vector<baseharness *> harnesses;
static int RunAllTests()
{
for(auto it = harnesses.begin(); it != harnesses.end(); ++it)
{
(*it)->run_unittest();
}
return 0;
}
template <typename T>
static void add_harness()
{
static T *harness = nullptr;
if (!harness)
{
harness = new T;
harnesses.push_back(harness);
}
}
};
vector<baseharness *> TestRunner::harnesses;
template <typename T>
struct testharness : public baseharness
{
typedef T class_t;
typedef void (T::*unittest_t)(void);
static vector<unittest_t>& ut_arr()
{
static vector<unittest_t> ut_arr_;
return ut_arr_;
}
// This is called from a child nested class, its parent class
// inherits from testharness<T>, CRTP style. However the macro
// parms doesn't include the parent so there's no way for the
// child class to refer to the parent by name.
// This is static so child can call parent's base w/o naming anything.
static bool add_unittest(unittest_t ut)
{
ut_arr().push_back(ut);
return true;
}
// This is non-static because it has to override
// virtual run_unittest from baseharness
void run_unittest()
{
for(auto it = ut_arr().begin(); it != ut_arr().end(); ++it)
{
T newobj;
newobj.SetUp();
(newobj.*(*it))();
newobj.TearDown();
}
}
};
template <typename T>
struct register_harness
{
register_harness() { TestRunner::add_harness<T> (); }
};
Describe(test)
{
void SetUp() { cout << __FUNCTION__ << '\n'; }
It(method1) { cout << __FUNCTION__ << '\n'; }
It(method2) { cout << __FUNCTION__ << '\n'; }
It(method3) { cout << __FUNCTION__ << '\n'; }
Describe(test2)
{
void TearDown() { cout << __FUNCTION__ << '\n'; }
It(method4) { cout << __FUNCTION__ << '\n'; }
It(method5) { cout << __FUNCTION__ << '\n'; }
};
};
int main()
{
return TestRunner::RunAllTests();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment