r8 | charles.nicholson | 2010-03-16 21:27:33 -0500 (Tue, 16 Mar 2010) | 1 line

fixed bug where tests weren't correctly executing while testing the TestRunner (accessing the Details and Results singletons was redirecting failures to bogus RecordingReporters, instead of the real UT++ test engine).  Hoisted assert failure reporting into ReportAssert, in preparation for setjmp/longjmp assert handling in the absence of exceptions.  Slight renamings and cosmetic fixups
This commit is contained in:
Patrick Johnmeyer 2013-01-09 23:43:07 -06:00
parent ab8b818591
commit 3a40aa80a1
16 changed files with 196 additions and 98 deletions

View file

@ -2,38 +2,16 @@
#ifdef UNITTEST_USE_EXCEPTIONS
#include <cstring>
namespace UnitTest {
AssertException::AssertException(char const* description, char const* filename, int lineNumber)
: m_lineNumber(lineNumber)
AssertException::AssertException()
{
using namespace std;
strcpy(m_description, description);
strcpy(m_filename, filename);
}
AssertException::~AssertException()
{
}
char const* AssertException::what() const
{
return m_description;
}
char const* AssertException::Filename() const
{
return m_filename;
}
int AssertException::LineNumber() const
{
return m_lineNumber;
}
}
#endif

View file

@ -12,18 +12,8 @@ namespace UnitTest {
class AssertException : public std::exception
{
public:
AssertException(char const* description, char const* filename, int lineNumber);
AssertException();
virtual ~AssertException();
virtual char const* what() const;
char const* Filename() const;
int LineNumber() const;
private:
char m_description[512];
char m_filename[256];
int m_lineNumber;
};
}

View file

@ -130,10 +130,15 @@
if (!caught_) \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), "Expected exception: \"" #ExpectedExceptionType "\" not thrown"); \
} while(0)
#endif
#define CHECK_ASSERT(expression) \
CHECK_THROW(expression, UnitTest::AssertException);
do \
{ \
UnitTest::ExpectAssert(true); \
CHECK_THROW(expression, UnitTest::AssertException); \
UnitTest::ExpectAssert(false); \
} while(0)
#endif
#endif

View file

