Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ $ vcpkg install cpputest (More information: https://github.com/microsoft/vcpkg)
* `TEST_SETUP()` - Declare a void setup method in a `TEST_GROUP` - this is the same as declaring void `setup()`
* `TEST_TEARDOWN()` - Declare a void setup method in a `TEST_GROUP`
* `IMPORT_TEST_GROUP(group)` - Export the name of a test group so it can be linked in from a library. Needs to be done in `main`.
* `TEST_PROPERTY(name, value)` - Attach a key-value string property to the current test. Properties appear as `<property>` elements inside the `<testcase>` block in JUnit XML output. For use in C files, use `TEST_PROPERTY_C(name, value)` instead.

## Set up and tear down support

Expand Down
1 change: 1 addition & 0 deletions include/CppUTest/JUnitTestOutput.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class JUnitTestOutput: public TestOutput
virtual void print(long) CPPUTEST_OVERRIDE;
virtual void print(size_t) CPPUTEST_OVERRIDE;
virtual void printFailure(const TestFailure& failure) CPPUTEST_OVERRIDE;
virtual void printTestProperty(const char* name, const char* value) CPPUTEST_OVERRIDE;

virtual void flush() CPPUTEST_OVERRIDE;

Expand Down
1 change: 1 addition & 0 deletions include/CppUTest/TestHarness_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ extern void CHECK_EQUAL_C_BITS_LOCATION(unsigned int expected, unsigned int actu
extern void FAIL_TEXT_C_LOCATION(const char* text, const char* fileName, size_t lineNumber);
extern void FAIL_C_LOCATION(const char* fileName, size_t lineNumber);
extern void CHECK_C_LOCATION(int condition, const char* conditionString, const char* text, const char* fileName, size_t lineNumber);
extern void TEST_PROPERTY_C(const char* name, const char* value);

extern void* cpputest_malloc(size_t size);
extern char* cpputest_strdup(const char* str);
Expand Down
2 changes: 2 additions & 0 deletions include/CppUTest/TestOutput.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class TestOutput
virtual void setProgressIndicator(const char*);

virtual void printVeryVerbose(const char*);
virtual void printTestProperty(const char* name, const char* value);

virtual void flush()=0;

Expand Down Expand Up @@ -199,6 +200,7 @@ class CompositeTestOutput : public TestOutput
virtual void setProgressIndicator(const char*) CPPUTEST_OVERRIDE;

virtual void printVeryVerbose(const char*) CPPUTEST_OVERRIDE;
virtual void printTestProperty(const char* name, const char* value) CPPUTEST_OVERRIDE;

virtual void flush() CPPUTEST_OVERRIDE;

Expand Down
1 change: 1 addition & 0 deletions include/CppUTest/TestResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class TestResult
virtual void countFilteredOut();
virtual void countIgnored();
virtual void addFailure(const TestFailure& failure);
virtual void addProperty(const char* name, const char* value);
virtual void print(const char* text);
virtual void printVeryVerbose(const char* text);

Expand Down
1 change: 1 addition & 0 deletions include/CppUTest/Utest.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ class UtestShell
virtual void print(const char *text, const char *fileName, size_t lineNumber);
virtual void print(const SimpleString & text, const char *fileName, size_t lineNumber);
virtual void printVeryVerbose(const char* text);
virtual void addTestProperty(const char* name, const char* value);

void setFileName(const char *fileName);
void setLineNumber(size_t lineNumber);
Expand Down
3 changes: 3 additions & 0 deletions include/CppUTest/UtestMacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,4 +387,7 @@
#define UT_CRASH() do { UtestShell::crash(); } while(0)
#define RUN_ALL_TESTS(ac, av) CommandLineTestRunner::RunAllTests(ac, av)

#define TEST_PROPERTY(name, value) \
do { UtestShell::getCurrent()->addTestProperty(name, value); } while(0)

#endif /*D_UTestMacros_h*/
49 changes: 48 additions & 1 deletion src/CppUTest/JUnitTestOutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,19 @@
#include "CppUTest/TestFailure.h"
#include "CppUTest/PlatformSpecificFunctions.h"

struct TestPropertyResultNode
{
TestPropertyResultNode() : next_(NULLPTR) {}
SimpleString name_;
SimpleString value_;
TestPropertyResultNode* next_;
};

struct JUnitTestCaseResultNode
{
JUnitTestCaseResultNode() :
execTime_(0), failure_(NULLPTR), ignored_(false), lineNumber_ (0), checkCount_ (0), next_(NULLPTR)
execTime_(0), failure_(NULLPTR), ignored_(false), lineNumber_ (0), checkCount_ (0),
properties_(NULLPTR), propertiesTail_(NULLPTR), next_(NULLPTR)
{
}

Expand All @@ -45,6 +54,8 @@ struct JUnitTestCaseResultNode
SimpleString file_;
size_t lineNumber_;
size_t checkCount_;
TestPropertyResultNode* properties_;
TestPropertyResultNode* propertiesTail_;
JUnitTestCaseResultNode* next_;
};

Expand Down Expand Up @@ -93,6 +104,12 @@ void JUnitTestOutput::resetTestGroupResult()
while (cur) {
JUnitTestCaseResultNode* tmp = cur->next_;
delete cur->failure_;
TestPropertyResultNode* prop = cur->properties_;
while (prop) {
TestPropertyResultNode* tmpProp = prop->next_;
delete prop;
prop = tmpProp;
}
delete cur;
cur = tmp;
}
Expand Down Expand Up @@ -233,6 +250,20 @@ void JUnitTestOutput::writeTestCases()

impl_->results_.totalCheckCount_ = cur->checkCount_;

if (cur->properties_) {
writeToFile("<properties>\n");
TestPropertyResultNode* prop = cur->properties_;
while (prop) {
SimpleString propBuf = StringFromFormat(
"<property name=\"%s\" value=\"%s\"/>\n",
encodeXmlText(prop->name_).asCharString(),
encodeXmlText(prop->value_).asCharString());
writeToFile(propBuf.asCharString());
prop = prop->next_;
}
writeToFile("</properties>\n");
}

if (cur->failure_) {
writeFailure(cur);
}
Expand Down Expand Up @@ -309,6 +340,22 @@ void JUnitTestOutput::printFailure(const TestFailure& failure)
}
}

