Last active
August 29, 2015 14:24
-
-
Save greatwolf/4bb61e08374a7c931ddc to your computer and use it in GitHub Desktop.
BDD test implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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