Skip to content

Commit

Permalink
Merge pull request #1296 from basvodde/master
Browse files Browse the repository at this point in the history
Cleaned up shuffling some more and added reversing
  • Loading branch information
basvodde committed Apr 16, 2020
2 parents 0ab4e30 + e48696c commit 8f7d387
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 77 deletions.
4 changes: 2 additions & 2 deletions include/CppUTest/TestRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ class TestRegistry
virtual void unDoLastAddTest();
virtual size_t countTests();
virtual void runAllTests(TestResult& result);
virtual void shuffleRunOrder();
virtual void shuffleTests(unsigned seed);
virtual void reverseTests();
virtual void listTestGroupNames(TestResult& result);
virtual void listTestGroupAndCaseNames(TestResult& result);
virtual void setNameFilters(const TestFilter* filters);
Expand All @@ -76,7 +77,6 @@ class TestRegistry
int getCurrentRepetition();
void setRunIgnored();

static void shuffleList(size_t numElems, void* listToShuffleInPlace[]);
private:

bool testShouldRun(UtestShell* test, TestResult& result);
Expand Down
23 changes: 23 additions & 0 deletions include/CppUTest/Utest.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,29 @@ class IgnoredUtestShell : public UtestShell

};

//////////////////// UtestShellPointerArray

class UtestShellPointerArray
{
public:
UtestShellPointerArray(UtestShell* firstTest);
~UtestShellPointerArray();

void shuffle(unsigned seed);
void reverse();
void relinkTestsInOrder();
UtestShell* getFirstTest() const;
UtestShell* get(unsigned index) const;

private:

void swap(size_t index1, size_t index2);

UtestShell** arrayOfTests_;
size_t count_;
};


//////////////////// TestInstaller

class TestInstaller
Expand Down
3 changes: 1 addition & 2 deletions src/CppUTest/CommandLineTestRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,11 @@ int CommandLineTestRunner::runAllTests()
output_->print("Test order shuffling enabled with seed: ");
output_->print(arguments_->getShuffleSeed());
output_->print("\n");
PlatformSpecificSrand(arguments_->getShuffleSeed());
}
while (loopCount++ < repeatCount) {

if (arguments_->isShuffling())
registry_->shuffleRunOrder();
registry_->shuffleTests(arguments_->getShuffleSeed());

output_->printTestRun(loopCount, repeatCount);
TestResult tr(*output_);
Expand Down
44 changes: 8 additions & 36 deletions src/CppUTest/TestRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,46 +228,18 @@ UtestShell* TestRegistry::getFirstTest()
return tests_;
}

// "Durstenfeld shuffle" according to Wikipedia
void TestRegistry::shuffleList(size_t numElems, void* listToShuffleInPlace[])
void TestRegistry::shuffleTests(unsigned seed)
{
if( numElems == 0 ) return;

for (size_t i = numElems - 1; i >= 1; --i)
{
const size_t j = ((size_t)PlatformSpecificRand()) % (i + 1); // distribution biased by modulo, but good enough for shuffling
void* e1 = listToShuffleInPlace[j];
void* e2 = listToShuffleInPlace[i];
listToShuffleInPlace[i] = e1;
listToShuffleInPlace[j] = e2;
}
UtestShellPointerArray array(getFirstTest());
array.shuffle(seed);
tests_ = array.getFirstTest();
}

void TestRegistry::shuffleRunOrder()
void TestRegistry::reverseTests()
{
if (getFirstTest() == NULLPTR)
return;

const size_t testCount = getFirstTest()->countTests();

UtestShell** arrayOfTests = new UtestShell*[testCount];

UtestShell* currentTest = getFirstTest();
for (size_t i = 0; i < testCount; i++)
{
arrayOfTests[i] = currentTest;
currentTest = currentTest->getNext();
}

shuffleList(testCount, (void**)arrayOfTests);

tests_ = NULLPTR;
for (size_t i = 0; i < testCount; i++)
{
tests_ = arrayOfTests[testCount - 1 - i]->addTest(tests_);
}

delete[] arrayOfTests;
UtestShellPointerArray array(getFirstTest());
array.reverse();
tests_ = array.getFirstTest();
}