void JUnitTestOutput::printTestProperty(const char* name, const char* value)
{
TestPropertyResultNode* node = new TestPropertyResultNode;
node->name_ = name;
node->value_ = value;

if (impl_->results_.tail_->propertiesTail_ == NULLPTR) {
impl_->results_.tail_->properties_ = node;
impl_->results_.tail_->propertiesTail_ = node;
}
else {
impl_->results_.tail_->propertiesTail_->next_ = node;
impl_->results_.tail_->propertiesTail_ = node;
}
}

void JUnitTestOutput::openFileForWrite(const SimpleString& fileName)
{
impl_->file_ = PlatformSpecificFOpen(fileName.asCharString(), "w");
Expand Down
5 changes: 5 additions & 0 deletions src/CppUTest/TestHarness_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ void CHECK_C_LOCATION(int condition, const char* conditionString, const char* te
UtestShell::getCurrent()->assertTrue(condition != 0, "CHECK_C", conditionString, text, fileName, lineNumber, UtestShell::getCurrentTestTerminatorWithoutExceptions());
}

void TEST_PROPERTY_C(const char* name, const char* value)
{
UtestShell::getCurrent()->addTestProperty(name, value);
}

enum { NO_COUNTDOWN = -1, OUT_OF_MEMORRY = 0 };
static int malloc_out_of_memory_counter = NO_COUNTDOWN;
static int malloc_count = 0;
Expand Down
10 changes: 10 additions & 0 deletions src/CppUTest/TestOutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ void TestOutput::printVeryVerbose(const char* str)
printBuffer(str);
}

