|
#ifndef _SHORTCUT_H_
#define _SHORTCUT_H_
//
// ShortCUT - A Short C++ Unit Testing Framework
//
// Copyright (C) 2007 Todd Lucas (tl@onlyshallow.com)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#include <stdio.h>
#include <stdarg.h>
struct TestSuite;
struct TestCase
{
TestCase() : next(0) {}
virtual void test(TestSuite* suite) {}
virtual const char* name() { return "?"; }
TestCase* next;
};
struct TestSuite
{
TestSuite() : next(0), tests(0) {}
virtual void setup() {}
virtual void teardown() {}
virtual const char* name() { return "?"; }
void AddTest(TestCase* tc)
{
tc->next = tests;
tests = tc;
}
TestSuite* next;
TestCase* tests;
};
struct TestException
{
virtual const char* text() { return "exception"; };
};
struct TestLog
{
virtual void write(const char* msg, ...) {}
};
struct TestLogStdout : TestLog
{
virtual void write(const char* msg, ...)
{
va_list arg;
va_start(arg, msg);
vprintf(msg, arg);
va_end(arg);
}
};
struct TestRunner
{
TestRunner() : suites(0), log(&defaultLog) { }
void AddSuite(TestSuite* ts)
{
ts->next = suites;
suites = ts;
}
void RunTests()
{
int testCount = 0, suiteCount = 0, passCount = 0;
TestSuite* suite = suites;
while (suite)
{
RunSuite(suite, testCount, passCount);
suite = suite->next;
suiteCount++;
}
log->write("RESULTS: %d tests passed out of %d in %d test suites ",
passCount, testCount, suiteCount);
log->write("for a %d%% pass rate.\n",
(int)(passCount * 100 / testCount));
}
void SetLog(TestLog* l)
{
log = l;
}
protected:
void RunSuite(TestSuite* suite, int& testCount, int& passCount)
{
TestCase* test = suite->tests;
while (test)
{
try
{
suite->setup();
test->test(suite);
passCount++;
}
catch (TestException& te)
{
log->write("FAILED '%s': %s\n", test->name(), te.text());
}
catch (...)
{
log->write("FAILED '%s': unknown exception\n", test->name());
}
try
{
suite->teardown();
}
catch (...)
{
log->write("FAILED: teardown error in suite '%s'\n", suite->name());
}
test = test->next;
testCount++;
}
}
TestLogStdout defaultLog;
TestLog* log;
TestSuite* suites;
};
//
// ShortCUT extensions
//
// Example exception (assumes string is in the program's static data section).
struct TestMessageException : TestException
{
TestMessageException(const char* message) : msg(message) { }
virtual const char* text() { return msg; }
const char* msg;
};
#define T_STR2(x) #x
#define T_STR(x) T_STR2(x)
#define T_ASSERT_MSG(cond, msg) \
do { \
if (!(cond)) { \
throw TestMessageException(msg); \
} \
} while (false)
#define T_ASSERT(cond) \
T_ASSERT_MSG(cond, "assert condition '" #cond "' failed on line " T_STR(__LINE__))
//
// Convenience macros
//
// A helper to declare test case and test suite names.
#define T_NAME(n) const char* name() { return n; }
// A casting helper to access the suite data from within a test.
#define T_DATA(data, SuiteClass, param) \
SuiteClass* data = static_cast<SuiteClass*>(param)
// Test declaration helper
#define T_TEST(SuiteClass, TestClass) \
struct TestClass : TestCase { \
T_NAME( #TestClass ); \
void test(TestSuite* suite) { \
test_(static_cast<SuiteClass*>(suite)); \
} \
void test_(SuiteClass* data); \
}; \
inline void TestClass::test_(SuiteClass* data)
// Instantiate a test suite on the stack and add it to a runner.
#define T_ADDSUITE(RunnerObject, suiteName, TestSuite) \
TestSuite suiteName; \
RunnerObject.AddSuite(&suiteName)
// Instantiate a test case on the stack and add it to a suite.
#define T_ADDTEST(SuiteObject, Number, TestClass) \
TestClass t ## Number; \
SuiteObject.AddTest(&t ## Number)
#endif _SHORTCUT_H_
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I work as a developer in the Seattle area. I am currently residing in France.