UtestShell* TestRegistry::getTestWithNext(UtestShell* test)
Expand Down
79 changes: 79 additions & 0 deletions src/CppUTest/Utest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,85 @@ void IgnoredUtestShell::setRunIgnored()
runIgnored_ = true;
}

//////////////////// UtestShellPointerArray

UtestShellPointerArray::UtestShellPointerArray(UtestShell* firstTest)
: arrayOfTests_(NULLPTR), count_(0)
{
count_ = (firstTest) ? firstTest->countTests() : 0;
if (count_ == 0) return;

arrayOfTests_ = new UtestShell*[count_];

UtestShell*currentTest = firstTest;
for (size_t i = 0; i < count_; i++)
{
arrayOfTests_[i] = currentTest;
currentTest = currentTest->getNext();
}
}

UtestShellPointerArray::~UtestShellPointerArray()
{
delete [] arrayOfTests_;
}

void UtestShellPointerArray::swap(size_t index1, size_t index2)
{
UtestShell* e2 = arrayOfTests_[index2];
UtestShell* e1 = arrayOfTests_[index1];
arrayOfTests_[index1] = e2;
arrayOfTests_[index2] = e1;
}

void UtestShellPointerArray::shuffle(unsigned seed)
{
if (count_ == 0) return;

PlatformSpecificSrand(seed);

for (size_t i = count_ - 1; i >= 1; --i)
{
if (count_ == 0) return;

const size_t j = ((size_t)PlatformSpecificRand()) % (i + 1); // distribution biased by modulo, but good enough for shuffling
swap(i, j);
}
relinkTestsInOrder();
}

void UtestShellPointerArray::reverse()
{
if (count_ == 0) return;

size_t halfCount = count_ / 2;
for (size_t i = 0; i < halfCount; i++)
{
size_t j = count_ - i - 1;
swap(i, j);
}
relinkTestsInOrder();
}

void UtestShellPointerArray::relinkTestsInOrder()
{
UtestShell *tests = NULLPTR;
for (size_t i = 0; i < count_; i++)
tests = arrayOfTests_[count_ - i - 1]->addTest(tests);
}

UtestShell* UtestShellPointerArray::getFirstTest() const
{
return get(0);
}

UtestShell* UtestShellPointerArray::get(unsigned index) const
{
if (index >= count_) return NULLPTR;
return arrayOfTests_[index];
}



////////////// TestInstaller ////////////

Expand Down
98 changes: 65 additions & 33 deletions tests/CppUTest/ShuffleTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,72 +30,104 @@
#include "CppUTest/TestRegistry.h"
#include "CppUTest/PlatformSpecificFunctions.h"

static const int maxNumItems = 3;
static int getZero()
{
return 0;
}

TEST_GROUP(ShuffleTest)
static int getOne()
{
int x0;
int x1;
int x2;
return 1;
}

void* elements[maxNumItems];
TEST_GROUP(ShuffleTest)
{
UtestShell* test0;
UtestShell* test1;
UtestShell* test2;

void setup()
{
x0 = 0;
x1 = 1;
x2 = 2;
test0 = new IgnoredUtestShell();
test1 = new IgnoredUtestShell();
test2 = new IgnoredUtestShell();

elements[0] = &x0;
elements[1] = &x1;
elements[2] = &x2;
test0->addTest(test1);
test1->addTest(test2);
}

void teardown()
{
delete test0;
delete test1;
delete test2;
}
};

static int getZero()

TEST(ShuffleTest, empty)
{
return 0;
UtestShellPointerArray tests(NULLPTR);
tests.shuffle(0);
CHECK(NULL == tests.getFirstTest());
}

static int getOne()
TEST(ShuffleTest, testsAreInOrder)
{
return 1;
UtestShellPointerArray tests(test0);
CHECK(tests.get(0) == test0);
CHECK(tests.get(1) == test1);
CHECK(tests.get(2) == test2);
}

static int getValueExceedingMaxIdx()
TEST(ShuffleTest, relinkingTestsWillKeepThemTheSameWhenNothingWasDone)
{
return maxNumItems + 1;
UtestShellPointerArray tests(test0);
tests.relinkTestsInOrder();
CHECK(tests.get(0) == test0);
CHECK(tests.get(1) == test1);
CHECK(tests.get(2) == test2);
}

