Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add interface tests and parametrized mix-ins
The basic idea is:
 - have so called mix-in tests that can be inserted to other test groups
 - use a second, non-executed test registry (reuse TestRegistry) -> mix-in registry
 - add tests and test groups to this mix-in registry (derived from Utest and UTestShell) -> mix-in tests, mix-in groups
 - have a normal test that injects the appropriate test from the second registry in the scope of the current test group -> apply mix-in group to test group
 - this injection test is self-looped until all tests from the mix-in group are executed
  • Loading branch information
the-real-orca committed May 27, 2015
commit e868b05bad86e1f7de7cef60a0a3b928f8d82ac7
2 changes: 2 additions & 0 deletions include/CppUTest/TestRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class TestRegistry
static TestRegistry* getCurrentRegistry();
virtual void setCurrentRegistry(TestRegistry* registry);

static TestRegistry* getMixInRegistry();

virtual void setRunTestsInSeperateProcess();
int getCurrentRepetition();

Expand Down
93 changes: 90 additions & 3 deletions include/CppUTest/Utest.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ class UtestShell
virtual UtestShell *getNext() const;
virtual int countTests();

bool shouldRun(const TestFilter* groupFilters, const TestFilter* nameFilters) const;
const SimpleString getName() const;
const SimpleString getGroup() const;
virtual bool shouldRun(const TestFilter* groupFilters, const TestFilter* nameFilters) const;
virtual const SimpleString getName() const;
virtual const SimpleString getGroup() const;
virtual SimpleString getFormattedName() const;
const SimpleString getFile() const;
int getLineNumber() const;
Expand Down Expand Up @@ -247,4 +247,91 @@ class TestInstaller

};

//////////////////// MixInInstaller

class MixInInstaller
{
public:
explicit MixInInstaller(UtestShell& shell, const char* groupName, const char* testName,
const char* fileName, int lineNumber);
virtual ~MixInInstaller();

void unDo();

private:

MixInInstaller(const MixInInstaller&);
MixInInstaller& operator=(const MixInInstaller&);

};

//////////////////// MixInUtest

class MixInUtest : public Utest
{
public:
virtual void* getParams() { return NULL; };
};

//////////////////// MixInInUtestShell

class MixInInUtestShell: public UtestShell
{
friend class MixInInjectionUTest;
public:
MixInInUtestShell() : currentMixinTest_(NULL), nextMixinTest_(NULL) {};
virtual ~MixInInUtestShell() {};

virtual const SimpleString getName() const;

virtual const SimpleString getMixinGroupName() const;
virtual void setMixinGroupName(const char *mixinGroupName);

protected:
UtestShell* currentMixinTest_;
UtestShell* nextMixinTest_;

virtual void prepareMixin();
UtestShell* getCurrentMixinTest() const;

private:
const char* mixinGroup_;

UtestShell* next_;
};

//////////////////// MixInInjectionUTest

class MixInInjectionUTest
{
public:
MixInInjectionUTest(MixInInUtestShell* testShell);

virtual void prepareScope() {}
void mixinInjection();

private:
virtual void setParams(void* p) {} // we can do an unsafe, old-style cast in pre-setup / post-teardown since we are sure that testToRun is derived from the current MixIn group base class

MixInInUtestShell* testShell_;
};

//////////////////// MixinApplyInstaller

class MixinApplyInstaller
{
public:
explicit MixinApplyInstaller(MixInInUtestShell& shell, const char* groupName, const char* testName,
const char* fileName, int lineNumber, const char* mixinGroupName);
virtual ~MixinApplyInstaller();

void unDo();

private:

MixinApplyInstaller(const MixinApplyInstaller&);
MixinApplyInstaller& operator=(const MixinApplyInstaller&);

};

#endif
40 changes: 40 additions & 0 deletions include/CppUTest/UtestMacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@
#define TEST_GROUP(testGroup) \
TEST_GROUP_BASE(testGroup, Utest)

#define MIXIN_PARAMS(mixinGroup) \
struct MIXIN_##mixinGroup##_Params