@ -14,9 +14,10 @@
namespace UnitTest {
template< typename T >
void ExecuteTest(T& testObject, TestDetails const& details)
void ExecuteTest(T& testObject, TestDetails const& details, bool isMockTest)
{
CurrentTest::Details() = &details;
if (isMockTest == false)
CurrentTest::Details() = &details;
#ifndef UNITTEST_POSIX
UT_TRY
@ -33,8 +34,7 @@ void ExecuteTest(T& testObject, TestDetails const& details)
UT_CATCH(AssertException, e,
{
CurrentTest::Results()->OnTestFailure(
TestDetails(details.testName, details.suiteName, e.Filename(), e.LineNumber()), e.what());
(void)e;
})
UT_CATCH(std::exception, e,
{
@ -44,7 +44,7 @@ void ExecuteTest(T& testObject, TestDetails const& details)
})
UT_CATCH_ALL
({
CurrentTest::Results()->OnTestFailure(details, "Unhandled exception: Crash!");
CurrentTest::Results()->OnTestFailure(details, "Unhandled exception: test crashed");
})
}

View file

@ -1,17 +1,52 @@
#include "ReportAssert.h"
#include "AssertException.h"
#include "CurrentTest.h"
#include "TestResults.h"
#include "TestDetails.h"
namespace UnitTest {
namespace
{
bool& AssertExpectedFlag()
{
static bool s_assertExpected = false;
return s_assertExpected;
}
}
void ReportAssert(char const* description, char const* filename, int lineNumber)
{
(void)description;
(void)filename;
(void)lineNumber;
ReportAssertEx(CurrentTest::Results(), CurrentTest::Details(), description, filename, lineNumber);
}
void ReportAssertEx(TestResults* testResults,
const TestDetails* testDetails,
char const* description,
char const* filename,
int lineNumber)
{
if (AssertExpectedFlag() == false)
{
TestDetails assertDetails(testDetails->testName, testDetails->suiteName, filename, lineNumber);
testResults->OnTestFailure(assertDetails, description);
}
ExpectAssert(false);
#ifdef UNITTEST_USE_EXCEPTIONS
throw AssertException(description, filename, lineNumber);
throw AssertException();
#endif
}
void ExpectAssert(bool expected)
{
AssertExpectedFlag() = expected;
}
bool AssertExpected()
{
return AssertExpectedFlag();
}
}

View file

@ -3,8 +3,20 @@
namespace UnitTest {
class TestResults;
class TestDetails;
void ReportAssert(char const* description, char const* filename, int lineNumber);
void ReportAssertEx(TestResults* testResults,
const TestDetails* testDetails,
char const* description,
char const* filename,
int lineNumber);
void ExpectAssert(bool expected);
bool AssertExpected();
}
#endif

View file

@ -20,8 +20,9 @@ TestList& Test::GetTestList()
Test::Test(char const* testName, char const* suiteName, char const* filename, int lineNumber)
: m_details(testName, suiteName, filename, lineNumber)
, next(0)
, m_nextTest(0)
, m_timeConstraintExempt(false)
, m_isMockTest(false)
{
}
@ -31,7 +32,7 @@ Test::~Test()
void Test::Run()
{
ExecuteTest(*this, m_details);
ExecuteTest(*this, m_details, m_isMockTest);
}
void Test::RunImpl() const

View file

@ -16,8 +16,9 @@ public:
void Run();
TestDetails const m_details;
Test* next;
Test* m_nextTest;
mutable bool m_timeConstraintExempt;
mutable bool m_isMockTest;
static TestList& GetTestList();

View file

@ -21,7 +21,7 @@ void TestList::Add(Test* test)
}
else
{
m_tail->next = test;
m_tail->m_nextTest = test;
m_tail = test;
}
}

View file

@ -83,11 +83,11 @@
({ \
Fixture##Name##Helper fixtureHelper(m_details); \
ctorOk = true; \
UnitTest::ExecuteTest(fixtureHelper, m_details); \
UnitTest::ExecuteTest(fixtureHelper, m_details, false); \
}) \
UT_CATCH (UnitTest::AssertException, e, \
{ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(m_details.testName, m_details.suiteName, e.Filename(), e.LineNumber()), e.what()); \
(void)e; \
}) \
UT_CATCH (std::exception, e, \
{ \

View file

@ -32,6 +32,11 @@ TestRunner::~TestRunner()
delete m_timer;
}
TestResults* TestRunner::GetTestResults()
{
return m_result;
}
int TestRunner::Finish() const
{
float const secondsElapsed = static_cast<float>(m_timer->GetTimeInMs() / 1000.0);
@ -51,7 +56,8 @@ bool TestRunner::IsTestInSuite(const Test* const curTest, char const* suiteName)
void TestRunner::RunTest(TestResults* const result, Test* const curTest, int const maxTestTimeInMs) const
{
CurrentTest::Results() = result;
if (curTest->m_isMockTest == false)
CurrentTest::Results() = result;
Timer testTimer;
testTimer.Start();
@ -70,7 +76,7 @@ void TestRunner::RunTest(TestResults* const result, Test* const curTest, int con
result->OnTestFailure(curTest->m_details, stream.GetText());
}
result->OnTestFinish(curTest->m_details, static_cast<float>(testTimeInMs/1000.0));
result->OnTestFinish(curTest->m_details, static_cast< float >(testTimeInMs / 1000.0));
}
}

View file

@ -27,7 +27,7 @@ public:
explicit TestRunner(TestReporter& reporter);
~TestRunner();
template <class Predicate>
template< class Predicate >
int RunTestsIf(TestList const& list, char const* suiteName,
const Predicate& predicate, int maxTestTimeInMs) const
{
@ -38,12 +38,14 @@ public:
if (IsTestInSuite(curTest, suiteName) && predicate(curTest))
RunTest(m_result, curTest, maxTestTimeInMs);
curTest = curTest->next;
curTest = curTest->m_nextTest;
}
return Finish();
}
TestResults* GetTestResults();
private:
TestReporter* m_reporter;
TestResults* m_result;