TEST(ShuffleTest, ShuffleListTestWithNoElementsInList)
{
UT_PTR_SET(PlatformSpecificRand, getValueExceedingMaxIdx);
TestRegistry::shuffleList(0, elements);

CHECK(elements[0] == &x0);
CHECK(elements[1] == &x1);
CHECK(elements[2] == &x2);
TEST(ShuffleTest, firstTestisNotTheFirstTestWithSeed1234)
{
UtestShellPointerArray tests(test0);
tests.shuffle(1234);
CHECK(tests.getFirstTest() != test0);
}

TEST(ShuffleTest, ShuffleListTestWithRandomAlwaysReturningZero)
{
UT_PTR_SET(PlatformSpecificRand, getZero);
TestRegistry::shuffleList(3, elements);

CHECK(elements[0] == &x1);
CHECK(elements[1] == &x2);
CHECK(elements[2] == &x0);
UtestShellPointerArray tests(test0);
tests.shuffle(3);
CHECK(tests.get(0) == test1);
CHECK(tests.get(1) == test2);
CHECK(tests.get(2) == test0);
}

// swaps with 4 mod 3 (1) then 4 mod 2 (0): 1, [2], [0] --> [1], [0], 2 --> 0, 1, 2
TEST(ShuffleTest, ShuffleListTestWithRandomAlwaysReturningOne)
{
UT_PTR_SET(PlatformSpecificRand, getOne);
TestRegistry::shuffleList(3, elements);

CHECK(elements[0] == &x0);
CHECK(elements[1] == &x2);
CHECK(elements[2] == &x1);
UtestShellPointerArray tests(test0);
tests.shuffle(3);
CHECK(tests.get(0) == test0);
CHECK(tests.get(1) == test2);
CHECK(tests.get(2) == test1);
}

TEST(ShuffleTest, reverse)
{
UT_PTR_SET(PlatformSpecificRand, getOne);

UtestShellPointerArray tests(test0);
tests.reverse();
CHECK(tests.get(0) == test2);
CHECK(tests.get(1) == test1);
CHECK(tests.get(2) == test0);
}

25 changes: 21 additions & 4 deletions tests/CppUTest/TestRegistryTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,14 +364,14 @@ TEST(TestRegistry, listTestGroupAndCaseNames_shouldListBackwardsGroupATestaAfter
TEST(TestRegistry, shuffleEmptyListIsNoOp)
{
CHECK_TRUE(myRegistry->getFirstTest() == NULLPTR);
myRegistry->shuffleRunOrder();
myRegistry->shuffleTests(0);
CHECK_TRUE(myRegistry->getFirstTest() == NULLPTR);
}

TEST(TestRegistry, shuffleSingleTestIsNoOp)
{
myRegistry->addTest(test1);
myRegistry->shuffleRunOrder();
myRegistry->shuffleTests(0);
CHECK_TRUE(myRegistry->getFirstTest() == test1);
}

Expand All @@ -380,7 +380,7 @@ static int getZero()
return 0;
}

TEST(TestRegistry, shuffleTestList)
IGNORE_TEST(TestRegistry, shuffleTestList)
{
UT_PTR_SET(PlatformSpecificRand, getZero);
myRegistry->addTest(test3);
Expand All @@ -397,7 +397,7 @@ TEST(TestRegistry, shuffleTestList)
CHECK_TRUE(third_before->getNext() == NULLPTR);

// shuffle always with element at index 0: [1] 2 [3] --> [3] [2] 1 --> 2 3 1
myRegistry->shuffleRunOrder();
myRegistry->shuffleTests(0);

UtestShell* first_after = myRegistry->getFirstTest();
UtestShell* second_after = first_after->getNext();
Expand All @@ -408,3 +408,20 @@ TEST(TestRegistry, shuffleTestList)
CHECK_TRUE(third_after == test1);
CHECK_TRUE(third_after->getNext() == NULLPTR);
}

TEST(TestRegistry, reverseTests)
{
myRegistry->addTest(test1);
myRegistry->addTest(test2);

myRegistry->reverseTests();

CHECK(test1 == myRegistry->getFirstTest());
}

TEST(TestRegistry, reverseZeroTests)
{
myRegistry->reverseTests();

CHECK(NULLPTR == myRegistry->getFirstTest());
}

0 comments on commit 8f7d387

Please sign in to comment.