#define MIXIN_GROUP(mixinGroup) \
struct MIXIN_BASE_##CppUTestGroup##mixinGroup : public MixInUtest { \
void* getParams() { return &params; } \
MIXIN_##mixinGroup##_Params params; }; \
TEST_GROUP_BASE(mixinGroup, MIXIN_BASE_##CppUTestGroup##mixinGroup)

#define TEST_SETUP() \
virtual void setup()

Expand Down Expand Up @@ -83,6 +92,37 @@
static TestInstaller TEST_##testGroup##testName##_Installer(IGNORE##testGroup##_##testName##_TestShell_instance, #testGroup, #testName, __FILE__,__LINE__); \
void IGNORE##testGroup##_##testName##_Test::testBodyThatNeverRuns ()

#define MIXIN_TEST(mixinGroup, testName) \
/* External declarations for strict compilers */ \
class MIXIN_##mixinGroup##_##testName##_TestShell; \
extern MIXIN_##mixinGroup##_##testName##_TestShell MIXIN_##mixinGroup##_##testName##_TestShell_instance; \
\
class MIXIN_##mixinGroup##_##testName##_Test : public TEST_GROUP_##CppUTestGroup##mixinGroup \
{ public: MIXIN_##mixinGroup##_##testName##_Test () : TEST_GROUP_##CppUTestGroup##mixinGroup () {} \
void testBody(); }; \
class MIXIN_##mixinGroup##_##testName##_TestShell : public UtestShell { \
virtual Utest* createTest() _override { return new MIXIN_##mixinGroup##_##testName##_Test; } \
} MIXIN_##mixinGroup##_##testName##_TestShell_instance; \
static MixInInstaller MIXIN_##mixinGroup##_##testName##_Installer(MIXIN_##mixinGroup##_##testName##_TestShell_instance, #mixinGroup, #testName, __FILE__,__LINE__); \
void MIXIN_##mixinGroup##_##testName##_Test::testBody()

#define MIXIN_APPLY(testGroup, mixinGroup, testName) \
/* External declarations for strict compilers */ \
class TEST_##testGroup##_##testName##_TestShell; \
extern TEST_##testGroup##_##testName##_TestShell TEST_##testGroup##_##testName##_TestShell_instance; \
\
class TEST_##testGroup##_##testName##_Test : public TEST_GROUP_##CppUTestGroup##testGroup, public MixInInjectionUTest \
{ public: TEST_##testGroup##_##testName##_Test () : TEST_GROUP_##CppUTestGroup##testGroup (), MixInInjectionUTest((MixInInUtestShell*)&TEST_##testGroup##_##testName##_TestShell_instance) {} \
void testBody() { mixinInjection(); } \
void setParams(void* p) { params = (MIXIN_##mixinGroup##_Params *)p; } \
virtual void prepareScope(); \
MIXIN_##mixinGroup##_Params *params; }; \
class TEST_##testGroup##_##testName##_TestShell : public MixInInUtestShell { \
virtual Utest* createTest() _override { prepareMixin(); return new TEST_##testGroup##_##testName##_Test; } \
} TEST_##testGroup##_##testName##_TestShell_instance; \
static MixinApplyInstaller TEST_##testGroup##_##testName##_Installer(TEST_##testGroup##_##testName##_TestShell_instance, #testGroup, #testName, __FILE__,__LINE__, #mixinGroup); \
void TEST_##testGroup##_##testName##_Test::prepareScope()

#define IMPORT_TEST_GROUP(testGroup) \
extern int externTestGroup##testGroup;\
extern int* p##testGroup; \
Expand Down
6 changes: 6 additions & 0 deletions src/CppUTest/TestRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ TestRegistry* TestRegistry::getCurrentRegistry()
return (currentRegistry_ == 0) ? &registry : currentRegistry_;
}

TestRegistry* TestRegistry::getMixInRegistry()
{
static TestRegistry registry;
return &registry;
}

void TestRegistry::setCurrentRegistry(TestRegistry* registry)
{
currentRegistry_ = registry;
Expand Down
149 changes: 147 additions & 2 deletions src/CppUTest/Utest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,9 @@ SimpleString UtestShell::getFormattedName() const
{
SimpleString formattedName(getMacroName());
formattedName += "(";
formattedName += group_;
formattedName += getGroup();
formattedName += ", ";
formattedName += name_;
formattedName += getName();
formattedName += ")";

return formattedName;
Expand Down Expand Up @@ -654,3 +654,148 @@ void TestInstaller::unDo()
{
TestRegistry::getCurrentRegistry()->unDoLastAddTest();
}

//////////////////// MixInInstaller

MixInInstaller::MixInInstaller(UtestShell& shell, const char* groupName, const char* testName, const char* fileName, int lineNumber)
{
shell.setGroupName(groupName);
shell.setTestName(testName);
shell.setFileName(fileName);
shell.setLineNumber(lineNumber);
TestRegistry::getMixInRegistry()->addTest(&shell);
}

MixInInstaller::~MixInInstaller()
{
}

void MixInInstaller::unDo()
{
TestRegistry::getMixInRegistry()->unDoLastAddTest();
}

////////////// MixinApplyInstaller ////////////

MixinApplyInstaller::MixinApplyInstaller(MixInInUtestShell& shell, const char* groupName, const char* testName, const char* fileName, int lineNumber, const char* mixinGroupName)
{
shell.setGroupName(groupName);
shell.setTestName(testName);
shell.setFileName(fileName);
shell.setLineNumber(lineNumber);
shell.setMixinGroupName(mixinGroupName);
TestRegistry::getCurrentRegistry()->addTest(&shell);
}

MixinApplyInstaller::~MixinApplyInstaller()
{
}

void MixinApplyInstaller::unDo()
{
TestRegistry::getCurrentRegistry()->unDoLastAddTest();
}

//////////////////// MixInInUtestShell

const SimpleString MixInInUtestShell::getName() const
{
SimpleString name = SimpleString(UtestShell::getName());
UtestShell* test = getCurrentMixinTest();
if ( test )
{
name += ": "; name += test->getName();
}
return name;
}

const SimpleString MixInInUtestShell::getMixinGroupName() const
{
return SimpleString(mixinGroup_);
}


void MixInInUtestShell::setMixinGroupName(const char *mixinGroupName)
{
mixinGroup_ = mixinGroupName;
}

UtestShell* MixInInUtestShell::getCurrentMixinTest() const
{
if ( currentMixinTest_ )
{
return currentMixinTest_;
}

// no active MixIn Test, search for first match
return TestRegistry::getMixInRegistry()->findTestWithGroup(mixinGroup_);
}

void MixInInUtestShell::prepareMixin()
{
// first run
if ( !nextMixinTest_ )
{
// save next test pointer
next_ = getNext();

// get first MixIn Test
TestRegistry* registry = TestRegistry::getMixInRegistry();
nextMixinTest_ = registry->findTestWithGroup(mixinGroup_);

// set self-loop
addTest(this);
}

// set current MixIn Test
currentMixinTest_ = nextMixinTest_;

// get next test
if ( nextMixinTest_ )
{
nextMixinTest_ = nextMixinTest_->getNext(); // pre-fetch next test, in case the current one crashes
if ( nextMixinTest_ ) if ( nextMixinTest_->getGroup() != getMixinGroupName() ) nextMixinTest_ = NULL;
}

// exit self-loop on last MixIn
if ( !nextMixinTest_ )
{
addTest(next_);
next_ = NULL;
}

}

//////////////////// MixInInjectionUTest

MixInInjectionUTest::MixInInjectionUTest(MixInInUtestShell* testShell) :
testShell_(testShell)
{
}

void MixInInjectionUTest::mixinInjection()
{
// injected actual MixIn test
if ( testShell_->currentMixinTest_ )
{
// run test
MixInUtest* testToRun = (MixInUtest *) testShell_->currentMixinTest_->createTest();
if ( testToRun )
{
try
{
setParams( testToRun->getParams() );
prepareScope();
testToRun->run();
setParams( NULL );
}
catch (...) {}

testShell_->currentMixinTest_->destroyTest(testToRun);
}
else
{
FAIL("cannot create test");
}
}
}