Unit Testing framework based on http://cpputest.github.io/

CppUTest

Where to find more information

Getting test reports on the console

You may need to tailor the file src/Platforms/mbed/UtestPlatform.cpp to your needs. In particular, if you want console output, you might want to look at the function PlatformSpecificPutchar().

Quick introduction (some code!)

To write your first test, all you need is a new cpp file with a TEST_GROUP and a TEST, like:

#include "CppUTest/TestHarness.h"

TEST_GROUP(FirstTestGroup)
{
};

TEST(FirstTestGroup, FirstTest)
{
   FAIL("Fail me!");
}

This test will fail.

You can add new tests to the test group by just writing more tests in the file, like this:

TEST(FirstTestGroup, SecondTest)
{
   STRCMP_EQUAL("hello", "world");
   LONGS_EQUAL(1, 2);
   CHECK(false);
}

You do need to trigger the tests from somewhere in your program. It could look something like:

#include "CppUTest/TestRegistry.h"
#include "CppUTest/CommandLineTestRunner.h"

int main(int ac, char** av)
{
    ....
    unsigned failureCount = 0;
    {
        ConsoleTestOutput output;
        CommandLineTestRunner runner(ac, av, &output, TestRegistry::getCurrentRegistry());
        failureCount = runner.runAllTestsMain();
    }

    if (failureCount == 0) {
        console.printf("PASSED\r\n");
    }
    ...
}

For more information, We’d recommend to read the manual or, even better, check some existing tests such as SimpleStringTest or (a bit more complicated) MemoryLeakDetectorTest or the mocking tests or just check out the Cheat Sheet.