void TestOutput::printTestProperty(const char*, const char*)
{
}


void ConsoleTestOutput::printBuffer(const char* s)
{
Expand Down Expand Up @@ -406,6 +410,12 @@ void CompositeTestOutput::printVeryVerbose(const char* str)
if (outputTwo_) outputTwo_->printVeryVerbose(str);
}

void CompositeTestOutput::printTestProperty(const char* name, const char* value)
{
if (outputOne_) outputOne_->printTestProperty(name, value);
if (outputTwo_) outputTwo_->printTestProperty(name, value);
}

void CompositeTestOutput::flush()
{
if (outputOne_) outputOne_->flush();
Expand Down
5 changes: 5 additions & 0 deletions src/CppUTest/TestResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ void TestResult::addFailure(const TestFailure& failure)
failureCount_++;
}

void TestResult::addProperty(const char* name, const char* value)
{
output_.printTestProperty(name, value);
}

void TestResult::countTest()
{
testCount_++;
Expand Down
5 changes: 5 additions & 0 deletions src/CppUTest/Utest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,11 @@ void UtestShell::printVeryVerbose(const char* text)
getTestResult()->printVeryVerbose(text);
}

void UtestShell::addTestProperty(const char* name, const char* value)
{
getTestResult()->addProperty(name, value);
}

TestResult* UtestShell::testResult_ = NULLPTR;
UtestShell* UtestShell::currentTest_ = NULLPTR;

Expand Down
117 changes: 116 additions & 1 deletion tests/CppUTest/JUnitOutputTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ extern "C" {
}
}

struct PendingProperty
{
const char* name_;
const char* value_;
PendingProperty* next_;
PendingProperty(const char* n, const char* v, PendingProperty* nx) : name_(n), value_(v), next_(nx) {}
};

class JUnitTestOutputTestRunner
{
TestResult result_;
Expand All @@ -159,11 +167,13 @@ class JUnitTestOutputTestRunner
unsigned int timeTheTestTakes_;
unsigned int numberOfChecksInTest_;
TestFailure* testFailure_;
PendingProperty* pendingProperties_;
PendingProperty* pendingPropertiesTail_;

public:

explicit JUnitTestOutputTestRunner(const TestResult& result) :
result_(result), currentGroupName_(NULLPTR), currentTest_(NULLPTR), firstTestInGroup_(true), timeTheTestTakes_(0), numberOfChecksInTest_(0), testFailure_(NULLPTR)
result_(result), currentGroupName_(NULLPTR), currentTest_(NULLPTR), firstTestInGroup_(true), timeTheTestTakes_(0), numberOfChecksInTest_(0), testFailure_(NULLPTR), pendingProperties_(NULLPTR), pendingPropertiesTail_(NULLPTR)
{
millisTime = 0;
theTime = "1978-10-03T00:00:00";
Expand Down Expand Up @@ -264,6 +274,16 @@ class JUnitTestOutputTestRunner
}
numberOfChecksInTest_ = 0;

PendingProperty* prop = pendingProperties_;
pendingProperties_ = NULLPTR;
pendingPropertiesTail_ = NULLPTR;
while (prop) {
PendingProperty* next = prop->next_;
result_.addProperty(prop->name_, prop->value_);
delete prop;
prop = next;
}

if (testFailure_) {
result_.addFailure(*testFailure_);
delete testFailure_;
Expand Down Expand Up @@ -308,6 +328,20 @@ class JUnitTestOutputTestRunner
result_.print(output);
return *this;
}

JUnitTestOutputTestRunner& withProperty(const char* name, const char* value)
{
PendingProperty* node = new PendingProperty(name, value, NULLPTR);
if (pendingPropertiesTail_ == NULLPTR) {
pendingProperties_ = node;
pendingPropertiesTail_ = node;
}
else {
pendingPropertiesTail_->next_ = node;
pendingPropertiesTail_ = node;
}
return *this;
}
};