View file

@ -1,49 +1,111 @@
#include "../Config.h"
#ifdef UNITTEST_USE_EXCEPTIONS
#include "../unittestpp.h"
#include "../AssertException.h"
#include "../ReportAssert.h"
#include "../AssertException.h"
#include "RecordingReporter.h"
using namespace UnitTest;
namespace {
TEST(CanSetAssertExpected)
{
ExpectAssert(true);
CHECK(AssertExpected());
ExpectAssert(false);
CHECK(!AssertExpected());
}
#ifdef UNITTEST_USE_EXCEPTIONS
TEST(ReportAssertThrowsAssertException)
{
bool caught = false;
try
{
ReportAssert("", "", 0);
TestResults testResults;
TestDetails testDetails("", "", "", 0);
ReportAssertEx(&testResults, &testDetails, "", "", 0);
}
catch(AssertException const&)
{
caught = true;
}
CHECK (true == caught);
CHECK(true == caught);
}
TEST(ReportAssertSetsCorrectInfoInException)
TEST(ReportAssertClearsExpectAssertFlag)
{
RecordingReporter reporter;
TestResults testResults(&reporter);
TestDetails testDetails("", "", "", 0);
try
{
ExpectAssert(true);
ReportAssertEx(&testResults, &testDetails, "", "", 0);
}
catch(AssertException const&)
{
}
CHECK(AssertExpected() == false);
CHECK_EQUAL(0, reporter.testFailedCount);
}
TEST(ReportAssertWritesFailureToResultsAndDetailsWhenAssertIsNotExpected)
{
const int lineNumber = 12345;
const char* description = "description";
const char* filename = "filename";
RecordingReporter reporter;
TestResults testResults(&reporter);
TestDetails testDetails("", "", "", 0);
try
{
ReportAssert(description, filename, lineNumber);
ReportAssertEx(&testResults, &testDetails, description, filename, lineNumber);
}
catch(AssertException const& e)
catch(AssertException const&)
{
CHECK_EQUAL(description, e.what());
CHECK_EQUAL(filename, e.Filename());
CHECK_EQUAL(lineNumber, e.LineNumber());
}
CHECK_EQUAL(description, reporter.lastFailedMessage);
CHECK_EQUAL(filename, reporter.lastFailedFile);
CHECK_EQUAL(lineNumber, reporter.lastFailedLine);
}
TEST(ReportAssertReportsNoErrorsWhenAssertIsExpected)
{
ExpectAssert(true);
RecordingReporter reporter;
TestResults testResults(&reporter);
TestDetails testDetails("", "", "", 0);
try
{
ReportAssertEx(&testResults, &testDetails, "", "", 0);
}
catch(AssertException const&)
{
}
CHECK_EQUAL(0, reporter.testFailedCount);
}
#endif
TEST(CheckAssertMacroSetsAssertExpectationToFalseAfterRunning)
{
CHECK_ASSERT(ReportAssert("", "", 0));
CHECK(!AssertExpected());
}
}

View file