Committer:
rgrover1
Date:
Tue Jan 28 09:27:41 2014 +0000
Revision:
0:0b799af9d58e
Child:
1:4769360130ed
CppUTest unit test framework.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 0:0b799af9d58e 1 /*
rgrover1 0:0b799af9d58e 2 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
rgrover1 0:0b799af9d58e 3 * All rights reserved.
rgrover1 0:0b799af9d58e 4 *
rgrover1 0:0b799af9d58e 5 * Redistribution and use in source and binary forms, with or without
rgrover1 0:0b799af9d58e 6 * modification, are permitted provided that the following conditions are met:
rgrover1 0:0b799af9d58e 7 * * Redistributions of source code must retain the above copyright
rgrover1 0:0b799af9d58e 8 * notice, this list of conditions and the following disclaimer.
rgrover1 0:0b799af9d58e 9 * * Redistributions in binary form must reproduce the above copyright
rgrover1 0:0b799af9d58e 10 * notice, this list of conditions and the following disclaimer in the
rgrover1 0:0b799af9d58e 11 * documentation and/or other materials provided with the distribution.
rgrover1 0:0b799af9d58e 12 * * Neither the name of the <organization> nor the
rgrover1 0:0b799af9d58e 13 * names of its contributors may be used to endorse or promote products
rgrover1 0:0b799af9d58e 14 * derived from this software without specific prior written permission.
rgrover1 0:0b799af9d58e 15 *
rgrover1 0:0b799af9d58e 16 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
rgrover1 0:0b799af9d58e 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
rgrover1 0:0b799af9d58e 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
rgrover1 0:0b799af9d58e 19 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
rgrover1 0:0b799af9d58e 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
rgrover1 0:0b799af9d58e 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
rgrover1 0:0b799af9d58e 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
rgrover1 0:0b799af9d58e 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
rgrover1 0:0b799af9d58e 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
rgrover1 0:0b799af9d58e 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
rgrover1 0:0b799af9d58e 26 */
rgrover1 0:0b799af9d58e 27
rgrover1 0:0b799af9d58e 28 #include "CppUTest/TestHarness.h"
rgrover1 0:0b799af9d58e 29 #include "CppUTest/TestFailure.h"
rgrover1 0:0b799af9d58e 30 #include "CppUTest/TestOutput.h"
rgrover1 0:0b799af9d58e 31 #include "CppUTest/PlatformSpecificFunctions.h"
rgrover1 0:0b799af9d58e 32
rgrover1 0:0b799af9d58e 33 static SimpleString removeAllPrintableCharactersFrom(const SimpleString& str)
rgrover1 0:0b799af9d58e 34 {
rgrover1 0:0b799af9d58e 35 size_t bufferSize = str.size()+1;
rgrover1 0:0b799af9d58e 36 char* buffer = (char*) PlatformSpecificMalloc(bufferSize);
rgrover1 0:0b799af9d58e 37 str.copyToBuffer(buffer, bufferSize);
rgrover1 0:0b799af9d58e 38
rgrover1 0:0b799af9d58e 39 for (size_t i = 0; i < bufferSize-1; i++)
rgrover1 0:0b799af9d58e 40 if (buffer[i] != '\t' && buffer[i] != '\n')
rgrover1 0:0b799af9d58e 41 buffer[i] = ' ';
rgrover1 0:0b799af9d58e 42
rgrover1 0:0b799af9d58e 43 SimpleString result(buffer);
rgrover1 0:0b799af9d58e 44 PlatformSpecificFree(buffer);
rgrover1 0:0b799af9d58e 45 return result;
rgrover1 0:0b799af9d58e 46 }
rgrover1 0:0b799af9d58e 47
rgrover1 0:0b799af9d58e 48 static SimpleString addMarkerToString(const SimpleString& str, int markerPos)
rgrover1 0:0b799af9d58e 49 {
rgrover1 0:0b799af9d58e 50 size_t bufferSize = str.size()+1;
rgrover1 0:0b799af9d58e 51 char* buffer = (char*) PlatformSpecificMalloc(bufferSize);
rgrover1 0:0b799af9d58e 52 str.copyToBuffer(buffer, bufferSize);
rgrover1 0:0b799af9d58e 53
rgrover1 0:0b799af9d58e 54 buffer[markerPos] = '^';
rgrover1 0:0b799af9d58e 55
rgrover1 0:0b799af9d58e 56 SimpleString result(buffer);
rgrover1 0:0b799af9d58e 57 PlatformSpecificFree(buffer);
rgrover1 0:0b799af9d58e 58 return result;
rgrover1 0:0b799af9d58e 59
rgrover1 0:0b799af9d58e 60 }
rgrover1 0:0b799af9d58e 61
rgrover1 0:0b799af9d58e 62 TestFailure::TestFailure(UtestShell* test, const char* fileName, int lineNumber, const SimpleString& theMessage) :
rgrover1 0:0b799af9d58e 63 testName_(test->getFormattedName()), fileName_(fileName), lineNumber_(lineNumber), testFileName_(test->getFile()), testLineNumber_(test->getLineNumber()), message_(theMessage)
rgrover1 0:0b799af9d58e 64 {
rgrover1 0:0b799af9d58e 65 }
rgrover1 0:0b799af9d58e 66
rgrover1 0:0b799af9d58e 67 TestFailure::TestFailure(UtestShell* test, const SimpleString& theMessage) :
rgrover1 0:0b799af9d58e 68 testName_(test->getFormattedName()), fileName_(test->getFile()), lineNumber_(test->getLineNumber()), testFileName_(test->getFile()), testLineNumber_(test->getLineNumber()), message_(theMessage)
rgrover1 0:0b799af9d58e 69 {
rgrover1 0:0b799af9d58e 70 }
rgrover1 0:0b799af9d58e 71
rgrover1 0:0b799af9d58e 72 TestFailure::TestFailure(UtestShell* test, const char* fileName, int lineNum) :
rgrover1 0:0b799af9d58e 73 testName_(test->getFormattedName()), fileName_(fileName), lineNumber_(lineNum), testFileName_(test->getFile()), testLineNumber_(test->getLineNumber()), message_("no message")
rgrover1 0:0b799af9d58e 74 {
rgrover1 0:0b799af9d58e 75 }
rgrover1 0:0b799af9d58e 76
rgrover1 0:0b799af9d58e 77 TestFailure::TestFailure(const TestFailure& f) :
rgrover1 0:0b799af9d58e 78 testName_(f.testName_), fileName_(f.fileName_), lineNumber_(f.lineNumber_), testFileName_(f.testFileName_), testLineNumber_(f.testLineNumber_), message_(f.message_)
rgrover1 0:0b799af9d58e 79 {
rgrover1 0:0b799af9d58e 80 }
rgrover1 0:0b799af9d58e 81
rgrover1 0:0b799af9d58e 82
rgrover1 0:0b799af9d58e 83 TestFailure::~TestFailure()
rgrover1 0:0b799af9d58e 84 {
rgrover1 0:0b799af9d58e 85 }
rgrover1 0:0b799af9d58e 86
rgrover1 0:0b799af9d58e 87 SimpleString TestFailure::getFileName() const
rgrover1 0:0b799af9d58e 88 {
rgrover1 0:0b799af9d58e 89 return fileName_;
rgrover1 0:0b799af9d58e 90 }
rgrover1 0:0b799af9d58e 91
rgrover1 0:0b799af9d58e 92 SimpleString TestFailure::getTestFileName() const
rgrover1 0:0b799af9d58e 93 {
rgrover1 0:0b799af9d58e 94 return testFileName_;
rgrover1 0:0b799af9d58e 95 }
rgrover1 0:0b799af9d58e 96
rgrover1 0:0b799af9d58e 97 SimpleString TestFailure::getTestName() const
rgrover1 0:0b799af9d58e 98 {
rgrover1 0:0b799af9d58e 99 return testName_;
rgrover1 0:0b799af9d58e 100 }
rgrover1 0:0b799af9d58e 101
rgrover1 0:0b799af9d58e 102 int TestFailure::getFailureLineNumber() const
rgrover1 0:0b799af9d58e 103 {
rgrover1 0:0b799af9d58e 104 return lineNumber_;
rgrover1 0:0b799af9d58e 105 }
rgrover1 0:0b799af9d58e 106
rgrover1 0:0b799af9d58e 107 int TestFailure::getTestLineNumber() const
rgrover1 0:0b799af9d58e 108 {
rgrover1 0:0b799af9d58e 109 return testLineNumber_;
rgrover1 0:0b799af9d58e 110 }
rgrover1 0:0b799af9d58e 111
rgrover1 0:0b799af9d58e 112 SimpleString TestFailure::getMessage() const
rgrover1 0:0b799af9d58e 113 {
rgrover1 0:0b799af9d58e 114 return message_;
rgrover1 0:0b799af9d58e 115 }
rgrover1 0:0b799af9d58e 116
rgrover1 0:0b799af9d58e 117 bool TestFailure::isOutsideTestFile() const
rgrover1 0:0b799af9d58e 118 {
rgrover1 0:0b799af9d58e 119 return testFileName_ != fileName_;
rgrover1 0:0b799af9d58e 120 }
rgrover1 0:0b799af9d58e 121
rgrover1 0:0b799af9d58e 122 bool TestFailure::isInHelperFunction() const
rgrover1 0:0b799af9d58e 123 {
rgrover1 0:0b799af9d58e 124 return lineNumber_ < testLineNumber_;
rgrover1 0:0b799af9d58e 125 }
rgrover1 0:0b799af9d58e 126
rgrover1 0:0b799af9d58e 127 SimpleString TestFailure::createButWasString(const SimpleString& expected, const SimpleString& actual)
rgrover1 0:0b799af9d58e 128 {
rgrover1 0:0b799af9d58e 129 return StringFromFormat("expected <%s>\n\tbut was <%s>", expected.asCharString(), actual.asCharString());
rgrover1 0:0b799af9d58e 130 }
rgrover1 0:0b799af9d58e 131
rgrover1 0:0b799af9d58e 132 SimpleString TestFailure::createDifferenceAtPosString(const SimpleString& actual, size_t position)
rgrover1 0:0b799af9d58e 133 {
rgrover1 0:0b799af9d58e 134 SimpleString result;
rgrover1 0:0b799af9d58e 135 const size_t extraCharactersWindow = 20;
rgrover1 0:0b799af9d58e 136 const size_t halfOfExtraCharactersWindow = extraCharactersWindow / 2;
rgrover1 0:0b799af9d58e 137
rgrover1 0:0b799af9d58e 138 SimpleString paddingForPreventingOutOfBounds (" ", halfOfExtraCharactersWindow);
rgrover1 0:0b799af9d58e 139 SimpleString actualString = paddingForPreventingOutOfBounds + actual + paddingForPreventingOutOfBounds;
rgrover1 0:0b799af9d58e 140 SimpleString differentString = StringFromFormat("difference starts at position %lu at: <", (unsigned long) position);
rgrover1 0:0b799af9d58e 141
rgrover1 0:0b799af9d58e 142 result += "\n";
rgrover1 0:0b799af9d58e 143 result += StringFromFormat("\t%s%s>\n", differentString.asCharString(), actualString.subString(position, extraCharactersWindow).asCharString());
rgrover1 0:0b799af9d58e 144
rgrover1 0:0b799af9d58e 145 SimpleString markString = actualString.subString(position, halfOfExtraCharactersWindow+1);
rgrover1 0:0b799af9d58e 146 markString = removeAllPrintableCharactersFrom(markString);
rgrover1 0:0b799af9d58e 147 markString = addMarkerToString(markString, halfOfExtraCharactersWindow);
rgrover1 0:0b799af9d58e 148
rgrover1 0:0b799af9d58e 149 result += StringFromFormat("\t%s%s", SimpleString(" ", differentString.size()).asCharString(), markString.asCharString());
rgrover1 0:0b799af9d58e 150 return result;
rgrover1 0:0b799af9d58e 151 }
rgrover1 0:0b799af9d58e 152
rgrover1 0:0b799af9d58e 153 EqualsFailure::EqualsFailure(UtestShell* test, const char* fileName, int lineNumber, const char* expected, const char* actual) :
rgrover1 0:0b799af9d58e 154 TestFailure(test, fileName, lineNumber)
rgrover1 0:0b799af9d58e 155 {
rgrover1 0:0b799af9d58e 156 message_ = createButWasString(StringFromOrNull(expected), StringFromOrNull(actual));
rgrover1 0:0b799af9d58e 157 }
rgrover1 0:0b799af9d58e 158
rgrover1 0:0b799af9d58e 159 EqualsFailure::EqualsFailure(UtestShell* test, const char* fileName, int lineNumber, const SimpleString& expected, const SimpleString& actual)
rgrover1 0:0b799af9d58e 160 : TestFailure(test, fileName, lineNumber)
rgrover1 0:0b799af9d58e 161 {
rgrover1 0:0b799af9d58e 162 message_ = createButWasString(expected, actual);
rgrover1 0:0b799af9d58e 163 }
rgrover1 0:0b799af9d58e 164
rgrover1 0:0b799af9d58e 165 static SimpleString StringFromOrNan(double d)
rgrover1 0:0b799af9d58e 166 {
rgrover1 0:0b799af9d58e 167 if (PlatformSpecificIsNan(d))
rgrover1 0:0b799af9d58e 168 return "Nan - Not a number";
rgrover1 0:0b799af9d58e 169 return StringFrom(d);
rgrover1 0:0b799af9d58e 170 }
rgrover1 0:0b799af9d58e 171
rgrover1 0:0b799af9d58e 172 DoublesEqualFailure::DoublesEqualFailure(UtestShell* test, const char* fileName, int lineNumber, double expected, double actual, double threshold) : TestFailure(test, fileName, lineNumber)
rgrover1 0:0b799af9d58e 173 {
rgrover1 0:0b799af9d58e 174 message_ = createButWasString(StringFromOrNan(expected), StringFromOrNan(actual));
rgrover1 0:0b799af9d58e 175 message_ += " threshold used was <";
rgrover1 0:0b799af9d58e 176 message_ += StringFromOrNan(threshold);
rgrover1 0:0b799af9d58e 177 message_ += ">";
rgrover1 0:0b799af9d58e 178
rgrover1 0:0b799af9d58e 179 if (PlatformSpecificIsNan(expected) || PlatformSpecificIsNan(actual) || PlatformSpecificIsNan(threshold))
rgrover1 0:0b799af9d58e 180 message_ += "\n\tCannot make comparisons with Nan";
rgrover1 0:0b799af9d58e 181 }
rgrover1 0:0b799af9d58e 182
rgrover1 0:0b799af9d58e 183 CheckEqualFailure::CheckEqualFailure(UtestShell* test, const char* fileName, int lineNumber, const SimpleString& expected, const SimpleString& actual) : TestFailure(test, fileName, lineNumber)
rgrover1 0:0b799af9d58e 184 {
rgrover1 0:0b799af9d58e 185 size_t failStart;
rgrover1 0:0b799af9d58e 186 for (failStart = 0; actual.asCharString()[failStart] == expected.asCharString()[failStart]; failStart++)
rgrover1 0:0b799af9d58e 187 ;
rgrover1 0:0b799af9d58e 188 message_ = createButWasString(expected, actual);
rgrover1 0:0b799af9d58e 189 message_ += createDifferenceAtPosString(actual, failStart);
rgrover1 0:0b799af9d58e 190
rgrover1 0:0b799af9d58e 191 }
rgrover1 0:0b799af9d58e 192
rgrover1 0:0b799af9d58e 193 ContainsFailure::ContainsFailure(UtestShell* test, const char* fileName, int lineNumber, const SimpleString& expected, const SimpleString& actual) :
rgrover1 0:0b799af9d58e 194 TestFailure(test, fileName, lineNumber)
rgrover1 0:0b799af9d58e 195 {
rgrover1 0:0b799af9d58e 196 message_ = StringFromFormat("actual <%s>\n\tdid not contain <%s>", actual.asCharString(), expected.asCharString());
rgrover1 0:0b799af9d58e 197 }
rgrover1 0:0b799af9d58e 198
rgrover1 0:0b799af9d58e 199 CheckFailure::CheckFailure(UtestShell* test, const char* fileName, int lineNumber, const SimpleString& checkString, const SimpleString& conditionString, const SimpleString& text) : TestFailure(test, fileName, lineNumber)
rgrover1 0:0b799af9d58e 200 {
rgrover1 0:0b799af9d58e 201 message_ = "";
rgrover1 0:0b799af9d58e 202 if (!text.isEmpty()) {
rgrover1 0:0b799af9d58e 203 message_ += "Message: ";
rgrover1 0:0b799af9d58e 204 message_ += text;
rgrover1 0:0b799af9d58e 205 message_ += "\n\t";
rgrover1 0:0b799af9d58e 206 }
rgrover1 0:0b799af9d58e 207 message_ += checkString;
rgrover1 0:0b799af9d58e 208 message_ += "(";
rgrover1 0:0b799af9d58e 209 message_ += conditionString;
rgrover1 0:0b799af9d58e 210 message_ += ") failed";
rgrover1 0:0b799af9d58e 211 }
rgrover1 0:0b799af9d58e 212
rgrover1 0:0b799af9d58e 213 FailFailure::FailFailure(UtestShell* test, const char* fileName, int lineNumber, const SimpleString& message) : TestFailure(test, fileName, lineNumber)
rgrover1 0:0b799af9d58e 214 {
rgrover1 0:0b799af9d58e 215 message_ = message;
rgrover1 0:0b799af9d58e 216 }
rgrover1 0:0b799af9d58e 217
rgrover1 0:0b799af9d58e 218 LongsEqualFailure::LongsEqualFailure(UtestShell* test, const char* fileName, int lineNumber, long expected, long actual) : TestFailure(test, fileName, lineNumber)
rgrover1 0:0b799af9d58e 219 {
rgrover1 0:0b799af9d58e 220 SimpleString aDecimal = StringFrom(actual);
rgrover1 0:0b799af9d58e 221 SimpleString aHex = HexStringFrom(actual);
rgrover1 0:0b799af9d58e 222 SimpleString eDecimal = StringFrom(expected);
rgrover1 0:0b799af9d58e 223 SimpleString eHex = HexStringFrom(expected);
rgrover1 0:0b799af9d58e 224
rgrover1 0:0b799af9d58e 225 SimpleString::padStringsToSameLength(aDecimal, eDecimal, ' ');
rgrover1 0:0b799af9d58e 226 SimpleString::padStringsToSameLength(aHex, eHex, '0');
rgrover1 0:0b799af9d58e 227
rgrover1 0:0b799af9d58e 228 SimpleString actualReported = aDecimal + " 0x" + aHex;
rgrover1 0:0b799af9d58e 229 SimpleString expectedReported = eDecimal + " 0x" + eHex;
rgrover1 0:0b799af9d58e 230 message_ = createButWasString(expectedReported, actualReported);
rgrover1 0:0b799af9d58e 231 }
rgrover1 0:0b799af9d58e 232
rgrover1 0:0b799af9d58e 233
rgrover1 0:0b799af9d58e 234 StringEqualFailure::StringEqualFailure(UtestShell* test, const char* fileName, int lineNumber, const char* expected, const char* actual) : TestFailure(test, fileName, lineNumber)
rgrover1 0:0b799af9d58e 235 {
rgrover1 0:0b799af9d58e 236 size_t failStart;
rgrover1 0:0b799af9d58e 237 for (failStart = 0; actual[failStart] == expected[failStart]; failStart++)
rgrover1 0:0b799af9d58e 238 ;
rgrover1 0:0b799af9d58e 239 message_ = createButWasString(expected, actual);
rgrover1 0:0b799af9d58e 240 message_ += createDifferenceAtPosString(actual, failStart);
rgrover1 0:0b799af9d58e 241 }
rgrover1 0:0b799af9d58e 242
rgrover1 0:0b799af9d58e 243 StringEqualNoCaseFailure::StringEqualNoCaseFailure(UtestShell* test, const char* fileName, int lineNumber, const char* expected, const char* actual) : TestFailure(test, fileName, lineNumber)
rgrover1 0:0b799af9d58e 244 {
rgrover1 0:0b799af9d58e 245 size_t failStart;
rgrover1 0:0b799af9d58e 246 for (failStart = 0; PlatformSpecificToLower(actual[failStart]) == PlatformSpecificToLower(expected[failStart]); failStart++)
rgrover1 0:0b799af9d58e 247 ;
rgrover1 0:0b799af9d58e 248 message_ = createButWasString(expected, actual);
rgrover1 0:0b799af9d58e 249 message_ += createDifferenceAtPosString(actual, failStart);
rgrover1 0:0b799af9d58e 250 }
rgrover1 0:0b799af9d58e 251
rgrover1 0:0b799af9d58e 252