mirror of
https://github.com/unittest-cpp/unittest-cpp
synced 2026-09-26 16:19:30 +03:00
Merge 17d6e82ca6 into c331bb0dea
This commit is contained in:
commit
05d62be59a
25 changed files with 1498 additions and 41 deletions
|
|
@ -9,6 +9,7 @@
|
|||
#include "AssertException.h"
|
||||
#include "RequiredCheckException.h"
|
||||
#include "CurrentTest.h"
|
||||
#include "ParameterizedManager.h"
|
||||
|
||||
#ifdef UNITTEST_NO_EXCEPTIONS
|
||||
#include "ReportAssertImpl.h"
|
||||
|
|
@ -20,12 +21,16 @@
|
|||
|
||||
namespace UnitTest {
|
||||
|
||||
//TODO remove template and parameter "templateIsTest", replace with an interface
|
||||
template< typename T >
|
||||
void ExecuteTest(T& testObject, TestDetails const& details, bool isMockTest)
|
||||
void ExecuteTest(T& testObject, TestDetails const& details, bool isMockTest, bool templateIsTest)
|
||||
{
|
||||
if (isMockTest == false)
|
||||
CurrentTest::Details() = &details;
|
||||
|
||||
if (templateIsTest)
|
||||
ParameterizedManager::getInstance().beginExecute(&details);
|
||||
|
||||
#ifdef UNITTEST_NO_EXCEPTIONS
|
||||
if (UNITTEST_SET_ASSERT_JUMP_TARGET() == 0)
|
||||
{
|
||||
|
|
@ -54,6 +59,8 @@ namespace UnitTest {
|
|||
#ifdef UNITTEST_NO_EXCEPTIONS
|
||||
}
|
||||
#endif
|
||||
if (templateIsTest)
|
||||
ParameterizedManager::getInstance().endExecute(&details);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
43
UnitTest++/ParameterizedMacros.h
Normal file
43
UnitTest++/ParameterizedMacros.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef UNITTEST_PARAMETERIZEDMACROS_H
|
||||
#define UNITTEST_PARAMETERIZEDMACROS_H
|
||||
|
||||
#include "TestParameter.h"
|
||||
|
||||
|
||||
#define UNITTEST_SET_TEST_PARAMETER_LISTENER(Type, Name, ListenerPtr, SetUpBody) \
|
||||
class ParameterizedCreator##Name \
|
||||
{ \
|
||||
public: \
|
||||
ParameterizedCreator##Name() : globalInstance(getGlobalInstance()) {} \
|
||||
UnitTest::TestParameter<Type> & globalInstance; \
|
||||
private: \
|
||||
static UnitTest::TestParameter<Type> & getGlobalInstance() \
|
||||
{ \
|
||||
static UnitTest::TestParameter<Type> instance(#Name, create(), ListenerPtr); \
|
||||
return instance; \
|
||||
} \
|
||||
static vector<Type> create() { vector<Type> values; SetUpBody return values; } \
|
||||
} static parameterizedCreator##Name##Instance; \
|
||||
\
|
||||
static UnitTest::TestParameter<Type> & Name(parameterizedCreator##Name##Instance.globalInstance)
|
||||
|
||||
|
||||
#define UNITTEST_SET_TEST_PARAMETER(Type, Name, SetUpBody) \
|
||||
UNITTEST_SET_TEST_PARAMETER_LISTENER(Type, Name, nullptr, SetUpBody)
|
||||
|
||||
|
||||
#ifndef UNITTEST_DISABLE_SHORT_MACROS
|
||||
#ifdef SET_TEST_PARAMETER_LISTENER
|
||||
#error SET_TEST_PARAMETER_LISTENER already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_SET_TEST_PARAMETER_LISTENER instead
|
||||
#else
|
||||
#define SET_TEST_PARAMETER_LISTENER UNITTEST_SET_TEST_PARAMETER_LISTENER
|
||||
#endif
|
||||
|
||||
#ifdef SET_TEST_PARAMETER
|
||||
#error SET_TEST_PARAMETER already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_SET_TEST_PARAMETER instead
|
||||
#else
|
||||
#define SET_TEST_PARAMETER UNITTEST_SET_TEST_PARAMETER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
371
UnitTest++/ParameterizedManager.cpp
Normal file
371
UnitTest++/ParameterizedManager.cpp
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
#include "ParameterizedManager.h"
|
||||
|
||||
#include "Test.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
using namespace UnitTest;
|
||||
|
||||
|
||||
ParameterizedManager::ParameterizedManager()
|
||||
: _currentTest(nullptr),
|
||||
_nextTestBackup(nullptr),
|
||||
_iterationDone(false),
|
||||
_executing(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ParameterizedManager::~ParameterizedManager()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ParameterizedManager & ParameterizedManager::getInstance()
|
||||
{
|
||||
static ParameterizedManager stored;
|
||||
return stored;
|
||||
}
|
||||
|
||||
|
||||
TestListNode* const ParameterizedManager::retrieveTest(TestDetails const * const details)
|
||||
{
|
||||
for (TestListNode* iNode = Test::GetTestList().GetHead(); iNode != nullptr; iNode = iNode->m_next)
|
||||
{
|
||||
// Warning: do not use TestDetails::sameTest here for optimisation reason
|
||||
if (&iNode->m_test->m_details == details)
|
||||
{
|
||||
return iNode;
|
||||
}
|
||||
}
|
||||
|
||||
string errorMessage = "Impossible to retrieve test ";
|
||||
errorMessage += details->testName;
|
||||
throw runtime_error(errorMessage);
|
||||
}
|
||||
|
||||
|
||||
bool ParameterizedManager::isCurrentTest(TestDetails const * const details) const
|
||||
{
|
||||
if (_currentTest == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _currentTest->m_test->m_details.sameTest(*details);
|
||||
}
|
||||
|
||||
|
||||
bool ParameterizedManager::hasMoreIndexes(TestParameterAbstract* const parameterized)
|
||||
{
|
||||
if (!parameterized->hasMoreValues(1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<IgnoredIndex> & ignoredIndexes = _ignoredIndexes[parameterized];
|
||||
if (!ignoredIndexes.empty())
|
||||
{
|
||||
bool allRemainingsAreIgnored = true;
|
||||
for (size_t iIndex = parameterized->_index + 1; iIndex < parameterized->valuesCount(); iIndex++)
|
||||
{
|
||||
if (findIgnored(ignoredIndexes, iIndex) == ignoredIndexes.end())
|
||||
{
|
||||
allRemainingsAreIgnored = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allRemainingsAreIgnored)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ParameterizedManager::beginExecute(TestDetails const * const details)
|
||||
{
|
||||
if (_currentTest != nullptr)
|
||||
{
|
||||
if (isCurrentTest(details))
|
||||
{
|
||||
_currentTest->m_next = _nextTestBackup;
|
||||
_executing = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
_currentTest = retrieveTest(details);
|
||||
_nextTestBackup = _currentTest->m_next;
|
||||
_iterationDone = false;
|
||||
_executing = true;
|
||||
}
|
||||
|
||||
|
||||
void ParameterizedManager::endExecute(TestDetails const * const details)
|
||||
{
|
||||
if (!isCurrentTest(details))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (!_stack.empty())
|
||||
{
|
||||
TestParameterAbstract* iParameterized = _stack.back();
|
||||
if (hasMoreIndexes(iParameterized))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_stack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
if (_stack.empty())
|
||||
{
|
||||
_currentTest = nullptr;
|
||||
_nextTestBackup = nullptr;
|
||||
clearNonGlobalIgnoredIndexes();
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentTest->m_next = _currentTest; // Loop itself
|
||||
}
|
||||
|
||||
_iterationDone = false;
|
||||
_executing = false;
|
||||
}
|
||||
|
||||
|
||||
void ParameterizedManager::clearNonGlobalIgnoredIndexes()
|
||||
{
|
||||
for (IgnoredIndexesMap::iterator it1 = _ignoredIndexes.begin(); it1 != _ignoredIndexes.end();)
|
||||
{
|
||||
vector<IgnoredIndex> & ignoredIndexes = it1->second;
|
||||
|
||||
for (vector<IgnoredIndex>::iterator it2 = ignoredIndexes.begin(); it2 != ignoredIndexes.end();)
|
||||
{
|
||||
if (!it2->global)
|
||||
{
|
||||
it2 = ignoredIndexes.erase(it2);
|
||||
}
|
||||
else
|
||||
{
|
||||
it2++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ignoredIndexes.empty())
|
||||
{
|
||||
_ignoredIndexes.erase(it1++); // Note: map erase is a bit special
|
||||
}
|
||||
else
|
||||
{
|
||||
it1++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ParameterizedManager::updateParameter(TestParameterAbstract* const parameterized)
|
||||
{
|
||||
importIgnoredParameter(parameterized);
|
||||
vector<IgnoredIndex> & ignoredIndexes = _ignoredIndexes[parameterized];
|
||||
bool repeat = true;
|
||||
while (repeat)
|
||||
{
|
||||
iterate(parameterized);
|
||||
|
||||
vector<IgnoredIndex>::iterator ignoredIt = findIgnored(ignoredIndexes, parameterized->_index);
|
||||
repeat = (ignoredIt != ignoredIndexes.end());
|
||||
if (repeat)
|
||||
{
|
||||
_iterationDone = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ParameterizedManager::iterate(TestParameterAbstract* const parameterized)
|
||||
{
|
||||
bool firstIndex = false;
|
||||
if (stackParameter(parameterized, firstIndex))
|
||||
{
|
||||
parameterized->nextIndex(firstIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ParameterizedManager::stackParameter(TestParameterAbstract* const parameterized, bool & outFirstIndex)
|
||||
{
|
||||
if (find(_stack.begin(), _stack.end(), parameterized) == _stack.end())
|
||||
{
|
||||
_iterationDone = true;
|
||||
outFirstIndex = true;
|
||||
_stack.push_back(parameterized);
|
||||
return true;
|
||||
}
|
||||
if (!_iterationDone)
|
||||
{
|
||||
if (!_stack.empty() && _stack.back() == parameterized)
|
||||
{
|
||||
_iterationDone = true;
|
||||
outFirstIndex = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
outFirstIndex = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
vector<ParameterizedManager::IgnoredIndex>::iterator ParameterizedManager::findIgnored(vector<IgnoredIndex> & ignoredIndexes, size_t index)
|
||||
{
|
||||
for (vector<IgnoredIndex>::iterator it = ignoredIndexes.begin(); it != ignoredIndexes.end(); it++)
|
||||
{
|
||||
if (index == it->index)
|
||||
{
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return ignoredIndexes.end();
|
||||
}
|
||||
|
||||
|
||||
void ParameterizedManager::importIgnoredParameter(TestParameterAbstract* const parameterized)
|
||||
{
|
||||
IgnoredIndexesByNameMap::iterator it = _pendingIgnoredIndexes.find(parameterized->getName());
|
||||
if (it == _pendingIgnoredIndexes.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vector<IgnoredIndex> & pendingIgnoredIndexes = it->second;
|
||||
while (!pendingIgnoredIndexes.empty())
|
||||
{
|
||||
const IgnoredIndex & iIgnored = pendingIgnoredIndexes.back();
|
||||
ignoreIndex(parameterized, iIgnored.index, iIgnored.global ? GLOBAL : LOCAL);
|
||||
pendingIgnoredIndexes.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ParameterizedManager::isGlobal(IgnoreScope scope)
|
||||
{
|
||||
switch (scope)
|
||||
{
|
||||
case AUTO: return !_executing;
|
||||
case LOCAL: return false;
|
||||
case GLOBAL:return true;
|
||||
}
|
||||
throw runtime_error("Invalid enum value for ignore scope");
|
||||
}
|
||||
|
||||
|
||||
ParameterizedManager & ParameterizedManager::ignoreIndex(TestParameterAbstract* const parameterized, size_t index, IgnoreScope scope)
|
||||
{
|
||||
bool global = isGlobal(scope);
|
||||
vector<IgnoredIndex> & ignoredIndexes = _ignoredIndexes[parameterized];
|
||||
|
||||
if (index >= parameterized->valuesCount())
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
vector<IgnoredIndex>::iterator ignoredIt = findIgnored(ignoredIndexes, index);
|
||||
if (ignoredIt != ignoredIndexes.end())
|
||||
{
|
||||
// Upgrade to global if required
|
||||
if (global && !ignoredIt->global)
|
||||
{
|
||||
ignoredIt->global = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ignoredIndexes.size() + 1 == parameterized->valuesCount())
|
||||
{
|
||||
throw runtime_error("all parameters have been ignored, can not proceed");
|
||||
}
|
||||
ignoredIndexes.push_back(IgnoredIndex(index, global));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ParameterizedManager & ParameterizedManager::ignoreIndex(const string & parameterName, size_t index, IgnoreScope scope)
|
||||
{
|
||||
if (parameterName.empty())
|
||||
{
|
||||
throw invalid_argument("Empty parameter name given in ignore index");
|
||||
}
|
||||
|
||||
// Note: do not care about duplicates indexes for now
|
||||
bool global = isGlobal(scope);
|
||||
_pendingIgnoredIndexes[parameterName].push_back(IgnoredIndex(index, global));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ParameterizedManager & ParameterizedManager::ignoreIndexes(const string & parametersArrayRange, IgnoreScope scope)
|
||||
{
|
||||
string parameterName;
|
||||
vector<int> indexes = parseParameter(parametersArrayRange, parameterName);
|
||||
for (size_t i = 0; i < indexes.size(); i++)
|
||||
{
|
||||
ignoreIndex(parameterName, indexes[i], scope);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
vector<int> ParameterizedManager::parseParameter(const string & parametersArrayRange, string & outParameterName)
|
||||
{
|
||||
if (parametersArrayRange.empty())
|
||||
{
|
||||
throw invalid_argument("Empty parameter array range given");
|
||||
}
|
||||
|
||||
size_t openPos = parametersArrayRange.find('[');
|
||||
size_t closePos = parametersArrayRange.find(']');
|
||||
if (openPos == 0 || openPos == string::npos || closePos == string::npos || closePos < openPos)
|
||||
{
|
||||
throw invalid_argument("Misformatted parameter array range index, should be pzMyParam[0,1,2]");
|
||||
}
|
||||
|
||||
outParameterName = parametersArrayRange.substr(0, openPos);
|
||||
string indexes = parametersArrayRange.substr(openPos + 1, closePos - openPos - 1);
|
||||
|
||||
stringstream stream(indexes);
|
||||
string item;
|
||||
vector<int> indexesList;
|
||||
while (getline(stream, item, ','))
|
||||
{
|
||||
int index = stoi(item);
|
||||
indexesList.push_back(index);
|
||||
}
|
||||
|
||||
return indexesList;
|
||||
}
|
||||
|
||||
|
||||
bool ParameterizedManager::isIndexIgnored(TestParameterAbstract* const parameterized, size_t index)
|
||||
{
|
||||
vector<IgnoredIndex> & ignoredIndexes = _ignoredIndexes[parameterized];
|
||||
vector<IgnoredIndex>::iterator ignoredIt = findIgnored(ignoredIndexes, index);
|
||||
return (ignoredIt != ignoredIndexes.end());
|
||||
}
|
||||
|
||||
|
||||
const vector<TestParameterAbstract*> & ParameterizedManager::getStack(TestDetails const * const details) const
|
||||
{
|
||||
if (!isCurrentTest(details))
|
||||
{
|
||||
static vector<TestParameterAbstract*> emptyStored;
|
||||
return emptyStored;
|
||||
}
|
||||
return _stack;
|
||||
}
|
||||
63
UnitTest++/ParameterizedManager.h
Normal file
63
UnitTest++/ParameterizedManager.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef UNITTEST_PARAMETERIZEDMANAGER_H
|
||||
#define UNITTEST_PARAMETERIZEDMANAGER_H
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "TestDetails.h"
|
||||
#include "TestList.h"
|
||||
#include "TestParameter.h"
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
class ParameterizedManager
|
||||
{
|
||||
public:
|
||||
static ParameterizedManager & getInstance();
|
||||
TestListNode* const getCurrentTest() const { return _currentTest; }
|
||||
bool isCurrentTest(TestDetails const * const details) const;
|
||||
void beginExecute(TestDetails const * const details);
|
||||
void endExecute(TestDetails const * const details);
|
||||
void updateParameter(TestParameterAbstract* const parameterized);
|
||||
ParameterizedManager & ignoreIndex(TestParameterAbstract* const parameterized, size_t index, IgnoreScope scope = AUTO);
|
||||
ParameterizedManager & ignoreIndex(const string & parameterName, size_t index, IgnoreScope scope = AUTO);
|
||||
ParameterizedManager & ignoreIndexes(const string & parametersArrayRange, IgnoreScope scope = AUTO);
|
||||
bool isIndexIgnored(TestParameterAbstract* const parameterized, size_t index);
|
||||
const vector<TestParameterAbstract*> & getStack(TestDetails const * const details) const;
|
||||
|
||||
private:
|
||||
struct IgnoredIndex
|
||||
{
|
||||
IgnoredIndex(size_t index, bool global) : index(index), global(global) {}
|
||||
size_t index;
|
||||
bool global;
|
||||
};
|
||||
|
||||
typedef unordered_map<TestParameterAbstract*, vector<IgnoredIndex>> IgnoredIndexesMap;
|
||||
typedef unordered_map<string, vector<IgnoredIndex>> IgnoredIndexesByNameMap;
|
||||
|
||||
ParameterizedManager();
|
||||
virtual ~ParameterizedManager();
|
||||
TestListNode* const retrieveTest(TestDetails const * const details);
|
||||
void iterate(TestParameterAbstract* const parameterized);
|
||||
bool stackParameter(TestParameterAbstract* const parameterized, bool & outFirstIndex);
|
||||
bool hasMoreIndexes(TestParameterAbstract* const parameterized);
|
||||
bool isGlobal(IgnoreScope scope);
|
||||
vector<IgnoredIndex>::iterator findIgnored(vector<IgnoredIndex> & ignoredIndexes, size_t index);
|
||||
void importIgnoredParameter(TestParameterAbstract* const parameterized);
|
||||
void clearNonGlobalIgnoredIndexes();
|
||||
|
||||
static vector<int> parseParameter(const string & parametersArrayRange, string & outParameterName);
|
||||
|
||||
TestListNode* _currentTest;
|
||||
TestListNode* _nextTestBackup;
|
||||
vector<TestParameterAbstract*> _stack;
|
||||
IgnoredIndexesMap _ignoredIndexes;
|
||||
IgnoredIndexesByNameMap _pendingIgnoredIndexes;
|
||||
volatile bool _iterationDone;
|
||||
volatile bool _executing;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
69
UnitTest++/SuitePredicate.cpp
Normal file
69
UnitTest++/SuitePredicate.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#include "SuitePredicate.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace UnitTest;
|
||||
|
||||
|
||||
SuitePredicate::SuitePredicate()
|
||||
: _all(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SuitePredicate::~SuitePredicate()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SuitePredicate::addSuite(char const* suiteName)
|
||||
{
|
||||
_suiteNames.push_back(suiteName);
|
||||
}
|
||||
|
||||
|
||||
void SuitePredicate::addTest(char const* testName)
|
||||
{
|
||||
_testNames.push_back(testName);
|
||||
}
|
||||
|
||||
|
||||
void SuitePredicate::addAll()
|
||||
{
|
||||
_all = true;
|
||||
}
|
||||
|
||||
|
||||
bool SuitePredicate::operator()(Test const * const test) const
|
||||
{
|
||||
if (_all)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return (mustExecuteSuite(test) || mustExecuteTest(test));
|
||||
}
|
||||
|
||||
|
||||
bool SuitePredicate::mustExecuteSuite(Test const * const test) const
|
||||
{
|
||||
for (size_t i = 0; i < _suiteNames.size(); i++)
|
||||
{
|
||||
if (_suiteNames[i] == test->m_details.suiteName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SuitePredicate::mustExecuteTest(Test const * const test) const
|
||||
{
|
||||
for (size_t i = 0; i < _testNames.size(); i++)
|
||||
{
|
||||
if (_testNames[i] == test->m_details.testName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
34
UnitTest++/SuitePredicate.h
Normal file
34
UnitTest++/SuitePredicate.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef UNITTEST_SUITEPREDICATE_H
|
||||
#define UNITTEST_SUITEPREDICATE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Test.h"
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
class UNITTEST_LINKAGE SuitePredicate
|
||||
{
|
||||
public:
|
||||
SuitePredicate();
|
||||
virtual ~SuitePredicate();
|
||||
|
||||
void addSuite(char const* suiteName);
|
||||
void addTest(char const* testName);
|
||||
void addAll();
|
||||
|
||||
bool operator()(Test const * const test) const;
|
||||
|
||||
private:
|
||||
bool mustExecuteSuite(Test const * const test) const;
|
||||
bool mustExecuteTest(Test const * const test) const;
|
||||
|
||||
vector<string> _suiteNames;
|
||||
vector<string> _testNames;
|
||||
bool _all;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -20,7 +20,6 @@ namespace UnitTest {
|
|||
|
||||
Test::Test(char const* testName, char const* suiteName, char const* filename, int lineNumber)
|
||||
: m_details(testName, suiteName, filename, lineNumber)
|
||||
, m_nextTest(0)
|
||||
, m_isMockTest(false)
|
||||
{}
|
||||
|
||||
|
|
@ -29,7 +28,7 @@ namespace UnitTest {
|
|||
|
||||
void Test::Run()
|
||||
{
|
||||
ExecuteTest(*this, m_details, m_isMockTest);
|
||||
ExecuteTest(*this, m_details, m_isMockTest, true);
|
||||
}
|
||||
|
||||
void Test::RunImpl() const
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ namespace UnitTest {
|
|||
void Run();
|
||||
|
||||
TestDetails const m_details;
|
||||
Test* m_nextTest;
|
||||
|
||||
mutable bool m_isMockTest;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "TestDetails.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace UnitTest {
|
||||
|
||||
|
|
@ -18,5 +19,29 @@ namespace UnitTest {
|
|||
, timeConstraintExempt(details.timeConstraintExempt)
|
||||
{}
|
||||
|
||||
bool TestDetails::sameTest(const TestDetails & details) const
|
||||
{
|
||||
if (&details == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fast pointer comparison
|
||||
if (details.suiteName == suiteName &&
|
||||
details.testName == testName &&
|
||||
details.filename == filename)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Long string comparison
|
||||
if (!strcmp(details.suiteName, suiteName) &&
|
||||
!strcmp(details.testName, testName) &&
|
||||
!strcmp(details.filename, filename))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ namespace UnitTest {
|
|||
int const lineNumber;
|
||||
mutable bool timeConstraintExempt;
|
||||
|
||||
bool sameTest(const TestDetails & details) const;
|
||||
|
||||
TestDetails(TestDetails const&); // Why is it public? --> http://gcc.gnu.org/bugs.html#cxx_rvalbind
|
||||
private:
|
||||
TestDetails& operator=(TestDetails const&);
|
||||
|
|
|
|||
|
|
@ -5,27 +5,37 @@
|
|||
|
||||
namespace UnitTest {
|
||||
|
||||
TestListNode::TestListNode(Test* test)
|
||||
: m_test(test),
|
||||
m_next(0)
|
||||
{
|
||||
}
|
||||
|
||||
TestList::TestList()
|
||||
: m_head(0)
|
||||
, m_tail(0)
|
||||
{}
|
||||
|
||||
void TestList::Add(Test* test)
|
||||
TestListNode* TestList::Add(Test* test)
|
||||
{
|
||||
TestListNode* node = 0;
|
||||
if (m_tail == 0)
|
||||
{
|
||||
assert(m_head == 0);
|
||||
m_head = test;
|
||||
m_tail = test;
|
||||
node = new TestListNode(test);
|
||||
m_head = node;
|
||||
m_tail = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tail->m_nextTest = test;
|
||||
m_tail = test;
|
||||
node = new TestListNode(test);
|
||||
m_tail->m_next = node;
|
||||
m_tail = node;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
Test* TestList::GetHead() const
|
||||
TestListNode* TestList::GetHead() const
|
||||
{
|
||||
return m_head;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,17 +7,25 @@ namespace UnitTest {
|
|||
|
||||
class Test;
|
||||
|
||||
class UNITTEST_LINKAGE TestListNode
|
||||
{
|
||||
public:
|
||||
TestListNode(Test* test);
|
||||
Test* m_test;
|
||||
TestListNode* m_next;
|
||||
};
|
||||
|
||||
class UNITTEST_LINKAGE TestList
|
||||
{
|
||||
public:
|
||||
TestList();
|
||||
void Add (Test* test);
|
||||
TestListNode* Add(Test* test);
|
||||
|
||||
Test* GetHead() const;
|
||||
TestListNode* GetHead() const;
|
||||
|
||||
private:
|
||||
Test* m_head;
|
||||
Test* m_tail;
|
||||
TestListNode* m_head;
|
||||
TestListNode* m_tail;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@
|
|||
({ \
|
||||
Fixture ## Name ## Helper fixtureHelper(m_details); \
|
||||
ctorOk = true; \
|
||||
UnitTest::ExecuteTest(fixtureHelper, m_details, false); \
|
||||
UnitTest::ExecuteTest(fixtureHelper, m_details, false, false); \
|
||||
}) \
|
||||
UNITTEST_IMPL_CATCH (UnitTest::AssertException, e, \
|
||||
{ \
|
||||
|
|
|
|||
78
UnitTest++/TestParameter.cpp
Normal file
78
UnitTest++/TestParameter.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#include "TestParameter.h"
|
||||
|
||||
#include <sstream>
|
||||
#include "ParameterizedManager.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace UnitTest;
|
||||
|
||||
|
||||
TestParameterAbstract::TestParameterAbstract(const string & name)
|
||||
: _name(name),
|
||||
_index(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TestParameterAbstract::~TestParameterAbstract()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
size_t TestParameterAbstract::getCurrentIndex()
|
||||
{
|
||||
updateCurrentIndex();
|
||||
return _index;
|
||||
}
|
||||
|
||||
|
||||
string TestParameterAbstract::getNameCurrent() const
|
||||
{
|
||||
stringstream output;
|
||||
output << (_name.empty() ? "unknown" : _name) << "[" << _index << "]";
|
||||
return output.str();
|
||||
}
|
||||
|
||||
|
||||
void TestParameterAbstract::updateCurrentIndex()
|
||||
{
|
||||
ParameterizedManager::getInstance().updateParameter(this);
|
||||
}
|
||||
|
||||
|
||||
bool TestParameterAbstract::hasMoreValues(int advance) const
|
||||
{
|
||||
return (_index + advance < (int)valuesCount());
|
||||
}
|
||||
|
||||
|
||||
void TestParameterAbstract::nextIndex(bool first)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
if (valuesCount() == 0)
|
||||
{
|
||||
throw runtime_error("No values for parameterized test");
|
||||
}
|
||||
_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_index++;
|
||||
}
|
||||
|
||||
peekCurrent(&ParameterizedManager::getInstance().getCurrentTest()->m_test->m_details, _index);
|
||||
}
|
||||
|
||||
|
||||
TestParameterAbstract & TestParameterAbstract::ignoreIndex(size_t index, IgnoreScope scope)
|
||||
{
|
||||
ParameterizedManager::getInstance().ignoreIndex(this, index, scope);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool TestParameterAbstract::isIndexIgnored(size_t index)
|
||||
{
|
||||
return ParameterizedManager::getInstance().isIndexIgnored(this, index);
|
||||
}
|
||||
121
UnitTest++/TestParameter.h
Normal file
121
UnitTest++/TestParameter.h
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
#ifndef UNITTEST_TESTPARAMETER_H
|
||||
#define UNITTEST_TESTPARAMETER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Test.h"
|
||||
#include "TestList.h"
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
enum IgnoreScope
|
||||
{
|
||||
AUTO,
|
||||
LOCAL,
|
||||
GLOBAL
|
||||
};
|
||||
|
||||
class TestParameterAbstract
|
||||
{
|
||||
friend class ParameterizedManager;
|
||||
public:
|
||||
TestParameterAbstract(const string & name);
|
||||
virtual ~TestParameterAbstract();
|
||||
size_t getCurrentIndex();
|
||||
const string & getName() const { return _name; }
|
||||
string getNameCurrent() const;
|
||||
TestParameterAbstract & ignoreIndex(size_t index, IgnoreScope scope = AUTO);
|
||||
bool isIndexIgnored(size_t index);
|
||||
|
||||
protected:
|
||||
void updateCurrentIndex();
|
||||
virtual void peekCurrent(TestDetails const * const details, size_t index) = 0;
|
||||
virtual size_t valuesCount() const = 0;
|
||||
|
||||
private:
|
||||
bool hasMoreValues(int advance = 0) const;
|
||||
void nextIndex(bool first);
|
||||
|
||||
string _name;
|
||||
size_t _index;
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
class TestParameter : public TestParameterAbstract
|
||||
{
|
||||
public:
|
||||
struct IParameterListener
|
||||
{
|
||||
virtual void onNext(TestDetails const * const details, T currentValue, size_t currentIndex) = 0;
|
||||
};
|
||||
|
||||
TestParameter(const string & name, vector<T> values, IParameterListener* const listener = nullptr)
|
||||
: TestParameterAbstract(name),
|
||||
_values(values),
|
||||
_listener(listener)
|
||||
{
|
||||
}
|
||||
|
||||
T operator()()
|
||||
{
|
||||
size_t index = getCurrentIndex();
|
||||
return _values[index];
|
||||
}
|
||||
|
||||
const vector<T> & values() const
|
||||
{
|
||||
return _values;
|
||||
}
|
||||
|
||||
TestParameter<T> & ignoreIndex(size_t index)
|
||||
{
|
||||
TestParameterAbstract::ignoreIndex(index);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TestParameter<T> & ignore(T p)
|
||||
{
|
||||
vector<T>::iterator it = find(_values.begin(), _values.end(), p);
|
||||
if (it == _values.end())
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
return ignoreIndex(it - _values.begin());
|
||||
}
|
||||
|
||||
bool isIgnored(T p)
|
||||
{
|
||||
vector<T>::iterator it = find(_values.begin(), _values.end(), p);
|
||||
if (it == _values.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return isIndexIgnored(it - _values.begin());
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void peekCurrent(TestDetails const * const details, size_t index) override
|
||||
{
|
||||
if (_listener != nullptr)
|
||||
{
|
||||
_listener->onNext(details, _values[index], index);
|
||||
}
|
||||
}
|
||||
|
||||
virtual size_t valuesCount() const override
|
||||
{
|
||||
return _values.size();
|
||||
}
|
||||
|
||||
private:
|
||||
vector<T> _values;
|
||||
IParameterListener* const _listener;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
#include "TestReporter.h"
|
||||
|
||||
#include "TestDetails.h"
|
||||
#include "MemoryOutStream.h"
|
||||
#include "ParameterizedManager.h"
|
||||
|
||||
namespace UnitTest {
|
||||
|
||||
|
|
@ -31,7 +33,24 @@ namespace UnitTest {
|
|||
}
|
||||
|
||||
if (m_testReporter)
|
||||
m_testReporter->ReportFailure(test, failure);
|
||||
{
|
||||
MemoryOutStream stream;
|
||||
stream << failure;
|
||||
const vector<TestParameterAbstract*> & parameters = ParameterizedManager::getInstance().getStack(&test);
|
||||
if (!parameters.empty())
|
||||
{
|
||||
stream << " Parameters: ";
|
||||
for (size_t i = 0; i < parameters.size(); i++)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
stream << ", ";
|
||||
}
|
||||
stream << parameters[i]->getNameCurrent();
|
||||
}
|
||||
}
|
||||
m_testReporter->ReportFailure(test, stream.GetText());
|
||||
}
|
||||
}
|
||||
|
||||
void TestResults::OnTestFinish(TestDetails const& test, float secondsElapsed)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
#include "TestReporterStdout.h"
|
||||
#include "TimeHelpers.h"
|
||||
#include "MemoryOutStream.h"
|
||||
#include "SuitePredicate.h"
|
||||
#include "ParameterizedManager.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
|
@ -17,6 +19,112 @@ namespace UnitTest {
|
|||
return runner.RunTestsIf(Test::GetTestList(), NULL, True(), 0);
|
||||
}
|
||||
|
||||
bool findArgumentListIndex(int argc, char**argv, char const* argument, int & outFrom, int & outCount)
|
||||
{
|
||||
if (argc <= 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
outCount = 0;
|
||||
if (strlen(argument) > 0)
|
||||
{
|
||||
outFrom = 0;
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if (strcmp(argument, argv[i]) == 0)
|
||||
{
|
||||
outFrom = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (outFrom == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
outFrom = 1;
|
||||
}
|
||||
|
||||
for (int i = outFrom; i < argc; i++)
|
||||
{
|
||||
char* value = argv[i];
|
||||
if (strlen(value) >= 2 && value[0] == '-'&& value[1] == '-')
|
||||
{
|
||||
break;
|
||||
}
|
||||
outCount++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readSuiteArgument(SuitePredicate & predicate, int argc, char**argv, char const* argument)
|
||||
{
|
||||
int from, count;
|
||||
if (!findArgumentListIndex(argc, argv, argument, from, count))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = from; i < from + count; i++)
|
||||
{
|
||||
predicate.addSuite(argv[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readTestArgument(SuitePredicate & predicate, int argc, char**argv, char const* argument)
|
||||
{
|
||||
int from, count;
|
||||
if (!findArgumentListIndex(argc, argv, argument, from, count))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = from; i < from + count; i++)
|
||||
{
|
||||
predicate.addTest(argv[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readIgnoreParamArgument(int argc, char**argv, char const* argument)
|
||||
{
|
||||
int from, count;
|
||||
if (!findArgumentListIndex(argc, argv, argument, from, count))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = from; i < from + count; i++)
|
||||
{
|
||||
ParameterizedManager::getInstance().ignoreIndexes(argv[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int RunTestsCmd(int argc, char**argv, char const* suiteArgument, char const* testArgument, char const* ignoreParamArgument)
|
||||
{
|
||||
SuitePredicate predicate;
|
||||
|
||||
bool specific = false;
|
||||
specific |= readSuiteArgument(predicate, argc, argv, suiteArgument);
|
||||
specific |= readTestArgument(predicate, argc, argv, testArgument);
|
||||
specific |= readTestArgument(predicate, argc, argv, "");
|
||||
|
||||
readIgnoreParamArgument(argc, argv, ignoreParamArgument);
|
||||
|
||||
if (!specific)
|
||||
{
|
||||
predicate.addAll();
|
||||
}
|
||||
|
||||
//run selected test(s) only
|
||||
TestReporterStdout reporter;
|
||||
TestRunner runner(reporter);
|
||||
|
||||
return runner.RunTestsIf(Test::GetTestList(), 0, predicate, 0);
|
||||
}
|
||||
|
||||
TestRunner::TestRunner(TestReporter& reporter)
|
||||
: m_reporter(&reporter)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,18 @@ namespace UnitTest {
|
|||
|
||||
UNITTEST_LINKAGE int RunAllTests();
|
||||
|
||||
/**
|
||||
* Commands:
|
||||
* --test One or multiple test names to execute (specify "--test" is optional if it is the first argument), can be combined with --suite
|
||||
* --suite One or multiple suite names to execute, can be combined with --test
|
||||
* --ignoreparam One or multiple test parameter name, with index(es) specified, using this syntax: pzMyParam[4,8,12,7]
|
||||
*
|
||||
* Usage examples:
|
||||
* myTests.exe --suite MySuite1 MyOtherSuite --test MySpecialTest MyOtherTest --ignoreparam pzMyPlatforms[0,2,3] pzMyParam[4,8]
|
||||
* myTests.exe MySpecialTest MyOtherTest --suite MySuite1
|
||||
*/
|
||||
UNITTEST_LINKAGE int RunTestsCmd(int argc, char**argv, char const* suiteArgument = "--suite", char const* testArgument = "--test", char const* ignoreParamArgument = "--ignoreparam");
|
||||
|
||||
struct True
|
||||
{
|
||||
bool operator()(const Test* const) const
|
||||
|
|
@ -31,14 +43,14 @@ namespace UnitTest {
|
|||
int RunTestsIf(TestList const& list, char const* suiteName,
|
||||
const Predicate& predicate, int maxTestTimeInMs) const
|
||||
{
|
||||
Test* curTest = list.GetHead();
|
||||
TestListNode* curTest = list.GetHead();
|
||||
|
||||
while (curTest != 0)
|
||||
{
|
||||
if (IsTestInSuite(curTest, suiteName) && predicate(curTest))
|
||||
RunTest(m_result, curTest, maxTestTimeInMs);
|
||||
if (IsTestInSuite(curTest->m_test, suiteName) && predicate(curTest->m_test))
|
||||
RunTest(m_result, curTest->m_test, maxTestTimeInMs);
|
||||
|
||||
curTest = curTest->m_nextTest;
|
||||
curTest = curTest->m_next;
|
||||
}
|
||||
|
||||
return Finish();
|
||||
|
|
|
|||
|
|
@ -8,5 +8,6 @@
|
|||
#include "TestRunner.h"
|
||||
#include "TimeConstraint.h"
|
||||
#include "ReportAssert.h"
|
||||
#include "ParameterizedMacros.h"
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "UnitTest++/UnitTestPP.h"
|
||||
|
||||
int main(int, char const *[])
|
||||
int main(int argc, char**argv)
|
||||
{
|
||||
return UnitTest::RunAllTests();
|
||||
return UnitTest::RunTestsCmd(argc, argv);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,9 @@ UNITTEST_SUITE(LongMacros)
|
|||
defined(SUITE) || \
|
||||
defined(TEST) || \
|
||||
defined(TEST_FIXTURE) || \
|
||||
defined(REQUIRE)
|
||||
defined(REQUIRE) || \
|
||||
defined(SET_TEST_PARAMETER_LISTENER) || \
|
||||
defined(SET_TEST_PARAMETER)
|
||||
|
||||
UNITTEST_CHECK(false);
|
||||
#endif
|
||||
|
|
|
|||
451
tests/TestParameterizedTest.cpp
Normal file
451
tests/TestParameterizedTest.cpp
Normal file
|
|
@ -0,0 +1,451 @@
|
|||
#include "UnitTest++/UnitTest++.h"
|
||||
|
||||
#include <string>
|
||||
#include "UnitTest++/TestParameter.h"
|
||||
#include "UnitTest++/ParameterizedManager.h"
|
||||
#include "ScopedCurrentTest.h"
|
||||
#include "RecordingReporter.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace UnitTest;
|
||||
|
||||
|
||||
SUITE(ParameterizedTest)
|
||||
{
|
||||
string simpleVowels;
|
||||
int simpleVowelsHitCount = 0;
|
||||
|
||||
SET_TEST_PARAMETER(string, pzVowel, {
|
||||
values.push_back("A");
|
||||
values.push_back("E");
|
||||
values.push_back("I");
|
||||
values.push_back("O");
|
||||
values.push_back("U");
|
||||
values.push_back("Y");
|
||||
});
|
||||
|
||||
TEST(SimpleVowelConcat)
|
||||
{
|
||||
simpleVowels += pzVowel();
|
||||
simpleVowelsHitCount++;
|
||||
}
|
||||
|
||||
TEST(SimpleVowelConcat_Verify)
|
||||
{
|
||||
CHECK_EQUAL(6, simpleVowelsHitCount);
|
||||
CHECK_EQUAL("AEIOUY", simpleVowels);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
int hitCountNonParameterized = 0;
|
||||
TEST(NonParameterizedExecutedOnce)
|
||||
{
|
||||
hitCountNonParameterized++;
|
||||
CHECK_EQUAL(1, hitCountNonParameterized);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
bool enteredEmpty = false;
|
||||
int hitCountEmpty = 0;
|
||||
|
||||
SET_TEST_PARAMETER(int, pzEmpty, {});
|
||||
|
||||
TEST(WhenNoParameters_throwsException)
|
||||
{
|
||||
enteredEmpty = true;
|
||||
try
|
||||
{
|
||||
pzEmpty();
|
||||
}
|
||||
catch (runtime_error e) // Expected case
|
||||
{
|
||||
CHECK_EQUAL("No values for parameterized test", e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(false);
|
||||
hitCountEmpty++;
|
||||
}
|
||||
|
||||
TEST(WhenNoParameters_throwsException_Verify)
|
||||
{
|
||||
CHECK_EQUAL(0, hitCountEmpty);
|
||||
CHECK(enteredEmpty);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
int hitCountSingle = 0;
|
||||
static int singleValueSuiteSum = 0;
|
||||
|
||||
SET_TEST_PARAMETER(int, pzSingle, {
|
||||
values.push_back(2);
|
||||
});
|
||||
|
||||
TEST(WhenSingleValue_singleExecution)
|
||||
{
|
||||
singleValueSuiteSum += pzSingle();
|
||||
CHECK_EQUAL(2, singleValueSuiteSum);
|
||||
hitCountSingle++;
|
||||
}
|
||||
|
||||
TEST(WhenSingleValue_singleExecution_Verification)
|
||||
{
|
||||
CHECK_EQUAL(2, singleValueSuiteSum);
|
||||
CHECK_EQUAL(1, hitCountSingle);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
string voyelReuse;
|
||||
TEST(ReusePreviousParameterized)
|
||||
{
|
||||
voyelReuse += pzVowel() + "-"; // Add a separator for
|
||||
}
|
||||
|
||||
TEST(ReusePreviousParameterized_Verify)
|
||||
{
|
||||
CHECK_EQUAL("A-E-I-O-U-Y-", voyelReuse);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
SET_TEST_PARAMETER(string, pzOneTwo, {
|
||||
values.push_back("1");
|
||||
values.push_back("2");
|
||||
});
|
||||
|
||||
string nestedParameters;
|
||||
TEST(NestedParameters)
|
||||
{
|
||||
nestedParameters += pzVowel();
|
||||
nestedParameters += pzOneTwo();
|
||||
}
|
||||
|
||||
TEST(NestedParameters_Verify)
|
||||
{
|
||||
CHECK_EQUAL("A1A2E1E2I1I2O1O2U1U2Y1Y2", nestedParameters);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
string useSeveralTimes;
|
||||
TEST(UseSeveralTimes_DoesNotIncrement)
|
||||
{
|
||||
useSeveralTimes += pzOneTwo();
|
||||
useSeveralTimes += pzOneTwo();
|
||||
}
|
||||
|
||||
TEST(UseSeveralTimes_DoesNotIncrement_Verify)
|
||||
{
|
||||
CHECK_EQUAL("1122", useSeveralTimes);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
struct Fixture {};
|
||||
|
||||
string withFixture;
|
||||
TEST_FIXTURE(Fixture, WorksWithFixture)
|
||||
{
|
||||
withFixture += pzOneTwo();
|
||||
}
|
||||
|
||||
TEST(WorksWithFixture_Verify)
|
||||
{
|
||||
CHECK_EQUAL("12", withFixture);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
SET_TEST_PARAMETER(int, pzSingleBis, {
|
||||
values.push_back(3);
|
||||
});
|
||||
|
||||
TEST(FailedMessage_ContainsIndexes)
|
||||
{
|
||||
class FailingParameterizedTest : public Test
|
||||
{
|
||||
public:
|
||||
FailingParameterizedTest()
|
||||
: Test(CurrentTest::Details()->testName, CurrentTest::Details()->suiteName, CurrentTest::Details()->filename) {}
|
||||
virtual void RunImpl() const
|
||||
{
|
||||
pzSingle();
|
||||
pzSingleBis();
|
||||
REQUIRE CHECK(false);
|
||||
}
|
||||
};
|
||||
|
||||
RecordingReporter reporter;
|
||||
TestResults results(&reporter);
|
||||
{
|
||||
ScopedCurrentTest scopedResults(results);
|
||||
FailingParameterizedTest().Run();
|
||||
}
|
||||
|
||||
string expectedFailMessage = "false Parameters: "
|
||||
+ pzSingle.getName() + "[0], "
|
||||
+ pzSingleBis.getName() + "[0]";
|
||||
|
||||
CHECK_EQUAL(expectedFailMessage, string(reporter.lastFailedMessage));
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
TEST(IgnoreIndex_OutOfRange_DoesNotThrowException)
|
||||
{
|
||||
size_t out = pzVowel.values().size();
|
||||
pzVowel.ignoreIndex(out);
|
||||
}
|
||||
|
||||
TEST(IgnoreIndex_IgnoreAll_ThrowsException)
|
||||
{
|
||||
size_t last = pzVowel.values().size() - 1;
|
||||
for (size_t i = 0; i < last; i++)
|
||||
{
|
||||
pzVowel.ignoreIndex(i);
|
||||
}
|
||||
|
||||
CHECK_THROW(pzVowel.ignoreIndex(last), runtime_error);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
size_t ignoreIndexLast_count = 0;
|
||||
string ignoreIndexLast;
|
||||
TEST(IgnoreIndex_IgnoreLast)
|
||||
{
|
||||
size_t lastIndex = pzOneTwo.values().size() - 1;
|
||||
pzOneTwo.ignoreIndex(lastIndex);
|
||||
|
||||
ignoreIndexLast += pzOneTwo();
|
||||
|
||||
// WARNING: this is not the test itself, it is only for reveal a "dead loop"
|
||||
REQUIRE CHECK(ignoreIndexLast_count < lastIndex);
|
||||
ignoreIndexLast_count++;
|
||||
}
|
||||
|
||||
TEST(IgnoreIndex_IgnoreLast_Verify)
|
||||
{
|
||||
CHECK_EQUAL("1", ignoreIndexLast);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
string ignoreSomeVowels;
|
||||
TEST(IgnoreIndex_IgnoreSome)
|
||||
{
|
||||
pzVowel
|
||||
.ignoreIndex(1) // "E"
|
||||
.ignoreIndex(4); // "U"
|
||||
|
||||
ignoreSomeVowels += pzVowel();
|
||||
}
|
||||
|
||||
TEST(IgnoreIndex_IgnoreSome_Verify)
|
||||
{
|
||||
CHECK_EQUAL("AIOY", ignoreSomeVowels);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
string ignoreWithNested;
|
||||
TEST(IgnoreIndex_IgnoreWithNested)
|
||||
{
|
||||
pzVowel
|
||||
.ignoreIndex(0) // "A"
|
||||
.ignoreIndex(2) // "I"
|
||||
.ignoreIndex(3) // "O"
|
||||
.ignoreIndex(4); // "U"
|
||||
|
||||
ignoreWithNested += pzVowel();
|
||||
ignoreWithNested += pzOneTwo();
|
||||
}
|
||||
|
||||
TEST(IgnoreIndex_IgnoreWithNested_Verify)
|
||||
{
|
||||
CHECK_EQUAL("E1E2Y1Y2", ignoreWithNested);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
string ignoreSomeVowelsByValue;
|
||||
TEST(Ignore_IgnoreSome)
|
||||
{
|
||||
pzVowel
|
||||
.ignore("E")
|
||||
.ignore("U");
|
||||
|
||||
ignoreSomeVowelsByValue += pzVowel();
|
||||
}
|
||||
|
||||
TEST(Ignore_IgnoreSome_Verify)
|
||||
{
|
||||
CHECK_EQUAL("AIOY", ignoreSomeVowelsByValue);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
SET_TEST_PARAMETER(string, pzVowelPartial, {
|
||||
values = pzVowel.values();
|
||||
});
|
||||
|
||||
struct Initializer
|
||||
{
|
||||
Initializer()
|
||||
{
|
||||
ParameterizedManager::getInstance()
|
||||
.ignoreIndex(&pzVowelPartial, 1) // "E"
|
||||
.ignoreIndex(&pzVowelPartial, 4); // "U"
|
||||
}
|
||||
} initializerInstance;
|
||||
|
||||
string globalIgnoreSomeVowels;
|
||||
|
||||
// Note: the test is executed twice (A/B)
|
||||
TEST(GlobalIgnore_IgnoreSome_A)
|
||||
{
|
||||
globalIgnoreSomeVowels += pzVowelPartial();
|
||||
}
|
||||
TEST(GlobalIgnore_IgnoreSome_B)
|
||||
{
|
||||
globalIgnoreSomeVowels += pzVowelPartial();
|
||||
}
|
||||
|
||||
TEST(GlobalIgnore_IgnoreSome_Verify)
|
||||
{
|
||||
CHECK_EQUAL("AIOYAIOY", globalIgnoreSomeVowels);
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
TEST(Ignore_Getter)
|
||||
{
|
||||
pzVowel.ignore("E");
|
||||
CHECK(pzVowel.isIgnored("E"));
|
||||
CHECK(!pzVowel.isIgnored("Y"));
|
||||
}
|
||||
|
||||
TEST(IgnoreGlobal_Getter)
|
||||
{
|
||||
CHECK(pzVowelPartial.isIgnored("E"));
|
||||
CHECK(!pzVowelPartial.isIgnored("Y"));
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
vector<TestListNode*> currentTestsNodes;
|
||||
TEST(NoDeadLoopInTestList)
|
||||
{
|
||||
pzOneTwo(); // Important for perform looping
|
||||
|
||||
for (TestListNode* iNode = Test::GetTestList().GetHead(); iNode != nullptr; iNode = iNode->m_next)
|
||||
{
|
||||
REQUIRE CHECK(iNode != iNode->m_next);
|
||||
currentTestsNodes.push_back(iNode);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NoDeadLoopInTestList_Verify)
|
||||
{
|
||||
vector<TestListNode*> expectedNodes;
|
||||
|
||||
for (size_t i = 0; i < pzOneTwo.values().size(); i++) // tested vector contains repeated values because it is filled by parameterized test
|
||||
{
|
||||
for (TestListNode* iNode = Test::GetTestList().GetHead(); iNode != nullptr; iNode = iNode->m_next)
|
||||
{
|
||||
expectedNodes.push_back(iNode);
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE CHECK_EQUAL(expectedNodes.size(), currentTestsNodes.size());
|
||||
CHECK_ARRAY_EQUAL(expectedNodes, currentTestsNodes, expectedNodes.size());
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
struct Initializer4pzIgnoredByNameVowel
|
||||
{
|
||||
Initializer4pzIgnoredByNameVowel()
|
||||
{
|
||||
ParameterizedManager::getInstance()
|
||||
.ignoreIndex("pzIgnoredByNameVowel", 2) // "I"
|
||||
.ignoreIndex("pzIgnoredByNameVowel", 5); // "Y"
|
||||
}
|
||||
} initializer4pzIgnoredByNameVowelInstance;
|
||||
|
||||
SET_TEST_PARAMETER(string, pzIgnoredByNameVowel, {
|
||||
values = pzVowel.values();
|
||||
});
|
||||
|
||||
string ignoreSomeVowelsByName_Global;
|
||||
TEST(Ignore_IgnoreByName_Global)
|
||||
{
|
||||
ignoreSomeVowelsByName_Global += pzIgnoredByNameVowel();
|
||||
}
|
||||
|
||||
TEST(Ignore_IgnoreByName_Global_Verify)
|
||||
{
|
||||
CHECK_EQUAL("AEOU", ignoreSomeVowelsByName_Global);
|
||||
}
|
||||
|
||||
string ignoreSomeVowelsByName_Local;
|
||||
TEST(Ignore_IgnoreByName_Local)
|
||||
{
|
||||
ParameterizedManager::getInstance()
|
||||
.ignoreIndex("pzIgnoredByNameVowel", 3); // "O"
|
||||
|
||||
ignoreSomeVowelsByName_Local += pzIgnoredByNameVowel();
|
||||
}
|
||||
|
||||
TEST(Ignore_IgnoreByName_Local_Verify)
|
||||
{
|
||||
CHECK_EQUAL("AEU", ignoreSomeVowelsByName_Local);
|
||||
}
|
||||
|
||||
|
||||
//////////
|
||||
|
||||
SET_TEST_PARAMETER(string, pzIgnoredByNameVowelSome, {
|
||||
values = pzVowel.values();
|
||||
});
|
||||
|
||||
string ignoreByNameRangeEmptyIsAllowed;
|
||||
TEST(Ignore_IgnoreByNameRange_EmptyIsAllowed)
|
||||
{
|
||||
ParameterizedManager::getInstance().ignoreIndexes("pzIgnoredByNameVowelSome[]");
|
||||
ignoreByNameRangeEmptyIsAllowed += pzIgnoredByNameVowelSome();
|
||||
}
|
||||
|
||||
TEST(Ignore_IgnoreByNameRange_EmptyIsAllowed_Verify)
|
||||
{
|
||||
CHECK_EQUAL("AEIOUY", ignoreByNameRangeEmptyIsAllowed);
|
||||
}
|
||||
|
||||
string ignoreByNameRangeSingleValue;
|
||||
TEST(Ignore_IgnoreByNameRange_SingleValue)
|
||||
{
|
||||
ParameterizedManager::getInstance().ignoreIndexes("pzIgnoredByNameVowelSome[2]");
|
||||
ignoreByNameRangeSingleValue += pzIgnoredByNameVowelSome();
|
||||
}
|
||||
|
||||
TEST(Ignore_IgnoreByNameRange_SingleValue_Verify)
|
||||
{
|
||||
CHECK_EQUAL("AEOUY", ignoreByNameRangeSingleValue);
|
||||
}
|
||||
|
||||
string ignoreByNameRangeSeveralUnorderedValues;
|
||||
TEST(Ignore_IgnoreByNameRange_SeveralUnorderedValues)
|
||||
{
|
||||
ParameterizedManager::getInstance().ignoreIndexes("pzIgnoredByNameVowelSome[3,4,0]");
|
||||
ignoreByNameRangeSeveralUnorderedValues += pzIgnoredByNameVowelSome();
|
||||
}
|
||||
|
||||
TEST(Ignore_IgnoreByNameRange_SeveralUnorderedValues_Verify)
|
||||
{
|
||||
CHECK_EQUAL("EIY", ignoreByNameRangeSeveralUnorderedValues);
|
||||
}
|
||||
}
|
||||
35
tests/TestTestDetails.cpp
Normal file
35
tests/TestTestDetails.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include "UnitTest++/UnitTestPP.h"
|
||||
#include "UnitTest++/TestDetails.h"
|
||||
|
||||
using namespace UnitTest;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(SameTest_SameValues_AreEqual)
|
||||
{
|
||||
TestDetails details1("test1", "suite1", "file1", 1234);
|
||||
TestDetails details2("test1", "suite1", "file1", 1234);
|
||||
CHECK(details1.sameTest(details2));
|
||||
}
|
||||
|
||||
TEST(SameTest_DifferentValues_AreNotEqual)
|
||||
{
|
||||
TestDetails details1("test1", "suite1", "file1", 1234);
|
||||
TestDetails details2("test2", "suite2", "file2", 4321);
|
||||
CHECK(!details1.sameTest(details2));
|
||||
}
|
||||
|
||||
TEST(SameTest_LineNumber_AreIgnored)
|
||||
{
|
||||
TestDetails details1("test1", "suite1", "file1", 1234);
|
||||
TestDetails details2("test1", "suite1", "file1", 0);
|
||||
CHECK(details1.sameTest(details2));
|
||||
}
|
||||
|
||||
TEST(SameTest_CopyConstructor_AreEqual)
|
||||
{
|
||||
TestDetails details1("test1", "suite1", "file1", 1234);
|
||||
TestDetails details2(details1, 4321);
|
||||
CHECK(details1.sameTest(details2));
|
||||
}
|
||||
}
|
||||
|
|
@ -18,8 +18,8 @@ namespace {
|
|||
TestList list;
|
||||
list.Add(&test);
|
||||
|
||||
CHECK(list.GetHead() == &test);
|
||||
CHECK(test.m_nextTest == 0);
|
||||
CHECK(list.GetHead()->m_test == &test);
|
||||
CHECK(list.GetHead()->m_next == 0);
|
||||
}
|
||||
|
||||
TEST(AddingSecondTestAddsItToEndOfList)
|
||||
|
|
@ -28,12 +28,12 @@ namespace {
|
|||
Test test2("test2");
|
||||
|
||||
TestList list;
|
||||
list.Add(&test1);
|
||||
list.Add(&test2);
|
||||
TestListNode* test1Node = list.Add(&test1);
|
||||
TestListNode* test2Node = list.Add(&test2);
|
||||
|
||||
CHECK(list.GetHead() == &test1);
|
||||
CHECK(test1.m_nextTest == &test2);
|
||||
CHECK(test2.m_nextTest == 0);
|
||||
CHECK(list.GetHead()->m_test == &test1);
|
||||
CHECK(test1Node->m_next->m_test == &test2);
|
||||
CHECK(test2Node->m_next == 0);
|
||||
}
|
||||
|
||||
TEST(ListAdderAddsTestToList)
|
||||
|
|
@ -43,8 +43,8 @@ namespace {
|
|||
Test test("");
|
||||
ListAdder adder(list, &test);
|
||||
|
||||
CHECK(list.GetHead() == &test);
|
||||
CHECK(test.m_nextTest == 0);
|
||||
CHECK(list.GetHead()->m_test == &test);
|
||||
CHECK(list.GetHead()->m_next == 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ namespace {
|
|||
TEST (TestsAreAddedToTheListThroughMacro)
|
||||
{
|
||||
CHECK(list1.GetHead() != 0);
|
||||
CHECK(list1.GetHead()->m_nextTest == 0);
|
||||
CHECK(list1.GetHead()->m_next == 0);
|
||||
}
|
||||
|
||||
#ifndef UNITTEST_NO_EXCEPTIONS
|
||||
|
|
@ -78,7 +78,7 @@ namespace {
|
|||
TestResults result(&reporter);
|
||||
{
|
||||
ScopedCurrentTest scopedResults(result);
|
||||
list2.GetHead()->Run();
|
||||
list2.GetHead()->m_test->Run();
|
||||
}
|
||||
|
||||
CHECK(strstr(reporter.lastFailedMessage, "xception"));
|
||||
|
|
@ -119,8 +119,8 @@ namespace {
|
|||
TEST(TestAddedWithTEST_EXMacroGetsDefaultSuite)
|
||||
{
|
||||
CHECK(macroTestList1.GetHead() != NULL);
|
||||
CHECK_EQUAL ("MacroTestHelper1", macroTestList1.GetHead()->m_details.testName);
|
||||
CHECK_EQUAL ("DefaultSuite", macroTestList1.GetHead()->m_details.suiteName);
|
||||
CHECK_EQUAL ("MacroTestHelper1", macroTestList1.GetHead()->m_test->m_details.testName);
|
||||
CHECK_EQUAL ("DefaultSuite", macroTestList1.GetHead()->m_test->m_details.suiteName);
|
||||
}
|
||||
|
||||
TestList macroTestList2;
|
||||
|
|
@ -130,8 +130,8 @@ namespace {
|
|||
TEST(TestAddedWithTEST_FIXTURE_EXMacroGetsDefaultSuite)
|
||||
{
|
||||
CHECK(macroTestList2.GetHead() != NULL);
|
||||
CHECK_EQUAL ("MacroTestHelper2", macroTestList2.GetHead()->m_details.testName);
|
||||
CHECK_EQUAL ("DefaultSuite", macroTestList2.GetHead()->m_details.suiteName);
|
||||
CHECK_EQUAL ("MacroTestHelper2", macroTestList2.GetHead()->m_test->m_details.testName);
|
||||
CHECK_EQUAL ("DefaultSuite", macroTestList2.GetHead()->m_test->m_details.suiteName);
|
||||
}
|
||||
|
||||
#ifndef UNITTEST_NO_EXCEPTIONS
|
||||
|
|
@ -154,7 +154,7 @@ namespace {
|
|||
TestResults result(&reporter);
|
||||
{
|
||||
ScopedCurrentTest scopedResult(result);
|
||||
throwingFixtureTestList1.GetHead()->Run();
|
||||
throwingFixtureTestList1.GetHead()->m_test->Run();
|
||||
}
|
||||
|
||||
int const failureCount = result.GetFailedTestCount();
|
||||
|
|
@ -181,7 +181,7 @@ namespace {
|
|||
TestResults result(&reporter);
|
||||
{
|
||||
ScopedCurrentTest scopedResult(result);
|
||||
throwingFixtureTestList2.GetHead()->Run();
|
||||
throwingFixtureTestList2.GetHead()->m_test->Run();
|
||||
}
|
||||
|
||||
int const failureCount = result.GetFailedTestCount();
|
||||
|
|
@ -209,7 +209,7 @@ namespace {
|
|||
TestResults result(&reporter);
|
||||
{
|
||||
ScopedCurrentTest scopedResults(result);
|
||||
ctorAssertFixtureTestList.GetHead()->Run();
|
||||
ctorAssertFixtureTestList.GetHead()->m_test->Run();
|
||||
}
|
||||
|
||||
const int failureCount = result.GetFailedTestCount();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue