This commit is contained in:
Gabriel Schlozer 2017-01-20 01:02:41 +00:00 • committed by GitHub
commit d31befcf19
14 changed files with 574 additions and 2 deletions

View file

@ -0,0 +1,81 @@
#include "ArgumentsReader.h"
using namespace UnitTest;
ArgumentsReader::ArgumentsReader(int argc, char**argv)
{
_arguments.reserve(argc);
for (int i = 0; i < argc; i++)
{
_arguments.push_back(argv[i]);
}
}
ArgumentsReader::~ArgumentsReader()
{
}
bool ArgumentsReader::findArgumentListIndex(const string & argumentName, size_t & outFrom, size_t & outCount) const
{
if (_arguments.empty())
{
return false;
}
outCount = 0;
if (argumentName.empty())
{
outFrom = 1;
}
else
{
outFrom = 0;
for (size_t i = 1; i < _arguments.size(); i++)
{
if (argumentName == _arguments[i])
{
outFrom = i + 1;
break;
}
}
if (outFrom == 0)
{
return false;
}
}
for (size_t i = outFrom; i < _arguments.size(); i++)
{
const string & value = _arguments[i];
if (value.size() >= 2 && value.substr(0, 2) == "--")
{
break;
}
outCount++;
}
return true;
}
vector<string> ArgumentsReader::extractValues(const string & argumentName) const
{
size_t from, count;
if (!findArgumentListIndex(argumentName, from, count))
{
return vector<string>();
}
vector<string> values;
for (size_t i = from; i < from + count; i++)
{
values.push_back(getArgument(i));
}
return values;
}
string ArgumentsReader::getArgument(size_t index) const
{
return _arguments[index];
}

View file

@ -0,0 +1,21 @@
#include <string>
#include <vector>
namespace UnitTest {
using namespace std;
class ArgumentsReader
{
public:
ArgumentsReader(int argc, char**argv);
virtual ~ArgumentsReader();
bool findArgumentListIndex(const string & argumentName, size_t & outFrom, size_t & outCount) const;
vector<string> extractValues(const string & argumentName) const;
string getArgument(size_t index) const;
private:
vector<string> _arguments;
};
}

View file

@ -0,0 +1,23 @@
#include "PredicateCmdBuilder.h"
using namespace UnitTest;
void PredicateCmdBuilder::fillSuitePredicate(const ArgumentsReader & arguments, SuitePredicate & outPredicate, bool allowImplicitArgs)
{
outPredicate.addSuites(arguments.extractValues("--suite"));
outPredicate.addTests(arguments.extractValues("--test"));
if (allowImplicitArgs)
{
vector<string> implicitArguments = arguments.extractValues("");
outPredicate.addSuites(implicitArguments);
outPredicate.addTests(implicitArguments);
}
if (outPredicate.empty())
{
outPredicate.addAll();
}
}

View file

@ -0,0 +1,16 @@
#ifndef UNITTEST_PredicateCmdBuilder_H
#define UNITTEST_TESTRUNNERCMD_H
#include "ArgumentsReader.h"
#include "SuitePredicate.h"
namespace UnitTest {
class PredicateCmdBuilder
{
public:
static void fillSuitePredicate(const ArgumentsReader & arguments, SuitePredicate & outPredicate, bool allowImplicitArgs = true);
};
}
#endif

View file

@ -0,0 +1,105 @@
#include "SuitePredicate.h"
using namespace std;
using namespace UnitTest;
SuitePredicate::SuitePredicate()
: _all(false)
{
}
SuitePredicate::~SuitePredicate()
{
}
void SuitePredicate::addSuite(const string & suiteName)
{
_suiteNames.push_back(suiteName);
}
void SuitePredicate::addTest(const string & testName)
{
_testNames.push_back(testName);
}
void SuitePredicate::addSuites(const vector<string> & suiteNames)
{
for (size_t i = 0; i < suiteNames.size(); i++)
{
addSuite(suiteNames[i]);
}
}
void SuitePredicate::addTests(const vector<string> & testNames)
{
for (size_t i = 0; i < testNames.size(); i++)
{
addTest(testNames[i]);
}
}
void SuitePredicate::addAll()
{
_all = true;
}
bool SuitePredicate::empty()
{
if (!_suiteNames.empty())
{
return false;
}
if (!_testNames.empty())
{
return false;
}
if (_all)
{
return false;
}
return 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;
}

View file

@ -0,0 +1,40 @@
#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(const string & suiteName);
void addTest(const string & testName);
void addSuites(const vector<string> & suiteNames);
void addTests(const vector<string> & testNames);
void addAll();
bool empty();
bool operator()(Test const * const test) const;
const vector<string> & getSuites() const { return _suiteNames; }
const vector<string> & getTests() const { return _testNames; }
private:
bool mustExecuteSuite(Test const * const test) const;
bool mustExecuteTest(Test const * const test) const;
vector<string> _suiteNames;
vector<string> _testNames;
bool _all;
};
}
#endif

View file

@ -1,4 +1,5 @@
#include "TestDetails.h"
#include <cstring> // "c" version required for gcc
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;
}
}

View file

@ -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&);

View file

@ -4,6 +4,7 @@
#include "TestReporterStdout.h"
#include "TimeHelpers.h"
#include "MemoryOutStream.h"
#include "PredicateCmdBuilder.h"
#include <cstring>
@ -17,6 +18,21 @@ namespace UnitTest {
return runner.RunTestsIf(Test::GetTestList(), NULL, True(), 0);
}
int RunTestsCmd(int argc, char**argv, bool allowImplicitArgs)
{
SuitePredicate predicate;
ArgumentsReader arguments(argc, argv);
PredicateCmdBuilder::fillSuitePredicate(arguments, predicate, allowImplicitArgs);
TestReporterStdout reporter;
TestRunner runner(reporter);
return runner.RunTestsIf(Test::GetTestList(), 0, predicate, 0);
}
int RunTestsCmd(int argc, char**argv)
{
return RunTestsCmd(argc, argv, true);
}
TestRunner::TestRunner(TestReporter& reporter)
: m_reporter(&reporter)

View file

@ -11,6 +11,25 @@ namespace UnitTest {
class TestResults;
class Timer;
/**
* Run tests/suites using custom selection from command line.
*
* Commands:
* --test One or multiple test names to execute, can be combined with --suite
* --suite One or multiple suite names to execute, can be combined with --test
*
* Special feature: You do not have to specify explicitely --test and --suite, you
* can mix suite names and test names and the cmd will find the way. The
* constraint is that it must have no arguments beginning with --.
* For disabling this feature, set allowImplicitArgs=false
*
* Usage examples:
* Explicit: myTests.exe --suite MySuite1 MyOtherSuite --test MySpecialTest MyOtherTest
* Implicit: myTests.exe MySpecialTest MyOtherTest MySuite1
*/
UNITTEST_LINKAGE int RunTestsCmd(int argc, char**argv, bool allowImplicitArgs);
UNITTEST_LINKAGE int RunTestsCmd(int argc, char**argv); // Important: keep version with same signature as int main()
UNITTEST_LINKAGE int RunAllTests();
struct True

View file

@ -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);
}

View file

@ -0,0 +1,88 @@
#include "UnitTest++/UnitTestPP.h"
#include "UnitTest++/ArgumentsReader.h"
using namespace UnitTest;
SUITE(ArgumentsReader)
{
TEST(Extract_IgnoreUndesired)
{
char full[] = "C:\\myProgram.exe";
char valFake1[] = "fake";
char valFake2[] = "fakeBis";
char* argv[] = { full, valFake1, valFake2 };
ArgumentsReader args(3, argv);
CHECK(args.extractValues("--unexisting").empty());
}
TEST(Extract_CanExtractImplicitly)
{
char full[] = "C:\\myProgram.exe";
char val1[] = "val1";
char val2[] = "val2";
char* argv[] = { full, val1, val2 };
ArgumentsReader args(3, argv);
vector<string> values = args.extractValues("");
REQUIRE CHECK_EQUAL(2u, values.size());
CHECK_EQUAL(val1, values[0]);
CHECK_EQUAL(val2, values[1]);
}
TEST(Extract_ReadSimple)
{
char full[] = "C:\\myProgram.exe";
char paramToto[] = "--toto";
char val1[] = "myTest";
char* argv[] = { full, paramToto, val1 };
ArgumentsReader args(3, argv);
vector<string> values = args.extractValues(paramToto);
REQUIRE CHECK_EQUAL(1u, values.size());
CHECK_EQUAL(val1, values[0]);
}
TEST(Extract_CanReadMultiple)
{
char full[] = "C:\\myProgram.exe";
char fake[] = "fake";
char paramToto[] = "--toto";
char val1[] = "myTest";
char val2[] = "myOtherTest";
char* argv[] = { full, fake, paramToto, val1, val2 };
ArgumentsReader args(5, argv);
CHECK(args.extractValues("--unexisting").empty());
vector<string> values = args.extractValues(paramToto);
REQUIRE CHECK_EQUAL(2u, values.size());
CHECK_EQUAL(val1, values[0]);
CHECK_EQUAL(val2, values[1]);
}
TEST(Extract_BlindTest)
{
char full[] = "C:\\myProgram.exe";
char fake[] = "fake";
char paramToto[] = "--toto";
char totoVal1[] = "myTest";
char totoVal2[] = "myOtherTest";
char paramTiti[] = "--titi";
char titiVal[] = "yourTest";
char* argv[] = { full, fake, paramToto, totoVal1, totoVal2, paramTiti, titiVal };
ArgumentsReader args(7, argv);
vector<string> valuesToto = args.extractValues(paramToto);
REQUIRE CHECK_EQUAL(2u, valuesToto.size());
CHECK_EQUAL(totoVal1, valuesToto[0]);
CHECK_EQUAL(totoVal2, valuesToto[1]);
vector<string> valuesTiti = args.extractValues(paramTiti);
REQUIRE CHECK_EQUAL(1u, valuesTiti.size());
CHECK_EQUAL(titiVal, valuesTiti[0]);
}
}

View file

@ -0,0 +1,100 @@
#include "UnitTest++/UnitTestPP.h"
#include "UnitTest++/SuitePredicate.h"
SUITE(SuitePredicate)
{
using namespace UnitTest;
TEST(Operator_DetectsTests)
{
SuitePredicate predicate;
predicate.addTest("test1");
predicate.addTest("testFake");
Test test1("test1", "suite1");
Test test2("test2");
CHECK(predicate.operator()(&test1));
CHECK(!predicate.operator()(&test2));
}
TEST(Operator_DetectsSuites)
{
SuitePredicate predicate;
predicate.addSuite("suite1");
predicate.addSuite("suiteFake");
Test test1("test1", "suite1");
Test test2("test2");
CHECK(predicate.operator()(&test1));
CHECK(!predicate.operator()(&test2));
}
TEST(Operator_WhenAddAll_AllAreAdded)
{
SuitePredicate predicate;
predicate.addAll();
Test test1("test1", "suite1");
Test test2("test2");
CHECK(predicate.operator()(&test1));
CHECK(predicate.operator()(&test2));
}
TEST(AddMultiple_AndCheckWithGetters)
{
vector<string> tests;
tests.push_back("test1");
tests.push_back("test2");
vector<string> suites;
suites.push_back("suite1");
suites.push_back("suite2");
SuitePredicate predicate;
predicate.addTests(tests);
predicate.addSuites(suites);
REQUIRE CHECK_EQUAL(tests.size(), predicate.getTests().size());
CHECK_ARRAY_EQUAL(tests, predicate.getTests(), tests.size());
REQUIRE CHECK_EQUAL(suites.size(), predicate.getSuites().size());
CHECK_ARRAY_EQUAL(suites, predicate.getSuites(), suites.size());
}
TEST(EmptyPredicate_IsFlaggedAsEmpty)
{
SuitePredicate predicate;
CHECK(predicate.empty());
}
TEST(EmptyPredicate_WhenTestAdded_IsFlaggedAsNonEmpty)
{
SuitePredicate predicate;
predicate.addTest("toto");
CHECK(!predicate.empty());
}
TEST(EmptyPredicate_WhenSuiteAdded_IsFlaggedAsNonEmpty)
{
SuitePredicate predicate;
predicate.addSuite("toto");
CHECK(!predicate.empty());
}
TEST(EmptyPredicate_WhenAllAdded_IsFlaggedAsNonEmpty)
{
SuitePredicate predicate;
predicate.addAll();
CHECK(!predicate.empty());
}
}

36
tests/TestTestDetails.cpp Normal file
View file

@ -0,0 +1,36 @@
#include "UnitTest++/UnitTestPP.h"
#include "UnitTest++/TestDetails.h"
SUITE(TestDetails)
{
using namespace UnitTest;
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));
}
}