@ -6,23 +6,23 @@ using namespace UnitTest;
namespace {
TEST (TestListIsEmptyByDefault)
TEST(TestListIsEmptyByDefault)
{
TestList list;
CHECK (list.GetHead() == 0);
CHECK(list.GetHead() == 0);
}
TEST (AddingTestSetsHeadToTest)
TEST(AddingTestSetsHeadToTest)
{
Test test("test");
TestList list;
list.Add(&test);
CHECK (list.GetHead() == &test);
CHECK (test.next == 0);
CHECK(list.GetHead() == &test);
CHECK(test.m_nextTest == 0);
}
TEST (AddingSecondTestAddsItToEndOfList)
TEST(AddingSecondTestAddsItToEndOfList)
{
Test test1("test1");
Test test2("test2");
@ -31,20 +31,20 @@ TEST (AddingSecondTestAddsItToEndOfList)
list.Add(&test1);
list.Add(&test2);
CHECK (list.GetHead() == &test1);
CHECK (test1.next == &test2);
CHECK (test2.next == 0);
CHECK(list.GetHead() == &test1);
CHECK(test1.m_nextTest == &test2);
CHECK(test2.m_nextTest == 0);
}
TEST (ListAdderAddsTestToList)
TEST(ListAdderAddsTestToList)
{
TestList list;
Test test("");
ListAdder adder(list, &test);
CHECK (list.GetHead() == &test);
CHECK (test.next == 0);
CHECK(list.GetHead() == &test);
CHECK(test.m_nextTest == 0);
}
}

View file

@ -19,7 +19,7 @@ TEST_EX(DummyTest, list1)
TEST (TestsAreAddedToTheListThroughMacro)
{
CHECK(list1.GetHead() != 0);
CHECK(list1.GetHead()->next == 0);
CHECK(list1.GetHead()->m_nextTest == 0);
}
#ifdef UNITTEST_USE_EXCEPTIONS

View file

@ -10,6 +10,23 @@ using namespace UnitTest;
namespace
{
struct TestRunnerFixture
{
TestRunnerFixture()
: runner(reporter)
{
s_testRunnerFixtureTestResults = runner.GetTestResults();
}
static TestResults* s_testRunnerFixtureTestResults;
RecordingReporter reporter;
TestList list;
TestRunner runner;
};
TestResults* TestRunnerFixture::s_testRunnerFixtureTestResults = NULL;
struct MockTest : public Test
{
MockTest(char const* testName, bool const success_, bool const assert_, int const count_ = 1)
@ -18,16 +35,19 @@ struct MockTest : public Test
, asserted(assert_)
, count(count_)
{
m_isMockTest = true;
}
virtual void RunImpl(TestResults& testResults_) const
virtual void RunImpl() const
{
TestResults* testResults = TestRunnerFixture::s_testRunnerFixtureTestResults;
for (int i=0; i < count; ++i)
{
if (asserted)
ReportAssert("desc", "file", 0);
ReportAssertEx(testResults, &m_details, "desc", "file", 0);
else if (!success)
testResults_.OnTestFailure(m_details, "message");
testResults->OnTestFailure(m_details, "message");
}
}
@ -36,19 +56,6 @@ struct MockTest : public Test
int const count;
};
struct TestRunnerFixture
{
TestRunnerFixture()
: runner(reporter)
{
}
RecordingReporter reporter;
TestList list;
TestRunner runner;
};
TEST_FIXTURE(TestRunnerFixture, TestStartIsReportedCorrectly)
{
MockTest test("goodtest", true, false);
@ -104,7 +111,7 @@ TEST_FIXTURE(TestRunnerFixture, CallsReportFailureOncePerFailingTest)
MockTest test3("test", false, false);
list.Add(&test3);
CHECK_EQUAL(2, runner.RunTestsIf(list, NULL, True(), 0));
CHECK_EQUAL(2, runner.RunTestsIf(list, NULL, True(), 0));
CHECK_EQUAL(2, reporter.testFailedCount);
}
@ -117,7 +124,6 @@ TEST_FIXTURE(TestRunnerFixture, TestsThatAssertAreReportedAsFailing)
CHECK_EQUAL(1, reporter.testFailedCount);
}
TEST_FIXTURE(TestRunnerFixture, ReporterNotifiedOfTestCount)
{
MockTest test1("test", true, false);