diff options
author | Adam Domurad <[email protected]> | 2012-11-21 12:37:38 -0500 |
---|---|---|
committer | Adam Domurad <[email protected]> | 2012-11-21 12:37:38 -0500 |
commit | 47e24eece15121c917a30166037cbb072bb6a443 (patch) | |
tree | fe7730603d16164711ff8db7b9dea283888aae90 /tests/UnitTest++ | |
parent | 86bfc5f740524bdd7f341f9e1b90e39369ad7e8f (diff) |
Add UnitTest++ source code into ITW, without integration.
Diffstat (limited to 'tests/UnitTest++')
46 files changed, 2074 insertions, 0 deletions
diff --git a/tests/UnitTest++/COPYING b/tests/UnitTest++/COPYING new file mode 100644 index 0000000..9f96308 --- /dev/null +++ b/tests/UnitTest++/COPYING @@ -0,0 +1,20 @@ +Copyright (c) 2006 Noel Llopis and Charles Nicholson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tests/UnitTest++/Makefile b/tests/UnitTest++/Makefile new file mode 100644 index 0000000..007bc80 --- /dev/null +++ b/tests/UnitTest++/Makefile @@ -0,0 +1,96 @@ +CXX = g++ +CXXFLAGS ?= -g -Wall -W -ansi # -pedantic +LDFLAGS ?= +SED = sed +MV = mv +RM = rm + +.SUFFIXES: .o .cpp + +lib = libUnitTest++.a +test = TestUnitTest++ + +src = src/AssertException.cpp \ + src/Test.cpp \ + src/Checks.cpp \ + src/TestRunner.cpp \ + src/TestResults.cpp \ + src/TestReporter.cpp \ + src/TestReporterStdout.cpp \ + src/ReportAssert.cpp \ + src/TestList.cpp \ + src/TimeConstraint.cpp \ + src/TestDetails.cpp \ + src/MemoryOutStream.cpp \ + src/DeferredTestReporter.cpp \ + src/DeferredTestResult.cpp \ + src/XmlTestReporter.cpp \ + src/CurrentTest.cpp + +ifeq ($(MSYSTEM), MINGW32) + src += src/Win32/TimeHelpers.cpp +else + src += src/Posix/SignalTranslator.cpp \ + src/Posix/TimeHelpers.cpp +endif + +test_src = src/tests/Main.cpp \ + src/tests/TestAssertHandler.cpp \ + src/tests/TestChecks.cpp \ + src/tests/TestUnitTest++.cpp \ + src/tests/TestTest.cpp \ + src/tests/TestTestResults.cpp \ + src/tests/TestTestRunner.cpp \ + src/tests/TestCheckMacros.cpp \ + src/tests/TestTestList.cpp \ + src/tests/TestTestMacros.cpp \ + src/tests/TestTimeConstraint.cpp \ + src/tests/TestTimeConstraintMacro.cpp \ + src/tests/TestMemoryOutStream.cpp \ + src/tests/TestDeferredTestReporter.cpp \ + src/tests/TestXmlTestReporter.cpp \ + src/tests/TestCurrentTest.cpp + +objects = $(patsubst %.cpp, %.o, $(src)) +test_objects = $(patsubst %.cpp, %.o, $(test_src)) +dependencies = $(subst .o,.d,$(objects)) +test_dependencies = $(subst .o,.d,$(test_objects)) + +define make-depend + $(CXX) $(CXXFLAGS) -M $1 | \ + $(SED) -e 's,\($(notdir $2)\) *:,$(dir $2)\1: ,' > $3.tmp + $(SED) -e 's/#.*//' \ + -e 's/^[^:]*: *//' \ + -e 's/ *\\$$//' \ + -e '/^$$/ d' \ + -e 's/$$/ :/' $3.tmp >> $3.tmp + $(MV) $3.tmp $3 +endef + + +all: $(lib) + + +$(lib): $(objects) + @echo Creating $(lib) library... + @ar cr $(lib) $(objects) + +$(test): $(lib) $(test_objects) + @echo Linking $(test)... + @$(CXX) $(LDFLAGS) -o $(test) $(test_objects) $(lib) + @echo Running unit tests... + @./$(test) + +clean: + -@$(RM) $(objects) $(test_objects) $(dependencies) $(test_dependencies) $(test) $(lib) 2> /dev/null + +%.o : %.cpp + @echo $< + @$(call make-depend,$<,$@,$(subst .o,.d,$@)) + @$(CXX) $(CXXFLAGS) -c $< -o $(patsubst %.cpp, %.o, $<) + + +ifneq "$(MAKECMDGOALS)" "clean" +-include $(dependencies) +-include $(test_dependencies) +endif diff --git a/tests/UnitTest++/README b/tests/UnitTest++/README new file mode 100644 index 0000000..e0a5192 --- /dev/null +++ b/tests/UnitTest++/README @@ -0,0 +1,68 @@ +UnitTest++ README +Version: v1.4 +Last update: 2008-10-30 + +UnitTest++ is free software. You may copy, distribute, and modify it under +the terms of the License contained in the file COPYING distributed +with this package. This license is the same as the MIT/X Consortium +license. + +See src/tests/TestUnitTest++.cpp for usage. + +Authors: +Noel Llopis ([email protected]) +Charles Nicholson ([email protected]) + +Contributors: +Jim Tilander +Kim Grasman +Jonathan Jansson +Dirck Blaskey +Rory Driscoll +Dan Lind +Matt Kimmel -- Submitted with permission from Blue Fang Games +Anthony Moralez +Jeff Dixon +Randy Coulman +Lieven van der Heide + +Release notes: +-------------- +Version 1.4 (2008-10-30) +- CHECK macros work at arbitrary stack depth from inside TESTs. +- Remove obsolete TEST_UTILITY macros +- Predicated test execution (via TestRunner::RunTestsIf) +- Better exception handling for fixture ctors/dtors. +- VC6/7/8/9 support + +Version 1.3 (2007-4-22) +- Removed dynamic memory allocations (other than streams) +- MinGW support +- Consistent (native) line endings +- Minor bug fixing + +Version 1.2 (2006-10-29) +- First pass at documentation. +- More detailed error crash catching in fixtures. +- Standard streams used for printing objects under check. This should allow the + use of standard class types such as std::string or other custom classes with + stream operators to ostream. +- Standard streams can be optionally compiled off by defining UNITTEST_USE_CUSTOM_STREAMS + in Config.h +- Added named test suites +- Added CHECK_ARRAY2D_CLOSE +- Posix library name is libUnitTest++.a now +- Floating point numbers are postfixed with f in the failure reports + +Version 1.1 (2006-04-18) +- CHECK macros do not have side effects even if one of the parameters changes state +- Removed CHECK_ARRAY_EQUAL (too similar to CHECK_ARRAY_CLOSE) +- Added local and global time constraints +- Removed dependencies on strstream +- Improved Posix signal to exception translator +- Failing tests are added to Visual Studio's error list +- Fixed Visual Studio projects to work with spaces in directories + +Version 1.0 (2006-03-15) +- Initial release + diff --git a/tests/UnitTest++/src/AssertException.cpp b/tests/UnitTest++/src/AssertException.cpp new file mode 100644 index 0000000..63f556e --- /dev/null +++ b/tests/UnitTest++/src/AssertException.cpp @@ -0,0 +1,34 @@ +#include "AssertException.h" +#include <cstring> + +namespace UnitTest { + +AssertException::AssertException(char const* description, char const* filename, int lineNumber) + : m_lineNumber(lineNumber) +{ + using namespace std; + + strcpy(m_description, description); + strcpy(m_filename, filename); +} + +AssertException::~AssertException() throw() +{ +} + +char const* AssertException::what() const throw() +{ + return m_description; +} + +char const* AssertException::Filename() const +{ + return m_filename; +} + +int AssertException::LineNumber() const +{ + return m_lineNumber; +} + +} diff --git a/tests/UnitTest++/src/AssertException.h b/tests/UnitTest++/src/AssertException.h new file mode 100644 index 0000000..e04d450 --- /dev/null +++ b/tests/UnitTest++/src/AssertException.h @@ -0,0 +1,28 @@ +#ifndef UNITTEST_ASSERTEXCEPTION_H +#define UNITTEST_ASSERTEXCEPTION_H + +#include <exception> + + +namespace UnitTest { + +class AssertException : public std::exception +{ +public: + AssertException(char const* description, char const* filename, int lineNumber); + virtual ~AssertException() throw(); + + virtual char const* what() const throw(); + + char const* Filename() const; + int LineNumber() const; + +private: + char m_description[512]; + char m_filename[256]; + int m_lineNumber; +}; + +} + +#endif diff --git a/tests/UnitTest++/src/CheckMacros.h b/tests/UnitTest++/src/CheckMacros.h new file mode 100644 index 0000000..8fbdae7 --- /dev/null +++ b/tests/UnitTest++/src/CheckMacros.h @@ -0,0 +1,122 @@ +#ifndef UNITTEST_CHECKMACROS_H +#define UNITTEST_CHECKMACROS_H + +#include "Checks.h" +#include "AssertException.h" +#include "MemoryOutStream.h" +#include "TestDetails.h" +#include "CurrentTest.h" + +#ifdef CHECK + #error UnitTest++ redefines CHECK +#endif + +#ifdef CHECK_EQUAL + #error UnitTest++ redefines CHECK_EQUAL +#endif + +#ifdef CHECK_CLOSE + #error UnitTest++ redefines CHECK_CLOSE +#endif + +#ifdef CHECK_ARRAY_EQUAL + #error UnitTest++ redefines CHECK_ARRAY_EQUAL +#endif + +#ifdef CHECK_ARRAY_CLOSE + #error UnitTest++ redefines CHECK_ARRAY_CLOSE +#endif + +#ifdef CHECK_ARRAY2D_CLOSE + #error UnitTest++ redefines CHECK_ARRAY2D_CLOSE +#endif + +#define CHECK(value) \ + do \ + { \ + try { \ + if (!UnitTest::Check(value)) \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), #value); \ + } \ + catch (...) { \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + "Unhandled exception in CHECK(" #value ")"); \ + } \ + } while (0) + +#define CHECK_EQUAL(expected, actual) \ + do \ + { \ + try { \ + UnitTest::CheckEqual(*UnitTest::CurrentTest::Results(), expected, actual, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ + } \ + catch (...) { \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + "Unhandled exception in CHECK_EQUAL(" #expected ", " #actual ")"); \ + } \ + } while (0) + +#define CHECK_CLOSE(expected, actual, tolerance) \ + do \ + { \ + try { \ + UnitTest::CheckClose(*UnitTest::CurrentTest::Results(), expected, actual, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ + } \ + catch (...) { \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + "Unhandled exception in CHECK_CLOSE(" #expected ", " #actual ")"); \ + } \ + } while (0) + +#define CHECK_ARRAY_EQUAL(expected, actual, count) \ + do \ + { \ + try { \ + UnitTest::CheckArrayEqual(*UnitTest::CurrentTest::Results(), expected, actual, count, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ + } \ + catch (...) { \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + "Unhandled exception in CHECK_ARRAY_EQUAL(" #expected ", " #actual ")"); \ + } \ + } while (0) + +#define CHECK_ARRAY_CLOSE(expected, actual, count, tolerance) \ + do \ + { \ + try { \ + UnitTest::CheckArrayClose(*UnitTest::CurrentTest::Results(), expected, actual, count, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ + } \ + catch (...) { \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + "Unhandled exception in CHECK_ARRAY_CLOSE(" #expected ", " #actual ")"); \ + } \ + } while (0) + +#define CHECK_ARRAY2D_CLOSE(expected, actual, rows, columns, tolerance) \ + do \ + { \ + try { \ + UnitTest::CheckArray2DClose(*UnitTest::CurrentTest::Results(), expected, actual, rows, columns, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ + } \ + catch (...) { \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ + "Unhandled exception in CHECK_ARRAY_CLOSE(" #expected ", " #actual ")"); \ + } \ + } while (0) + + +#define CHECK_THROW(expression, ExpectedExceptionType) \ + do \ + { \ + bool caught_ = false; \ + try { expression; } \ + catch (ExpectedExceptionType const&) { caught_ = true; } \ + catch (...) {} \ + if (!caught_) \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), "Expected exception: \"" #ExpectedExceptionType "\" not thrown"); \ + } while(0) + +#define CHECK_ASSERT(expression) \ + CHECK_THROW(expression, UnitTest::AssertException); + +#endif diff --git a/tests/UnitTest++/src/Checks.cpp b/tests/UnitTest++/src/Checks.cpp new file mode 100644 index 0000000..2d09519 --- /dev/null +++ b/tests/UnitTest++/src/Checks.cpp @@ -0,0 +1,50 @@ +#include "Checks.h" +#include <cstring> + +namespace UnitTest { + +namespace { + +void CheckStringsEqual(TestResults& results, char const* expected, char const* actual, + TestDetails const& details) +{ + using namespace std; + + if (strcmp(expected, actual)) + { + UnitTest::MemoryOutStream stream; + stream << "Expected " << expected << " but was " << actual; + + results.OnTestFailure(details, stream.GetText()); + } +} + +} + + +void CheckEqual(TestResults& results, char const* expected, char const* actual, + TestDetails const& details) +{ + CheckStringsEqual(results, expected, actual, details); +} + +void CheckEqual(TestResults& results, char* expected, char* actual, + TestDetails const& details) +{ + CheckStringsEqual(results, expected, actual, details); +} + +void CheckEqual(TestResults& results, char* expected, char const* actual, + TestDetails const& details) +{ + CheckStringsEqual(results, expected, actual, details); +} + +void CheckEqual(TestResults& results, char const* expected, char* actual, + TestDetails const& details) +{ + CheckStringsEqual(results, expected, actual, details); +} + + +} diff --git a/tests/UnitTest++/src/Checks.h b/tests/UnitTest++/src/Checks.h new file mode 100644 index 0000000..0090084 --- /dev/null +++ b/tests/UnitTest++/src/Checks.h @@ -0,0 +1,158 @@ +#ifndef UNITTEST_CHECKS_H +#define UNITTEST_CHECKS_H + +#include "Config.h" +#include "TestResults.h" +#include "MemoryOutStream.h" + +namespace UnitTest { + + +template< typename Value > +bool Check(Value const value) +{ + return !!value; // doing double negative to avoid silly VS warnings +} + + +template< typename Expected, typename Actual > +void CheckEqual(TestResults& results, Expected const& expected, Actual const& actual, TestDetails const& details) +{ + if (!(expected == actual)) + { + UnitTest::MemoryOutStream stream; + stream << "Expected " << expected << " but was " << actual; + + results.OnTestFailure(details, stream.GetText()); + } +} + +void CheckEqual(TestResults& results, char const* expected, char const* actual, TestDetails const& details); + +void CheckEqual(TestResults& results, char* expected, char* actual, TestDetails const& details); + +void CheckEqual(TestResults& results, char* expected, char const* actual, TestDetails const& details); + +void CheckEqual(TestResults& results, char const* expected, char* actual, TestDetails const& details); + +template< typename Expected, typename Actual, typename Tolerance > +bool AreClose(Expected const& expected, Actual const& actual, Tolerance const& tolerance) +{ + return (actual >= (expected - tolerance)) && (actual <= (expected + tolerance)); +} + +template< typename Expected, typename Actual, typename Tolerance > +void CheckClose(TestResults& results, Expected const& expected, Actual const& actual, Tolerance const& tolerance, + TestDetails const& details) +{ + if (!AreClose(expected, actual, tolerance)) + { + UnitTest::MemoryOutStream stream; + stream << "Expected " << expected << " +/- " << tolerance << " but was " << actual; + + results.OnTestFailure(details, stream.GetText()); + } +} + + +template< typename Expected, typename Actual > +void CheckArrayEqual(TestResults& results, Expected const& expected, Actual const& actual, + int const count, TestDetails const& details) +{ + bool equal = true; + for (int i = 0; i < count; ++i) + equal &= (expected[i] == actual[i]); + + if (!equal) + { + UnitTest::MemoryOutStream stream; + + stream << "Expected [ "; + + for (int expectedIndex = 0; expectedIndex < count; ++expectedIndex) + stream << expected[expectedIndex] << " "; + + stream << "] but was [ "; + + for (int actualIndex = 0; actualIndex < count; ++actualIndex) + stream << actual[actualIndex] << " "; + + stream << "]"; + + results.OnTestFailure(details, stream.GetText()); + } +} + +template< typename Expected, typename Actual, typename Tolerance > +bool ArrayAreClose(Expected const& expected, Actual const& actual, int const count, Tolerance const& tolerance) +{ + bool equal = true; + for (int i = 0; i < count; ++i) + equal &= AreClose(expected[i], actual[i], tolerance); + return equal; +} + +template< typename Expected, typename Actual, typename Tolerance > +void CheckArrayClose(TestResults& results, Expected const& expected, Actual const& actual, + int const count, Tolerance const& tolerance, TestDetails const& details) +{ + bool equal = ArrayAreClose(expected, actual, count, tolerance); + + if (!equal) + { + UnitTest::MemoryOutStream stream; + + stream << "Expected [ "; + for (int expectedIndex = 0; expectedIndex < count; ++expectedIndex) + stream << expected[expectedIndex] << " "; + stream << "] +/- " << tolerance << " but was [ "; + + for (int actualIndex = 0; actualIndex < count; ++actualIndex) + stream << actual[actualIndex] << " "; + stream << "]"; + + results.OnTestFailure(details, stream.GetText()); + } +} + +template< typename Expected, typename Actual, typename Tolerance > +void CheckArray2DClose(TestResults& results, Expected const& expected, Actual const& actual, + int const rows, int const columns, Tolerance const& tolerance, TestDetails const& details) +{ + bool equal = true; + for (int i = 0; i < rows; ++i) + equal &= ArrayAreClose(expected[i], actual[i], columns, tolerance); + + if (!equal) + { + UnitTest::MemoryOutStream stream; + + stream << "Expected [ "; + + for (int expectedRow = 0; expectedRow < rows; ++expectedRow) + { + stream << "[ "; + for (int expectedColumn = 0; expectedColumn < columns; ++expectedColumn) + stream << expected[expectedRow][expectedColumn] << " "; + stream << "] "; + } + + stream << "] +/- " << tolerance << " but was [ "; + + for (int actualRow = 0; actualRow < rows; ++actualRow) + { + stream << "[ "; + for (int actualColumn = 0; actualColumn < columns; ++actualColumn) + stream << actual[actualRow][actualColumn] << " "; + stream << "] "; + } + + stream << "]"; + + results.OnTestFailure(details, stream.GetText()); + } +} + +} + +#endif diff --git a/tests/UnitTest++/src/Config.h b/tests/UnitTest++/src/Config.h new file mode 100644 index 0000000..0ba21a0 --- /dev/null +++ b/tests/UnitTest++/src/Config.h @@ -0,0 +1,31 @@ +#ifndef UNITTEST_CONFIG_H +#define UNITTEST_CONFIG_H + +// Standard defines documented here: http://predef.sourceforge.net + +#if defined(_MSC_VER) + #pragma warning(disable:4127) // conditional expression is constant + #pragma warning(disable:4702) // unreachable code + #pragma warning(disable:4722) // destructor never returns, potential memory leak + + #if (_MSC_VER == 1200) // VC6 + #pragma warning(disable:4786) + #pragma warning(disable:4290) + #endif +#endif + +#if defined(unix) || defined(__unix__) || defined(__unix) || defined(linux) || \ + defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) + #define UNITTEST_POSIX +#endif + +#if defined(__MINGW32__) + #define UNITTEST_MINGW +#endif + +// by default, MemoryOutStream is implemented in terms of std::ostringstream, which can be expensive. +// uncomment this line to use the custom MemoryOutStream (no deps on std::ostringstream). + +//#define UNITTEST_USE_CUSTOM_STREAMS + +#endif diff --git a/tests/UnitTest++/src/CurrentTest.cpp b/tests/UnitTest++/src/CurrentTest.cpp new file mode 100644 index 0000000..ad8d9af --- /dev/null +++ b/tests/UnitTest++/src/CurrentTest.cpp @@ -0,0 +1,18 @@ +#include "CurrentTest.h" +#include <cstddef> + +namespace UnitTest { + +TestResults*& CurrentTest::Results() +{ + static TestResults* testResults = NULL; + return testResults; +} + +const TestDetails*& CurrentTest::Details() +{ + static const TestDetails* testDetails = NULL; + return testDetails; +} + +} diff --git a/tests/UnitTest++/src/CurrentTest.h b/tests/UnitTest++/src/CurrentTest.h new file mode 100644 index 0000000..9e9d07a --- /dev/null +++ b/tests/UnitTest++/src/CurrentTest.h @@ -0,0 +1,17 @@ +#ifndef UNITTEST_CURRENTTESTRESULTS_H +#define UNITTEST_CURRENTTESTRESULTS_H + +namespace UnitTest { + +class TestResults; +class TestDetails; + +namespace CurrentTest +{ + TestResults*& Results(); + const TestDetails*& Details(); +} + +} + +#endif diff --git a/tests/UnitTest++/src/DeferredTestReporter.cpp b/tests/UnitTest++/src/DeferredTestReporter.cpp new file mode 100644 index 0000000..f90826b --- /dev/null +++ b/tests/UnitTest++/src/DeferredTestReporter.cpp @@ -0,0 +1,29 @@ +#include "DeferredTestReporter.h" +#include "TestDetails.h" +#include "Config.h" + +using namespace UnitTest; + +void DeferredTestReporter::ReportTestStart(TestDetails const& details) +{ + m_results.push_back(DeferredTestResult(details.suiteName, details.testName)); +} + +void DeferredTestReporter::ReportFailure(TestDetails const& details, char const* failure) +{ + DeferredTestResult& r = m_results.back(); + r.failed = true; + r.failures.push_back(DeferredTestResult::Failure(details.lineNumber, failure)); + r.failureFile = details.filename; +} + +void DeferredTestReporter::ReportTestFinish(TestDetails const&, float secondsElapsed) +{ + DeferredTestResult& r = m_results.back(); + r.timeElapsed = secondsElapsed; +} + +DeferredTestReporter::DeferredTestResultList& DeferredTestReporter::GetResults() +{ + return m_results; +} diff --git a/tests/UnitTest++/src/DeferredTestReporter.h b/tests/UnitTest++/src/DeferredTestReporter.h new file mode 100644 index 0000000..026ed05 --- /dev/null +++ b/tests/UnitTest++/src/DeferredTestReporter.h @@ -0,0 +1,28 @@ +#ifndef UNITTEST_DEFERREDTESTREPORTER_H +#define UNITTEST_DEFERREDTESTREPORTER_H + +#include "TestReporter.h" +#include "DeferredTestResult.h" + +#include <vector> + +namespace UnitTest +{ + +class DeferredTestReporter : public TestReporter +{ +public: + virtual void ReportTestStart(TestDetails const& details); + virtual void ReportFailure(TestDetails const& details, char const* failure); + virtual void ReportTestFinish(TestDetails const& details, float secondsElapsed); + + typedef std::vector< DeferredTestResult > DeferredTestResultList; + DeferredTestResultList& GetResults(); + +private: + DeferredTestResultList m_results; +}; + +} + +#endif diff --git a/tests/UnitTest++/src/DeferredTestResult.cpp b/tests/UnitTest++/src/DeferredTestResult.cpp new file mode 100644 index 0000000..c2daa25 --- /dev/null +++ b/tests/UnitTest++/src/DeferredTestResult.cpp @@ -0,0 +1,25 @@ +#include "DeferredTestResult.h" +#include "Config.h" + +namespace UnitTest +{ + +DeferredTestResult::DeferredTestResult() + : suiteName("") + , testName("") + , failureFile("") + , timeElapsed(0.0f) + , failed(false) +{ +} + +DeferredTestResult::DeferredTestResult(char const* suite, char const* test) + : suiteName(suite) + , testName(test) + , failureFile("") + , timeElapsed(0.0f) + , failed(false) +{ +} + +} diff --git a/tests/UnitTest++/src/DeferredTestResult.h b/tests/UnitTest++/src/DeferredTestResult.h new file mode 100644 index 0000000..6cca77c --- /dev/null +++ b/tests/UnitTest++/src/DeferredTestResult.h @@ -0,0 +1,29 @@ +#ifndef UNITTEST_DEFERREDTESTRESULT_H +#define UNITTEST_DEFERREDTESTRESULT_H + +#include <string> +#include <vector> + +namespace UnitTest +{ + +struct DeferredTestResult +{ + DeferredTestResult(); + DeferredTestResult(char const* suite, char const* test); + + std::string suiteName; + std::string testName; + std::string failureFile; + + typedef std::pair< int, std::string > Failure; + typedef std::vector< Failure > FailureVec; + FailureVec failures; + + float timeElapsed; + bool failed; +}; + +} + +#endif //UNITTEST_DEFERREDTESTRESULT_H diff --git a/tests/UnitTest++/src/ExecuteTest.h b/tests/UnitTest++/src/ExecuteTest.h new file mode 100644 index 0000000..a00d4c5 --- /dev/null +++ b/tests/UnitTest++/src/ExecuteTest.h @@ -0,0 +1,46 @@ +#ifndef UNITTEST_EXECUTE_TEST_H +#define UNITTEST_EXECUTE_TEST_H + +#include "TestDetails.h" +#include "MemoryOutStream.h" +#include "AssertException.h" +#include "CurrentTest.h" + +#ifdef UNITTEST_POSIX + #include "Posix/SignalTranslator.h" +#endif + +namespace UnitTest { + +template< typename T > +void ExecuteTest(T& testObject, TestDetails const& details) +{ + CurrentTest::Details() = &details; + + try + { +#ifdef UNITTEST_POSIX + UNITTEST_THROW_SIGNALS +#endif + testObject.RunImpl(); + } + catch (AssertException const& e) + { + CurrentTest::Results()->OnTestFailure( + TestDetails(details.testName, details.suiteName, e.Filename(), e.LineNumber()), e.what()); + } + catch (std::exception const& e) + { + MemoryOutStream stream; + stream << "Unhandled exception: " << e.what(); + CurrentTest::Results()->OnTestFailure(details, stream.GetText()); + } + catch (...) + { + CurrentTest::Results()->OnTestFailure(details, "Unhandled exception: Crash!"); + } +} + +} + +#endif diff --git a/tests/UnitTest++/src/MemoryOutStream.cpp b/tests/UnitTest++/src/MemoryOutStream.cpp new file mode 100644 index 0000000..67a3e37 --- /dev/null +++ b/tests/UnitTest++/src/MemoryOutStream.cpp @@ -0,0 +1,149 @@ +#include "MemoryOutStream.h" + +#ifndef UNITTEST_USE_CUSTOM_STREAMS + + +namespace UnitTest { + +char const* MemoryOutStream::GetText() const +{ + m_text = this->str(); + return m_text.c_str(); +} + + +} + + +#else + + +#include <cstring> +#include <cstdio> + +namespace UnitTest { + +namespace { + +template<typename ValueType> +void FormatToStream(MemoryOutStream& stream, char const* format, ValueType const& value) +{ + using namespace std; + + char txt[32]; + sprintf(txt, format, value); + stream << txt; +} + +int RoundUpToMultipleOfPow2Number (int n, int pow2Number) +{ + return (n + (pow2Number - 1)) & ~(pow2Number - 1); +} + +} + + +MemoryOutStream::MemoryOutStream(int const size) + : m_capacity (0) + , m_buffer (0) + +{ + GrowBuffer(size); +} + +MemoryOutStream::~MemoryOutStream() +{ + delete [] m_buffer; +} + +char const* MemoryOutStream::GetText() const +{ + return m_buffer; +} + +MemoryOutStream& MemoryOutStream::operator << (char const* txt) +{ + using namespace std; + + int const bytesLeft = m_capacity - (int)strlen(m_buffer); + int const bytesRequired = (int)strlen(txt) + 1; + + if (bytesRequired > bytesLeft) + { + int const requiredCapacity = bytesRequired + m_capacity - bytesLeft; + GrowBuffer(requiredCapacity); + } + + strcat(m_buffer, txt); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (int const n) +{ + FormatToStream(*this, "%i", n); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (long const n) +{ + FormatToStream(*this, "%li", n); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (unsigned long const n) +{ + FormatToStream(*this, "%lu", n); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (float const f) +{ + FormatToStream(*this, "%ff", f); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (void const* p) +{ + FormatToStream(*this, "%p", p); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (unsigned int const s) +{ + FormatToStream(*this, "%u", s); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator <<(double const d) +{ + FormatToStream(*this, "%f", d); + return *this; +} + +int MemoryOutStream::GetCapacity() const +{ + return m_capacity; +} + + +void MemoryOutStream::GrowBuffer(int const desiredCapacity) +{ + int const newCapacity = RoundUpToMultipleOfPow2Number(desiredCapacity, GROW_CHUNK_SIZE); + + using namespace std; + + char* buffer = new char[newCapacity]; + if (m_buffer) + strcpy(buffer, m_buffer); + else + strcpy(buffer, ""); + + delete [] m_buffer; + m_buffer = buffer; + m_capacity = newCapacity; +} + +} + + +#endif diff --git a/tests/UnitTest++/src/MemoryOutStream.h b/tests/UnitTest++/src/MemoryOutStream.h new file mode 100644 index 0000000..e03227e --- /dev/null +++ b/tests/UnitTest++/src/MemoryOutStream.h @@ -0,0 +1,67 @@ +#ifndef UNITTEST_MEMORYOUTSTREAM_H +#define UNITTEST_MEMORYOUTSTREAM_H + +#include "Config.h" + +#ifndef UNITTEST_USE_CUSTOM_STREAMS + +#include <sstream> + +namespace UnitTest +{ + +class MemoryOutStream : public std::ostringstream +{ +public: + MemoryOutStream() {} + char const* GetText() const; + +private: + MemoryOutStream(MemoryOutStream const&); + void operator =(MemoryOutStream const&); + + mutable std::string m_text; +}; + +} + +#else + +#include <cstddef> + +namespace UnitTest +{ + +class MemoryOutStream +{ +public: + explicit MemoryOutStream(int const size = 256); + ~MemoryOutStream(); + + char const* GetText() const; + + MemoryOutStream& operator << (char const* txt); + MemoryOutStream& operator << (int n); + MemoryOutStream& operator << (long n); + MemoryOutStream& operator << (unsigned long n); + MemoryOutStream& operator << (float f); + MemoryOutStream& operator << (double d); + MemoryOutStream& operator << (void const* p); + MemoryOutStream& operator << (unsigned int s); + + enum { GROW_CHUNK_SIZE = 32 }; + int GetCapacity() const; + +private: + void operator= (MemoryOutStream const&); + void GrowBuffer(int capacity); + + int m_capacity; + char* m_buffer; +}; + +} + +#endif + +#endif diff --git a/tests/UnitTest++/src/Posix/SignalTranslator.cpp b/tests/UnitTest++/src/Posix/SignalTranslator.cpp new file mode 100644 index 0000000..3689c8c --- /dev/null +++ b/tests/UnitTest++/src/Posix/SignalTranslator.cpp @@ -0,0 +1,46 @@ +#include "SignalTranslator.h" + +namespace UnitTest { + +sigjmp_buf* SignalTranslator::s_jumpTarget = 0; + +namespace { + +void SignalHandler(int sig) +{ + siglongjmp(*SignalTranslator::s_jumpTarget, sig ); +} + +} + + +SignalTranslator::SignalTranslator() +{ + m_oldJumpTarget = s_jumpTarget; + s_jumpTarget = &m_currentJumpTarget; + + struct sigaction action; + action.sa_flags = 0; + action.sa_handler = SignalHandler; + sigemptyset( &action.sa_mask ); + + sigaction( SIGSEGV, &action, &m_old_SIGSEGV_action ); + sigaction( SIGFPE , &action, &m_old_SIGFPE_action ); + sigaction( SIGTRAP, &action, &m_old_SIGTRAP_action ); + sigaction( SIGBUS , &action, &m_old_SIGBUS_action ); + sigaction( SIGILL , &action, &m_old_SIGBUS_action ); +} + +SignalTranslator::~SignalTranslator() +{ + sigaction( SIGILL , &m_old_SIGBUS_action , 0 ); + sigaction( SIGBUS , &m_old_SIGBUS_action , 0 ); + sigaction( SIGTRAP, &m_old_SIGTRAP_action, 0 ); + sigaction( SIGFPE , &m_old_SIGFPE_action , 0 ); + sigaction( SIGSEGV, &m_old_SIGSEGV_action, 0 ); + + s_jumpTarget = m_oldJumpTarget; +} + + +} diff --git a/tests/UnitTest++/src/Posix/SignalTranslator.h b/tests/UnitTest++/src/Posix/SignalTranslator.h new file mode 100644 index 0000000..bf98ad3 --- /dev/null +++ b/tests/UnitTest++/src/Posix/SignalTranslator.h @@ -0,0 +1,42 @@ +#ifndef UNITTEST_SIGNALTRANSLATOR_H +#define UNITTEST_SIGNALTRANSLATOR_H + +#include <setjmp.h> +#include <signal.h> + +namespace UnitTest { + +class SignalTranslator +{ +public: + SignalTranslator(); + ~SignalTranslator(); + + static sigjmp_buf* s_jumpTarget; + +private: + sigjmp_buf m_currentJumpTarget; + sigjmp_buf* m_oldJumpTarget; + + struct sigaction m_old_SIGFPE_action; + struct sigaction m_old_SIGTRAP_action; + struct sigaction m_old_SIGSEGV_action; + struct sigaction m_old_SIGBUS_action; + struct sigaction m_old_SIGABRT_action; + struct sigaction m_old_SIGALRM_action; +}; + +#if !defined (__GNUC__) + #define UNITTEST_EXTENSION +#else + #define UNITTEST_EXTENSION __extension__ +#endif + +#define UNITTEST_THROW_SIGNALS \ + UnitTest::SignalTranslator sig; \ + if (UNITTEST_EXTENSION sigsetjmp(*UnitTest::SignalTranslator::s_jumpTarget, 1) != 0) \ + throw ("Unhandled system exception"); + +} + +#endif diff --git a/tests/UnitTest++/src/Posix/TimeHelpers.cpp b/tests/UnitTest++/src/Posix/TimeHelpers.cpp new file mode 100644 index 0000000..bfd23c0 --- /dev/null +++ b/tests/UnitTest++/src/Posix/TimeHelpers.cpp @@ -0,0 +1,33 @@ +#include "TimeHelpers.h" +#include <unistd.h> + +namespace UnitTest { + +Timer::Timer() +{ + m_startTime.tv_sec = 0; + m_startTime.tv_usec = 0; +} + +void Timer::Start() +{ + gettimeofday(&m_startTime, 0); +} + + +int Timer::GetTimeInMs() const +{ + struct timeval currentTime; + gettimeofday(¤tTime, 0); + int const dsecs = currentTime.tv_sec - m_startTime.tv_sec; + int const dus = currentTime.tv_usec - m_startTime.tv_usec; + return dsecs*1000 + dus/1000; +} + + +void TimeHelpers::SleepMs (int ms) +{ + usleep(ms * 1000); +} + +} diff --git a/tests/UnitTest++/src/Posix/TimeHelpers.h b/tests/UnitTest++/src/Posix/TimeHelpers.h new file mode 100644 index 0000000..fdc8428 --- /dev/null +++ b/tests/UnitTest++/src/Posix/TimeHelpers.h @@ -0,0 +1,28 @@ +#ifndef UNITTEST_TIMEHELPERS_H +#define UNITTEST_TIMEHELPERS_H + +#include <sys/time.h> + +namespace UnitTest { + +class Timer +{ +public: + Timer(); + void Start(); + int GetTimeInMs() const; + +private: + struct timeval m_startTime; +}; + + +namespace TimeHelpers +{ +void SleepMs (int ms); +} + + +} + +#endif diff --git a/tests/UnitTest++/src/ReportAssert.cpp b/tests/UnitTest++/src/ReportAssert.cpp new file mode 100644 index 0000000..a1810d9 --- /dev/null +++ b/tests/UnitTest++/src/ReportAssert.cpp @@ -0,0 +1,10 @@ +#include "AssertException.h" + +namespace UnitTest { + +void ReportAssert(char const* description, char const* filename, int lineNumber) +{ + throw AssertException(description, filename, lineNumber); +} + +} diff --git a/tests/UnitTest++/src/ReportAssert.h b/tests/UnitTest++/src/ReportAssert.h new file mode 100644 index 0000000..d4dd864 --- /dev/null +++ b/tests/UnitTest++/src/ReportAssert.h @@ -0,0 +1,10 @@ +#ifndef UNITTEST_ASSERT_H +#define UNITTEST_ASSERT_H + +namespace UnitTest { + +void ReportAssert(char const* description, char const* filename, int lineNumber); + +} + +#endif diff --git a/tests/UnitTest++/src/Test.cpp b/tests/UnitTest++/src/Test.cpp new file mode 100644 index 0000000..bc9cb3d --- /dev/null +++ b/tests/UnitTest++/src/Test.cpp @@ -0,0 +1,41 @@ +#include "Config.h" +#include "Test.h" +#include "TestList.h" +#include "TestResults.h" +#include "AssertException.h" +#include "MemoryOutStream.h" +#include "ExecuteTest.h" + +#ifdef UNITTEST_POSIX + #include "Posix/SignalTranslator.h" +#endif + +namespace UnitTest { + +TestList& Test::GetTestList() +{ + static TestList s_list; + return s_list; +} + +Test::Test(char const* testName, char const* suiteName, char const* filename, int lineNumber) + : m_details(testName, suiteName, filename, lineNumber) + , next(0) + , m_timeConstraintExempt(false) +{ +} + +Test::~Test() +{ +} + +void Test::Run() +{ + ExecuteTest(*this, m_details); +} + +void Test::RunImpl() const +{ +} + +} diff --git a/tests/UnitTest++/src/Test.h b/tests/UnitTest++/src/Test.h new file mode 100644 index 0000000..91026b6 --- /dev/null +++ b/tests/UnitTest++/src/Test.h @@ -0,0 +1,34 @@ +#ifndef UNITTEST_TEST_H +#define UNITTEST_TEST_H + +#include "TestDetails.h" + +namespace UnitTest { + +class TestResults; +class TestList; + +class Test +{ +public: + explicit Test(char const* testName, char const* suiteName = "DefaultSuite", char const* filename = "", int lineNumber = 0); + virtual ~Test(); + void Run(); + + TestDetails const m_details; + Test* next; + mutable bool m_timeConstraintExempt; + + static TestList& GetTestList(); + + virtual void RunImpl() const; + +private: + Test(Test const&); + Test& operator =(Test const&); +}; + + +} + +#endif diff --git a/tests/UnitTest++/src/TestDetails.cpp b/tests/UnitTest++/src/TestDetails.cpp new file mode 100644 index 0000000..a13a168 --- /dev/null +++ b/tests/UnitTest++/src/TestDetails.cpp @@ -0,0 +1,22 @@ +#include "TestDetails.h" + +namespace UnitTest { + +TestDetails::TestDetails(char const* testName_, char const* suiteName_, char const* filename_, int lineNumber_) + : suiteName(suiteName_) + , testName(testName_) + , filename(filename_) + , lineNumber(lineNumber_) +{ +} + +TestDetails::TestDetails(const TestDetails& details, int lineNumber_) + : suiteName(details.suiteName) + , testName(details.testName) + , filename(details.filename) + , lineNumber(lineNumber_) +{ +} + + +} diff --git a/tests/UnitTest++/src/TestDetails.h b/tests/UnitTest++/src/TestDetails.h new file mode 100644 index 0000000..eae0e71 --- /dev/null +++ b/tests/UnitTest++/src/TestDetails.h @@ -0,0 +1,24 @@ +#ifndef UNITTEST_TESTDETAILS_H +#define UNITTEST_TESTDETAILS_H + +namespace UnitTest { + +class TestDetails +{ +public: + TestDetails(char const* testName, char const* suiteName, char const* filename, int lineNumber); + TestDetails(const TestDetails& details, int lineNumber); + + char const* const suiteName; + char const* const testName; + char const* const filename; + int const lineNumber; + + TestDetails(TestDetails const&); // Why is it public? --> http://gcc.gnu.org/bugs.html#cxx_rvalbind +private: + TestDetails& operator=(TestDetails const&); +}; + +} + +#endif diff --git a/tests/UnitTest++/src/TestList.cpp b/tests/UnitTest++/src/TestList.cpp new file mode 100644 index 0000000..e31e613 --- /dev/null +++ b/tests/UnitTest++/src/TestList.cpp @@ -0,0 +1,39 @@ +#include "TestList.h" +#include "Test.h" + +#include <cassert> + +namespace UnitTest { + +TestList::TestList() + : m_head(0) + , m_tail(0) +{ +} + +void TestList::Add(Test* test) +{ + if (m_tail == 0) + { + assert(m_head == 0); + m_head = test; + m_tail = test; + } + else + { + m_tail->next = test; + m_tail = test; + } +} + +Test* TestList::GetHead() const +{ + return m_head; +} + +ListAdder::ListAdder(TestList& list, Test* test) +{ + list.Add(test); +} + +} diff --git a/tests/UnitTest++/src/TestList.h b/tests/UnitTest++/src/TestList.h new file mode 100644 index 0000000..b17424b --- /dev/null +++ b/tests/UnitTest++/src/TestList.h @@ -0,0 +1,32 @@ +#ifndef UNITTEST_TESTLIST_H +#define UNITTEST_TESTLIST_H + + +namespace UnitTest { + +class Test; + +class TestList +{ +public: + TestList(); + void Add (Test* test); + + Test* GetHead() const; + +private: + Test* m_head; + Test* m_tail; +}; + + +class ListAdder +{ +public: + ListAdder(TestList& list, Test* test); +}; + +} + + +#endif diff --git a/tests/UnitTest++/src/TestMacros.h b/tests/UnitTest++/src/TestMacros.h new file mode 100644 index 0000000..a297f15 --- /dev/null +++ b/tests/UnitTest++/src/TestMacros.h @@ -0,0 +1,113 @@ +#ifndef UNITTEST_TESTMACROS_H +#define UNITTEST_TESTMACROS_H + +#include "Config.h" +#include "ExecuteTest.h" +#include "AssertException.h" +#include "TestDetails.h" +#include "MemoryOutStream.h" + +#ifndef UNITTEST_POSIX + #define UNITTEST_THROW_SIGNALS +#else + #include "Posix/SignalTranslator.h" +#endif + +#ifdef TEST + #error UnitTest++ redefines TEST +#endif + +#ifdef TEST_EX + #error UnitTest++ redefines TEST_EX +#endif + +#ifdef TEST_FIXTURE_EX + #error UnitTest++ redefines TEST_FIXTURE_EX +#endif + +#define SUITE(Name) \ + namespace Suite##Name { \ + namespace UnitTestSuite { \ + inline char const* GetSuiteName () { \ + return #Name ; \ + } \ + } \ + } \ + namespace Suite##Name + +#define TEST_EX(Name, List) \ + class Test##Name : public UnitTest::Test \ + { \ + public: \ + Test##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ + private: \ + virtual void RunImpl() const; \ + } test##Name##Instance; \ + \ + UnitTest::ListAdder adder##Name (List, &test##Name##Instance); \ + \ + void Test##Name::RunImpl() const + + +#define TEST(Name) TEST_EX(Name, UnitTest::Test::GetTestList()) + + +#define TEST_FIXTURE_EX(Fixture, Name, List) \ + class Fixture##Name##Helper : public Fixture \ + { \ + public: \ + explicit Fixture##Name##Helper(UnitTest::TestDetails const& details) : m_details(details) {} \ + void RunImpl(); \ + UnitTest::TestDetails const& m_details; \ + private: \ + Fixture##Name##Helper(Fixture##Name##Helper const&); \ + Fixture##Name##Helper& operator =(Fixture##Name##Helper const&); \ + }; \ + \ + class Test##Fixture##Name : public UnitTest::Test \ + { \ + public: \ + Test##Fixture##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ + private: \ + virtual void RunImpl() const; \ + } test##Fixture##Name##Instance; \ + \ + UnitTest::ListAdder adder##Fixture##Name (List, &test##Fixture##Name##Instance); \ + \ + void Test##Fixture##Name::RunImpl() const \ + { \ + bool ctorOk = false; \ + try { \ + Fixture##Name##Helper fixtureHelper(m_details); \ + ctorOk = true; \ + UnitTest::ExecuteTest(fixtureHelper, m_details); \ + } \ + catch (UnitTest::AssertException const& e) \ + { \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(m_details.testName, m_details.suiteName, e.Filename(), e.LineNumber()), e.what()); \ + } \ + catch (std::exception const& e) \ + { \ + UnitTest::MemoryOutStream stream; \ + stream << "Unhandled exception: " << e.what(); \ + UnitTest::CurrentTest::Results()->OnTestFailure(m_details, stream.GetText()); \ + } \ + catch (...) { \ + if (ctorOk) \ + { \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception while destroying fixture " #Fixture); \ + } \ + else \ + { \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception while constructing fixture " #Fixture); \ + } \ + } \ + } \ + void Fixture##Name##Helper::RunImpl() + +#define TEST_FIXTURE(Fixture,Name) TEST_FIXTURE_EX(Fixture, Name, UnitTest::Test::GetTestList()) + + +#endif diff --git a/tests/UnitTest++/src/TestReporter.cpp b/tests/UnitTest++/src/TestReporter.cpp new file mode 100644 index 0000000..608d3c6 --- /dev/null +++ b/tests/UnitTest++/src/TestReporter.cpp @@ -0,0 +1,10 @@ +#include "TestReporter.h" + +namespace UnitTest { + + +TestReporter::~TestReporter() +{ +} + +} diff --git a/tests/UnitTest++/src/TestReporter.h b/tests/UnitTest++/src/TestReporter.h new file mode 100644 index 0000000..5a2f404 --- /dev/null +++ b/tests/UnitTest++/src/TestReporter.h @@ -0,0 +1,20 @@ +#ifndef UNITTEST_TESTREPORTER_H +#define UNITTEST_TESTREPORTER_H + +namespace UnitTest { + +class TestDetails; + +class TestReporter +{ +public: + virtual ~TestReporter(); + + virtual void ReportTestStart(TestDetails const& test) = 0; + virtual void ReportFailure(TestDetails const& test, char const* failure) = 0; + virtual void ReportTestFinish(TestDetails const& test, float secondsElapsed) = 0; + virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed) = 0; +}; + +} +#endif diff --git a/tests/UnitTest++/src/TestReporterStdout.cpp b/tests/UnitTest++/src/TestReporterStdout.cpp new file mode 100644 index 0000000..f495c0f --- /dev/null +++ b/tests/UnitTest++/src/TestReporterStdout.cpp @@ -0,0 +1,41 @@ +#include "TestReporterStdout.h" +#include <cstdio> + +#include "TestDetails.h" + +namespace UnitTest { + +void TestReporterStdout::ReportFailure(TestDetails const& details, char const* failure) +{ +#if defined(__APPLE__) || defined(__GNUG__) + char const* const errorFormat = "%s:%d: error: Failure in %s: %s\n"; +#else + char const* const errorFormat = "%s(%d): error: Failure in %s: %s\n"; +#endif + + using namespace std; + printf(errorFormat, details.filename, details.lineNumber, details.testName, failure); +} + +void TestReporterStdout::ReportTestStart(TestDetails const& /*test*/) +{ +} + +void TestReporterStdout::ReportTestFinish(TestDetails const& /*test*/, float) +{ +} + +void TestReporterStdout::ReportSummary(int const totalTestCount, int const failedTestCount, + int const failureCount, float secondsElapsed) +{ + using namespace std; + + if (failureCount > 0) + printf("FAILURE: %d out of %d tests failed (%d failures).\n", failedTestCount, totalTestCount, failureCount); + else + printf("Success: %d tests passed.\n", totalTestCount); + + printf("Test time: %.2f seconds.\n", secondsElapsed); +} + +} diff --git a/tests/UnitTest++/src/TestReporterStdout.h b/tests/UnitTest++/src/TestReporterStdout.h new file mode 100644 index 0000000..eacbba3 --- /dev/null +++ b/tests/UnitTest++/src/TestReporterStdout.h @@ -0,0 +1,19 @@ +#ifndef UNITTEST_TESTREPORTERSTDOUT_H +#define UNITTEST_TESTREPORTERSTDOUT_H + +#include "TestReporter.h" + +namespace UnitTest { + +class TestReporterStdout : public TestReporter +{ +private: + virtual void ReportTestStart(TestDetails const& test); + virtual void ReportFailure(TestDetails const& test, char const* failure); + virtual void ReportTestFinish(TestDetails const& test, float secondsElapsed); + virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed); +}; + +} + +#endif diff --git a/tests/UnitTest++/src/TestResults.cpp b/tests/UnitTest++/src/TestResults.cpp new file mode 100644 index 0000000..b3b67c0 --- /dev/null +++ b/tests/UnitTest++/src/TestResults.cpp @@ -0,0 +1,60 @@ +#include "TestResults.h" +#include "TestReporter.h" + +#include "TestDetails.h" + +namespace UnitTest { + +TestResults::TestResults(TestReporter* testReporter) + : m_testReporter(testReporter) + , m_totalTestCount(0) + , m_failedTestCount(0) + , m_failureCount(0) + , m_currentTestFailed(false) +{ +} + +void TestResults::OnTestStart(TestDetails const& test) +{ + ++m_totalTestCount; + m_currentTestFailed = false; + if (m_testReporter) + m_testReporter->ReportTestStart(test); +} + +void TestResults::OnTestFailure(TestDetails const& test, char const* failure) +{ + ++m_failureCount; + if (!m_currentTestFailed) + { + ++m_failedTestCount; + m_currentTestFailed = true; + } + + if (m_testReporter) + m_testReporter->ReportFailure(test, failure); +} + +void TestResults::OnTestFinish(TestDetails const& test, float secondsElapsed) +{ + if (m_testReporter) + m_testReporter->ReportTestFinish(test, secondsElapsed); +} + +int TestResults::GetTotalTestCount() const +{ + return m_totalTestCount; +} + +int TestResults::GetFailedTestCount() const +{ + return m_failedTestCount; +} + +int TestResults::GetFailureCount() const +{ + return m_failureCount; +} + + +} diff --git a/tests/UnitTest++/src/TestResults.h b/tests/UnitTest++/src/TestResults.h new file mode 100644 index 0000000..8ef7fda --- /dev/null +++ b/tests/UnitTest++/src/TestResults.h @@ -0,0 +1,36 @@ +#ifndef UNITTEST_TESTRESULTS_H +#define UNITTEST_TESTRESULTS_H + +namespace UnitTest { + +class TestReporter; +class TestDetails; + +class TestResults +{ +public: + explicit TestResults(TestReporter* reporter = 0); + + void OnTestStart(TestDetails const& test); + void OnTestFailure(TestDetails const& test, char const* failure); + void OnTestFinish(TestDetails const& test, float secondsElapsed); + + int GetTotalTestCount() const; + int GetFailedTestCount() const; + int GetFailureCount() const; + +private: + TestReporter* m_testReporter; + int m_totalTestCount; + int m_failedTestCount; + int m_failureCount; + + bool m_currentTestFailed; + + TestResults(TestResults const&); + TestResults& operator =(TestResults const&); +}; + +} + +#endif diff --git a/tests/UnitTest++/src/TestRunner.cpp b/tests/UnitTest++/src/TestRunner.cpp new file mode 100644 index 0000000..466265d --- /dev/null +++ b/tests/UnitTest++/src/TestRunner.cpp @@ -0,0 +1,76 @@ +#include "TestRunner.h" +#include "TestResults.h" +#include "TestReporter.h" +#include "TestReporterStdout.h" +#include "TimeHelpers.h" +#include "MemoryOutStream.h" + +#include <cstring> + + +namespace UnitTest { + +int RunAllTests() +{ + TestReporterStdout reporter; + TestRunner runner(reporter); + return runner.RunTestsIf(Test::GetTestList(), NULL, True(), 0); +} + + +TestRunner::TestRunner(TestReporter& reporter) + : m_reporter(&reporter) + , m_result(new TestResults(&reporter)) + , m_timer(new Timer) +{ + m_timer->Start(); +} + +TestRunner::~TestRunner() +{ + delete m_result; + delete m_timer; +} + +int TestRunner::Finish() const +{ + float const secondsElapsed = m_timer->GetTimeInMs() / 1000.0f; + m_reporter->ReportSummary(m_result->GetTotalTestCount(), + m_result->GetFailedTestCount(), + m_result->GetFailureCount(), + secondsElapsed); + + return m_result->GetFailureCount(); +} + +bool TestRunner::IsTestInSuite(const Test* const curTest, char const* suiteName) const +{ + using namespace std; + return (suiteName == NULL) || !strcmp(curTest->m_details.suiteName, suiteName); +} + +void TestRunner::RunTest(TestResults* const result, Test* const curTest, int const maxTestTimeInMs) const +{ + CurrentTest::Results() = result; + + Timer testTimer; + testTimer.Start(); + + result->OnTestStart(curTest->m_details); + + curTest->Run(); + + int const testTimeInMs = testTimer.GetTimeInMs(); + if (maxTestTimeInMs > 0 && testTimeInMs > maxTestTimeInMs && !curTest->m_timeConstraintExempt) + { + MemoryOutStream stream; + stream << "Global time constraint failed. Expected under " << maxTestTimeInMs << + "ms but took " << testTimeInMs << "ms."; + + result->OnTestFailure(curTest->m_details, stream.GetText()); + } + + result->OnTestFinish(curTest->m_details, testTimeInMs/1000.0f); +} + +} diff --git a/tests/UnitTest++/src/TestRunner.h b/tests/UnitTest++/src/TestRunner.h new file mode 100644 index 0000000..0798af9 --- /dev/null +++ b/tests/UnitTest++/src/TestRunner.h @@ -0,0 +1,61 @@ +#ifndef UNITTEST_TESTRUNNER_H +#define UNITTEST_TESTRUNNER_H + +#include "Test.h" +#include "TestList.h" +#include "CurrentTest.h" + +namespace UnitTest { + +class TestReporter; +class TestResults; +class Timer; + +int RunAllTests(); + +struct True +{ + bool operator()(const Test* const) const + { + return true; + } +}; + +class TestRunner +{ +public: + explicit TestRunner(TestReporter& reporter); + ~TestRunner(); + + template <class Predicate> + int RunTestsIf(TestList const& list, char const* suiteName, + const Predicate& predicate, int maxTestTimeInMs) const + { + Test* curTest = list.GetHead(); + + while (curTest != 0) + { + if (IsTestInSuite(curTest,suiteName) && predicate(curTest)) + { + RunTest(m_result, curTest, maxTestTimeInMs); + } + + curTest = curTest->next; + } + + return Finish(); + } + +private: + TestReporter* m_reporter; + TestResults* m_result; + Timer* m_timer; + + int Finish() const; + bool IsTestInSuite(const Test* const curTest, char const* suiteName) const; + void RunTest(TestResults* const result, Test* const curTest, int const maxTestTimeInMs) const; +}; + +} + +#endif diff --git a/tests/UnitTest++/src/TestSuite.h b/tests/UnitTest++/src/TestSuite.h new file mode 100644 index 0000000..dd3717e --- /dev/null +++ b/tests/UnitTest++/src/TestSuite.h @@ -0,0 +1,14 @@ +#ifndef UNITTEST_TESTSUITE_H +#define UNITTEST_TESTSUITE_H + +namespace UnitTestSuite { + + inline char const* GetSuiteName () + { + return "DefaultSuite"; + } + +} + +#endif + diff --git a/tests/UnitTest++/src/TimeConstraint.cpp b/tests/UnitTest++/src/TimeConstraint.cpp new file mode 100644 index 0000000..b313be7 --- /dev/null +++ b/tests/UnitTest++/src/TimeConstraint.cpp @@ -0,0 +1,29 @@ +#include "TimeConstraint.h" +#include "TestResults.h" +#include "MemoryOutStream.h" +#include "CurrentTest.h" + +namespace UnitTest { + + +TimeConstraint::TimeConstraint(int ms, TestDetails const& details) + : m_details(details) + , m_maxMs(ms) +{ + m_timer.Start(); +} + +TimeConstraint::~TimeConstraint() +{ + int const totalTimeInMs = m_timer.GetTimeInMs(); + if (totalTimeInMs > m_maxMs) + { + MemoryOutStream stream; + stream << "Time constraint failed. Expected to run test under " << m_maxMs << + "ms but took " << totalTimeInMs << "ms."; + + UnitTest::CurrentTest::Results()->OnTestFailure(m_details, stream.GetText()); + } +} + +} diff --git a/tests/UnitTest++/src/TimeConstraint.h b/tests/UnitTest++/src/TimeConstraint.h new file mode 100644 index 0000000..ac32914 --- /dev/null +++ b/tests/UnitTest++/src/TimeConstraint.h @@ -0,0 +1,33 @@ +#ifndef UNITTEST_TIMECONSTRAINT_H +#define UNITTEST_TIMECONSTRAINT_H + +#include "TimeHelpers.h" + +namespace UnitTest { + +class TestResults; +class TestDetails; + +class TimeConstraint +{ +public: + TimeConstraint(int ms, TestDetails const& details); + ~TimeConstraint(); + +private: + void operator=(TimeConstraint const&); + TimeConstraint(TimeConstraint const&); + + Timer m_timer; + TestDetails const& m_details; + int const m_maxMs; +}; + +#define UNITTEST_TIME_CONSTRAINT(ms) \ + UnitTest::TimeConstraint unitTest__timeConstraint__(ms, UnitTest::TestDetails(m_details, __LINE__)) + +#define UNITTEST_TIME_CONSTRAINT_EXEMPT() do { m_timeConstraintExempt = true; } while (0) + +} + +#endif diff --git a/tests/UnitTest++/src/TimeHelpers.h b/tests/UnitTest++/src/TimeHelpers.h new file mode 100644 index 0000000..f34ed00 --- /dev/null +++ b/tests/UnitTest++/src/TimeHelpers.h @@ -0,0 +1,7 @@ +#include "Config.h" + +#if defined UNITTEST_POSIX + #include "Posix/TimeHelpers.h" +#else + #include "Win32/TimeHelpers.h" +#endif diff --git a/tests/UnitTest++/src/UnitTest++.h b/tests/UnitTest++/src/UnitTest++.h new file mode 100644 index 0000000..3318735 --- /dev/null +++ b/tests/UnitTest++/src/UnitTest++.h @@ -0,0 +1,18 @@ +#ifndef UNITTESTCPP_H +#define UNITTESTCPP_H + +//lint -esym(1509,*Fixture) + +#include "Config.h" +#include "Test.h" +#include "TestList.h" +#include "TestSuite.h" +#include "TestResults.h" + +#include "TestMacros.h" + +#include "CheckMacros.h" +#include "TestRunner.h" +#include "TimeConstraint.h" + +#endif diff --git a/tests/UnitTest++/src/XmlTestReporter.cpp b/tests/UnitTest++/src/XmlTestReporter.cpp new file mode 100644 index 0000000..fe8966f --- /dev/null +++ b/tests/UnitTest++/src/XmlTestReporter.cpp @@ -0,0 +1,127 @@ +#include "XmlTestReporter.h" +#include "Config.h" + +#include <iostream> +#include <sstream> +#include <string> + +using std::string; +using std::ostringstream; +using std::ostream; + +namespace { + +void ReplaceChar(string& str, char c, string const& replacement) +{ + for (size_t pos = str.find(c); pos != string::npos; pos = str.find(c, pos + 1)) + str.replace(pos, 1, replacement); +} + +string XmlEscape(string const& value) +{ + string escaped = value; + + ReplaceChar(escaped, '&', "&"); + ReplaceChar(escaped, '<', "<"); + ReplaceChar(escaped, '>', ">"); + ReplaceChar(escaped, '\'', "'"); + ReplaceChar(escaped, '\"', """); + + return escaped; +} + +string BuildFailureMessage(string const& file, int line, string const& message) +{ + ostringstream failureMessage; + failureMessage << file << "(" << line << ") : " << message; + return failureMessage.str(); +} + +} + +namespace UnitTest { + +XmlTestReporter::XmlTestReporter(ostream& ostream) + : m_ostream(ostream) +{ +} + +void XmlTestReporter::ReportSummary(int totalTestCount, int failedTestCount, + int failureCount, float secondsElapsed) +{ + AddXmlElement(m_ostream, NULL); + + BeginResults(m_ostream, totalTestCount, failedTestCount, failureCount, secondsElapsed); + + DeferredTestResultList const& results = GetResults(); + for (DeferredTestResultList::const_iterator i = results.begin(); i != results.end(); ++i) + { + BeginTest(m_ostream, *i); + + if (i->failed) + AddFailure(m_ostream, *i); + + EndTest(m_ostream, *i); + } + + EndResults(m_ostream); +} + +void XmlTestReporter::AddXmlElement(ostream& os, char const* encoding) +{ + os << "<?xml version=\"1.0\""; + + if (encoding != NULL) + os << " encoding=\"" << encoding << "\""; + + os << "?>"; +} + +void XmlTestReporter::BeginResults(std::ostream& os, int totalTestCount, int failedTestCount, + int failureCount, float secondsElapsed) +{ + os << "<unittest-results" + << " tests=\"" << totalTestCount << "\"" + << " failedtests=\"" << failedTestCount << "\"" + << " failures=\"" << failureCount << "\"" + << " time=\"" << secondsElapsed << "\"" + << ">"; +} + +void XmlTestReporter::EndResults(std::ostream& os) +{ + os << "</unittest-results>"; +} + +void XmlTestReporter::BeginTest(std::ostream& os, DeferredTestResult const& result) +{ + os << "<test" + << " suite=\"" << result.suiteName << "\"" + << " name=\"" << result.testName << "\"" + << " time=\"" << result.timeElapsed << "\""; +} + +void XmlTestReporter::EndTest(std::ostream& os, DeferredTestResult const& result) +{ + if (result.failed) + os << "</test>"; + else + os << "/>"; +} + +void XmlTestReporter::AddFailure(std::ostream& os, DeferredTestResult const& result) +{ + os << ">"; // close <test> element + + for (DeferredTestResult::FailureVec::const_iterator it = result.failures.begin(); + it != result.failures.end(); + ++it) + { + string const escapedMessage = XmlEscape(it->second); + string const message = BuildFailureMessage(result.failureFile, it->first, escapedMessage); + + os << "<failure" << " message=\"" << message << "\"" << "/>"; + } +} + +} diff --git a/tests/UnitTest++/src/XmlTestReporter.h b/tests/UnitTest++/src/XmlTestReporter.h new file mode 100644 index 0000000..884123b --- /dev/null +++ b/tests/UnitTest++/src/XmlTestReporter.h @@ -0,0 +1,34 @@ +#ifndef UNITTEST_XMLTESTREPORTER_H +#define UNITTEST_XMLTESTREPORTER_H + +#include "DeferredTestReporter.h" + +#include <iosfwd> + +namespace UnitTest +{ + +class XmlTestReporter : public DeferredTestReporter +{ +public: + explicit XmlTestReporter(std::ostream& ostream); + + virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed); + +private: + XmlTestReporter(XmlTestReporter const&); + XmlTestReporter& operator=(XmlTestReporter const&); + + void AddXmlElement(std::ostream& os, char const* encoding); + void BeginResults(std::ostream& os, int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed); + void EndResults(std::ostream& os); + void BeginTest(std::ostream& os, DeferredTestResult const& result); + void AddFailure(std::ostream& os, DeferredTestResult const& result); + void EndTest(std::ostream& os, DeferredTestResult const& result); + + std::ostream& m_ostream; +}; + +} + +#endif |