extern "C" {
Expand Down Expand Up @@ -767,3 +801,84 @@ TEST(JUnitOutputTest, UTPRINTOutputInJUnitOutputWithSpecials)
outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<system-out>The &lt;rain&gt; in &quot;Spain&quot;&#10;Goes&#13; \\mainly\\ down the Dr&amp;in&#10;</system-out>\n", outputFile->lineFromTheBack(3));
}

TEST(JUnitOutputTest, TestCaseWithOneProperty)
{
testCaseRunner->start()
.withGroup("groupname").withTest("testname").withProperty("key", "val")
.end();

outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<testcase classname=\"groupname\" name=\"testname\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
STRCMP_EQUAL("<properties>\n", outputFile->line(6));
STRCMP_EQUAL("<property name=\"key\" value=\"val\"/>\n", outputFile->line(7));
STRCMP_EQUAL("</properties>\n", outputFile->line(8));
STRCMP_EQUAL("</testcase>\n", outputFile->line(9));
}

TEST(JUnitOutputTest, TestCaseWithMultiplePropertiesInInsertionOrder)
{
testCaseRunner->start()
.withGroup("groupname").withTest("testname")
.withProperty("first", "one").withProperty("second", "two")
.end();

outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<property name=\"first\" value=\"one\"/>\n", outputFile->line(7));
STRCMP_EQUAL("<property name=\"second\" value=\"two\"/>\n", outputFile->line(8));
}

TEST(JUnitOutputTest, TestCaseWithNoPropertiesHasNoPropertiesBlock)
{
testCaseRunner->start()
.withGroup("groupname").withTest("testname")
.end();

outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<testcase classname=\"groupname\" name=\"testname\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
STRCMP_EQUAL("</testcase>\n", outputFile->line(6));
}

TEST(JUnitOutputTest, TestCasePropertyValuesAreXmlEncoded)
{
testCaseRunner->start()
.withGroup("groupname").withTest("testname")
.withProperty("a&b", "<val>")
.end();

outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<property name=\"a&amp;b\" value=\"&lt;val&gt;\"/>\n", outputFile->line(7));
}

TEST(JUnitOutputTest, PropertiesOnlyAppearOnCorrectTestInGroup)
{
testCaseRunner->start()
.withGroup("groupname")
.withTest("firstTest")
.withTest("secondTest").withProperty("k", "v")
.end();

outputFile = fileSystem.file("cpputest_groupname.xml");
// firstTest: lines 5-6 (no properties block)
STRCMP_EQUAL("<testcase classname=\"groupname\" name=\"firstTest\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
STRCMP_EQUAL("</testcase>\n", outputFile->line(6));
// secondTest: lines 7-11 (with properties)
STRCMP_EQUAL("<testcase classname=\"groupname\" name=\"secondTest\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(7));
STRCMP_EQUAL("<properties>\n", outputFile->line(8));
STRCMP_EQUAL("<property name=\"k\" value=\"v\"/>\n", outputFile->line(9));
STRCMP_EQUAL("</properties>\n", outputFile->line(10));
STRCMP_EQUAL("</testcase>\n", outputFile->line(11));
}

TEST(JUnitOutputTest, PropertiesDontLeakAcrossGroups)
{
testCaseRunner->start()
.withGroup("groupOne").withTest("testA").withProperty("x", "1")
.endGroupAndClearTest()
.withGroup("groupTwo").withTest("testB")
.end();

outputFile = fileSystem.file("cpputest_groupTwo.xml");
STRCMP_EQUAL("<testcase classname=\"groupTwo\" name=\"testB\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
STRCMP_EQUAL("</testcase>\n", outputFile->line(6));
}
Loading
Loading