|
@@ -0,0 +1,504 @@
|
|
|
+/*
|
|
|
+ * Copyright (c) 2003-2004 Pau Arum� & David Garc�a
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
|
+ * (at your option) any later version.
|
|
|
+ *
|
|
|
+ * This program 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 General Public License for more details.
|
|
|
+ *
|
|
|
+ * You should have received a copy of the GNU General Public License
|
|
|
+ * along with this program; if not, write to the Free Software
|
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+#ifndef MiniCppUnit_hxx
|
|
|
+#define MiniCppUnit_hxx
|
|
|
+
|
|
|
+/**
|
|
|
+ * @mainpage
|
|
|
+ * miniCppUnit
|
|
|
+ * (C) 2003-2006 Pau Arumi & David Garcia
|
|
|
+ *
|
|
|
+ * @version 2.5 2006-03-14
|
|
|
+ * - MS Visual compatibility: SConstruct ccflags, usage example, #ifdefs
|
|
|
+ * @version 2.4 2006-03-14
|
|
|
+ * - exit test case after first failure
|
|
|
+ * - double and float comparison with fuzzy equals (using scalable epsilon)
|
|
|
+ * - have into account not a numbers
|
|
|
+ * - new ASSERT_EQUALS_EPSILON macro
|
|
|
+ * - more colors, and disabled when comiled in MS Visual
|
|
|
+ * - removed catalan location.
|
|
|
+ * - UsageExample.cxx now uses all macros and features
|
|
|
+ * @version 2.3 2006-02-13 added usage example and SConstruct
|
|
|
+ * @version 2.2 2004-11-28 code in english and tests suites
|
|
|
+ * @version 2.1 2004-11-04 char* especialization
|
|
|
+ * @version 2.0 2004-10-26 TestsFactory
|
|
|
+ * @version 1.0 2003-10-28 initial
|
|
|
+ *
|
|
|
+ * Example of use:
|
|
|
+ *
|
|
|
+ * @code
|
|
|
+ * #include "MiniCppUnit.hxx"
|
|
|
+ * class MyTests : public TestFixture<MyTests>
|
|
|
+ * {
|
|
|
+ * public:
|
|
|
+ * TEST_FIXTURE( MyTests )
|
|
|
+ * {
|
|
|
+ * CAS_DE_TEST( testAddition );
|
|
|
+ * // etc
|
|
|
+ * }
|
|
|
+ * void testAddition()
|
|
|
+ * {
|
|
|
+ * ASSERT_EQUALS( 4, 1+1+2 );
|
|
|
+ * }
|
|
|
+ * // etc
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * REGISTER_FIXTURE( MyTests );
|
|
|
+ * @endcode
|
|
|
+ * @code
|
|
|
+ * int main()
|
|
|
+ * {
|
|
|
+ * return TestFixtureFactory::theInstance().runTests() ? 0 : -1;
|
|
|
+ * }
|
|
|
+ * @endcode
|
|
|
+ * Good things:
|
|
|
+ *
|
|
|
+ * - it's a tiny framework made up of two or three src files.
|
|
|
+ * => no need to install as a library
|
|
|
+ * - object oriented and makes use of several GoF patterns
|
|
|
+ * - very simple usage. Just needs to learn very few C macros
|
|
|
+ * - string asserts are simpler to use than cppunit
|
|
|
+ * - string asserts are enhanced with coloured diffs
|
|
|
+ * - concrete test classes are totally decoupled via static factory
|
|
|
+ * => no src file have to include them all.
|
|
|
+ * - it have test suite hierarchies
|
|
|
+ * - compatible with non-standard compliant VisualC6
|
|
|
+ * (though not necessary good ;)
|
|
|
+ */
|
|
|
+
|
|
|
+#include <iostream>
|
|
|
+#include <string>
|
|
|
+#include <sstream>
|
|
|
+#include <list>
|
|
|
+
|
|
|
+#if _MSC_VER < 1300
|
|
|
+/** necesary for Visual 6 which don't define std::min */
|
|
|
+namespace std
|
|
|
+{
|
|
|
+ template<typename T> T min(const T& a, const T& b) { return a < b ? a: b; }
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+#include "../teamcity/teamcity_cppunit.h"
|
|
|
+
|
|
|
+extern JetBrains::TeamcityProgressListener gTeamCityListener;
|
|
|
+
|
|
|
+/**
|
|
|
+ * A singleton class.
|
|
|
+ * Receives tests results and stores messages to the test log
|
|
|
+ * for later listing.
|
|
|
+ * It's a singleton for an easy global access from the 'Asserts'
|
|
|
+ * methods but it is probably asking for a refactoring in order to limit
|
|
|
+ * access only to TestFixtures
|
|
|
+ */
|
|
|
+class TestsListener
|
|
|
+{
|
|
|
+public:
|
|
|
+ /** accessor to the global (static) singleton instance */
|
|
|
+ static TestsListener& theInstance();
|
|
|
+ std::stringstream& errorsLog();
|
|
|
+ std::string logString();
|
|
|
+ void currentTestName( std::string& name);
|
|
|
+ static void testHasRun();
|
|
|
+ static void testHasPassed();
|
|
|
+ static void testHasFailed(const char* reason, const char* file, int line);
|
|
|
+ static void testHasThrown();
|
|
|
+ /** the human readable summary of run tests*/
|
|
|
+ std::string summary();
|
|
|
+ /** returns wheather all run tests have passed */
|
|
|
+ static bool allTestsPassed();
|
|
|
+
|
|
|
+private:
|
|
|
+ static const char* errmsgTag_nameOfTest() { return "Test failed: "; }
|
|
|
+
|
|
|
+ /** constructor private: force the singleton to be wellbehaved ! */
|
|
|
+ TestsListener();
|
|
|
+
|
|
|
+ std::string* _currentTestName;
|
|
|
+ std::stringstream _log;
|
|
|
+ unsigned _executed;
|
|
|
+ unsigned _failed;
|
|
|
+ unsigned _exceptions;
|
|
|
+};
|
|
|
+
|
|
|
+class TestFailedException
|
|
|
+{
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * Abstract class with interface that allows run a test. That is runTest
|
|
|
+ * and name. It is implemented by TestFixture and TestCase
|
|
|
+ *
|
|
|
+ * It does the 'Component' role in the 'Composite' patten
|
|
|
+ **/
|
|
|
+class Test
|
|
|
+{
|
|
|
+public:
|
|
|
+ virtual ~Test(){}
|
|
|
+ /** run the test: exercice the code and check results*/
|
|
|
+ virtual void runTest() = 0;
|
|
|
+ /** the test human-readable name */
|
|
|
+ virtual std::string name() const = 0;
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * This class is just a placeholder for all assert functions --as static methods.
|
|
|
+ * It is meant for being used just by the assert macros
|
|
|
+ */
|
|
|
+class Assert
|
|
|
+{
|
|
|
+ static const char * errmsgTag_testFailedIn() { return "Test failed in "; }
|
|
|
+ static const char * errmsgTag_inLine() { return ", line: "; };
|
|
|
+ static const char * errmsgTag_failedExpression() { return "Failed expression: "; }
|
|
|
+ static const char * errmsgTag_expected() { return "Expected: "; }
|
|
|
+ static const char * errmsgTag_butWas() { return "But was: "; }
|
|
|
+
|
|
|
+public:
|
|
|
+#ifdef _MSC_VER
|
|
|
+ static const char * blue() { return ""; }
|
|
|
+ static const char * green() { return ""; }
|
|
|
+ static const char * red() { return ""; }
|
|
|
+ static const char * normal() { return ""; }
|
|
|
+ static const char * bold() { return ""; }
|
|
|
+ static const char * yellow() { return ""; }
|
|
|
+#else
|
|
|
+ static const char * blue() { return "\033[36;1m"; }
|
|
|
+ static const char * green() { return "\033[32;1m"; }
|
|
|
+ static const char * red() { return "\033[31;1m"; }
|
|
|
+ static const char * normal() { return "\033[0m"; }
|
|
|
+ static const char * bold() { return "\033[" "1m"; }
|
|
|
+ static const char * yellow() { return "\033[93;1m"; }
|
|
|
+#endif
|
|
|
+ template<typename AType>
|
|
|
+ static void assertEquals( const AType& expected, const AType& result,
|
|
|
+ const char* file="", int linia=0 )
|
|
|
+ {
|
|
|
+ if(expected != result)
|
|
|
+ {
|
|
|
+ std::stringstream anError;
|
|
|
+
|
|
|
+ anError
|
|
|
+ << file << ", linia: " << linia << "\n"
|
|
|
+ << errmsgTag_expected() << " " << expected << " "
|
|
|
+ << errmsgTag_butWas() << " " << result << "\n";
|
|
|
+
|
|
|
+ TestsListener::theInstance().errorsLog() << anError;
|
|
|
+
|
|
|
+ TestsListener::theInstance().testHasFailed(anError.str().c_str(), file, linia);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static void assertTrue(char* strExpression, bool expression,
|
|
|
+ const char* file="", int linia=0);
|
|
|
+
|
|
|
+ static void assertTrueMissatge(char* strExpression, bool expression,
|
|
|
+ const char* missatge, const char* file="", int linia=0);
|
|
|
+
|
|
|
+ static void assertEquals( const char * expected, const char * result,
|
|
|
+ const char* file="", int linia=0 );
|
|
|
+
|
|
|
+ static void assertEquals( const bool& expected, const bool& result,
|
|
|
+ const char* file="", int linia=0 );
|
|
|
+
|
|
|
+ static void assertEquals( const double& expected, const double& result,
|
|
|
+ const char* file="", int linia=0 );
|
|
|
+
|
|
|
+ static void assertEquals( const float& expected, const float& result,
|
|
|
+ const char* file="", int linia=0 );
|
|
|
+
|
|
|
+ static void assertEquals( const long double& expected, const long double& result,
|
|
|
+ const char* file="", int linia=0 );
|
|
|
+
|
|
|
+ static void assertEqualsEpsilon( const double& expected, const double& result, const double& epsilon,
|
|
|
+ const char* file="", int linia=0 );
|
|
|
+
|
|
|
+ static int notEqualIndex( const std::string & one, const std::string & other );
|
|
|
+
|
|
|
+ /**
|
|
|
+ * we overload the assert with string doing colored diffs
|
|
|
+ *
|
|
|
+ * MS Visual6 doesn't allow string by reference :-(
|
|
|
+ */
|
|
|
+ static void assertEquals( const std::string expected, const std::string result,
|
|
|
+ const char* file="", int linia=0 );
|
|
|
+
|
|
|
+ static void fail(const char* motiu, const char* file="", int linia=0);
|
|
|
+
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * A TestFixture is a class that contain TestCases --which corresponds to
|
|
|
+ * ConcreteTestFixture methods-- common objects uder tests, and setUp and
|
|
|
+ * tearDown methods which are automatically executed before and after each
|
|
|
+ * test case.
|
|
|
+ *
|
|
|
+ * Is the base class of ConcreteFixtures implemented by the framework user
|
|
|
+ *
|
|
|
+ * It does the 'Composite' role in the 'Composite' GoF pattern.
|
|
|
+ * Its composite children are TestCases, which wrapps the test methods.
|
|
|
+ *
|
|
|
+ * It is a template class parametrized by ConcreteTestFixture so that it can
|
|
|
+ * instantiate TestCase objects templatized with this same parameter: it needs the
|
|
|
+ * concrete class type for calling its non-static methods.
|
|
|
+ */
|
|
|
+template <typename ConcreteTestFixture>
|
|
|
+class TestFixture : public Test
|
|
|
+{
|
|
|
+protected:
|
|
|
+
|
|
|
+ typedef ConcreteTestFixture ConcreteFixture;
|
|
|
+ typedef void(ConcreteTestFixture::*TestCaseMethod)();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Wrapper for the test methods of concrete TestFixtures.
|
|
|
+ *
|
|
|
+ * Makes the 'Leave' role in the 'Composite' GoF pattern because can't be
|
|
|
+ * be a composition of other tests.
|
|
|
+ *
|
|
|
+ * It's also a case of 'Command' pattern because it encapsules in an object
|
|
|
+ * certain functionality whose execution depends on some deferred entity.
|
|
|
+ */
|
|
|
+ class TestCase : public Test
|
|
|
+ {
|
|
|
+ public:
|
|
|
+ TestCase(ConcreteFixture* parent, TestCaseMethod method, const std::string & name) :
|
|
|
+ _parent(parent),
|
|
|
+ _testCaseMethod(method),
|
|
|
+ _name(name)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ /** calls TestFixture method. setUp and tearDown methods are called by
|
|
|
+ * its parent TestFixture (in its runTest method).
|
|
|
+ * it is robust to unexpected exceptions (throw) */
|
|
|
+ void runTest()
|
|
|
+ {
|
|
|
+ TestsListener::theInstance().testHasRun();
|
|
|
+ TestsListener::theInstance().currentTestName(_name);
|
|
|
+ try
|
|
|
+ {
|
|
|
+ (_parent->*_testCaseMethod)();
|
|
|
+ TestsListener::theInstance().testHasPassed();
|
|
|
+ }
|
|
|
+ catch( std::exception& error )
|
|
|
+ {
|
|
|
+ TestsListener::theInstance().testHasThrown();
|
|
|
+ TestsListener::theInstance().errorsLog()
|
|
|
+ << "std::exception catched by MiniCppUnit: \n"
|
|
|
+ << "what() : "
|
|
|
+ << Assert::yellow() << error.what()
|
|
|
+ << Assert::normal() << "\n";
|
|
|
+ }
|
|
|
+ catch ( TestFailedException& ) //just for skiping current test case
|
|
|
+ {
|
|
|
+ // the assert() calls testHasFailed()
|
|
|
+ }
|
|
|
+ catch(...)
|
|
|
+ {
|
|
|
+ TestsListener::theInstance().testHasThrown();
|
|
|
+ TestsListener::theInstance().errorsLog()
|
|
|
+ << "non standard exception catched by MiniCppUnit.\n";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** the TestFixture method hame */
|
|
|
+ std::string name() const
|
|
|
+ {
|
|
|
+ return _name;
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ ConcreteFixture* _parent;
|
|
|
+ TestCaseMethod _testCaseMethod;
|
|
|
+ std::string _name;
|
|
|
+ };
|
|
|
+ //------------- end of class TestCase ----------------------------
|
|
|
+
|
|
|
+private:
|
|
|
+
|
|
|
+ typedef std::list<Test*> TestCases;
|
|
|
+ TestCases _testCases;
|
|
|
+ std::string _name;
|
|
|
+
|
|
|
+ void testsList() const
|
|
|
+ {
|
|
|
+ std::cout << "\n+ " << name() << "\n";
|
|
|
+ for( TestCases::const_iterator it=_testCases.begin();
|
|
|
+ it!=_testCases.end(); it++ )
|
|
|
+ std::cout << " - "<< (*it)->name() << "\n";
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+public:
|
|
|
+ virtual void setUp() {}
|
|
|
+ virtual void tearDown() {}
|
|
|
+
|
|
|
+ std::string name() const
|
|
|
+ {
|
|
|
+ return _name;
|
|
|
+ };
|
|
|
+
|
|
|
+ TestFixture(const std::string& name="A text fixture") : _name(name)
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+ void afegeixCasDeTest(ConcreteFixture* parent, TestCaseMethod method, const char* name)
|
|
|
+ {
|
|
|
+ TestCase* casDeTest = new TestCase(parent, method, _name + "::" + name);
|
|
|
+ _testCases.push_back( casDeTest );
|
|
|
+ }
|
|
|
+ /** calls each test after setUp and tearDown TestFixture methods */
|
|
|
+ void runTest()
|
|
|
+ {
|
|
|
+ testsList();
|
|
|
+ TestCases::iterator it;
|
|
|
+ for( it=_testCases.begin(); it!=_testCases.end(); it++)
|
|
|
+ {
|
|
|
+ setUp();
|
|
|
+ (*it)->runTest();
|
|
|
+ tearDown();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /** TestCase that wrapps TestFixture methods are dynamically created and owned by
|
|
|
+ * the TestFixture. So here we clean it up*/
|
|
|
+ virtual ~TestFixture()
|
|
|
+ {
|
|
|
+ TestCases::iterator it;
|
|
|
+ for( it =_testCases.begin(); it!=_testCases.end(); it++)
|
|
|
+ delete (*it);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * This class is aimed to hold a creator method for each concrete TestFixture
|
|
|
+ */
|
|
|
+class TestFixtureFactory
|
|
|
+{
|
|
|
+private:
|
|
|
+ /** Well behaved singleton:
|
|
|
+ * Don't allow instantiation apart from theInstance(), so private ctr.*/
|
|
|
+ TestFixtureFactory()
|
|
|
+ {
|
|
|
+ }
|
|
|
+ typedef Test* (*FixtureCreator)();
|
|
|
+ std::list<FixtureCreator> _creators;
|
|
|
+public:
|
|
|
+ /** Accessor to the (static) singleton instance */
|
|
|
+ static TestFixtureFactory& theInstance()
|
|
|
+ {
|
|
|
+ static TestFixtureFactory theFactory;
|
|
|
+ return theFactory;
|
|
|
+ }
|
|
|
+ bool runTests()
|
|
|
+ {
|
|
|
+ std::list<FixtureCreator>::iterator it;
|
|
|
+ for(it=_creators.begin(); it!=_creators.end(); it++)
|
|
|
+ {
|
|
|
+ FixtureCreator creator = *it;
|
|
|
+ Test* test = creator();
|
|
|
+ test->runTest();
|
|
|
+ delete test;
|
|
|
+ }
|
|
|
+ std::string errors = TestsListener::theInstance().logString();
|
|
|
+ if (errors!="") std::cout << "\n\nError Details:\n" << errors;
|
|
|
+ std::cout << TestsListener::theInstance().summary();
|
|
|
+
|
|
|
+ return TestsListener::theInstance().allTestsPassed();
|
|
|
+ }
|
|
|
+ void addFixtureCreator(FixtureCreator creator)
|
|
|
+ {
|
|
|
+ _creators.push_back( creator );
|
|
|
+ }
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * Macro a usar despr�s de cada classe de test
|
|
|
+ */
|
|
|
+#define REGISTER_FIXTURE( ConcreteTestFixture ) \
|
|
|
+\
|
|
|
+Test* Creador##ConcreteTestFixture() { return new ConcreteTestFixture; } \
|
|
|
+\
|
|
|
+class Registrador##ConcreteTestFixture \
|
|
|
+{ \
|
|
|
+public: \
|
|
|
+ Registrador##ConcreteTestFixture() \
|
|
|
+ { \
|
|
|
+ TestFixtureFactory::theInstance().addFixtureCreator( \
|
|
|
+ Creador##ConcreteTestFixture); \
|
|
|
+ } \
|
|
|
+}; \
|
|
|
+static Registrador##ConcreteTestFixture estatic##ConcreteTestFixture;
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * Assert macros to use in test methods. An assert is a test condition
|
|
|
+ * we want to check.
|
|
|
+ */
|
|
|
+#define ASSERT_EQUALS( expected, result) \
|
|
|
+ Assert::assertEquals( expected, result, __FILE__, __LINE__ );
|
|
|
+
|
|
|
+#define ASSERT_EQUALS_EPSILON( expected, result, epsilon) \
|
|
|
+ Assert::assertEqualsEpsilon( expected, result, epsilon, __FILE__, __LINE__ );
|
|
|
+
|
|
|
+#define ASSERT( exp ) \
|
|
|
+ Assert::assertTrue(#exp, exp, __FILE__, __LINE__);
|
|
|
+
|
|
|
+#define ASSERT_MESSAGE( exp, message ) \
|
|
|
+ Assert::assertTrueMissatge(#exp, exp, message, __FILE__, __LINE__);
|
|
|
+
|
|
|
+#define FAIL( why ) \
|
|
|
+ Assert::fail(#why, __FILE__, __LINE__);
|
|
|
+
|
|
|
+/**
|
|
|
+ * Macros that allows to write the constructor of the concrete TestFixture.
|
|
|
+ * What the constructor does is agregate a wrapper for each test case (method)
|
|
|
+ * As easy to write as this:
|
|
|
+ *
|
|
|
+ * @code
|
|
|
+ * class MyTests : public TestFixture<MyTests>
|
|
|
+ * {
|
|
|
+ * public:
|
|
|
+ * TEST_FIXTURE( MyTests )
|
|
|
+ * {
|
|
|
+ * TEST_CASE( test );
|
|
|
+ * // etc
|
|
|
+ * }
|
|
|
+ * void test()
|
|
|
+ * {
|
|
|
+ * ASSERT_EQUALS( 4, 1+1+2 );
|
|
|
+ * }
|
|
|
+ * @endcode
|
|
|
+ */
|
|
|
+
|
|
|
+#define TEST_FIXTURE( ConcreteFixture ) \
|
|
|
+ ConcreteFixture() : TestFixture<ConcreteFixture>( #ConcreteFixture )
|
|
|
+
|
|
|
+#define TEST_CASE( methodName ) \
|
|
|
+ afegeixCasDeTest( this, &ConcreteFixture::methodName, #methodName );
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#endif // MiniCppUnit_hxx
|