git subrepo clone git@github.com:compihu/platform-test-f4-ll.git platforms/platform-test-f4-ll

subrepo:
  subdir:   "platforms/platform-test-f4-ll"
  merged:   "bc41134"
upstream:
  origin:   "git@github.com:compihu/platform-test-f4-ll.git"
  branch:   "master"
  commit:   "bc41134"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "87ee373"
This commit is contained in:
Attila Body 2021-02-24 21:46:35 +01:00
parent 46ce55c6a0
commit 95af4ce0d8
460 changed files with 84105 additions and 0 deletions

View file

@ -0,0 +1,24 @@
It is possible to integrate CppUTest as a sub-module of an enclosing CMake
project. This may be useful if CppUTest is being built for a target platform
other than that of the development host. The following is an example how an
external project can refer to this CMakeLists.txt to build CppUTest as a
library and include it as a target dependency.
```cmake
cmake_minimum_required(VERSION 3.7)
project(trying_CppUtest)
SET(CppUTestRootDirectory /path/to/cpputest)
# Either set CPP_PLATFORM to one of the provided platforms under
# ${CppUTestRootDirectory}/src/Platforms/, or provide a project-specific
# platform.cpp (as shown below)
add_subdirectory(${CppUTestRootDirectory}/src/CppUTest CppUTest)
target_sources(CppUTest
PRIVATE
${PROJECT_SOURCE_DIR}/UtestPlatform.cpp
)
add_executable(trying_CppUtest main.cpp)
target_link_libraries(trying_CppUtest CppUTest)
```

View file

@ -0,0 +1,79 @@
add_library(CppUTest
CommandLineArguments.cpp
MemoryLeakWarningPlugin.cpp
TestHarness_c.cpp
TestRegistry.cpp
CommandLineTestRunner.cpp
SimpleString.cpp
SimpleStringInternalCache.cpp
TestMemoryAllocator.cpp
TestResult.cpp
JUnitTestOutput.cpp
TeamCityTestOutput.cpp
TestFailure.cpp
TestOutput.cpp
MemoryLeakDetector.cpp
TestFilter.cpp
TestPlugin.cpp
TestTestingFixture.cpp
SimpleMutex.cpp
Utest.cpp
)
#[[Set CPP_PLATFORM in a parent CMakeLists.txt if reusing one of the provided platforms, else supply the missing definitions]]
if (CPP_PLATFORM)
target_sources(CppUTest
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/../Platforms/${CPP_PLATFORM}/UtestPlatform.cpp
)
endif(CPP_PLATFORM)
#[[Arrange for the include directory to be added to the include paths of any CMake target depending on CppUTest.]]
target_include_directories(CppUTest
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../include>
$<INSTALL_INTERFACE:include>
)
set(CppUTest_headers
${CppUTestRootDirectory}/include/CppUTest/CommandLineArguments.h
${CppUTestRootDirectory}/include/CppUTest/PlatformSpecificFunctions.h
${CppUTestRootDirectory}/include/CppUTest/TestMemoryAllocator.h
${CppUTestRootDirectory}/include/CppUTest/CommandLineTestRunner.h
${CppUTestRootDirectory}/include/CppUTest/PlatformSpecificFunctions_c.h
${CppUTestRootDirectory}/include/CppUTest/TestOutput.h
${CppUTestRootDirectory}/include/CppUTest/CppUTestConfig.h
${CppUTestRootDirectory}/include/CppUTest/SimpleString.h
${CppUTestRootDirectory}/include/CppUTest/SimpleStringInternalCache.h
${CppUTestRootDirectory}/include/CppUTest/TestPlugin.h
${CppUTestRootDirectory}/include/CppUTest/JUnitTestOutput.h
${CppUTestRootDirectory}/include/CppUTest/TeamCityTestOutput.h
${CppUTestRootDirectory}/include/CppUTest/StandardCLibrary.h
${CppUTestRootDirectory}/include/CppUTest/TestRegistry.h
${CppUTestRootDirectory}/include/CppUTest/MemoryLeakDetector.h
${CppUTestRootDirectory}/include/CppUTest/TestFailure.h
${CppUTestRootDirectory}/include/CppUTest/TestResult.h
${CppUTestRootDirectory}/include/CppUTest/MemoryLeakDetectorMallocMacros.h
${CppUTestRootDirectory}/include/CppUTest/TestFilter.h
${CppUTestRootDirectory}/include/CppUTest/TestTestingFixture.h
${CppUTestRootDirectory}/include/CppUTest/MemoryLeakDetectorNewMacros.h
${CppUTestRootDirectory}/include/CppUTest/TestHarness.h
${CppUTestRootDirectory}/include/CppUTest/Utest.h
${CppUTestRootDirectory}/include/CppUTest/MemoryLeakWarningPlugin.h
${CppUTestRootDirectory}/include/CppUTest/TestHarness_c.h
${CppUTestRootDirectory}/include/CppUTest/UtestMacros.h
${CppUTestRootDirectory}/include/CppUTest/SimpleMutex.h
)
set_target_properties(CppUTest PROPERTIES
PUBLIC_HEADER "${CppUTest_headers}")
if (WIN32)
target_link_libraries(CppUTest winmm.lib)
endif (WIN32)
install(TARGETS CppUTest
EXPORT CppUTestTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/CppUTest"
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/CppUTest")

View file

@ -0,0 +1,396 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/CommandLineArguments.h"
#include "CppUTest/PlatformSpecificFunctions.h"
CommandLineArguments::CommandLineArguments(int ac, const char *const *av) :
ac_(ac), av_(av), needHelp_(false), verbose_(false), veryVerbose_(false), color_(false), runTestsAsSeperateProcess_(false), listTestGroupNames_(false), listTestGroupAndCaseNames_(false), runIgnored_(false), reversing_(false), crashOnFail_(false), shuffling_(false), shufflingPreSeeded_(false), repeat_(1), shuffleSeed_(0), groupFilters_(NULLPTR), nameFilters_(NULLPTR), outputType_(OUTPUT_ECLIPSE)
{
}
CommandLineArguments::~CommandLineArguments()
{
while(groupFilters_) {
TestFilter* current = groupFilters_;
groupFilters_ = groupFilters_->getNext();
delete current;
}
while(nameFilters_) {
TestFilter* current = nameFilters_;
nameFilters_ = nameFilters_->getNext();
delete current;
}
}
bool CommandLineArguments::parse(TestPlugin* plugin)
{
bool correctParameters = true;
for (int i = 1; i < ac_; i++) {
SimpleString argument = av_[i];
if (argument == "-h") {
needHelp_ = true;
correctParameters = false;
}
else if (argument == "-v") verbose_ = true;
else if (argument == "-vv") veryVerbose_ = true;
else if (argument == "-c") color_ = true;
else if (argument == "-p") runTestsAsSeperateProcess_ = true;
else if (argument == "-b") reversing_ = true;
else if (argument == "-lg") listTestGroupNames_ = true;
else if (argument == "-ln") listTestGroupAndCaseNames_ = true;
else if (argument == "-ri") runIgnored_ = true;
else if (argument == "-f") crashOnFail_ = true;
else if (argument.startsWith("-r")) setRepeatCount(ac_, av_, i);
else if (argument.startsWith("-g")) addGroupFilter(ac_, av_, i);
else if (argument.startsWith("-t")) correctParameters = addGroupDotNameFilter(ac_, av_, i);
else if (argument.startsWith("-sg")) addStrictGroupFilter(ac_, av_, i);
else if (argument.startsWith("-xg")) addExcludeGroupFilter(ac_, av_, i);
else if (argument.startsWith("-xsg")) addExcludeStrictGroupFilter(ac_, av_, i);
else if (argument.startsWith("-n")) addNameFilter(ac_, av_, i);
else if (argument.startsWith("-sn")) addStrictNameFilter(ac_, av_, i);
else if (argument.startsWith("-xn")) addExcludeNameFilter(ac_, av_, i);
else if (argument.startsWith("-xsn")) addExcludeStrictNameFilter(ac_, av_, i);
else if (argument.startsWith("-s")) correctParameters = setShuffle(ac_, av_, i);
else if (argument.startsWith("TEST(")) addTestToRunBasedOnVerboseOutput(ac_, av_, i, "TEST(");
else if (argument.startsWith("IGNORE_TEST(")) addTestToRunBasedOnVerboseOutput(ac_, av_, i, "IGNORE_TEST(");
else if (argument.startsWith("-o")) correctParameters = setOutputType(ac_, av_, i);
else if (argument.startsWith("-p")) correctParameters = plugin->parseAllArguments(ac_, av_, i);
else if (argument.startsWith("-k")) setPackageName(ac_, av_, i);
else correctParameters = false;
if (correctParameters == false) {
return false;
}
}
return true;
}
const char* CommandLineArguments::usage() const
{
return "use -h for more extensive help\n"
"usage [-h] [-v] [-vv] [-c] [-p] [-lg] [-ln] [-ri] [-r#] [-f]\n"
" [-g|sg|xg|xsg groupName]... [-n|sn|xn|xsn testName]... [-t groupName.testName]...\n"
" [-b] [-s [randomizerSeed>0]] [\"TEST(groupName, testName)\"]...\n"
" [-o{normal, junit, teamcity}] [-k packageName]\n";
}
const char* CommandLineArguments::help() const
{
return
"Thanks for using CppUTest.\n"
"\n"
"Options that do not run tests but query:\n"
" -h - this wonderful help screen. Joy!\n"
" -lg - print a list of group names, separated by spaces\n"
" -ln - print a list of test names in the form of group.name, separated by spaces\n"
"\n"
"Options that change the output format:\n"
" -c - colorize output, print green if OK, or red if failed\n"
" -v - verbose, print each test name as it runs\n"
" -vv - very verbose, print internal information during test run\n"
"\n"
"Options that change the output location:\n"
" -oteamcity - output to xml files (as the name suggests, for TeamCity)\n"
" -ojunit - output to JUnit ant plugin style xml files (for CI systems)\n"
" -k package name - Add a package name in JUnit output (for classification in CI systems)\n"
"\n"
"\n"
"Options that control which tests are run:\n"
" -g group - only run test whose group contains the substring group\n"
" -n name - only run test whose name contains the substring name\n"
" -t group.name - only run test whose name contains the substring group and name\n"
" -sg group - only run test whose group exactly matches the string group\n"
" -sn name - only run test whose name exactly matches the string name\n"
" -xg group - exclude tests whose group contains the substring group (v3.8)\n"
" -xn name - exclude tests whose name contains the substring name (v3.8)\n"
" TEST(group,name) - only run test whose group and name matches the strings group and name.\n"
" This can be used to copy-paste output from the -v option on the command line.\n"
"\n"
"Options that control how the tests are run:\n"
" -p - run tests in a separate process.\n"
" -b - run the tests backwards, reversing the normal way\n"
" -s [seed] - shuffle tests randomly. Seed is optional\n"
" -r# - repeat the tests some number (#) of times, or twice if # is not specified.\n"
" -f - Cause the tests to crash on failure (to allow the test to be debugged if necessary)\n";
}
bool CommandLineArguments::needHelp() const
{
return needHelp_;
}
bool CommandLineArguments::isVerbose() const
{
return verbose_;
}
bool CommandLineArguments::isVeryVerbose() const
{
return veryVerbose_;
}
bool CommandLineArguments::isColor() const
{
return color_;
}
bool CommandLineArguments::isListingTestGroupNames() const
{
return listTestGroupNames_;
}
bool CommandLineArguments::isListingTestGroupAndCaseNames() const
{
return listTestGroupAndCaseNames_;
}
bool CommandLineArguments::isRunIgnored() const
{
return runIgnored_;
}
bool CommandLineArguments::runTestsInSeperateProcess() const
{
return runTestsAsSeperateProcess_;
}
size_t CommandLineArguments::getRepeatCount() const
{
return repeat_;
}
bool CommandLineArguments::isReversing() const
{
return reversing_;
}
bool CommandLineArguments::isCrashingOnFail() const
{
return crashOnFail_;
}
bool CommandLineArguments::isShuffling() const
{
return shuffling_;
}
size_t CommandLineArguments::getShuffleSeed() const
{
return shuffleSeed_;
}
const TestFilter* CommandLineArguments::getGroupFilters() const
{
return groupFilters_;
}
const TestFilter* CommandLineArguments::getNameFilters() const
{
return nameFilters_;
}
void CommandLineArguments::setRepeatCount(int ac, const char *const *av, int& i)
{
repeat_ = 0;
SimpleString repeatParameter(av[i]);
if (repeatParameter.size() > 2) repeat_ = (size_t) (SimpleString::AtoI(av[i] + 2));
else if (i + 1 < ac) {
repeat_ = (size_t) (SimpleString::AtoI(av[i + 1]));
if (repeat_ != 0) i++;
}
if (0 == repeat_) repeat_ = 2;
}
bool CommandLineArguments::setShuffle(int ac, const char * const *av, int& i)
{
shuffling_ = true;
shuffleSeed_ = (unsigned int)GetPlatformSpecificTimeInMillis();
if (shuffleSeed_ == 0) shuffleSeed_++;
SimpleString shuffleParameter = av[i];
if (shuffleParameter.size() > 2) {
shufflingPreSeeded_ = true;
shuffleSeed_ = SimpleString::AtoU(av[i] + 2);
} else if (i + 1 < ac) {
unsigned int parsedParameter = SimpleString::AtoU(av[i + 1]);
if (parsedParameter != 0)
{
shufflingPreSeeded_ = true;
shuffleSeed_ = parsedParameter;
i++;
}
}
return (shuffleSeed_ != 0);
}
SimpleString CommandLineArguments::getParameterField(int ac, const char * const *av, int& i, const SimpleString& parameterName)
{
size_t parameterLength = parameterName.size();
SimpleString parameter(av[i]);
if (parameter.size() > parameterLength) return av[i] + parameterLength;
else if (i + 1 < ac) return av[++i];
return "";
}
void CommandLineArguments::addGroupFilter(int ac, const char *const *av, int& i)
{
TestFilter* groupFilter = new TestFilter(getParameterField(ac, av, i, "-g"));
groupFilters_ = groupFilter->add(groupFilters_);
}
bool CommandLineArguments::addGroupDotNameFilter(int ac, const char *const *av, int& i)
{
SimpleString groupDotName = getParameterField(ac, av, i, "-t");
SimpleStringCollection collection;
groupDotName.split(".", collection);
if (collection.size() != 2) return false;
groupFilters_ = (new TestFilter(collection[0].subString(0, collection[0].size()-1)))->add(groupFilters_);
nameFilters_ = (new TestFilter(collection[1]))->add(nameFilters_);
return true;
}
void CommandLineArguments::addStrictGroupFilter(int ac, const char *const *av, int& i)
{
TestFilter* groupFilter = new TestFilter(getParameterField(ac, av, i, "-sg"));
groupFilter->strictMatching();
groupFilters_ = groupFilter->add(groupFilters_);
}
void CommandLineArguments::addExcludeGroupFilter(int ac, const char *const *av, int& i)
{
TestFilter* groupFilter = new TestFilter(getParameterField(ac, av, i, "-xg"));
groupFilter->invertMatching();
groupFilters_ = groupFilter->add(groupFilters_);
}
void CommandLineArguments::addExcludeStrictGroupFilter(int ac, const char *const *av, int& i)
{
TestFilter* groupFilter = new TestFilter(getParameterField(ac, av, i, "-xsg"));
groupFilter->strictMatching();
groupFilter->invertMatching();
groupFilters_ = groupFilter->add(groupFilters_);
}
void CommandLineArguments::addNameFilter(int ac, const char *const *av, int& i)
{
TestFilter* nameFilter = new TestFilter(getParameterField(ac, av, i, "-n"));
nameFilters_ = nameFilter->add(nameFilters_);
}
void CommandLineArguments::addStrictNameFilter(int ac, const char *const *av, int& index)
{
TestFilter* nameFilter = new TestFilter(getParameterField(ac, av, index, "-sn"));
nameFilter->strictMatching();
nameFilters_= nameFilter->add(nameFilters_);
}
void CommandLineArguments::addExcludeNameFilter(int ac, const char *const *av, int& index)
{
TestFilter* nameFilter = new TestFilter(getParameterField(ac, av, index, "-xn"));
nameFilter->invertMatching();
nameFilters_= nameFilter->add(nameFilters_);
}
void CommandLineArguments::addExcludeStrictNameFilter(int ac, const char *const *av, int& index)
{
TestFilter* nameFilter = new TestFilter(getParameterField(ac, av, index, "-xsn"));
nameFilter->invertMatching();
nameFilter->strictMatching();
nameFilters_= nameFilter->add(nameFilters_);
}
void CommandLineArguments::addTestToRunBasedOnVerboseOutput(int ac, const char *const *av, int& index, const char* parameterName)
{
SimpleString wholename = getParameterField(ac, av, index, parameterName);
SimpleString testname = wholename.subStringFromTill(',', ')');
testname = testname.subString(2);
TestFilter* namefilter = new TestFilter(testname);
TestFilter* groupfilter = new TestFilter(wholename.subStringFromTill(wholename.at(0), ','));
namefilter->strictMatching();
groupfilter->strictMatching();
groupFilters_ = groupfilter->add(groupFilters_);
nameFilters_ = namefilter->add(nameFilters_);
}
void CommandLineArguments::setPackageName(int ac, const char *const *av, int& i)
{
SimpleString packageName = getParameterField(ac, av, i, "-k");
if (packageName.size() == 0) return;
packageName_ = packageName;
}
bool CommandLineArguments::setOutputType(int ac, const char *const *av, int& i)
{
SimpleString outputType = getParameterField(ac, av, i, "-o");
if (outputType.size() == 0) return false;
if (outputType == "normal" || outputType == "eclipse") {
outputType_ = OUTPUT_ECLIPSE;
return true;
}
if (outputType == "junit") {
outputType_ = OUTPUT_JUNIT;
return true;
}
if (outputType == "teamcity") {
outputType_ = OUTPUT_TEAMCITY;
return true;
}
return false;
}
bool CommandLineArguments::isEclipseOutput() const
{
return outputType_ == OUTPUT_ECLIPSE;
}
bool CommandLineArguments::isJUnitOutput() const
{
return outputType_ == OUTPUT_JUNIT;
}
bool CommandLineArguments::isTeamCityOutput() const
{
return outputType_ == OUTPUT_TEAMCITY;
}
const SimpleString& CommandLineArguments::getPackageName() const
{
return packageName_;
}

View file

@ -0,0 +1,193 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/CommandLineTestRunner.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/JUnitTestOutput.h"
#include "CppUTest/PlatformSpecificFunctions.h"
#include "CppUTest/TeamCityTestOutput.h"
#include "CppUTest/TestRegistry.h"
int CommandLineTestRunner::RunAllTests(int ac, char** av)
{
return RunAllTests(ac, (const char *const *) av);
}
int CommandLineTestRunner::RunAllTests(int ac, const char *const *av)
{
int result = 0;
ConsoleTestOutput backupOutput;
MemoryLeakWarningPlugin memLeakWarn(DEF_PLUGIN_MEM_LEAK);
memLeakWarn.destroyGlobalDetectorAndTurnOffMemoryLeakDetectionInDestructor(true);
TestRegistry::getCurrentRegistry()->installPlugin(&memLeakWarn);
{
CommandLineTestRunner runner(ac, av, TestRegistry::getCurrentRegistry());
result = runner.runAllTestsMain();
}
if (result == 0) {
backupOutput << memLeakWarn.FinalReport(0);
}
TestRegistry::getCurrentRegistry()->removePluginByName(DEF_PLUGIN_MEM_LEAK);
return result;
}
CommandLineTestRunner::CommandLineTestRunner(int ac, const char *const *av, TestRegistry* registry) :
output_(NULLPTR), arguments_(NULLPTR), registry_(registry)
{
arguments_ = new CommandLineArguments(ac, av);
}
CommandLineTestRunner::~CommandLineTestRunner()
{
delete arguments_;
delete output_;
}
int CommandLineTestRunner::runAllTestsMain()
{
int testResult = 1;
SetPointerPlugin pPlugin(DEF_PLUGIN_SET_POINTER);
registry_->installPlugin(&pPlugin);
if (parseArguments(registry_->getFirstPlugin()))
testResult = runAllTests();
registry_->removePluginByName(DEF_PLUGIN_SET_POINTER);
return testResult;
}
void CommandLineTestRunner::initializeTestRun()
{
registry_->setGroupFilters(arguments_->getGroupFilters());
registry_->setNameFilters(arguments_->getNameFilters());
if (arguments_->isVerbose()) output_->verbose(TestOutput::level_verbose);
if (arguments_->isVeryVerbose()) output_->verbose(TestOutput::level_veryVerbose);
if (arguments_->isColor()) output_->color();
if (arguments_->runTestsInSeperateProcess()) registry_->setRunTestsInSeperateProcess();
if (arguments_->isRunIgnored()) registry_->setRunIgnored();
if (arguments_->isCrashingOnFail()) UtestShell::setCrashOnFail();
}
int CommandLineTestRunner::runAllTests()
{
initializeTestRun();
size_t loopCount = 0;
size_t failedTestCount = 0;
size_t failedExecutionCount = 0;
size_t repeatCount = arguments_->getRepeatCount();
if (arguments_->isListingTestGroupNames())
{
TestResult tr(*output_);
registry_->listTestGroupNames(tr);
return 0;
}
if (arguments_->isListingTestGroupAndCaseNames())
{
TestResult tr(*output_);
registry_->listTestGroupAndCaseNames(tr);
return 0;
}
if (arguments_->isReversing())
registry_->reverseTests();
if (arguments_->isShuffling())
{
output_->print("Test order shuffling enabled with seed: ");
output_->print(arguments_->getShuffleSeed());
output_->print("\n");
}
while (loopCount++ < repeatCount) {
if (arguments_->isShuffling())
registry_->shuffleTests(arguments_->getShuffleSeed());
output_->printTestRun(loopCount, repeatCount);
TestResult tr(*output_);
registry_->runAllTests(tr);
failedTestCount += tr.getFailureCount();
if (tr.isFailure()) {
failedExecutionCount++;
}
}
return (int) (failedTestCount != 0 ? failedTestCount : failedExecutionCount);
}
TestOutput* CommandLineTestRunner::createTeamCityOutput()
{
return new TeamCityTestOutput;
}
TestOutput* CommandLineTestRunner::createJUnitOutput(const SimpleString& packageName)
{
JUnitTestOutput* junitOutput = new JUnitTestOutput;
if (junitOutput != NULLPTR) {
junitOutput->setPackageName(packageName);
}
return junitOutput;
}
TestOutput* CommandLineTestRunner::createConsoleOutput()
{
return new ConsoleTestOutput;
}
TestOutput* CommandLineTestRunner::createCompositeOutput(TestOutput* outputOne, TestOutput* outputTwo)
{
CompositeTestOutput* composite = new CompositeTestOutput;
composite->setOutputOne(outputOne);
composite->setOutputTwo(outputTwo);
return composite;
}
bool CommandLineTestRunner::parseArguments(TestPlugin* plugin)
{
if (!arguments_->parse(plugin)) {
output_ = createConsoleOutput();
output_->print((arguments_->needHelp()) ? arguments_->help() : arguments_->usage());
return false;
}
if (arguments_->isJUnitOutput()) {
output_= createJUnitOutput(arguments_->getPackageName());
if (arguments_->isVerbose())
output_ = createCompositeOutput(output_, createConsoleOutput());
} else if (arguments_->isTeamCityOutput()) {
output_ = createTeamCityOutput();
} else
output_ = createConsoleOutput();
return true;
}

View file

@ -0,0 +1,324 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/JUnitTestOutput.h"
#include "CppUTest/TestResult.h"
#include "CppUTest/TestFailure.h"
#include "CppUTest/PlatformSpecificFunctions.h"
struct JUnitTestCaseResultNode
{
JUnitTestCaseResultNode() :
execTime_(0), failure_(NULLPTR), ignored_(false), lineNumber_ (0), checkCount_ (0), next_(NULLPTR)
{
}
SimpleString name_;
size_t execTime_;
TestFailure* failure_;
bool ignored_;
SimpleString file_;
size_t lineNumber_;
size_t checkCount_;
JUnitTestCaseResultNode* next_;
};
struct JUnitTestGroupResult
{
JUnitTestGroupResult() :
testCount_(0), failureCount_(0), totalCheckCount_(0), startTime_(0), groupExecTime_(0), head_(NULLPTR), tail_(NULLPTR)
{
}
size_t testCount_;
size_t failureCount_;
size_t totalCheckCount_;
size_t startTime_;
size_t groupExecTime_;
SimpleString group_;
JUnitTestCaseResultNode* head_;
JUnitTestCaseResultNode* tail_;
};
struct JUnitTestOutputImpl
{
JUnitTestGroupResult results_;
PlatformSpecificFile file_;
SimpleString package_;
SimpleString stdOutput_;
};
JUnitTestOutput::JUnitTestOutput() :
impl_(new JUnitTestOutputImpl)
{
}
JUnitTestOutput::~JUnitTestOutput()
{
resetTestGroupResult();
delete impl_;
}
void JUnitTestOutput::resetTestGroupResult()
{
impl_->results_.testCount_ = 0;
impl_->results_.failureCount_ = 0;
impl_->results_.group_ = "";
JUnitTestCaseResultNode* cur = impl_->results_.head_;
while (cur) {
JUnitTestCaseResultNode* tmp = cur->next_;
delete cur->failure_;
delete cur;
cur = tmp;
}
impl_->results_.head_ = NULLPTR;
impl_->results_.tail_ = NULLPTR;
}
void JUnitTestOutput::printTestsStarted()
{
}
void JUnitTestOutput::printCurrentGroupStarted(const UtestShell& /*test*/)
{
}
void JUnitTestOutput::printCurrentTestEnded(const TestResult& result)
{
impl_->results_.tail_->execTime_ = result.getCurrentTestTotalExecutionTime();
impl_->results_.tail_->checkCount_ = result.getCheckCount();
}
void JUnitTestOutput::printTestsEnded(const TestResult& /*result*/)
{
}
void JUnitTestOutput::printCurrentGroupEnded(const TestResult& result)
{
impl_->results_.groupExecTime_ = result.getCurrentGroupTotalExecutionTime();
writeTestGroupToFile();
resetTestGroupResult();
}
void JUnitTestOutput::printCurrentTestStarted(const UtestShell& test)
{
impl_->results_.testCount_++;
impl_->results_.group_ = test.getGroup();
impl_->results_.startTime_ = (size_t) GetPlatformSpecificTimeInMillis();
if (impl_->results_.tail_ == NULLPTR) {
impl_->results_.head_ = impl_->results_.tail_
= new JUnitTestCaseResultNode;
}
else {
impl_->results_.tail_->next_ = new JUnitTestCaseResultNode;
impl_->results_.tail_ = impl_->results_.tail_->next_;
}
impl_->results_.tail_->name_ = test.getName();
impl_->results_.tail_->file_ = test.getFile();
impl_->results_.tail_->lineNumber_ = test.getLineNumber();
if (!test.willRun()) {
impl_->results_.tail_->ignored_ = true;
}
}
SimpleString JUnitTestOutput::createFileName(const SimpleString& group)
{
SimpleString fileName = "cpputest_";
if (!impl_->package_.isEmpty()) {
fileName += impl_->package_;
fileName += "_";
}
fileName += group;
return encodeFileName(fileName) + ".xml";
}
SimpleString JUnitTestOutput::encodeFileName(const SimpleString& fileName)
{
// special character list based on: https://en.wikipedia.org/wiki/Filename
static const char* const forbiddenCharacters = "/\\?%*:|\"<>";
SimpleString result = fileName;
for (const char* sym = forbiddenCharacters; *sym; ++sym) {
result.replace(*sym, '_');
}
return result;
}
void JUnitTestOutput::setPackageName(const SimpleString& package)
{
if (impl_ != NULLPTR) {
impl_->package_ = package;
}
}
void JUnitTestOutput::writeXmlHeader()
{
writeToFile("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
}
void JUnitTestOutput::writeTestSuiteSummary()
{
SimpleString
buf =
StringFromFormat(
"<testsuite errors=\"0\" failures=\"%d\" hostname=\"localhost\" name=\"%s\" tests=\"%d\" time=\"%d.%03d\" timestamp=\"%s\">\n",
(int)impl_->results_.failureCount_,
impl_->results_.group_.asCharString(),
(int) impl_->results_.testCount_,
(int) (impl_->results_.groupExecTime_ / 1000), (int) (impl_->results_.groupExecTime_ % 1000),
GetPlatformSpecificTimeString());
writeToFile(buf.asCharString());
}
void JUnitTestOutput::writeProperties()
{
writeToFile("<properties>\n");
writeToFile("</properties>\n");
}
SimpleString JUnitTestOutput::encodeXmlText(const SimpleString& textbody)
{
SimpleString buf = textbody.asCharString();
buf.replace("&", "&amp;");
buf.replace("\"", "&quot;");
buf.replace("<", "&lt;");
buf.replace(">", "&gt;");
buf.replace("\n", "{newline}");
return buf;
}
void JUnitTestOutput::writeTestCases()
{
JUnitTestCaseResultNode* cur = impl_->results_.head_;
while (cur) {
SimpleString buf = StringFromFormat(
"<testcase classname=\"%s%s%s\" name=\"%s\" assertions=\"%d\" time=\"%d.%03d\" file=\"%s\" line=\"%d\">\n",
impl_->package_.asCharString(),
impl_->package_.isEmpty() ? "" : ".",
impl_->results_.group_.asCharString(),
cur->name_.asCharString(),
(int) (cur->checkCount_ - impl_->results_.totalCheckCount_),
(int) (cur->execTime_ / 1000), (int)(cur->execTime_ % 1000),
cur->file_.asCharString(),
(int) cur->lineNumber_);
writeToFile(buf.asCharString());
impl_->results_.totalCheckCount_ = cur->checkCount_;
if (cur->failure_) {
writeFailure(cur);
}
else if (cur->ignored_) {
writeToFile("<skipped />\n");
}
writeToFile("</testcase>\n");
cur = cur->next_;
}
}
void JUnitTestOutput::writeFailure(JUnitTestCaseResultNode* node)
{
SimpleString buf = StringFromFormat(
"<failure message=\"%s:%d: %s\" type=\"AssertionFailedError\">\n",
node->failure_->getFileName().asCharString(),
(int) node->failure_->getFailureLineNumber(),
encodeXmlText(node->failure_->getMessage()).asCharString());
writeToFile(buf.asCharString());
writeToFile("</failure>\n");
}
void JUnitTestOutput::writeFileEnding()
{
writeToFile("<system-out>");
writeToFile(encodeXmlText(impl_->stdOutput_));
writeToFile("</system-out>\n");
writeToFile("<system-err></system-err>\n");
writeToFile("</testsuite>\n");
}
void JUnitTestOutput::writeTestGroupToFile()
{
openFileForWrite(createFileName(impl_->results_.group_));
writeXmlHeader();
writeTestSuiteSummary();
writeProperties();
writeTestCases();
writeFileEnding();
closeFile();
}
// LCOV_EXCL_START
void JUnitTestOutput::printBuffer(const char*)
{
}
void JUnitTestOutput::print(const char *output)
{
impl_->stdOutput_ += output;
}
void JUnitTestOutput::print(long)
{
}
void JUnitTestOutput::print(size_t)
{
}
void JUnitTestOutput::flush()
{
}
// LCOV_EXCL_STOP
void JUnitTestOutput::printFailure(const TestFailure& failure)
{
if (impl_->results_.tail_->failure_ == NULLPTR) {
impl_->results_.failureCount_++;
impl_->results_.tail_->failure_ = new TestFailure(failure);
}
}
void JUnitTestOutput::openFileForWrite(const SimpleString& fileName)
{
impl_->file_ = PlatformSpecificFOpen(fileName.asCharString(), "w");
}
void JUnitTestOutput::writeToFile(const SimpleString& buffer)
{
PlatformSpecificFPuts(buffer.asCharString(), impl_->file_);
}
void JUnitTestOutput::closeFile()
{
PlatformSpecificFClose(impl_->file_);
}

View file

@ -0,0 +1,756 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/MemoryLeakDetector.h"
#include "CppUTest/TestMemoryAllocator.h"
#include "CppUTest/PlatformSpecificFunctions.h"
#include "CppUTest/SimpleMutex.h"
static const char* UNKNOWN = "<unknown>";
static const char GuardBytes[] = {'B','A','S'};
SimpleStringBuffer::SimpleStringBuffer() :
positions_filled_(0), write_limit_(SIMPLE_STRING_BUFFER_LEN-1)
{
buffer_[0] = '\0';
}
void SimpleStringBuffer::clear()
{
positions_filled_ = 0;
buffer_[0] = '\0';
}
void SimpleStringBuffer::add(const char* format, ...)
{
const size_t positions_left = write_limit_ - positions_filled_;
if (positions_left == 0) return;
va_list arguments;
va_start(arguments, format);
const int count = PlatformSpecificVSNprintf(buffer_ + positions_filled_, positions_left+1, format, arguments);
if (count > 0) positions_filled_ += (size_t) count;
if (positions_filled_ > write_limit_) positions_filled_ = write_limit_;
va_end(arguments);
}
void SimpleStringBuffer::addMemoryDump(const void* memory, size_t memorySize)
{
const unsigned char* byteMemory = (const unsigned char*)memory;
const size_t maxLineBytes = 16;
size_t currentPos = 0;
size_t p;
while (currentPos < memorySize) {
add(" %04lx: ", (unsigned long) currentPos);
size_t bytesInLine = memorySize - currentPos;
if (bytesInLine > maxLineBytes) {
bytesInLine = maxLineBytes;
}
const size_t leftoverBytes = maxLineBytes - bytesInLine;
for (p = 0; p < bytesInLine; p++) {
add("%02hx ", (unsigned short) byteMemory[currentPos + p]);
if (p == ((maxLineBytes / 2) - 1)) {
add(" ");
}
}
for (p = 0; p < leftoverBytes; p++) {
add(" ");
}
if (leftoverBytes > (maxLineBytes/2)) {
add(" ");
}
add("|");
for (p = 0; p < bytesInLine; p++) {
char toAdd = (char)byteMemory[currentPos + p];
if (toAdd < ' ' || toAdd > '~') {
toAdd = '.';
}
add("%c", (int)toAdd);
}
add("|\n");
currentPos += bytesInLine;
}
}
char* SimpleStringBuffer::toString()
{
return buffer_;
}
void SimpleStringBuffer::setWriteLimit(size_t write_limit)
{
write_limit_ = write_limit;
if (write_limit_ > SIMPLE_STRING_BUFFER_LEN-1)
write_limit_ = SIMPLE_STRING_BUFFER_LEN-1;
}
void SimpleStringBuffer::resetWriteLimit()
{
write_limit_ = SIMPLE_STRING_BUFFER_LEN-1;
}
bool SimpleStringBuffer::reachedItsCapacity()
{
return positions_filled_ >= write_limit_;
}
////////////////////////
#define MEM_LEAK_TOO_MUCH "\netc etc etc etc. !!!! Too many memory leaks to report. Bailing out\n"
#define MEM_LEAK_FOOTER "Total number of leaks: "
#define MEM_LEAK_ADDITION_MALLOC_WARNING "NOTE:\n" \
"\tMemory leak reports about malloc and free can be caused by allocating using the cpputest version of malloc,\n" \
"\tbut deallocate using the standard free.\n" \
"\tIf this is the case, check whether your malloc/free replacements are working (#define malloc cpputest_malloc etc).\n"
MemoryLeakOutputStringBuffer::MemoryLeakOutputStringBuffer()
: total_leaks_(0), giveWarningOnUsingMalloc_(false)
{
}
void MemoryLeakOutputStringBuffer::addAllocationLocation(const char* allocationFile, size_t allocationLineNumber, size_t allocationSize, TestMemoryAllocator* allocator)
{
outputBuffer_.add(" allocated at file: %s line: %d size: %lu type: %s\n", allocationFile, (int) allocationLineNumber, (unsigned long) allocationSize, allocator->alloc_name());
}
void MemoryLeakOutputStringBuffer::addDeallocationLocation(const char* freeFile, size_t freeLineNumber, TestMemoryAllocator* allocator)
{
outputBuffer_.add(" deallocated at file: %s line: %d type: %s\n", freeFile, (int) freeLineNumber, allocator->free_name());
}
void MemoryLeakOutputStringBuffer::addNoMemoryLeaksMessage()
{
outputBuffer_.add("No memory leaks were detected.");
}
void MemoryLeakOutputStringBuffer::startMemoryLeakReporting()
{
giveWarningOnUsingMalloc_ = false;
total_leaks_ = 0;
size_t memory_leak_normal_footer_size = sizeof(MEM_LEAK_FOOTER) + 10 + sizeof(MEM_LEAK_TOO_MUCH); /* the number of leaks */
size_t memory_leak_foot_size_with_malloc_warning = memory_leak_normal_footer_size + sizeof(MEM_LEAK_ADDITION_MALLOC_WARNING);
outputBuffer_.setWriteLimit(SimpleStringBuffer::SIMPLE_STRING_BUFFER_LEN - memory_leak_foot_size_with_malloc_warning);
}
void MemoryLeakOutputStringBuffer::reportMemoryLeak(MemoryLeakDetectorNode* leak)
{
if (total_leaks_ == 0) {
addMemoryLeakHeader();
}
total_leaks_++;
outputBuffer_.add("Alloc num (%u) Leak size: %lu Allocated at: %s and line: %d. Type: \"%s\"\n\tMemory: <%p> Content:\n",
leak->number_, (unsigned long) leak->size_, leak->file_, (int) leak->line_, leak->allocator_->alloc_name(), (void*) leak->memory_);
outputBuffer_.addMemoryDump(leak->memory_, leak->size_);
if (SimpleString::StrCmp(leak->allocator_->alloc_name(), (const char*) "malloc") == 0)
giveWarningOnUsingMalloc_ = true;
}
void MemoryLeakOutputStringBuffer::stopMemoryLeakReporting()
{
if (total_leaks_ == 0) {
addNoMemoryLeaksMessage();
return;
}
bool buffer_reached_its_capacity = outputBuffer_.reachedItsCapacity();
outputBuffer_.resetWriteLimit();
if (buffer_reached_its_capacity)
addErrorMessageForTooMuchLeaks();
addMemoryLeakFooter(total_leaks_);
if (giveWarningOnUsingMalloc_)
addWarningForUsingMalloc();
}
void MemoryLeakOutputStringBuffer::addMemoryLeakHeader()
{
outputBuffer_.add("Memory leak(s) found.\n");
}
void MemoryLeakOutputStringBuffer::addErrorMessageForTooMuchLeaks()
{
outputBuffer_.add(MEM_LEAK_TOO_MUCH);
}
void MemoryLeakOutputStringBuffer::addMemoryLeakFooter(size_t amountOfLeaks)
{
outputBuffer_.add("%s %d\n", MEM_LEAK_FOOTER, (int) amountOfLeaks);
}
void MemoryLeakOutputStringBuffer::addWarningForUsingMalloc()
{
outputBuffer_.add(MEM_LEAK_ADDITION_MALLOC_WARNING);
}
void MemoryLeakOutputStringBuffer::reportDeallocateNonAllocatedMemoryFailure(const char* freeFile, size_t freeLine, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter)
{
reportFailure("Deallocating non-allocated memory\n", "<unknown>", 0, 0, NullUnknownAllocator::defaultAllocator(), freeFile, freeLine, freeAllocator, reporter);
}
void MemoryLeakOutputStringBuffer::reportAllocationDeallocationMismatchFailure(MemoryLeakDetectorNode* node, const char* freeFile, size_t freeLineNumber, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter)
{
reportFailure("Allocation/deallocation type mismatch\n", node->file_, node->line_, node->size_, node->allocator_, freeFile, freeLineNumber, freeAllocator, reporter);
}
void MemoryLeakOutputStringBuffer::reportMemoryCorruptionFailure(MemoryLeakDetectorNode* node, const char* freeFile, size_t freeLineNumber, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter)
{
reportFailure("Memory corruption (written out of bounds?)\n", node->file_, node->line_, node->size_, node->allocator_, freeFile, freeLineNumber, freeAllocator, reporter);
}
void MemoryLeakOutputStringBuffer::reportFailure(const char* message, const char* allocFile, size_t allocLine, size_t allocSize, TestMemoryAllocator* allocAllocator, const char* freeFile, size_t freeLine,
TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter)
{
outputBuffer_.add("%s", message);
addAllocationLocation(allocFile, allocLine, allocSize, allocAllocator);
addDeallocationLocation(freeFile, freeLine, freeAllocator);
reporter->fail(toString());
}
char* MemoryLeakOutputStringBuffer::toString()
{
return outputBuffer_.toString();
}
void MemoryLeakOutputStringBuffer::clear()
{
outputBuffer_.clear();
}
////////////////////////
void MemoryLeakDetectorNode::init(char* memory, unsigned number, size_t size, TestMemoryAllocator* allocator, MemLeakPeriod period, unsigned char allocation_stage, const char* file, size_t line)
{
number_ = number;
memory_ = memory;
size_ = size;
allocator_ = allocator;
period_ = period;
allocation_stage_ = allocation_stage;
file_ = file;
line_ = line;
}
///////////////////////
bool MemoryLeakDetectorList::isInPeriod(MemoryLeakDetectorNode* node, MemLeakPeriod period)
{
return period == mem_leak_period_all || node->period_ == period || (node->period_ != mem_leak_period_disabled && period == mem_leak_period_enabled);
}
bool MemoryLeakDetectorList::isInAllocationStage(MemoryLeakDetectorNode* node, unsigned char allocation_stage)
{
return node->allocation_stage_ == allocation_stage;
}
void MemoryLeakDetectorList::clearAllAccounting(MemLeakPeriod period)
{
MemoryLeakDetectorNode* cur = head_;
MemoryLeakDetectorNode* prev = NULLPTR;
while (cur) {
if (isInPeriod(cur, period)) {
if (prev) {
prev->next_ = cur->next_;
cur = prev;
}
else {
head_ = cur->next_;
cur = head_;
continue;
}
}
prev = cur;
cur = cur->next_;
}
}
void MemoryLeakDetectorList::addNewNode(MemoryLeakDetectorNode* node)
{
node->next_ = head_;
head_ = node;
}
MemoryLeakDetectorNode* MemoryLeakDetectorList::removeNode(char* memory)
{
MemoryLeakDetectorNode* cur = head_;
MemoryLeakDetectorNode* prev = NULLPTR;
while (cur) {
if (cur->memory_ == memory) {
if (prev) {
prev->next_ = cur->next_;
return cur;
}
else {
head_ = cur->next_;
return cur;
}
}
prev = cur;
cur = cur->next_;
}
return NULLPTR;
}
MemoryLeakDetectorNode* MemoryLeakDetectorList::retrieveNode(char* memory)
{
MemoryLeakDetectorNode* cur = head_;
while (cur) {
if (cur->memory_ == memory)
return cur;
cur = cur->next_;
}
return NULLPTR;
}
MemoryLeakDetectorNode* MemoryLeakDetectorList::getLeakFrom(MemoryLeakDetectorNode* node, MemLeakPeriod period)
{
for (MemoryLeakDetectorNode* cur = node; cur; cur = cur->next_)
if (isInPeriod(cur, period)) return cur;
return NULLPTR;
}
MemoryLeakDetectorNode* MemoryLeakDetectorList::getLeakForAllocationStageFrom(MemoryLeakDetectorNode* node, unsigned char allocation_stage)
{
for (MemoryLeakDetectorNode* cur = node; cur; cur = cur->next_)
if (isInAllocationStage(cur, allocation_stage)) return cur;
return NULLPTR;
}
MemoryLeakDetectorNode* MemoryLeakDetectorList::getFirstLeak(MemLeakPeriod period)
{
return getLeakFrom(head_, period);
}
MemoryLeakDetectorNode* MemoryLeakDetectorList::getFirstLeakForAllocationStage(unsigned char allocation_stage)
{
return getLeakForAllocationStageFrom(head_, allocation_stage);
}
MemoryLeakDetectorNode* MemoryLeakDetectorList::getNextLeak(MemoryLeakDetectorNode* node, MemLeakPeriod period)
{
return getLeakFrom(node->next_, period);
}
MemoryLeakDetectorNode* MemoryLeakDetectorList::getNextLeakForAllocationStage(MemoryLeakDetectorNode* node, unsigned char allocation_stage)
{
return getLeakForAllocationStageFrom(node->next_, allocation_stage);
}
size_t MemoryLeakDetectorList::getTotalLeaks(MemLeakPeriod period)
{
size_t total_leaks = 0;
for (MemoryLeakDetectorNode* node = head_; node; node = node->next_) {
if (isInPeriod(node, period)) total_leaks++;
}
return total_leaks;
}
/////////////////////////////////////////////////////////////
unsigned long MemoryLeakDetectorTable::hash(char* memory)
{
return (unsigned long)((size_t)memory % hash_prime);
}
void MemoryLeakDetectorTable::clearAllAccounting(MemLeakPeriod period)
{
for (int i = 0; i < hash_prime; i++)
table_[i].clearAllAccounting(period);
}
void MemoryLeakDetectorTable::addNewNode(MemoryLeakDetectorNode* node)
{
table_[hash(node->memory_)].addNewNode(node);
}
MemoryLeakDetectorNode* MemoryLeakDetectorTable::removeNode(char* memory)
{
return table_[hash(memory)].removeNode(memory);
}
MemoryLeakDetectorNode* MemoryLeakDetectorTable::retrieveNode(char* memory)
{
return table_[hash(memory)].retrieveNode(memory);
}
size_t MemoryLeakDetectorTable::getTotalLeaks(MemLeakPeriod period)
{
size_t total_leaks = 0;
for (int i = 0; i < hash_prime; i++)
total_leaks += table_[i].getTotalLeaks(period);
return total_leaks;
}
MemoryLeakDetectorNode* MemoryLeakDetectorTable::getFirstLeak(MemLeakPeriod period)
{
for (int i = 0; i < hash_prime; i++) {
MemoryLeakDetectorNode* node = table_[i].getFirstLeak(period);
if (node) return node;
}
return NULLPTR;
}
MemoryLeakDetectorNode* MemoryLeakDetectorTable::getFirstLeakForAllocationStage(unsigned char allocation_stage)
{
for (int i = 0; i < hash_prime; i++) {
MemoryLeakDetectorNode* node = table_[i].getFirstLeakForAllocationStage(allocation_stage);
if (node) return node;
}
return NULLPTR;
}
MemoryLeakDetectorNode* MemoryLeakDetectorTable::getNextLeak(MemoryLeakDetectorNode* leak, MemLeakPeriod period)
{
unsigned long i = hash(leak->memory_);
MemoryLeakDetectorNode* node = table_[i].getNextLeak(leak, period);
if (node) return node;
for (++i; i < hash_prime; i++) {
node = table_[i].getFirstLeak(period);
if (node) return node;
}
return NULLPTR;
}
MemoryLeakDetectorNode* MemoryLeakDetectorTable::getNextLeakForAllocationStage(MemoryLeakDetectorNode* leak, unsigned char allocation_stage)
{
unsigned long i = hash(leak->memory_);
MemoryLeakDetectorNode* node = table_[i].getNextLeakForAllocationStage(leak, allocation_stage);
if (node) return node;
for (++i; i < hash_prime; i++) {
node = table_[i].getFirstLeakForAllocationStage(allocation_stage);
if (node) return node;
}
return NULLPTR;
}
/////////////////////////////////////////////////////////////
MemoryLeakDetector::MemoryLeakDetector(MemoryLeakFailure* reporter)
{
doAllocationTypeChecking_ = true;
allocationSequenceNumber_ = 1;
current_period_ = mem_leak_period_disabled;
current_allocation_stage_ = 0;
reporter_ = reporter;
mutex_ = new SimpleMutex;
}
MemoryLeakDetector::~MemoryLeakDetector()
{
if (mutex_)
{
delete mutex_;
}
}
void MemoryLeakDetector::clearAllAccounting(MemLeakPeriod period)
{
memoryTable_.clearAllAccounting(period);
}
void MemoryLeakDetector::startChecking()
{
outputBuffer_.clear();
current_period_ = mem_leak_period_checking;
}
void MemoryLeakDetector::stopChecking()
{
current_period_ = mem_leak_period_enabled;
}
unsigned char MemoryLeakDetector::getCurrentAllocationStage() const
{
return current_allocation_stage_;
}
void MemoryLeakDetector::enable()
{
current_period_ = mem_leak_period_enabled;
}
void MemoryLeakDetector::disable()
{
current_period_ = mem_leak_period_disabled;
}
void MemoryLeakDetector::disableAllocationTypeChecking()
{
doAllocationTypeChecking_ = false;
}
void MemoryLeakDetector::enableAllocationTypeChecking()
{
doAllocationTypeChecking_ = true;
}
unsigned MemoryLeakDetector::getCurrentAllocationNumber()
{
return allocationSequenceNumber_;
}
void MemoryLeakDetector::increaseAllocationStage()
{
current_allocation_stage_++;
}
void MemoryLeakDetector::decreaseAllocationStage()
{
current_allocation_stage_--;
}
SimpleMutex *MemoryLeakDetector::getMutex()
{
return mutex_;
}
static size_t calculateVoidPointerAlignedSize(size_t size)
{
#ifndef CPPUTEST_DISABLE_MEM_CORRUPTION_CHECK
return (sizeof(void*) - (size % sizeof(void*))) + size;
#else
return size;
#endif
}
size_t MemoryLeakDetector::sizeOfMemoryWithCorruptionInfo(size_t size)
{
return calculateVoidPointerAlignedSize(size + memory_corruption_buffer_size);
}
MemoryLeakDetectorNode* MemoryLeakDetector::getNodeFromMemoryPointer(char* memory, size_t memory_size)
{
return (MemoryLeakDetectorNode*) (void*) (memory + sizeOfMemoryWithCorruptionInfo(memory_size));
}
void MemoryLeakDetector::storeLeakInformation(MemoryLeakDetectorNode * node, char *new_memory, size_t size, TestMemoryAllocator *allocator, const char *file, size_t line)
{
node->init(new_memory, allocationSequenceNumber_++, size, allocator, current_period_, current_allocation_stage_, file, line);
addMemoryCorruptionInformation(node->memory_ + node->size_);
memoryTable_.addNewNode(node);
}
char* MemoryLeakDetector::reallocateMemoryAndLeakInformation(TestMemoryAllocator* allocator, char* memory, size_t size, const char* file, size_t line, bool allocatNodesSeperately)
{
char* new_memory = reallocateMemoryWithAccountingInformation(allocator, memory, size, file, line, allocatNodesSeperately);
if (new_memory == NULLPTR) return NULLPTR;
MemoryLeakDetectorNode *node = createMemoryLeakAccountingInformation(allocator, size, new_memory, allocatNodesSeperately);
storeLeakInformation(node, new_memory, size, allocator, file, line);
return node->memory_;
}
void MemoryLeakDetector::invalidateMemory(char* memory)
{
#ifndef CPPUTEST_DISABLE_HEAP_POISON
MemoryLeakDetectorNode* node = memoryTable_.retrieveNode(memory);
if (node)
PlatformSpecificMemset(memory, 0xCD, node->size_);
#endif
}
void MemoryLeakDetector::addMemoryCorruptionInformation(char* memory)
{
for (size_t i=0; i<memory_corruption_buffer_size; i++)
memory[i] = GuardBytes[i % sizeof(GuardBytes)];
}
bool MemoryLeakDetector::validMemoryCorruptionInformation(char* memory)
{
for (size_t i=0; i<memory_corruption_buffer_size; i++)
if (memory[i] != GuardBytes[i % sizeof(GuardBytes)])
return false;
return true;
}
bool MemoryLeakDetector::matchingAllocation(TestMemoryAllocator *alloc_allocator, TestMemoryAllocator *free_allocator)
{
if (alloc_allocator == free_allocator) return true;
if (!doAllocationTypeChecking_) return true;
return free_allocator->isOfEqualType(alloc_allocator);
}
void MemoryLeakDetector::checkForCorruption(MemoryLeakDetectorNode* node, const char* file, size_t line, TestMemoryAllocator* allocator, bool allocateNodesSeperately)
{
if (!matchingAllocation(node->allocator_->actualAllocator(), allocator->actualAllocator()))
outputBuffer_.reportAllocationDeallocationMismatchFailure(node, file, line, allocator->actualAllocator(), reporter_);
else if (!validMemoryCorruptionInformation(node->memory_ + node->size_))
outputBuffer_.reportMemoryCorruptionFailure(node, file, line, allocator->actualAllocator(), reporter_);
else if (allocateNodesSeperately)
allocator->freeMemoryLeakNode((char*) node);
}
char* MemoryLeakDetector::allocMemory(TestMemoryAllocator* allocator, size_t size, bool allocatNodesSeperately)
{
return allocMemory(allocator, size, UNKNOWN, 0, allocatNodesSeperately);
}
char* MemoryLeakDetector::allocateMemoryWithAccountingInformation(TestMemoryAllocator* allocator, size_t size, const char* file, size_t line, bool allocatNodesSeperately)
{
if (allocatNodesSeperately) return allocator->alloc_memory(sizeOfMemoryWithCorruptionInfo(size), file, line);
else return allocator->alloc_memory(sizeOfMemoryWithCorruptionInfo(size) + sizeof(MemoryLeakDetectorNode), file, line);
}
char* MemoryLeakDetector::reallocateMemoryWithAccountingInformation(TestMemoryAllocator* /*allocator*/, char* memory, size_t size, const char* /*file*/, size_t /*line*/, bool allocatNodesSeperately)
{
if (allocatNodesSeperately) return (char*) PlatformSpecificRealloc(memory, sizeOfMemoryWithCorruptionInfo(size));
else return (char*) PlatformSpecificRealloc(memory, sizeOfMemoryWithCorruptionInfo(size) + sizeof(MemoryLeakDetectorNode));
}
MemoryLeakDetectorNode* MemoryLeakDetector::createMemoryLeakAccountingInformation(TestMemoryAllocator* allocator, size_t size, char* memory, bool allocatNodesSeperately)
{
if (allocatNodesSeperately) return (MemoryLeakDetectorNode*) (void*) allocator->allocMemoryLeakNode(sizeof(MemoryLeakDetectorNode));
else return getNodeFromMemoryPointer(memory, size);
}
char* MemoryLeakDetector::allocMemory(TestMemoryAllocator* allocator, size_t size, const char* file, size_t line, bool allocatNodesSeperately)
{
#ifdef CPPUTEST_DISABLE_MEM_CORRUPTION_CHECK
allocatNodesSeperately = true;
#endif
/* With malloc, it is harder to guarantee that the allocator free is called.
* This is because operator new is overloaded via linker symbols, but malloc just via #defines.
* If the same allocation is used and the wrong free is called, it will deallocate the memory leak information
* without the memory leak detector ever noticing it!
* So, for malloc, we'll allocate the memory separately so we can detect this and give a proper error.
*/
char* memory = allocateMemoryWithAccountingInformation(allocator, size, file, line, allocatNodesSeperately);
if (memory == NULLPTR) return NULLPTR;
MemoryLeakDetectorNode* node = createMemoryLeakAccountingInformation(allocator, size, memory, allocatNodesSeperately);
storeLeakInformation(node, memory, size, allocator, file, line);
return node->memory_;
}
void MemoryLeakDetector::removeMemoryLeakInformationWithoutCheckingOrDeallocatingTheMemoryButDeallocatingTheAccountInformation(TestMemoryAllocator* allocator, void* memory, bool allocatNodesSeperately)
{
MemoryLeakDetectorNode* node = memoryTable_.removeNode((char*) memory);
if (allocatNodesSeperately) allocator->freeMemoryLeakNode( (char*) node);
}
void MemoryLeakDetector::deallocMemory(TestMemoryAllocator* allocator, void* memory, const char* file, size_t line, bool allocatNodesSeperately)
{
if (memory == NULLPTR) return;
MemoryLeakDetectorNode* node = memoryTable_.removeNode((char*) memory);
if (node == NULLPTR) {
outputBuffer_.reportDeallocateNonAllocatedMemoryFailure(file, line, allocator, reporter_);
return;
}
#ifdef CPPUTEST_DISABLE_MEM_CORRUPTION_CHECK
allocatNodesSeperately = true;
#endif
if (!allocator->hasBeenDestroyed()) {
size_t size = node->size_;
checkForCorruption(node, file, line, allocator, allocatNodesSeperately);
allocator->free_memory((char*) memory, size, file, line);
}
}
void MemoryLeakDetector::deallocMemory(TestMemoryAllocator* allocator, void* memory, bool allocatNodesSeperately)
{
deallocMemory(allocator, (char*) memory, UNKNOWN, 0, allocatNodesSeperately);
}
void MemoryLeakDetector::deallocAllMemoryInCurrentAllocationStage()
{
char* memory = NULLPTR;
MemoryLeakDetectorNode* node = memoryTable_.getFirstLeakForAllocationStage(current_allocation_stage_);
while (node) {
memory = node->memory_;
TestMemoryAllocator* allocator = node->allocator_;
node = memoryTable_.getNextLeakForAllocationStage(node, current_allocation_stage_);
deallocMemory(allocator, memory, __FILE__, __LINE__);
}
}
char* MemoryLeakDetector::reallocMemory(TestMemoryAllocator* allocator, char* memory, size_t size, const char* file, size_t line, bool allocatNodesSeperately)
{
#ifdef CPPUTEST_DISABLE_MEM_CORRUPTION_CHECK
allocatNodesSeperately = true;
#endif
if (memory) {
MemoryLeakDetectorNode* node = memoryTable_.removeNode(memory);
if (node == NULLPTR) {
outputBuffer_.reportDeallocateNonAllocatedMemoryFailure(file, line, allocator, reporter_);
return NULLPTR;
}
checkForCorruption(node, file, line, allocator, allocatNodesSeperately);
}
return reallocateMemoryAndLeakInformation(allocator, memory, size, file, line, allocatNodesSeperately);
}
void MemoryLeakDetector::ConstructMemoryLeakReport(MemLeakPeriod period)
{
MemoryLeakDetectorNode* leak = memoryTable_.getFirstLeak(period);
outputBuffer_.startMemoryLeakReporting();
while (leak) {
outputBuffer_.reportMemoryLeak(leak);
leak = memoryTable_.getNextLeak(leak, period);
}
outputBuffer_.stopMemoryLeakReporting();
}
const char* MemoryLeakDetector::report(MemLeakPeriod period)
{
ConstructMemoryLeakReport(period);
return outputBuffer_.toString();
}
void MemoryLeakDetector::markCheckingPeriodLeaksAsNonCheckingPeriod()
{
MemoryLeakDetectorNode* leak = memoryTable_.getFirstLeak(mem_leak_period_checking);
while (leak) {
if (leak->period_ == mem_leak_period_checking) leak->period_ = mem_leak_period_enabled;
leak = memoryTable_.getNextLeak(leak, mem_leak_period_checking);
}
}
size_t MemoryLeakDetector::totalMemoryLeaks(MemLeakPeriod period)
{
return memoryTable_.getTotalLeaks(period);
}

View file

@ -0,0 +1,665 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/MemoryLeakWarningPlugin.h"
#include "CppUTest/MemoryLeakDetector.h"
#include "CppUTest/TestMemoryAllocator.h"
#include "CppUTest/PlatformSpecificFunctions.h"
#include "CppUTest/SimpleMutex.h"
/********** Enabling and disabling for C also *********/
#if CPPUTEST_USE_MEM_LEAK_DETECTION
class MemLeakScopedMutex
{
public:
MemLeakScopedMutex() : lock(MemoryLeakWarningPlugin::getGlobalDetector()->getMutex()) { }
private:
ScopedMutexLock lock;
};
static void* threadsafe_mem_leak_malloc(size_t size, const char* file, size_t line)
{
MemLeakScopedMutex lock;
return MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentMallocAllocator(), size, file, line, true);
}
static void threadsafe_mem_leak_free(void* buffer, const char* file, size_t line)
{
MemLeakScopedMutex lock;
MemoryLeakWarningPlugin::getGlobalDetector()->invalidateMemory((char*) buffer);
MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(getCurrentMallocAllocator(), (char*) buffer, file, line, true);
}
static void* threadsafe_mem_leak_realloc(void* memory, size_t size, const char* file, size_t line)
{
MemLeakScopedMutex lock;
return MemoryLeakWarningPlugin::getGlobalDetector()->reallocMemory(getCurrentMallocAllocator(), (char*) memory, size, file, line, true);
}
static void* mem_leak_malloc(size_t size, const char* file, size_t line)
{
return MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentMallocAllocator(), size, file, line, true);
}
static void mem_leak_free(void* buffer, const char* file, size_t line)
{
MemoryLeakWarningPlugin::getGlobalDetector()->invalidateMemory((char*) buffer);
MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(getCurrentMallocAllocator(), (char*) buffer, file, line, true);
}
static void* mem_leak_realloc(void* memory, size_t size, const char* file, size_t line)
{
return MemoryLeakWarningPlugin::getGlobalDetector()->reallocMemory(getCurrentMallocAllocator(), (char*) memory, size, file, line, true);
}
#endif
static void* normal_malloc(size_t size, const char*, size_t)
{
return PlatformSpecificMalloc(size);
}
static void* normal_realloc(void* memory, size_t size, const char*, size_t)
{
return PlatformSpecificRealloc(memory, size);
}
static void normal_free(void* buffer, const char*, size_t)
{
PlatformSpecificFree(buffer);
}
#if CPPUTEST_USE_MEM_LEAK_DETECTION
static void *(*malloc_fptr)(size_t size, const char* file, size_t line) = mem_leak_malloc;
static void (*free_fptr)(void* mem, const char* file, size_t line) = mem_leak_free;
static void*(*realloc_fptr)(void* memory, size_t size, const char* file, size_t line) = mem_leak_realloc;
static void *(*saved_malloc_fptr)(size_t size, const char* file, size_t line) = mem_leak_malloc;
static void (*saved_free_fptr)(void* mem, const char* file, size_t line) = mem_leak_free;
static void*(*saved_realloc_fptr)(void* memory, size_t size, const char* file, size_t line) = mem_leak_realloc;
#else
static void *(*malloc_fptr)(size_t size, const char* file, size_t line) = normal_malloc;
static void (*free_fptr)(void* mem, const char* file, size_t line) = normal_free;
static void*(*realloc_fptr)(void* memory, size_t size, const char* file, size_t line) = normal_realloc;
#endif
void* cpputest_malloc_location_with_leak_detection(size_t size, const char* file, size_t line)
{
return malloc_fptr(size, file, line);
}
void* cpputest_realloc_location_with_leak_detection(void* memory, size_t size, const char* file, size_t line)
{
return realloc_fptr(memory, size, file, line);
}
void cpputest_free_location_with_leak_detection(void* buffer, const char* file, size_t line)
{
free_fptr(buffer, file, line);
}
/********** C++ *************/
#if CPPUTEST_USE_MEM_LEAK_DETECTION
#undef new
#if CPPUTEST_USE_STD_CPP_LIB
#define UT_THROW_BAD_ALLOC_WHEN_NULL(memory) if (memory == NULLPTR) throw std::bad_alloc()
#else
#define UT_THROW_BAD_ALLOC_WHEN_NULL(memory)
#endif
static void* threadsafe_mem_leak_operator_new (size_t size) UT_THROW(std::bad_alloc)
{
MemLeakScopedMutex lock;
void* memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewAllocator(), size);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void* threadsafe_mem_leak_operator_new_nothrow (size_t size) UT_NOTHROW
{
MemLeakScopedMutex lock;
return MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewAllocator(), size);
}
static void* threadsafe_mem_leak_operator_new_debug (size_t size, const char* file, size_t line) UT_THROW(std::bad_alloc)
{
MemLeakScopedMutex lock;
void *memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewAllocator(), size, file, line);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void* threadsafe_mem_leak_operator_new_array (size_t size) UT_THROW(std::bad_alloc)
{
MemLeakScopedMutex lock;
void* memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewArrayAllocator(), size);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void* threadsafe_mem_leak_operator_new_array_nothrow (size_t size) UT_NOTHROW
{
MemLeakScopedMutex lock;
return MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewArrayAllocator(), size);
}
static void* threadsafe_mem_leak_operator_new_array_debug (size_t size, const char* file, size_t line) UT_THROW(std::bad_alloc)
{
MemLeakScopedMutex lock;
void* memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewArrayAllocator(), size, file, line);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void threadsafe_mem_leak_operator_delete (void* mem) UT_NOTHROW
{
MemLeakScopedMutex lock;
MemoryLeakWarningPlugin::getGlobalDetector()->invalidateMemory((char*) mem);
MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(getCurrentNewAllocator(), (char*) mem);
}
static void threadsafe_mem_leak_operator_delete_array (void* mem) UT_NOTHROW
{
MemLeakScopedMutex lock;
MemoryLeakWarningPlugin::getGlobalDetector()->invalidateMemory((char*) mem);
MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(getCurrentNewArrayAllocator(), (char*) mem);
}
static void* mem_leak_operator_new (size_t size) UT_THROW(std::bad_alloc)
{
void* memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewAllocator(), size);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void* mem_leak_operator_new_nothrow (size_t size) UT_NOTHROW
{
return MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewAllocator(), size);
}
static void* mem_leak_operator_new_debug (size_t size, const char* file, size_t line) UT_THROW(std::bad_alloc)
{
void *memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewAllocator(), size, file, line);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void* mem_leak_operator_new_array (size_t size) UT_THROW(std::bad_alloc)
{
void* memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewArrayAllocator(), size);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void* mem_leak_operator_new_array_nothrow (size_t size) UT_NOTHROW
{
return MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewArrayAllocator(), size);
}
static void* mem_leak_operator_new_array_debug (size_t size, const char* file, size_t line) UT_THROW(std::bad_alloc)
{
void* memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewArrayAllocator(), size, file, line);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void mem_leak_operator_delete (void* mem) UT_NOTHROW
{
MemoryLeakWarningPlugin::getGlobalDetector()->invalidateMemory((char*) mem);
MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(getCurrentNewAllocator(), (char*) mem);
}
static void mem_leak_operator_delete_array (void* mem) UT_NOTHROW
{
MemoryLeakWarningPlugin::getGlobalDetector()->invalidateMemory((char*) mem);
MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(getCurrentNewArrayAllocator(), (char*) mem);
}
static void* normal_operator_new (size_t size) UT_THROW(std::bad_alloc)
{
void* memory = PlatformSpecificMalloc(size);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void* normal_operator_new_nothrow (size_t size) UT_NOTHROW
{
return PlatformSpecificMalloc(size);
}
static void* normal_operator_new_debug (size_t size, const char* /*file*/, size_t /*line*/) UT_THROW(std::bad_alloc)
{
void* memory = PlatformSpecificMalloc(size);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void* normal_operator_new_array (size_t size) UT_THROW(std::bad_alloc)
{
void* memory = PlatformSpecificMalloc(size);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void* normal_operator_new_array_nothrow (size_t size) UT_NOTHROW
{
return PlatformSpecificMalloc(size);
}
static void* normal_operator_new_array_debug (size_t size, const char* /*file*/, size_t /*line*/) UT_THROW(std::bad_alloc)
{
void* memory = PlatformSpecificMalloc(size);
UT_THROW_BAD_ALLOC_WHEN_NULL(memory);
return memory;
}
static void normal_operator_delete (void* mem) UT_NOTHROW
{
PlatformSpecificFree(mem);
}
static void normal_operator_delete_array (void* mem) UT_NOTHROW
{
PlatformSpecificFree(mem);
}
static void *(*operator_new_fptr)(size_t size) UT_THROW(std::bad_alloc) = mem_leak_operator_new;
static void *(*operator_new_nothrow_fptr)(size_t size) UT_NOTHROW = mem_leak_operator_new_nothrow;
static void *(*operator_new_debug_fptr)(size_t size, const char* file, size_t line) UT_THROW(std::bad_alloc) = mem_leak_operator_new_debug;
static void *(*operator_new_array_fptr)(size_t size) UT_THROW(std::bad_alloc) = mem_leak_operator_new_array;
static void *(*operator_new_array_nothrow_fptr)(size_t size) UT_NOTHROW = mem_leak_operator_new_array_nothrow;
static void *(*operator_new_array_debug_fptr)(size_t size, const char* file, size_t line) UT_THROW(std::bad_alloc) = mem_leak_operator_new_array_debug;
static void (*operator_delete_fptr)(void* mem) UT_NOTHROW = mem_leak_operator_delete;
static void (*operator_delete_array_fptr)(void* mem) UT_NOTHROW = mem_leak_operator_delete_array;
static void *(*saved_operator_new_fptr)(size_t size) UT_THROW(std::bad_alloc) = mem_leak_operator_new;
static void *(*saved_operator_new_nothrow_fptr)(size_t size) UT_NOTHROW = mem_leak_operator_new_nothrow;
static void *(*saved_operator_new_debug_fptr)(size_t size, const char* file, size_t line) UT_THROW(std::bad_alloc) = mem_leak_operator_new_debug;
static void *(*saved_operator_new_array_fptr)(size_t size) UT_THROW(std::bad_alloc) = mem_leak_operator_new_array;
static void *(*saved_operator_new_array_nothrow_fptr)(size_t size) UT_NOTHROW = mem_leak_operator_new_array_nothrow;
static void *(*saved_operator_new_array_debug_fptr)(size_t size, const char* file, size_t line) UT_THROW(std::bad_alloc) = mem_leak_operator_new_array_debug;
static void (*saved_operator_delete_fptr)(void* mem) UT_NOTHROW = mem_leak_operator_delete;
static void (*saved_operator_delete_array_fptr)(void* mem) UT_NOTHROW = mem_leak_operator_delete_array;
static int save_counter = 0;
void* operator new(size_t size) UT_THROW(std::bad_alloc)
{
return operator_new_fptr(size);
}
void* operator new(size_t size, const char* file, int line) UT_THROW(std::bad_alloc)
{
return operator_new_debug_fptr(size, file, (size_t)line);
}
void* operator new(size_t size, const char* file, size_t line) UT_THROW(std::bad_alloc)
{
return operator_new_debug_fptr(size, file, line);
}
void operator delete(void* mem) UT_NOTHROW
{
operator_delete_fptr(mem);
}
void operator delete(void* mem, const char*, int) UT_NOTHROW
{
operator_delete_fptr(mem);
}
void operator delete(void* mem, const char*, size_t) UT_NOTHROW
{
operator_delete_fptr(mem);
}
#if __cplusplus >= 201402L
void operator delete (void* mem, size_t) UT_NOTHROW
{
operator_delete_fptr(mem);
}
#endif
void* operator new[](size_t size) UT_THROW(std::bad_alloc)
{
return operator_new_array_fptr(size);
}
void* operator new [](size_t size, const char* file, int line) UT_THROW(std::bad_alloc)
{
return operator_new_array_debug_fptr(size, file, (size_t)line);
}
void* operator new [](size_t size, const char* file, size_t line) UT_THROW(std::bad_alloc)
{
return operator_new_array_debug_fptr(size, file, line);
}
void operator delete[](void* mem) UT_NOTHROW
{
operator_delete_array_fptr(mem);
}
void operator delete[](void* mem, const char*, int) UT_NOTHROW
{
operator_delete_array_fptr(mem);
}
void operator delete[](void* mem, const char*, size_t) UT_NOTHROW
{
operator_delete_array_fptr(mem);
}
#if __cplusplus >= 201402L
void operator delete[] (void* mem, size_t) UT_NOTHROW
{
operator_delete_array_fptr(mem);
}
#endif
#if CPPUTEST_USE_STD_CPP_LIB
void* operator new(size_t size, const std::nothrow_t&) UT_NOTHROW
{
return operator_new_nothrow_fptr(size);
}
void operator delete(void* mem, const std::nothrow_t&) UT_NOTHROW
{
operator_delete_fptr(mem);
}
void* operator new[](size_t size, const std::nothrow_t&) UT_NOTHROW
{
return operator_new_array_nothrow_fptr(size);
}
void operator delete[](void* mem, const std::nothrow_t&) UT_NOTHROW
{
operator_delete_array_fptr(mem);
}
#else
/* Have a similar method. This avoid unused operator_new_nothrow_fptr warning */
extern void* operator_new_nothrow(size_t size) UT_NOTHROW;
extern void* operator_new_array_nothrow(size_t size) UT_NOTHROW;
void* operator_new_nothrow(size_t size) UT_NOTHROW
{
return operator_new_nothrow_fptr(size);
}
void* operator_new_array_nothrow(size_t size) UT_NOTHROW
{
return operator_new_array_nothrow_fptr(size);
}
#endif
#endif
void MemoryLeakWarningPlugin::turnOffNewDeleteOverloads()
{
#if CPPUTEST_USE_MEM_LEAK_DETECTION
operator_new_fptr = normal_operator_new;
operator_new_nothrow_fptr = normal_operator_new_nothrow;
operator_new_debug_fptr = normal_operator_new_debug;
operator_new_array_fptr = normal_operator_new_array;
operator_new_array_nothrow_fptr = normal_operator_new_array_nothrow;
operator_new_array_debug_fptr = normal_operator_new_array_debug;
operator_delete_fptr = normal_operator_delete;
operator_delete_array_fptr = normal_operator_delete_array;
malloc_fptr = normal_malloc;
realloc_fptr = normal_realloc;
free_fptr = normal_free;
#endif
}
void MemoryLeakWarningPlugin::turnOnDefaultNotThreadSafeNewDeleteOverloads()
{
#if CPPUTEST_USE_MEM_LEAK_DETECTION
operator_new_fptr = mem_leak_operator_new;
operator_new_nothrow_fptr = mem_leak_operator_new_nothrow;
operator_new_debug_fptr = mem_leak_operator_new_debug;
operator_new_array_fptr = mem_leak_operator_new_array;
operator_new_array_nothrow_fptr = mem_leak_operator_new_array_nothrow;
operator_new_array_debug_fptr = mem_leak_operator_new_array_debug;
operator_delete_fptr = mem_leak_operator_delete;
operator_delete_array_fptr = mem_leak_operator_delete_array;
malloc_fptr = mem_leak_malloc;
realloc_fptr = mem_leak_realloc;
free_fptr = mem_leak_free;
#endif
}
void MemoryLeakWarningPlugin::turnOnThreadSafeNewDeleteOverloads()
{
#if CPPUTEST_USE_MEM_LEAK_DETECTION
operator_new_fptr = threadsafe_mem_leak_operator_new;
operator_new_nothrow_fptr = threadsafe_mem_leak_operator_new_nothrow;
operator_new_debug_fptr = threadsafe_mem_leak_operator_new_debug;
operator_new_array_fptr = threadsafe_mem_leak_operator_new_array;
operator_new_array_nothrow_fptr = threadsafe_mem_leak_operator_new_array_nothrow;
operator_new_array_debug_fptr = threadsafe_mem_leak_operator_new_array_debug;
operator_delete_fptr = threadsafe_mem_leak_operator_delete;
operator_delete_array_fptr = threadsafe_mem_leak_operator_delete_array;
malloc_fptr = threadsafe_mem_leak_malloc;
realloc_fptr = threadsafe_mem_leak_realloc;
free_fptr = threadsafe_mem_leak_free;
#endif
}
bool MemoryLeakWarningPlugin::areNewDeleteOverloaded()
{
#if CPPUTEST_USE_MEM_LEAK_DETECTION
return operator_new_fptr == mem_leak_operator_new || operator_new_fptr == threadsafe_mem_leak_operator_new;
#else
return false;
#endif
}
void MemoryLeakWarningPlugin::saveAndDisableNewDeleteOverloads()
{
#if CPPUTEST_USE_MEM_LEAK_DETECTION
if (++save_counter > 1) return;
saved_operator_new_fptr = operator_new_fptr;
saved_operator_new_nothrow_fptr = operator_new_nothrow_fptr;
saved_operator_new_debug_fptr = operator_new_debug_fptr;
saved_operator_new_array_fptr = operator_new_array_fptr;
saved_operator_new_array_nothrow_fptr = operator_new_array_nothrow_fptr;
saved_operator_new_array_debug_fptr = operator_new_array_debug_fptr;
saved_operator_delete_fptr = operator_delete_fptr;
saved_operator_delete_array_fptr = operator_delete_array_fptr;
saved_malloc_fptr = malloc_fptr;
saved_realloc_fptr = realloc_fptr;
saved_free_fptr = free_fptr;
turnOffNewDeleteOverloads();
#endif
}
void MemoryLeakWarningPlugin::restoreNewDeleteOverloads()
{
#if CPPUTEST_USE_MEM_LEAK_DETECTION
if (--save_counter > 0) return;
operator_new_fptr = saved_operator_new_fptr;
operator_new_nothrow_fptr = saved_operator_new_nothrow_fptr;
operator_new_debug_fptr = saved_operator_new_debug_fptr;
operator_new_array_fptr = saved_operator_new_array_fptr;
operator_new_array_nothrow_fptr = saved_operator_new_array_nothrow_fptr;
operator_new_array_debug_fptr = saved_operator_new_array_debug_fptr;
operator_delete_fptr = saved_operator_delete_fptr;
operator_delete_array_fptr = saved_operator_delete_array_fptr;
malloc_fptr = saved_malloc_fptr;
realloc_fptr = saved_realloc_fptr;
free_fptr = saved_free_fptr;
#endif
}
void crash_on_allocation_number(unsigned alloc_number)
{
static CrashOnAllocationAllocator crashAllocator;
crashAllocator.setNumberToCrashOn(alloc_number);
setCurrentMallocAllocator(&crashAllocator);
setCurrentNewAllocator(&crashAllocator);
setCurrentNewArrayAllocator(&crashAllocator);
}
class MemoryLeakWarningReporter: public MemoryLeakFailure
{
public:
virtual ~MemoryLeakWarningReporter() _destructor_override
{
}
virtual void fail(char* fail_string) _override
{
UtestShell* currentTest = UtestShell::getCurrent();
currentTest->failWith(FailFailure(currentTest, currentTest->getName().asCharString(), currentTest->getLineNumber(), fail_string), TestTerminatorWithoutExceptions());
} // LCOV_EXCL_LINE
};
static MemoryLeakFailure* globalReporter = NULLPTR;
static MemoryLeakDetector* globalDetector = NULLPTR;
MemoryLeakDetector* MemoryLeakWarningPlugin::getGlobalDetector()
{
if (globalDetector == NULLPTR) {
saveAndDisableNewDeleteOverloads();
globalReporter = new MemoryLeakWarningReporter;
globalDetector = new MemoryLeakDetector(globalReporter);
restoreNewDeleteOverloads();
}
return globalDetector;
}
MemoryLeakFailure* MemoryLeakWarningPlugin::getGlobalFailureReporter()
{
return globalReporter;
}
void MemoryLeakWarningPlugin::destroyGlobalDetectorAndTurnOffMemoryLeakDetectionInDestructor(bool des)
{
destroyGlobalDetectorAndTurnOfMemoryLeakDetectionInDestructor_ = des;
}
void MemoryLeakWarningPlugin::setGlobalDetector(MemoryLeakDetector* detector, MemoryLeakFailure* reporter)
{
globalDetector = detector;
globalReporter = reporter;
}
void MemoryLeakWarningPlugin::destroyGlobalDetector()
{
turnOffNewDeleteOverloads();
delete globalDetector;
delete globalReporter;
globalDetector = NULLPTR;
}
MemoryLeakWarningPlugin* MemoryLeakWarningPlugin::firstPlugin_ = NULLPTR;
MemoryLeakWarningPlugin* MemoryLeakWarningPlugin::getFirstPlugin()
{
return firstPlugin_;
}
MemoryLeakDetector* MemoryLeakWarningPlugin::getMemoryLeakDetector()
{
return memLeakDetector_;
}
void MemoryLeakWarningPlugin::ignoreAllLeaksInTest()
{
ignoreAllWarnings_ = true;
}
void MemoryLeakWarningPlugin::expectLeaksInTest(size_t n)
{
expectedLeaks_ = n;
}
MemoryLeakWarningPlugin::MemoryLeakWarningPlugin(const SimpleString& name, MemoryLeakDetector* localDetector) :
TestPlugin(name), ignoreAllWarnings_(false), destroyGlobalDetectorAndTurnOfMemoryLeakDetectionInDestructor_(false), expectedLeaks_(0)
{
if (firstPlugin_ == NULLPTR) firstPlugin_ = this;
if (localDetector) memLeakDetector_ = localDetector;
else memLeakDetector_ = getGlobalDetector();
memLeakDetector_->enable();
}
MemoryLeakWarningPlugin::~MemoryLeakWarningPlugin()
{
if (destroyGlobalDetectorAndTurnOfMemoryLeakDetectionInDestructor_) {
MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
MemoryLeakWarningPlugin::destroyGlobalDetector();
}
}
void MemoryLeakWarningPlugin::preTestAction(UtestShell& /*test*/, TestResult& result)
{
memLeakDetector_->startChecking();
failureCount_ = result.getFailureCount();
}
void MemoryLeakWarningPlugin::postTestAction(UtestShell& test, TestResult& result)
{
memLeakDetector_->stopChecking();
size_t leaks = memLeakDetector_->totalMemoryLeaks(mem_leak_period_checking);
if (!ignoreAllWarnings_ && expectedLeaks_ != leaks && failureCount_ == result.getFailureCount()) {
if(MemoryLeakWarningPlugin::areNewDeleteOverloaded()) {
TestFailure f(&test, memLeakDetector_->report(mem_leak_period_checking));
result.addFailure(f);
} else if(expectedLeaks_ > 0) {
result.print(StringFromFormat("Warning: Expected %d leak(s), but leak detection was disabled", (int) expectedLeaks_).asCharString());
}
}
memLeakDetector_->markCheckingPeriodLeaksAsNonCheckingPeriod();
ignoreAllWarnings_ = false;
expectedLeaks_ = 0;
}
const char* MemoryLeakWarningPlugin::FinalReport(size_t toBeDeletedLeaks)
{
size_t leaks = memLeakDetector_->totalMemoryLeaks(mem_leak_period_enabled);
if (leaks != toBeDeletedLeaks) return memLeakDetector_->report(mem_leak_period_enabled);
return "";
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2014, Michael Feathers, James Grenning, Bas Vodde and Chen YewMing
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/SimpleMutex.h"
SimpleMutex::SimpleMutex(void)
{
psMtx = PlatformSpecificMutexCreate();
}
SimpleMutex::~SimpleMutex(void)
{
PlatformSpecificMutexDestroy(psMtx);
}
void SimpleMutex::Lock(void)
{
PlatformSpecificMutexLock(psMtx);
}
void SimpleMutex::Unlock(void)
{
PlatformSpecificMutexUnlock(psMtx);
}
ScopedMutexLock::ScopedMutexLock(SimpleMutex *mtx) :
mutex(mtx)
{
mutex->Lock();
}
ScopedMutexLock::~ScopedMutexLock()
{
mutex->Unlock();
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,312 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/SimpleStringInternalCache.h"
struct SimpleStringMemoryBlock
{
SimpleStringMemoryBlock* next_;
char* memory_;
};
struct SimpleStringInternalCacheNode
{
size_t size_;
SimpleStringMemoryBlock* freeMemoryHead_;
SimpleStringMemoryBlock* usedMemoryHead_;
};
SimpleStringInternalCache::SimpleStringInternalCache()
: allocator_(defaultMallocAllocator()), cache_(NULLPTR), nonCachedAllocations_(NULLPTR), hasWarnedAboutDeallocations(false)
{
cache_ = createInternalCacheNodes();
}
SimpleStringInternalCache::~SimpleStringInternalCache()
{
allocator_ = defaultMallocAllocator();
destroyInternalCacheNode(cache_);
}
void SimpleStringInternalCache::setAllocator(TestMemoryAllocator* allocator)
{
allocator_ = allocator;
}
SimpleStringInternalCacheNode* SimpleStringInternalCache::createInternalCacheNodes()
{
SimpleStringInternalCacheNode* node = (SimpleStringInternalCacheNode*) (void*) allocator_->alloc_memory(sizeof(SimpleStringInternalCacheNode) * amountOfInternalCacheNodes, __FILE__, __LINE__);
for (int i = 0; i < amountOfInternalCacheNodes; i++) {
node[i].freeMemoryHead_ = NULLPTR;
node[i].usedMemoryHead_ = NULLPTR;
}
node[0].size_ = 32;
node[1].size_ = 64;
node[2].size_ = 96;
node[3].size_ = 128;
node[4].size_ = 256;
return node;
}
bool SimpleStringInternalCache::isCached(size_t size)
{
return size <= 256;
}
size_t SimpleStringInternalCache::getIndexForCache(size_t size)
{
for (size_t i = 0; i < amountOfInternalCacheNodes; i++)
if (size <= cache_[i].size_)
return i;
return 0; // LCOV_EXCL_LINE
}
SimpleStringInternalCacheNode* SimpleStringInternalCache::getCacheNodeFromSize(size_t size)
{
size_t index = getIndexForCache(size);
return &cache_[index];
}
void SimpleStringInternalCache::destroyInternalCacheNode(SimpleStringInternalCacheNode * node)
{
allocator_->free_memory((char*) node, sizeof(SimpleStringInternalCacheNode) * amountOfInternalCacheNodes, __FILE__, __LINE__);
}
SimpleStringMemoryBlock* SimpleStringInternalCache::createSimpleStringMemoryBlock(size_t size, SimpleStringMemoryBlock* next)
{
SimpleStringMemoryBlock* block = (SimpleStringMemoryBlock*) (void*) allocator_->alloc_memory(sizeof(SimpleStringMemoryBlock) , __FILE__, __LINE__);
block->memory_ = allocator_->alloc_memory(size , __FILE__, __LINE__);
block->next_ = next;
return block;
}
void SimpleStringInternalCache::destroySimpleStringMemoryBlock(SimpleStringMemoryBlock * block, size_t size)
{
allocator_->free_memory(block->memory_, size, __FILE__, __LINE__);
allocator_->free_memory((char*) block, sizeof(SimpleStringMemoryBlock), __FILE__, __LINE__);
}
void SimpleStringInternalCache::destroySimpleStringMemoryBlockList(SimpleStringMemoryBlock * block, size_t size)
{
SimpleStringMemoryBlock* current = block;
while (current) {
SimpleStringMemoryBlock* next = current->next_;
destroySimpleStringMemoryBlock(current, size);
current = next;
}
}
SimpleStringMemoryBlock* SimpleStringInternalCache::addToSimpleStringMemoryBlockList(SimpleStringMemoryBlock* newBlock, SimpleStringMemoryBlock* previousHead)
{
newBlock->next_ = previousHead;
return newBlock;
}
bool SimpleStringInternalCache::hasFreeBlocksOfSize(size_t size)
{
return getCacheNodeFromSize(size)->freeMemoryHead_ != NULLPTR;
}
SimpleStringMemoryBlock* SimpleStringInternalCache::reserveCachedBlockFrom(SimpleStringInternalCacheNode* node)
{
SimpleStringMemoryBlock* block = node->freeMemoryHead_;
node->freeMemoryHead_ = block->next_;
node->usedMemoryHead_ = addToSimpleStringMemoryBlockList(block, node->usedMemoryHead_);
return block;
}
SimpleStringMemoryBlock* SimpleStringInternalCache::allocateNewCacheBlockFrom(SimpleStringInternalCacheNode* node)
{
SimpleStringMemoryBlock* block = createSimpleStringMemoryBlock(node->size_, node->usedMemoryHead_);
node->usedMemoryHead_ = addToSimpleStringMemoryBlockList(block, node->usedMemoryHead_);
return block;
}
void SimpleStringInternalCache::printDeallocatingUnknownMemory(char* memory)
{
if (!hasWarnedAboutDeallocations) {
hasWarnedAboutDeallocations = true;
UtestShell::getCurrent()->print(StringFromFormat("\nWARNING: Attempting to deallocate a String buffer that was allocated while not caching. Ignoring it!\n"
"This is likely due statics and will cause problems.\n"
"Only warning once to avoid recursive warnings.\n"
"String we are deallocating: \"%s\"\n", memory).asCharString(), __FILE__, __LINE__);
}
}
void SimpleStringInternalCache::releaseCachedBlockFrom(char* memory, SimpleStringInternalCacheNode* node)
{
if (node->usedMemoryHead_ && node->usedMemoryHead_->memory_ == memory) {
SimpleStringMemoryBlock* block = node->usedMemoryHead_;
node->usedMemoryHead_ = node->usedMemoryHead_->next_;
node->freeMemoryHead_ = addToSimpleStringMemoryBlockList(block, node->freeMemoryHead_);
return;
}
for (SimpleStringMemoryBlock* block = node->usedMemoryHead_; block; block = block->next_) {
if (block->next_ && block->next_->memory_ == memory) {
SimpleStringMemoryBlock* blockToFree = block->next_;
block->next_ = block->next_->next_;
node->freeMemoryHead_ = addToSimpleStringMemoryBlockList(blockToFree, node->freeMemoryHead_);
return;
}
}
printDeallocatingUnknownMemory(memory);
}
void SimpleStringInternalCache::releaseNonCachedMemory(char* memory, size_t size)
{
if (nonCachedAllocations_ && nonCachedAllocations_->memory_ == memory) {
SimpleStringMemoryBlock* block = nonCachedAllocations_;
nonCachedAllocations_ = block->next_;
destroySimpleStringMemoryBlock(block, size);
return;
}
for (SimpleStringMemoryBlock* block = nonCachedAllocations_; block; block = block->next_) {
if (block->next_ && block->next_->memory_ == memory) {
SimpleStringMemoryBlock* blockToFree = block->next_;
block->next_ = block->next_->next_;
destroySimpleStringMemoryBlock(blockToFree, size);
return;
}
}
printDeallocatingUnknownMemory(memory);
}
char* SimpleStringInternalCache::alloc(size_t size)
{
if (isCached(size)) {
if (hasFreeBlocksOfSize(size))
return reserveCachedBlockFrom(getCacheNodeFromSize(size))->memory_;
else
return allocateNewCacheBlockFrom(getCacheNodeFromSize(size))->memory_;
}
nonCachedAllocations_ = createSimpleStringMemoryBlock(size, nonCachedAllocations_);
return nonCachedAllocations_->memory_;
}
void SimpleStringInternalCache::dealloc(char* memory, size_t size)
{
if (isCached(size)) {
size_t index = getIndexForCache(size);
SimpleStringInternalCacheNode* cacheNode = &cache_[index];
releaseCachedBlockFrom(memory, cacheNode);
return;
}
releaseNonCachedMemory(memory, size);
}
void SimpleStringInternalCache::clearCache()
{
for (size_t i = 0; i < amountOfInternalCacheNodes; i++) {
destroySimpleStringMemoryBlockList(cache_[i].freeMemoryHead_, cache_[i].size_);
cache_[i].freeMemoryHead_ = NULLPTR;
}
}
void SimpleStringInternalCache::clearAllIncludingCurrentlyUsedMemory()
{
for (size_t i = 0; i < amountOfInternalCacheNodes; i++) {
destroySimpleStringMemoryBlockList(cache_[i].freeMemoryHead_, cache_[i].size_);
destroySimpleStringMemoryBlockList(cache_[i].usedMemoryHead_, cache_[i].size_);
cache_[i].freeMemoryHead_ = NULLPTR;
cache_[i].usedMemoryHead_ = NULLPTR;
}
destroySimpleStringMemoryBlockList(nonCachedAllocations_, 0);
nonCachedAllocations_ = NULLPTR;
}
GlobalSimpleStringCache::GlobalSimpleStringCache()
{
allocator_ = new SimpleStringCacheAllocator(cache_, SimpleString::getStringAllocator());
SimpleString::setStringAllocator(allocator_);
}
GlobalSimpleStringCache::~GlobalSimpleStringCache()
{
SimpleString::setStringAllocator(allocator_->originalAllocator());
cache_.clearAllIncludingCurrentlyUsedMemory();
delete allocator_;
}
TestMemoryAllocator* GlobalSimpleStringCache::getAllocator()
{
return allocator_;
}
SimpleStringCacheAllocator::SimpleStringCacheAllocator(SimpleStringInternalCache& cache, TestMemoryAllocator* origAllocator)
: cache_(cache), originalAllocator_(origAllocator)
{
cache_.setAllocator(origAllocator);
}
SimpleStringCacheAllocator::~SimpleStringCacheAllocator()
{
cache_.setAllocator(NULLPTR);
}
char* SimpleStringCacheAllocator::alloc_memory(size_t size, const char*, size_t)
{
return cache_.alloc(size);
}
void SimpleStringCacheAllocator::free_memory(char* memory, size_t size, const char*, size_t)
{
cache_.dealloc(memory, size);
}
const char* SimpleStringCacheAllocator::name() const
{
return "SimpleStringCacheAllocator";
}
const char* SimpleStringCacheAllocator::alloc_name() const
{
return originalAllocator_->alloc_name();
}
const char* SimpleStringCacheAllocator::free_name() const
{
return originalAllocator_->free_name();
}
TestMemoryAllocator* SimpleStringCacheAllocator::actualAllocator()
{
return originalAllocator_->actualAllocator();
}
TestMemoryAllocator* SimpleStringCacheAllocator::originalAllocator()
{
return originalAllocator_;
}

View file

@ -0,0 +1,100 @@
#include "CppUTest/TestHarness.h"
#include "CppUTest/TeamCityTestOutput.h"
TeamCityTestOutput::TeamCityTestOutput() : currtest_(NULLPTR), currGroup_()
{
}
TeamCityTestOutput::~TeamCityTestOutput()
{
}
void TeamCityTestOutput::printCurrentTestStarted(const UtestShell& test)
{
print("##teamcity[testStarted name='");
printEscaped(test.getName().asCharString());
print("']\n");
if (!test.willRun()) {
print("##teamcity[testIgnored name='");
printEscaped(test.getName().asCharString());
print("']\n");
}
currtest_ = &test;
}
void TeamCityTestOutput::printCurrentTestEnded(const TestResult& res)
{
if (!currtest_)
return;
print("##teamcity[testFinished name='");
printEscaped(currtest_->getName().asCharString());
print("' duration='");
print(res.getCurrentTestTotalExecutionTime());
print("']\n");
}
void TeamCityTestOutput::printCurrentGroupStarted(const UtestShell& test)
{
currGroup_ = test.getGroup();
print("##teamcity[testSuiteStarted name='");
printEscaped(currGroup_.asCharString());
print("']\n");
}
void TeamCityTestOutput::printCurrentGroupEnded(const TestResult& /*res*/)
{
if (currGroup_ == "")
return;
print("##teamcity[testSuiteFinished name='");
printEscaped(currGroup_.asCharString());
print("']\n");
}
void TeamCityTestOutput::printEscaped(const char* s)
{
while (*s) {
char str[3];
if ((*s == '\'') || (*s == '|') || (*s == '[') || (*s == ']')) {
str[0] = '|';
str[1] = *s;
str[2] = 0;
} else if (*s == '\r') {
str[0] = '|';
str[1] = 'r';
str[2] = 0;
} else if (*s == '\n') {
str[0] = '|';
str[1] = 'n';
str[2] = 0;
} else {
str[0] = *s;
str[1] = 0;
}
printBuffer(str);
s++;
}
}
void TeamCityTestOutput::printFailure(const TestFailure& failure)
{
print("##teamcity[testFailed name='");
printEscaped(failure.getTestNameOnly().asCharString());
print("' message='");
if (failure.isOutsideTestFile() || failure.isInHelperFunction()) {
print("TEST failed (");
print(failure.getTestFileName().asCharString());
print(":");
print(failure.getTestLineNumber());
print("): ");
}
printEscaped(failure.getFileName().asCharString());
print(":");
print(failure.getFailureLineNumber());
print("' details='");
printEscaped(failure.getMessage().asCharString());
print("']\n");
}

View file

@ -0,0 +1,380 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestFailure.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/SimpleString.h"
#include "CppUTest/PlatformSpecificFunctions.h"
TestFailure::TestFailure(UtestShell* test, const char* fileName, size_t lineNumber, const SimpleString& theMessage) :
testName_(test->getFormattedName()), testNameOnly_(test->getName()), fileName_(fileName), lineNumber_(lineNumber), testFileName_(test->getFile()), testLineNumber_(test->getLineNumber()), message_(theMessage)
{
}
TestFailure::TestFailure(UtestShell* test, const SimpleString& theMessage) :
testName_(test->getFormattedName()), testNameOnly_(test->getName()), fileName_(test->getFile()), lineNumber_(test->getLineNumber()), testFileName_(test->getFile()), testLineNumber_(test->getLineNumber()), message_(theMessage)
{
}
TestFailure::TestFailure(UtestShell* test, const char* fileName, size_t lineNum) :
testName_(test->getFormattedName()), testNameOnly_(test->getName()), fileName_(fileName), lineNumber_(lineNum), testFileName_(test->getFile()), testLineNumber_(test->getLineNumber()), message_("no message")
{
}
TestFailure::TestFailure(const TestFailure& f) :
testName_(f.testName_), testNameOnly_(f.testNameOnly_), fileName_(f.fileName_), lineNumber_(f.lineNumber_), testFileName_(f.testFileName_), testLineNumber_(f.testLineNumber_), message_(f.message_)
{
}
TestFailure::~TestFailure()
{
}
SimpleString TestFailure::getFileName() const
{
return fileName_;
}
SimpleString TestFailure::getTestFileName() const
{
return testFileName_;
}
SimpleString TestFailure::getTestName() const
{
return testName_;
}
SimpleString TestFailure::getTestNameOnly() const
{
return testNameOnly_;
}
size_t TestFailure::getFailureLineNumber() const
{
return lineNumber_;
}
size_t TestFailure::getTestLineNumber() const
{
return testLineNumber_;
}
SimpleString TestFailure::getMessage() const
{
return message_;
}
bool TestFailure::isOutsideTestFile() const
{
return testFileName_ != fileName_;
}
bool TestFailure::isInHelperFunction() const
{
return lineNumber_ < testLineNumber_;
}
SimpleString TestFailure::createButWasString(const SimpleString& expected, const SimpleString& actual)
{
return StringFromFormat("expected <%s>\n\tbut was <%s>", expected.asCharString(), actual.asCharString());
}
SimpleString TestFailure::createDifferenceAtPosString(const SimpleString& actual, size_t offset, size_t reportedPosition)
{
SimpleString result;
const size_t extraCharactersWindow = 20;
const size_t halfOfExtraCharactersWindow = extraCharactersWindow / 2;
SimpleString paddingForPreventingOutOfBounds (" ", halfOfExtraCharactersWindow);
SimpleString actualString = paddingForPreventingOutOfBounds + actual + paddingForPreventingOutOfBounds;
SimpleString differentString = StringFromFormat("difference starts at position %lu at: <", (unsigned long) reportedPosition);
result += "\n";
result += StringFromFormat("\t%s%s>\n", differentString.asCharString(), actualString.subString(offset, extraCharactersWindow).asCharString());
result += StringFromFormat("\t%s^", SimpleString(" ", (differentString.size() + halfOfExtraCharactersWindow)).asCharString());
return result;
}
SimpleString TestFailure::createUserText(const SimpleString& text)
{
SimpleString userMessage = "";
if (!text.isEmpty())
{
//This is a kludge to turn off "Message: " for this case.
//I don't think "Message: " adds anything, as you get to see the
//message. I propose we remove "Message: " lead in
if (!text.startsWith("LONGS_EQUAL"))
userMessage += "Message: ";
userMessage += text;
userMessage += "\n\t";
}
return userMessage;
}
EqualsFailure::EqualsFailure(UtestShell* test, const char* fileName, size_t lineNumber, const char* expected, const char* actual, const SimpleString& text) :
TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
message_ += createButWasString(StringFromOrNull(expected), StringFromOrNull(actual));
}
EqualsFailure::EqualsFailure(UtestShell* test, const char* fileName, size_t lineNumber, const SimpleString& expected, const SimpleString& actual, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
message_ += createButWasString(expected, actual);
}
DoublesEqualFailure::DoublesEqualFailure(UtestShell* test, const char* fileName, size_t lineNumber, double expected, double actual, double threshold, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
message_ += createButWasString(StringFrom(expected, 7), StringFrom(actual, 7));
message_ += " threshold used was <";
message_ += StringFrom(threshold, 7);
message_ += ">";
if (PlatformSpecificIsNan(expected) || PlatformSpecificIsNan(actual) || PlatformSpecificIsNan(threshold))
message_ += "\n\tCannot make comparisons with Nan";
}
CheckEqualFailure::CheckEqualFailure(UtestShell* test, const char* fileName, size_t lineNumber, const SimpleString& expected, const SimpleString& actual, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
SimpleString printableExpected = PrintableStringFromOrNull(expected.asCharString());
SimpleString printableActual = PrintableStringFromOrNull(actual.asCharString());
message_ += createButWasString(printableExpected, printableActual);
size_t failStart;
for (failStart = 0; actual.at(failStart) == expected.at(failStart); failStart++)
;
size_t failStartPrintable;
for (failStartPrintable = 0; printableActual.at(failStartPrintable) == printableExpected.at(failStartPrintable); failStartPrintable++)
;
message_ += createDifferenceAtPosString(printableActual, failStartPrintable, failStart);
}
ComparisonFailure::ComparisonFailure(UtestShell *test, const char *fileName, size_t lineNumber, const SimpleString& checkString, const SimpleString &comparisonString, const SimpleString &text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
message_ += checkString;
message_ += "(";
message_ += comparisonString;
message_ += ") failed";
}
ContainsFailure::ContainsFailure(UtestShell* test, const char* fileName, size_t lineNumber, const SimpleString& expected, const SimpleString& actual, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
message_ += StringFromFormat("actual <%s>\n\tdid not contain <%s>", actual.asCharString(), expected.asCharString());
}
CheckFailure::CheckFailure(UtestShell* test, const char* fileName, size_t lineNumber, const SimpleString& checkString, const SimpleString& conditionString, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
message_ += checkString;
message_ += "(";
message_ += conditionString;
message_ += ") failed";
}
FailFailure::FailFailure(UtestShell* test, const char* fileName, size_t lineNumber, const SimpleString& message) : TestFailure(test, fileName, lineNumber)
{
message_ = message;
}
LongsEqualFailure::LongsEqualFailure(UtestShell* test, const char* fileName, size_t lineNumber, long expected, long actual, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
SimpleString aDecimal = StringFrom(actual);
SimpleString eDecimal = StringFrom(expected);
SimpleString::padStringsToSameLength(aDecimal, eDecimal, ' ');
SimpleString actualReported = aDecimal + " " + BracketsFormattedHexStringFrom(actual);
SimpleString expectedReported = eDecimal + " " + BracketsFormattedHexStringFrom(expected);
message_ += createButWasString(expectedReported, actualReported);
}
UnsignedLongsEqualFailure::UnsignedLongsEqualFailure(UtestShell* test, const char* fileName, size_t lineNumber, unsigned long expected, unsigned long actual, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
SimpleString aDecimal = StringFrom(actual);
SimpleString eDecimal = StringFrom(expected);
SimpleString::padStringsToSameLength(aDecimal, eDecimal, ' ');
SimpleString actualReported = aDecimal + " " + BracketsFormattedHexStringFrom(actual);
SimpleString expectedReported = eDecimal + " " + BracketsFormattedHexStringFrom(expected);
message_ += createButWasString(expectedReported, actualReported);
}
LongLongsEqualFailure::LongLongsEqualFailure(UtestShell* test, const char* fileName, size_t lineNumber, cpputest_longlong expected, cpputest_longlong actual, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
SimpleString aDecimal = StringFrom(actual);
SimpleString eDecimal = StringFrom(expected);
SimpleString::padStringsToSameLength(aDecimal, eDecimal, ' ');
SimpleString actualReported = aDecimal + " " + BracketsFormattedHexStringFrom(actual);
SimpleString expectedReported = eDecimal + " " + BracketsFormattedHexStringFrom(expected);
message_ += createButWasString(expectedReported, actualReported);
}
UnsignedLongLongsEqualFailure::UnsignedLongLongsEqualFailure(UtestShell* test, const char* fileName, size_t lineNumber, cpputest_ulonglong expected, cpputest_ulonglong actual, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
SimpleString aDecimal = StringFrom(actual);
SimpleString eDecimal = StringFrom(expected);
SimpleString::padStringsToSameLength(aDecimal, eDecimal, ' ');
SimpleString actualReported = aDecimal + " " + BracketsFormattedHexStringFrom(actual);
SimpleString expectedReported = eDecimal + " " + BracketsFormattedHexStringFrom(expected);
message_ += createButWasString(expectedReported, actualReported);
}
SignedBytesEqualFailure::SignedBytesEqualFailure (UtestShell* test, const char* fileName, size_t lineNumber, signed char expected, signed char actual, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
SimpleString aDecimal = StringFrom((int)actual);
SimpleString eDecimal = StringFrom((int)expected);
SimpleString::padStringsToSameLength(aDecimal, eDecimal, ' ');
SimpleString actualReported = aDecimal + " " + BracketsFormattedHexStringFrom(actual);
SimpleString expectedReported = eDecimal + " " + BracketsFormattedHexStringFrom(expected);
message_ += createButWasString(expectedReported, actualReported);
}
StringEqualFailure::StringEqualFailure(UtestShell* test, const char* fileName, size_t lineNumber, const char* expected, const char* actual, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
SimpleString printableExpected = PrintableStringFromOrNull(expected);
SimpleString printableActual = PrintableStringFromOrNull(actual);
message_ += createButWasString(printableExpected, printableActual);
if((expected) && (actual))
{
size_t failStart;
for (failStart = 0; actual[failStart] == expected[failStart]; failStart++)
;
size_t failStartPrintable;
for (failStartPrintable = 0; printableActual.at(failStartPrintable) == printableExpected.at(failStartPrintable); failStartPrintable++)
;
message_ += createDifferenceAtPosString(printableActual, failStartPrintable, failStart);
}
}
StringEqualNoCaseFailure::StringEqualNoCaseFailure(UtestShell* test, const char* fileName, size_t lineNumber, const char* expected, const char* actual, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
SimpleString printableExpected = PrintableStringFromOrNull(expected);
SimpleString printableActual = PrintableStringFromOrNull(actual);
message_ += createButWasString(printableExpected, printableActual);
if((expected) && (actual))
{
size_t failStart;
for (failStart = 0; SimpleString::ToLower(actual[failStart]) == SimpleString::ToLower(expected[failStart]); failStart++)
;
size_t failStartPrintable;
for (failStartPrintable = 0;
SimpleString::ToLower(printableActual.at(failStartPrintable)) == SimpleString::ToLower(printableExpected.at(failStartPrintable));
failStartPrintable++)
;
message_ += createDifferenceAtPosString(printableActual, failStartPrintable, failStart);
}
}
BinaryEqualFailure::BinaryEqualFailure(UtestShell* test, const char* fileName, size_t lineNumber, const unsigned char* expected,
const unsigned char* actual, size_t size, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
SimpleString actualHex = StringFromBinaryOrNull(actual, size);
message_ += createButWasString(StringFromBinaryOrNull(expected, size), actualHex);
if ((expected) && (actual))
{
size_t failStart;
for (failStart = 0; actual[failStart] == expected[failStart]; failStart++)
;
message_ += createDifferenceAtPosString(actualHex, (failStart * 3 + 1), failStart);
}
}
BitsEqualFailure::BitsEqualFailure(UtestShell* test, const char* fileName, size_t lineNumber, unsigned long expected, unsigned long actual,
unsigned long mask, size_t byteCount, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
message_ += createButWasString(StringFromMaskedBits(expected, mask, byteCount), StringFromMaskedBits(actual, mask, byteCount));
}
FeatureUnsupportedFailure::FeatureUnsupportedFailure(UtestShell* test, const char* fileName, size_t lineNumber,
const SimpleString& featureName, const SimpleString& text)
: TestFailure(test, fileName, lineNumber)
{
message_ = createUserText(text);
message_ += StringFromFormat("The feature \"%s\" is not supported in this environment or with the feature set selected when building the library.", featureName.asCharString());
}

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/CppUTestConfig.h"
#include "CppUTest/TestFilter.h"
TestFilter::TestFilter() : strictMatching_(false), invertMatching_(false), next_(NULLPTR)
{
}
TestFilter::TestFilter(const SimpleString& filter) : strictMatching_(false), invertMatching_(false), next_(NULLPTR)
{
filter_ = filter;
}
TestFilter::TestFilter(const char* filter) : strictMatching_(false), invertMatching_(false), next_(NULLPTR)
{
filter_ = filter;
}
TestFilter* TestFilter::add(TestFilter* filter)
{
next_ = filter;
return this;
}
TestFilter* TestFilter::getNext() const
{
return next_;
}
void TestFilter::strictMatching()
{
strictMatching_ = true;
}
void TestFilter::invertMatching()
{
invertMatching_ = true;
}
bool TestFilter::match(const SimpleString& name) const
{
bool matches = false;
if(strictMatching_)
matches = name == filter_;
else
matches = name.contains(filter_);
return invertMatching_ ? !matches : matches;
}
bool TestFilter::operator==(const TestFilter& filter) const
{
return (filter_ == filter.filter_ &&
strictMatching_ == filter.strictMatching_ &&
invertMatching_ == filter.invertMatching_);
}
bool TestFilter::operator!=(const TestFilter& filter) const
{
return !(filter == *this);
}
SimpleString TestFilter::asString() const
{
SimpleString textFilter = StringFromFormat("TestFilter: \"%s\"", filter_.asCharString());
if (strictMatching_ && invertMatching_)
textFilter += " with strict, invert matching";
else if (strictMatching_)
textFilter += " with strict matching";
else if (invertMatching_)
textFilter += " with invert matching";
return textFilter;
}
SimpleString StringFrom(const TestFilter& filter)
{
return filter.asString();
}

View file

@ -0,0 +1,258 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/MemoryLeakDetector.h"
#include "CppUTest/TestMemoryAllocator.h"
#include "CppUTest/PlatformSpecificFunctions.h"
#include "CppUTest/TestHarness_c.h"
extern "C"
{
void CHECK_EQUAL_C_BOOL_LOCATION(int expected, int actual, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertEquals(!!expected != !!actual, expected ? "true" : "false", actual ? "true" : "false", text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void CHECK_EQUAL_C_INT_LOCATION(int expected, int actual, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertLongsEqual((long)expected, (long)actual, text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void CHECK_EQUAL_C_UINT_LOCATION(unsigned int expected, unsigned int actual, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertUnsignedLongsEqual((unsigned long)expected, (unsigned long)actual, text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void CHECK_EQUAL_C_LONG_LOCATION(long expected, long actual, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertLongsEqual(expected, actual, text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void CHECK_EQUAL_C_ULONG_LOCATION(unsigned long expected, unsigned long actual, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertUnsignedLongsEqual(expected, actual, text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void CHECK_EQUAL_C_LONGLONG_LOCATION(cpputest_longlong expected, cpputest_longlong actual, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertLongLongsEqual(expected, actual, text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void CHECK_EQUAL_C_ULONGLONG_LOCATION(cpputest_ulonglong expected, cpputest_ulonglong actual, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertUnsignedLongLongsEqual(expected, actual, text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void CHECK_EQUAL_C_REAL_LOCATION(double expected, double actual, double threshold, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertDoublesEqual(expected, actual, threshold, text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void CHECK_EQUAL_C_CHAR_LOCATION(char expected, char actual, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertEquals(((expected) != (actual)), StringFrom(expected).asCharString(), StringFrom(actual).asCharString(), text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
extern void CHECK_EQUAL_C_UBYTE_LOCATION(unsigned char expected, unsigned char actual, const char* text, const char* fileName, size_t lineNumber)\
{
UtestShell::getCurrent()->assertEquals(((expected) != (actual)),StringFrom((int)expected).asCharString(), StringFrom((int) actual).asCharString(), text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void CHECK_EQUAL_C_SBYTE_LOCATION(char signed expected, signed char actual, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertEquals(((expected) != (actual)),StringFrom((int)expected).asCharString(), StringFrom((int) actual).asCharString(), text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void CHECK_EQUAL_C_STRING_LOCATION(const char* expected, const char* actual, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertCstrEqual(expected, actual, text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void CHECK_EQUAL_C_POINTER_LOCATION(const void* expected, const void* actual, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertPointersEqual(expected, actual, text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
extern void CHECK_EQUAL_C_BITS_LOCATION(unsigned int expected, unsigned int actual, unsigned int mask, size_t size, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertBitsEqual(expected, actual, mask, size, text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
void FAIL_TEXT_C_LOCATION(const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->fail(text, fileName, lineNumber, TestTerminatorWithoutExceptions());
} // LCOV_EXCL_LINE
void FAIL_C_LOCATION(const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->fail("", fileName, lineNumber, TestTerminatorWithoutExceptions());
} // LCOV_EXCL_LINE
void CHECK_C_LOCATION(int condition, const char* conditionString, const char* text, const char* fileName, size_t lineNumber)
{
UtestShell::getCurrent()->assertTrue(condition != 0, "CHECK_C", conditionString, text, fileName, lineNumber, TestTerminatorWithoutExceptions());
}
enum { NO_COUNTDOWN = -1, OUT_OF_MEMORRY = 0 };
static int malloc_out_of_memory_counter = NO_COUNTDOWN;
static int malloc_count = 0;
void cpputest_malloc_count_reset(void)
{
malloc_count = 0;
}
int cpputest_malloc_get_count()
{
return malloc_count;
}
static TestMemoryAllocator* originalAllocator = NULLPTR;
void cpputest_malloc_set_out_of_memory()
{
if (originalAllocator == NULLPTR)
originalAllocator = getCurrentMallocAllocator();
setCurrentMallocAllocator(NullUnknownAllocator::defaultAllocator());
}
void cpputest_malloc_set_not_out_of_memory()
{
malloc_out_of_memory_counter = NO_COUNTDOWN;
setCurrentMallocAllocator(originalAllocator);
originalAllocator = NULLPTR;
}
void cpputest_malloc_set_out_of_memory_countdown(int count)
{
malloc_out_of_memory_counter = count;
if (malloc_out_of_memory_counter == OUT_OF_MEMORRY)
cpputest_malloc_set_out_of_memory();
}
void* cpputest_malloc(size_t size)
{
return cpputest_malloc_location(size, "<unknown>", 0);
}
char* cpputest_strdup(const char* str)
{
return cpputest_strdup_location(str, "<unknown>", 0);
}
char* cpputest_strndup(const char* str, size_t n)
{
return cpputest_strndup_location(str, n, "<unknown>", 0);
}
void* cpputest_calloc(size_t num, size_t size)
{
return cpputest_calloc_location(num, size, "<unknown>", 0);
}
void* cpputest_realloc(void* ptr, size_t size)
{
return cpputest_realloc_location(ptr, size, "<unknown>", 0);
}
void cpputest_free(void* buffer)
{
cpputest_free_location(buffer, "<unknown>", 0);
}
static void countdown()
{
if (malloc_out_of_memory_counter <= NO_COUNTDOWN)
return;
if (malloc_out_of_memory_counter == OUT_OF_MEMORRY)
return;
malloc_out_of_memory_counter--;
if (malloc_out_of_memory_counter == OUT_OF_MEMORRY)
cpputest_malloc_set_out_of_memory();
}
void* cpputest_malloc_location(size_t size, const char* file, size_t line)
{
countdown();
malloc_count++;
return cpputest_malloc_location_with_leak_detection(size, file, line);
}
static size_t test_harness_c_strlen(const char * str)
{
size_t n = 0;
while (*str++) n++;
return n;
}
static char* strdup_alloc(const char * str, size_t size, const char* file, size_t line)
{
char* result = (char*) cpputest_malloc_location(size, file, line);
PlatformSpecificMemCpy(result, str, size);
result[size-1] = '\0';
return result;
}
char* cpputest_strdup_location(const char * str, const char* file, size_t line)
{
size_t length = 1 + test_harness_c_strlen(str);
return strdup_alloc(str, length, file, line);
}
char* cpputest_strndup_location(const char * str, size_t n, const char* file, size_t line)
{
size_t length = test_harness_c_strlen(str);
length = length < n ? length : n;
length = length + 1;
return strdup_alloc(str, length, file, line);
}
void* cpputest_calloc_location(size_t num, size_t size, const char* file, size_t line)
{
void* mem = cpputest_malloc_location(num * size, file, line);
if (mem)
PlatformSpecificMemset(mem, 0, num*size);
return mem;
}
void* cpputest_realloc_location(void* memory, size_t size, const char* file, size_t line)
{
return cpputest_realloc_location_with_leak_detection(memory, size, file, line);
}
void cpputest_free_location(void* buffer, const char* file, size_t line)
{
cpputest_free_location_with_leak_detection(buffer, file, line);
}
}

View file

@ -0,0 +1,792 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestMemoryAllocator.h"
#include "CppUTest/PlatformSpecificFunctions.h"
#include "CppUTest/MemoryLeakDetector.h"
static char* checkedMalloc(size_t size)
{
char* mem = (char*) PlatformSpecificMalloc(size);
if (mem == NULLPTR)
FAIL("malloc returned null pointer");
return mem;
}
static TestMemoryAllocator* currentNewAllocator = NULLPTR;
static TestMemoryAllocator* currentNewArrayAllocator = NULLPTR;
static TestMemoryAllocator* currentMallocAllocator = NULLPTR;
void setCurrentNewAllocator(TestMemoryAllocator* allocator)
{
currentNewAllocator = allocator;
}
TestMemoryAllocator* getCurrentNewAllocator()
{
if (currentNewAllocator == NULLPTR) setCurrentNewAllocatorToDefault();
return currentNewAllocator;
}
void setCurrentNewAllocatorToDefault()
{
currentNewAllocator = defaultNewAllocator();
}
TestMemoryAllocator* defaultNewAllocator()
{
static TestMemoryAllocator allocator("Standard New Allocator", "new", "delete");
return &allocator;
}
void setCurrentNewArrayAllocator(TestMemoryAllocator* allocator)
{
currentNewArrayAllocator = allocator;
}
TestMemoryAllocator* getCurrentNewArrayAllocator()
{
if (currentNewArrayAllocator == NULLPTR) setCurrentNewArrayAllocatorToDefault();
return currentNewArrayAllocator;
}
void setCurrentNewArrayAllocatorToDefault()
{
currentNewArrayAllocator = defaultNewArrayAllocator();
}
TestMemoryAllocator* defaultNewArrayAllocator()
{
static TestMemoryAllocator allocator("Standard New [] Allocator", "new []", "delete []");
return &allocator;
}
void setCurrentMallocAllocator(TestMemoryAllocator* allocator)
{
currentMallocAllocator = allocator;
}
TestMemoryAllocator* getCurrentMallocAllocator()
{
if (currentMallocAllocator == NULLPTR) setCurrentMallocAllocatorToDefault();
return currentMallocAllocator;
}
void setCurrentMallocAllocatorToDefault()
{
currentMallocAllocator = defaultMallocAllocator();
}
TestMemoryAllocator* defaultMallocAllocator()
{
static TestMemoryAllocator allocator("Standard Malloc Allocator", "malloc", "free");
return &allocator;
}
/////////////////////////////////////////////
GlobalMemoryAllocatorStash::GlobalMemoryAllocatorStash()
: originalMallocAllocator(NULLPTR), originalNewAllocator(NULLPTR), originalNewArrayAllocator(NULLPTR)
{
}
void GlobalMemoryAllocatorStash::save()
{
originalMallocAllocator = getCurrentMallocAllocator();
originalNewAllocator = getCurrentNewAllocator();
originalNewArrayAllocator = getCurrentNewArrayAllocator();
}
void GlobalMemoryAllocatorStash::restore()
{
if (originalMallocAllocator) setCurrentMallocAllocator(originalMallocAllocator);
if (originalNewAllocator) setCurrentNewAllocator(originalNewAllocator);
if (originalNewArrayAllocator) setCurrentNewArrayAllocator(originalNewArrayAllocator);
}
TestMemoryAllocator::TestMemoryAllocator(const char* name_str, const char* alloc_name_str, const char* free_name_str)
: name_(name_str), alloc_name_(alloc_name_str), free_name_(free_name_str), hasBeenDestroyed_(false)
{
}
TestMemoryAllocator::~TestMemoryAllocator()
{
hasBeenDestroyed_ = true;
}
bool TestMemoryAllocator::hasBeenDestroyed()
{
return hasBeenDestroyed_;
}
bool TestMemoryAllocator::isOfEqualType(TestMemoryAllocator* allocator)
{
return SimpleString::StrCmp(this->name(), allocator->name()) == 0;
}
char* TestMemoryAllocator::allocMemoryLeakNode(size_t size)
{
return alloc_memory(size, "MemoryLeakNode", 1);
}
void TestMemoryAllocator::freeMemoryLeakNode(char* memory)
{
free_memory(memory, 0, "MemoryLeakNode", 1);
}
char* TestMemoryAllocator::alloc_memory(size_t size, const char*, size_t)
{
return checkedMalloc(size);
}
void TestMemoryAllocator::free_memory(char* memory, size_t, const char*, size_t)
{
PlatformSpecificFree(memory);
}
const char* TestMemoryAllocator::name() const
{
return name_;
}
const char* TestMemoryAllocator::alloc_name() const
{
return alloc_name_;
}
const char* TestMemoryAllocator::free_name() const
{
return free_name_;
}
TestMemoryAllocator* TestMemoryAllocator::actualAllocator()
{
return this;
}
MemoryLeakAllocator::MemoryLeakAllocator(TestMemoryAllocator* originalAllocator)
: originalAllocator_(originalAllocator)
{
}
MemoryLeakAllocator::~MemoryLeakAllocator()
{
}
char* MemoryLeakAllocator::alloc_memory(size_t size, const char* file, size_t line)
{
return MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(originalAllocator_, size, file, line);
}
void MemoryLeakAllocator::free_memory(char* memory, size_t, const char* file, size_t line)
{
MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(originalAllocator_, memory, file, line);
}
const char* MemoryLeakAllocator::name() const
{
return "MemoryLeakAllocator";
}
const char* MemoryLeakAllocator::alloc_name() const
{
return originalAllocator_->alloc_name();
}
const char* MemoryLeakAllocator::free_name() const
{
return originalAllocator_->free_name();
}
TestMemoryAllocator* MemoryLeakAllocator::actualAllocator()
{
return originalAllocator_->actualAllocator();
}
CrashOnAllocationAllocator::CrashOnAllocationAllocator() : allocationToCrashOn_(0)
{
}
CrashOnAllocationAllocator::~CrashOnAllocationAllocator()
{
}
void CrashOnAllocationAllocator::setNumberToCrashOn(unsigned allocationToCrashOn)
{
allocationToCrashOn_ = allocationToCrashOn;
}
char* CrashOnAllocationAllocator::alloc_memory(size_t size, const char* file, size_t line)
{
if (MemoryLeakWarningPlugin::getGlobalDetector()->getCurrentAllocationNumber() == allocationToCrashOn_)
UT_CRASH();
return TestMemoryAllocator::alloc_memory(size, file, line);
}
NullUnknownAllocator::~NullUnknownAllocator()
{
}
char* NullUnknownAllocator::alloc_memory(size_t /*size*/, const char*, size_t)
{
return NULLPTR;
}
void NullUnknownAllocator::free_memory(char* /*memory*/, size_t, const char*, size_t)
{
}
NullUnknownAllocator::NullUnknownAllocator()
: TestMemoryAllocator("Null Allocator", "unknown", "unknown")
{
}
TestMemoryAllocator* NullUnknownAllocator::defaultAllocator()
{
static NullUnknownAllocator allocator;
return &allocator;
}
class LocationToFailAllocNode
{
public:
int allocNumberToFail_;
int actualAllocNumber_;
const char* file_;
size_t line_;
LocationToFailAllocNode* next_;
void failAtAllocNumber(int number, LocationToFailAllocNode* next)
{
init(next);
allocNumberToFail_ = number;
}
void failNthAllocAt(int allocationNumber, const char* file, size_t line, LocationToFailAllocNode* next)
{
init(next);
allocNumberToFail_ = allocationNumber;
file_ = file;
line_ = line;
}
bool shouldFail(int allocationNumber, const char* file, size_t line)
{
if (file_ && SimpleString::StrCmp(file, file_) == 0 && line == line_) {
actualAllocNumber_++;
return actualAllocNumber_ == allocNumberToFail_;
}
if (allocationNumber == allocNumberToFail_)
return true;
return false;
}
private:
void init(LocationToFailAllocNode* next = NULLPTR)
{
allocNumberToFail_ = 0;
actualAllocNumber_ = 0;
file_ = NULLPTR;
line_ = 0;
next_ = next;
}
};
FailableMemoryAllocator::~FailableMemoryAllocator()
{
}
FailableMemoryAllocator::FailableMemoryAllocator(const char* name_str, const char* alloc_name_str, const char* free_name_str)
: TestMemoryAllocator(name_str, alloc_name_str, free_name_str), head_(NULLPTR), currentAllocNumber_(0)
{
}
void FailableMemoryAllocator::failAllocNumber(int number)
{
LocationToFailAllocNode* newNode = (LocationToFailAllocNode*) (void*) allocMemoryLeakNode(sizeof(LocationToFailAllocNode));
newNode->failAtAllocNumber(number, head_);
head_ = newNode;
}
void FailableMemoryAllocator::failNthAllocAt(int allocationNumber, const char* file, size_t line)
{
LocationToFailAllocNode* newNode = (LocationToFailAllocNode*) (void*) allocMemoryLeakNode(sizeof(LocationToFailAllocNode));
newNode->failNthAllocAt(allocationNumber, file, line, head_);
head_ = newNode;
}
char* FailableMemoryAllocator::alloc_memory(size_t size, const char* file, size_t line)
{
currentAllocNumber_++;
LocationToFailAllocNode* current = head_;
LocationToFailAllocNode* previous = NULLPTR;
while (current) {
if (current->shouldFail(currentAllocNumber_, file, line)) {
if (previous) previous->next_ = current->next_;
else head_ = current->next_;
free_memory((char*) current, size, __FILE__, __LINE__);
return NULLPTR;
}
previous = current;
current = current->next_;
}
return TestMemoryAllocator::alloc_memory(size, file, line);
}
char* FailableMemoryAllocator::allocMemoryLeakNode(size_t size)
{
return (char*)PlatformSpecificMalloc(size);
}
void FailableMemoryAllocator::checkAllFailedAllocsWereDone()
{
if (head_) {
UtestShell* currentTest = UtestShell::getCurrent();
SimpleString failText;
if (head_->file_)
failText = StringFromFormat("Expected failing alloc at %s:%d was never done", head_->file_, (int) head_->line_);
else
failText = StringFromFormat("Expected allocation number %d was never done", (int) head_->allocNumberToFail_);
currentTest->failWith(FailFailure(currentTest, currentTest->getName().asCharString(), currentTest->getLineNumber(), failText));
}
}
void FailableMemoryAllocator::clearFailedAllocs()
{
LocationToFailAllocNode* current = head_;
while (current) {
head_ = current->next_;
free_memory((char*) current, 0, __FILE__, __LINE__);
current = head_;
}
currentAllocNumber_ = 0;
}
struct MemoryAccountantAllocationNode
{
size_t size_;
size_t allocations_;
size_t deallocations_;
size_t maxAllocations_;
size_t currentAllocations_;
MemoryAccountantAllocationNode* next_;
};
MemoryAccountantAllocationNode* MemoryAccountant::createNewAccountantAllocationNode(size_t size, MemoryAccountantAllocationNode* next) const
{
MemoryAccountantAllocationNode* node = (MemoryAccountantAllocationNode*) (void*) allocator_->alloc_memory(sizeof(MemoryAccountantAllocationNode), __FILE__, __LINE__);
node->size_ = size;
node->allocations_ = 0;
node->deallocations_ = 0;
node->maxAllocations_ = 0;
node->currentAllocations_ = 0;
node->next_ = next;
return node;
}
void MemoryAccountant::destroyAccountantAllocationNode(MemoryAccountantAllocationNode* node) const
{
allocator_->free_memory((char*) node, sizeof(node), __FILE__, __LINE__);
}
MemoryAccountant::MemoryAccountant()
: head_(NULLPTR), allocator_(defaultMallocAllocator()), useCacheSizes_(false)
{
}
MemoryAccountant::~MemoryAccountant()
{
clear();
}
void MemoryAccountant::createCacheSizeNodes(size_t sizes[], size_t length)
{
for (size_t i = 0; i < length; i++)
findOrCreateNodeOfSize(sizes[i]);
if (head_ == NULLPTR)
head_ = createNewAccountantAllocationNode(0, NULLPTR);
else {
for (MemoryAccountantAllocationNode* lastNode = head_; lastNode; lastNode = lastNode->next_) {
if (lastNode->next_ == NULLPTR) {
lastNode->next_ = createNewAccountantAllocationNode(0, NULLPTR);
break;
}
}
}
}
void MemoryAccountant::useCacheSizes(size_t sizes[], size_t length)
{
if (head_)
FAIL("MemoryAccountant: Cannot set cache sizes as allocations already occured!");
createCacheSizeNodes(sizes, length);
useCacheSizes_ = true;
}
void MemoryAccountant::setAllocator(TestMemoryAllocator* allocator)
{
allocator_ = allocator;
}
void MemoryAccountant::clear()
{
MemoryAccountantAllocationNode* node = head_;
MemoryAccountantAllocationNode* to_be_deleted = NULLPTR;
while (node) {
to_be_deleted = node;
node = node->next_;
destroyAccountantAllocationNode(to_be_deleted);
}
head_ = NULLPTR;
}
MemoryAccountantAllocationNode* MemoryAccountant::findNodeOfSize(size_t size) const
{
if (useCacheSizes_) {
for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_) {
if (size > node->size_ && node->next_ == NULLPTR)
return node;
else if (size <= node->size_ && !(node->next_->size_ != 0 && node->next_->size_ <= size))
return node;
}
}
else
for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_)
if (node->size_ == size)
return node;
return NULLPTR;
}
MemoryAccountantAllocationNode* MemoryAccountant::findOrCreateNodeOfSize(size_t size)
{
if (useCacheSizes_)
return findNodeOfSize(size);
if (head_ && head_->size_ > size)
head_ = createNewAccountantAllocationNode(size, head_);
for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_) {
if (node->size_ == size)
return node;
if (node->next_ == NULLPTR || node->next_->size_ > size)
node->next_ = createNewAccountantAllocationNode(size, node->next_);
}
head_ = createNewAccountantAllocationNode(size, head_);
return head_;
}
void MemoryAccountant::alloc(size_t size)
{
MemoryAccountantAllocationNode* node = findOrCreateNodeOfSize(size);
node->allocations_++;
node->currentAllocations_++;
node->maxAllocations_ = (node->currentAllocations_ > node->maxAllocations_) ? node->currentAllocations_ : node->maxAllocations_;
}
void MemoryAccountant::dealloc(size_t size)
{
MemoryAccountantAllocationNode* node = findOrCreateNodeOfSize(size);
node->deallocations_++;
if (node->currentAllocations_)
node->currentAllocations_--;
}
size_t MemoryAccountant::totalAllocationsOfSize(size_t size) const
{
MemoryAccountantAllocationNode* node = findNodeOfSize(size);
if (node)
return node->allocations_;
return 0;
}
size_t MemoryAccountant::totalDeallocationsOfSize(size_t size) const
{
MemoryAccountantAllocationNode* node = findNodeOfSize(size);
if (node)
return node->deallocations_;
return 0;
}
size_t MemoryAccountant::maximumAllocationAtATimeOfSize(size_t size) const
{
MemoryAccountantAllocationNode* node = findNodeOfSize(size);
if (node)
return node->maxAllocations_;
return 0;
}
size_t MemoryAccountant::totalAllocations() const
{
size_t theTotalAllocations = 0;
for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_)
theTotalAllocations += node->allocations_;
return theTotalAllocations;
}
size_t MemoryAccountant::totalDeallocations() const
{
size_t theTotalDeallocations = 0;
for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_)
theTotalDeallocations += node->deallocations_;
return theTotalDeallocations;
}
SimpleString MemoryAccountant::reportNoAllocations() const
{
return SimpleString("CppUTest Memory Accountant has not noticed any allocations or deallocations. Sorry\n");
}
SimpleString MemoryAccountant::reportTitle() const
{
if (useCacheSizes_)
return "CppUTest Memory Accountant report (with cache sizes):\n";
return "CppUTest Memory Accountant report:\n";
}
SimpleString MemoryAccountant::reportHeader() const
{
if (useCacheSizes_)
return "Cache size # allocations # deallocations max # allocations at one time\n";
return "Allocation size # allocations # deallocations max # allocations at one time\n";
}
#define MEMORY_ACCOUNTANT_ROW_FORMAT "%s %5d %5d %5d\n"
SimpleString MemoryAccountant::reportFooter() const
{
return SimpleString(" Thank you for your business\n");
}
SimpleString MemoryAccountant::stringSize(size_t size) const
{
return (size == 0) ? "other" : StringFromFormat("%5d", (int) size);
}
SimpleString MemoryAccountant::report() const
{
if (head_ == NULLPTR)
return reportNoAllocations();
SimpleString accountantReport = reportTitle() + reportHeader();
for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_)
accountantReport += StringFromFormat(MEMORY_ACCOUNTANT_ROW_FORMAT, stringSize(node->size_).asCharString(), (int) node->allocations_, (int) node->deallocations_, (int) node->maxAllocations_);
return accountantReport + reportFooter();
}
AccountingTestMemoryAllocator::AccountingTestMemoryAllocator(MemoryAccountant& accountant, TestMemoryAllocator* origAllocator)
: accountant_(accountant), originalAllocator_(origAllocator), head_(NULLPTR)
{
}
AccountingTestMemoryAllocator::~AccountingTestMemoryAllocator()
{
}
struct AccountingTestMemoryAllocatorMemoryNode
{
char* memory_;
size_t size_;
AccountingTestMemoryAllocatorMemoryNode* next_;
};
void AccountingTestMemoryAllocator::addMemoryToMemoryTrackingToKeepTrackOfSize(char* memory, size_t size)
{
AccountingTestMemoryAllocatorMemoryNode* node = (AccountingTestMemoryAllocatorMemoryNode*) (void*) originalAllocator_->alloc_memory(sizeof(AccountingTestMemoryAllocatorMemoryNode), __FILE__, __LINE__);
node->memory_ = memory;
node->size_ = size;
node->next_ = head_;
head_ = node;
}
size_t AccountingTestMemoryAllocator::removeNextNodeAndReturnSize(AccountingTestMemoryAllocatorMemoryNode* node)
{
AccountingTestMemoryAllocatorMemoryNode* foundNode = node->next_;
node->next_ = node->next_->next_;
size_t size = foundNode->size_;
originalAllocator_->free_memory((char*) foundNode, size, __FILE__, __LINE__);
return size;
}
size_t AccountingTestMemoryAllocator::removeHeadAndReturnSize()
{
AccountingTestMemoryAllocatorMemoryNode* foundNode = head_;
head_ = head_->next_;
size_t size = foundNode->size_;
originalAllocator_->free_memory((char*) foundNode, size, __FILE__, __LINE__);
return size;
}
size_t AccountingTestMemoryAllocator::removeMemoryFromTrackingAndReturnAllocatedSize(char* memory)
{
if (head_ && head_->memory_ == memory)
return removeHeadAndReturnSize();
for (AccountingTestMemoryAllocatorMemoryNode* node = head_; node; node = node->next_) {
if (node->next_ && node->next_->memory_ == memory)
return removeNextNodeAndReturnSize(node);
}
return 0;
}
char* AccountingTestMemoryAllocator::alloc_memory(size_t size, const char* file, size_t line)
{
accountant_.alloc(size);
char* memory = originalAllocator_->alloc_memory(size, file, line);
addMemoryToMemoryTrackingToKeepTrackOfSize(memory, size);
return memory;
}
void AccountingTestMemoryAllocator::free_memory(char* memory, size_t, const char* file, size_t line)
{
size_t size = removeMemoryFromTrackingAndReturnAllocatedSize(memory);
accountant_.dealloc(size);
originalAllocator_->free_memory(memory, size, file, line);
}
TestMemoryAllocator* AccountingTestMemoryAllocator::actualAllocator()
{
return originalAllocator_->actualAllocator();
}
TestMemoryAllocator* AccountingTestMemoryAllocator::originalAllocator()
{
return originalAllocator_;
}
const char* AccountingTestMemoryAllocator::alloc_name() const
{
return originalAllocator_->alloc_name();
}
const char* AccountingTestMemoryAllocator::free_name() const
{
return originalAllocator_->free_name();
}
GlobalMemoryAccountant::GlobalMemoryAccountant()
: mallocAllocator_(NULLPTR), newAllocator_(NULLPTR), newArrayAllocator_(NULLPTR)
{
}
GlobalMemoryAccountant::~GlobalMemoryAccountant()
{
restoreMemoryAllocators();
delete mallocAllocator_;
delete newAllocator_;
delete newArrayAllocator_;
}
void GlobalMemoryAccountant::useCacheSizes(size_t sizes[], size_t length)
{
accountant_.useCacheSizes(sizes, length);
}
void GlobalMemoryAccountant::start()
{
if (mallocAllocator_ != NULLPTR)
FAIL("Global allocator start called twice!");
mallocAllocator_ = new AccountingTestMemoryAllocator(accountant_, getCurrentMallocAllocator());
newAllocator_ = new AccountingTestMemoryAllocator(accountant_, getCurrentNewAllocator());
newArrayAllocator_ = new AccountingTestMemoryAllocator(accountant_, getCurrentNewArrayAllocator());
accountant_.setAllocator(getCurrentMallocAllocator());
setCurrentMallocAllocator(mallocAllocator_);
setCurrentNewAllocator(newAllocator_);
setCurrentNewArrayAllocator(newArrayAllocator_);
}
void GlobalMemoryAccountant::restoreMemoryAllocators()
{
if (getCurrentMallocAllocator() == mallocAllocator_)
setCurrentMallocAllocator(mallocAllocator_->originalAllocator());
if (getCurrentNewAllocator() == newAllocator_)
setCurrentNewAllocator(newAllocator_->originalAllocator());
if (getCurrentNewArrayAllocator() == newArrayAllocator_)
setCurrentNewArrayAllocator(newArrayAllocator_->originalAllocator());
}
void GlobalMemoryAccountant::stop()
{
if (mallocAllocator_ == NULLPTR)
FAIL("GlobalMemoryAccount: Stop called without starting");
if (getCurrentMallocAllocator() != mallocAllocator_)
FAIL("GlobalMemoryAccountant: Malloc memory allocator has been changed while accounting for memory");
if (getCurrentNewAllocator() != newAllocator_)
FAIL("GlobalMemoryAccountant: New memory allocator has been changed while accounting for memory");
if (getCurrentNewArrayAllocator() != newArrayAllocator_)
FAIL("GlobalMemoryAccountant: New Array memory allocator has been changed while accounting for memory");
restoreMemoryAllocators();
}
SimpleString GlobalMemoryAccountant::report()
{
return accountant_.report();
}
TestMemoryAllocator* GlobalMemoryAccountant::getMallocAllocator()
{
return mallocAllocator_;
}
TestMemoryAllocator* GlobalMemoryAccountant::getNewAllocator()
{
return newAllocator_;
}
TestMemoryAllocator* GlobalMemoryAccountant::getNewArrayAllocator()
{
return newArrayAllocator_;
}

View file

@ -0,0 +1,411 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/PlatformSpecificFunctions.h"
TestOutput::WorkingEnvironment TestOutput::workingEnvironment_ = TestOutput::detectEnvironment;
void TestOutput::setWorkingEnvironment(TestOutput::WorkingEnvironment workEnvironment)
{
workingEnvironment_ = workEnvironment;
}
TestOutput::WorkingEnvironment TestOutput::getWorkingEnvironment()
{
if (workingEnvironment_ == TestOutput::detectEnvironment)
return PlatformSpecificGetWorkingEnvironment();
return workingEnvironment_;
}
TestOutput::TestOutput() :
dotCount_(0), verbose_(level_quiet), color_(false), progressIndication_(".")
{
}
TestOutput::~TestOutput()
{
}
void TestOutput::verbose(VerbosityLevel level)
{
verbose_ = level;
}
void TestOutput::color()
{
color_ = true;
}
void TestOutput::print(const char* str)
{
printBuffer(str);
}
void TestOutput::print(long n)
{
print(StringFrom(n).asCharString());
}
void TestOutput::print(size_t n)
{
print(StringFrom(n).asCharString());
}
void TestOutput::printDouble(double d)
{
print(StringFrom(d).asCharString());
}
TestOutput& operator<<(TestOutput& p, const char* s)
{
p.print(s);
return p;
}
TestOutput& operator<<(TestOutput& p, long int i)
{
p.print(i);
return p;
}
void TestOutput::printCurrentTestStarted(const UtestShell& test)
{
if (verbose_ > level_quiet) print(test.getFormattedName().asCharString());
if (test.willRun()) {
setProgressIndicator(".");
}
else {
setProgressIndicator("!");
}
}
void TestOutput::printCurrentTestEnded(const TestResult& res)
{
if (verbose_ > level_quiet) {
print(" - ");
print(res.getCurrentTestTotalExecutionTime());
print(" ms\n");
}
else {
printProgressIndicator();
}
}
void TestOutput::printProgressIndicator()
{
print(progressIndication_);
if (++dotCount_ % 50 == 0) print("\n");
}
void TestOutput::setProgressIndicator(const char* indicator)
{
progressIndication_ = indicator;
}
void TestOutput::printTestsStarted()
{
}
void TestOutput::printCurrentGroupStarted(const UtestShell& /*test*/)
{
}
void TestOutput::printCurrentGroupEnded(const TestResult& /*res*/)
{
}
void TestOutput::printTestsEnded(const TestResult& result)
{
print("\n");
const bool isFailure = result.isFailure();
const size_t failureCount = result.getFailureCount();
if (isFailure) {
if (color_) {
print("\033[31;1m");
}
print("Errors (");
if (failureCount > 0) {
print(failureCount);
print(" failures, ");
}
else {
print("ran nothing, ");
}
}
else {
if (color_) {
print("\033[32;1m");
}
print("OK (");
}
print(result.getTestCount());
print(" tests, ");
print(result.getRunCount());
print(" ran, ");
print(result.getCheckCount());
print(" checks, ");
print(result.getIgnoredCount());
print(" ignored, ");
print(result.getFilteredOutCount());
print(" filtered out, ");
print(result.getTotalExecutionTime());
print(" ms)");
if (color_) {
print("\033[m");
}
if (isFailure && failureCount == 0) {
print("\nNote: test run failed because no tests were run or ignored. Assuming something went wrong. "
"This often happens because of linking errors or typos in test filter.");
}
print("\n\n");
dotCount_ = 0;
}
void TestOutput::printTestRun(size_t number, size_t total)
{
if (total > 1) {
print("Test run ");
print(number);
print(" of ");
print(total);
print("\n");
}
}
void TestOutput::printFailure(const TestFailure& failure)
{
if (failure.isOutsideTestFile() || failure.isInHelperFunction())
printFileAndLineForTestAndFailure(failure);
else
printFileAndLineForFailure(failure);
printFailureMessage(failure.getMessage());
}
void TestOutput::printFileAndLineForTestAndFailure(const TestFailure& failure)
{
printErrorInFileOnLineFormattedForWorkingEnvironment(failure.getTestFileName(), failure.getTestLineNumber());
printFailureInTest(failure.getTestName());
printErrorInFileOnLineFormattedForWorkingEnvironment(failure.getFileName(), failure.getFailureLineNumber());
}
void TestOutput::printFileAndLineForFailure(const TestFailure& failure)
{
printErrorInFileOnLineFormattedForWorkingEnvironment(failure.getFileName(), failure.getFailureLineNumber());
printFailureInTest(failure.getTestName());
}
void TestOutput::printFailureInTest(SimpleString testName)
{
print(" Failure in ");
print(testName.asCharString());
}
void TestOutput::printFailureMessage(SimpleString reason)
{
print("\n");
print("\t");
print(reason.asCharString());
print("\n\n");
}
void TestOutput::printErrorInFileOnLineFormattedForWorkingEnvironment(SimpleString file, size_t lineNumber)
{
if (TestOutput::getWorkingEnvironment() == TestOutput::visualStudio)
printVisualStudioErrorInFileOnLine(file, lineNumber);
else
printEclipseErrorInFileOnLine(file, lineNumber);
}
void TestOutput::printEclipseErrorInFileOnLine(SimpleString file, size_t lineNumber)
{
print("\n");
print(file.asCharString());
print(":");
print(lineNumber);
print(":");
print(" error:");
}
void TestOutput::printVisualStudioErrorInFileOnLine(SimpleString file, size_t lineNumber)
{
print("\n");
print(file.asCharString());
print("(");
print(lineNumber);
print("):");
print(" error:");
}
void TestOutput::printVeryVerbose(const char* str)
{
if(verbose_ == level_veryVerbose)
printBuffer(str);
}
void ConsoleTestOutput::printBuffer(const char* s)
{
while (*s) {
PlatformSpecificPutchar(*s);
s++;
}
flush();
}
void ConsoleTestOutput::flush()
{
PlatformSpecificFlush();
}
StringBufferTestOutput::~StringBufferTestOutput()
{
}
CompositeTestOutput::CompositeTestOutput()
: outputOne_(NULLPTR), outputTwo_(NULLPTR)
{
}
CompositeTestOutput::~CompositeTestOutput()
{
delete outputOne_;
delete outputTwo_;
}
void CompositeTestOutput::setOutputOne(TestOutput* output)
{
delete outputOne_;
outputOne_ = output;
}
void CompositeTestOutput::setOutputTwo(TestOutput* output)
{
delete outputTwo_;
outputTwo_ = output;
}
void CompositeTestOutput::printTestsStarted()
{
if (outputOne_) outputOne_->printTestsStarted();
if (outputTwo_) outputTwo_->printTestsStarted();
}
void CompositeTestOutput::printTestsEnded(const TestResult& result)
{
if (outputOne_) outputOne_->printTestsEnded(result);
if (outputTwo_) outputTwo_->printTestsEnded(result);
}
void CompositeTestOutput::printCurrentTestStarted(const UtestShell& test)
{
if (outputOne_) outputOne_->printCurrentTestStarted(test);
if (outputTwo_) outputTwo_->printCurrentTestStarted(test);
}
void CompositeTestOutput::printCurrentTestEnded(const TestResult& res)
{
if (outputOne_) outputOne_->printCurrentTestEnded(res);
if (outputTwo_) outputTwo_->printCurrentTestEnded(res);
}
void CompositeTestOutput::printCurrentGroupStarted(const UtestShell& test)
{
if (outputOne_) outputOne_->printCurrentGroupStarted(test);
if (outputTwo_) outputTwo_->printCurrentGroupStarted(test);
}
void CompositeTestOutput::printCurrentGroupEnded(const TestResult& res)
{
if (outputOne_) outputOne_->printCurrentGroupEnded(res);
if (outputTwo_) outputTwo_->printCurrentGroupEnded(res);
}
void CompositeTestOutput::verbose(VerbosityLevel level)
{
if (outputOne_) outputOne_->verbose(level);
if (outputTwo_) outputTwo_->verbose(level);
}
void CompositeTestOutput::color()
{
if (outputOne_) outputOne_->color();
if (outputTwo_) outputTwo_->color();
}
void CompositeTestOutput::printBuffer(const char* buffer)
{
if (outputOne_) outputOne_->printBuffer(buffer);
if (outputTwo_) outputTwo_->printBuffer(buffer);
}
void CompositeTestOutput::print(const char* buffer)
{
if (outputOne_) outputOne_->print(buffer);
if (outputTwo_) outputTwo_->print(buffer);
}
void CompositeTestOutput::print(long number)
{
if (outputOne_) outputOne_->print(number);
if (outputTwo_) outputTwo_->print(number);
}
void CompositeTestOutput::print(size_t number)
{
if (outputOne_) outputOne_->print(number);
if (outputTwo_) outputTwo_->print(number);
}
void CompositeTestOutput::printDouble(double number)
{
if (outputOne_) outputOne_->printDouble(number);
if (outputTwo_) outputTwo_->printDouble(number);
}
void CompositeTestOutput::printFailure(const TestFailure& failure)
{
if (outputOne_) outputOne_->printFailure(failure);
if (outputTwo_) outputTwo_->printFailure(failure);
}
void CompositeTestOutput::setProgressIndicator(const char* indicator)
{
if (outputOne_) outputOne_->setProgressIndicator(indicator);
if (outputTwo_) outputTwo_->setProgressIndicator(indicator);
}
void CompositeTestOutput::flush()
{
if (outputOne_) outputOne_->flush();
if (outputTwo_) outputTwo_->flush();
}

View file

@ -0,0 +1,169 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestPlugin.h"
TestPlugin::TestPlugin(const SimpleString& name) :
next_(NullTestPlugin::instance()), name_(name), enabled_(true)
{
}
TestPlugin::TestPlugin(TestPlugin* next) :
next_(next), name_("null"), enabled_(true)
{
}
TestPlugin::~TestPlugin()
{
}
TestPlugin* TestPlugin::addPlugin(TestPlugin* plugin)
{
next_ = plugin;
return this;
}
void TestPlugin::runAllPreTestAction(UtestShell& test, TestResult& result)
{
if (enabled_) preTestAction(test, result);
next_->runAllPreTestAction(test, result);
}
void TestPlugin::runAllPostTestAction(UtestShell& test, TestResult& result)
{
next_ ->runAllPostTestAction(test, result);
if (enabled_) postTestAction(test, result);
}
bool TestPlugin::parseAllArguments(int ac, char** av, int index)
{
return parseAllArguments(ac, const_cast<const char *const *> (av), index);
}
bool TestPlugin::parseAllArguments(int ac, const char *const *av, int index)
{
if (parseArguments(ac, av, index)) return true;
if (next_) return next_->parseAllArguments(ac, av, index);
return false;
}
const SimpleString& TestPlugin::getName()
{
return name_;
}
TestPlugin* TestPlugin::getPluginByName(const SimpleString& name)
{
if (name == name_) return this;
if (next_) return next_->getPluginByName(name);
return (next_);
}
TestPlugin* TestPlugin::getNext()
{
return next_;
}
TestPlugin* TestPlugin::removePluginByName(const SimpleString& name)
{
TestPlugin* removed = NULLPTR;
if (next_ && next_->getName() == name) {
removed = next_;
next_ = next_->next_;
}
return removed;
}
void TestPlugin::disable()
{
enabled_ = false;
}
void TestPlugin::enable()
{
enabled_ = true;
}
bool TestPlugin::isEnabled()
{
return enabled_;
}
struct cpputest_pair
{
void **orig;
void *orig_value;
};
//////// SetPlugin
static int pointerTableIndex;
static cpputest_pair setlist[SetPointerPlugin::MAX_SET];
SetPointerPlugin::SetPointerPlugin(const SimpleString& name) :
TestPlugin(name)
{
pointerTableIndex = 0;
}
void CppUTestStore(void**function)
{
if (pointerTableIndex >= SetPointerPlugin::MAX_SET) {
FAIL("Maximum number of function pointers installed!");
}
setlist[pointerTableIndex].orig_value = *function;
setlist[pointerTableIndex].orig = function;
pointerTableIndex++;
}
void SetPointerPlugin::postTestAction(UtestShell& /*test*/, TestResult& /*result*/)
{
for (int i = pointerTableIndex - 1; i >= 0; i--)
*((void**) setlist[i].orig) = setlist[i].orig_value;
pointerTableIndex = 0;
}
//////// NullPlugin
NullTestPlugin::NullTestPlugin() :
TestPlugin(NULLPTR)
{
}
NullTestPlugin* NullTestPlugin::instance()
{
static NullTestPlugin _instance;
return &_instance;
}
void NullTestPlugin::runAllPreTestAction(UtestShell&, TestResult&)
{
}
void NullTestPlugin::runAllPostTestAction(UtestShell&, TestResult&)
{
}

View file

@ -0,0 +1,273 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/PlatformSpecificFunctions.h"
TestRegistry::TestRegistry() :
tests_(NULLPTR), nameFilters_(NULLPTR), groupFilters_(NULLPTR), firstPlugin_(NullTestPlugin::instance()), runInSeperateProcess_(false), currentRepetition_(0), runIgnored_(false)
{
}
TestRegistry::~TestRegistry()
{
}
void TestRegistry::addTest(UtestShell *test)
{
tests_ = test->addTest(tests_);
}
void TestRegistry::runAllTests(TestResult& result)
{
bool groupStart = true;
result.testsStarted();
for (UtestShell *test = tests_; test != NULLPTR; test = test->getNext()) {
if (runInSeperateProcess_) test->setRunInSeperateProcess();
if (runIgnored_) test->setRunIgnored();
if (groupStart) {
result.currentGroupStarted(test);
groupStart = false;
}
result.countTest();
if (testShouldRun(test, result)) {
result.currentTestStarted(test);
test->runOneTest(firstPlugin_, result);
result.currentTestEnded(test);
}
if (endOfGroup(test)) {
groupStart = true;
result.currentGroupEnded(test);
}
}
result.testsEnded();
currentRepetition_++;
}
void TestRegistry::listTestGroupNames(TestResult& result)
{
SimpleString groupList;
for (UtestShell *test = tests_; test != NULLPTR; test = test->getNext()) {
SimpleString gname;
gname += "#";
gname += test->getGroup();
gname += "#";
if (!groupList.contains(gname)) {
groupList += gname;
groupList += " ";
}
}
groupList.replace("#", "");
if (groupList.endsWith(" "))
groupList = groupList.subString(0, groupList.size() - 1);
result.print(groupList.asCharString());
}
void TestRegistry::listTestGroupAndCaseNames(TestResult& result)
{
SimpleString groupAndNameList;
for (UtestShell *test = tests_; test != NULLPTR; test = test->getNext()) {
if (testShouldRun(test, result)) {
SimpleString groupAndName;
groupAndName += "#";
groupAndName += test->getGroup();
groupAndName += ".";
groupAndName += test->getName();
groupAndName += "#";
if (!groupAndNameList.contains(groupAndName)) {
groupAndNameList += groupAndName;
groupAndNameList += " ";
}
}
}
groupAndNameList.replace("#", "");
if (groupAndNameList.endsWith(" "))
groupAndNameList = groupAndNameList.subString(0, groupAndNameList.size() - 1);
result.print(groupAndNameList.asCharString());
}
bool TestRegistry::endOfGroup(UtestShell* test)
{
return (!test || !test->getNext() || test->getGroup() != test->getNext()->getGroup());
}
size_t TestRegistry::countTests()
{
return tests_ ? tests_->countTests() : 0;
}
TestRegistry* TestRegistry::currentRegistry_ = NULLPTR;
TestRegistry* TestRegistry::getCurrentRegistry()
{
static TestRegistry registry;
return (currentRegistry_ == NULLPTR) ? &registry : currentRegistry_;
}
void TestRegistry::setCurrentRegistry(TestRegistry* registry)
{
currentRegistry_ = registry;
}
void TestRegistry::unDoLastAddTest()
{
tests_ = tests_ ? tests_->getNext() : NULLPTR;
}
void TestRegistry::setNameFilters(const TestFilter* filters)
{
nameFilters_ = filters;
}
void TestRegistry::setGroupFilters(const TestFilter* filters)
{
groupFilters_ = filters;
}
void TestRegistry::setRunIgnored()
{
runIgnored_ = true;
}
void TestRegistry::setRunTestsInSeperateProcess()
{
runInSeperateProcess_ = true;
}
int TestRegistry::getCurrentRepetition()
{
return currentRepetition_;
}
bool TestRegistry::testShouldRun(UtestShell* test, TestResult& result)
{
if (test->shouldRun(groupFilters_, nameFilters_)) return true;
else {
result.countFilteredOut();
return false;
}
}
void TestRegistry::resetPlugins()
{
firstPlugin_ = NullTestPlugin::instance();
}
void TestRegistry::installPlugin(TestPlugin* plugin)
{
firstPlugin_ = plugin->addPlugin(firstPlugin_);
}
TestPlugin* TestRegistry::getFirstPlugin()
{
return firstPlugin_;
}
TestPlugin* TestRegistry::getPluginByName(const SimpleString& name)
{
return firstPlugin_->getPluginByName(name);
}
void TestRegistry::removePluginByName(const SimpleString& name)
{
if (firstPlugin_->removePluginByName(name) == firstPlugin_) firstPlugin_ = firstPlugin_->getNext();
if (firstPlugin_->getName() == name) firstPlugin_ = firstPlugin_->getNext();
firstPlugin_->removePluginByName(name);
}
int TestRegistry::countPlugins()
{
int count = 0;
for (TestPlugin* plugin = firstPlugin_; plugin != NullTestPlugin::instance(); plugin = plugin->getNext())
count++;
return count;
}
UtestShell* TestRegistry::getFirstTest()
{
return tests_;
}
void TestRegistry::shuffleTests(size_t seed)
{
UtestShellPointerArray array(getFirstTest());
array.shuffle(seed);
tests_ = array.getFirstTest();
}
void TestRegistry::reverseTests()
{
UtestShellPointerArray array(getFirstTest());
array.reverse();
tests_ = array.getFirstTest();
}
UtestShell* TestRegistry::getTestWithNext(UtestShell* test)
{
UtestShell* current = tests_;
while (current && current->getNext() != test)
current = current->getNext();
return current;
}
UtestShell* TestRegistry::findTestWithName(const SimpleString& name)
{
UtestShell* current = tests_;
while (current) {
if (current->getName() == name)
return current;
current = current->getNext();
}
return NULLPTR;
}
UtestShell* TestRegistry::findTestWithGroup(const SimpleString& group)
{
UtestShell* current = tests_;
while (current) {
if (current->getGroup() == group)
return current;
current = current->getNext();
}
return NULLPTR;
}

View file

@ -0,0 +1,142 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestResult.h"
#include "CppUTest/TestFailure.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/PlatformSpecificFunctions.h"
TestResult::TestResult(TestOutput& p) :
output_(p), testCount_(0), runCount_(0), checkCount_(0), failureCount_(0), filteredOutCount_(0), ignoredCount_(0), totalExecutionTime_(0), timeStarted_(0), currentTestTimeStarted_(0),
currentTestTotalExecutionTime_(0), currentGroupTimeStarted_(0), currentGroupTotalExecutionTime_(0)
{
}
TestResult::~TestResult()
{
}
void TestResult::currentGroupStarted(UtestShell* test)
{
output_.printCurrentGroupStarted(*test);
currentGroupTimeStarted_ = (size_t) GetPlatformSpecificTimeInMillis();
}
void TestResult::currentGroupEnded(UtestShell* /*test*/)
{
currentGroupTotalExecutionTime_ = (size_t) GetPlatformSpecificTimeInMillis() - currentGroupTimeStarted_;
output_.printCurrentGroupEnded(*this);
}
void TestResult::currentTestStarted(UtestShell* test)
{
output_.printCurrentTestStarted(*test);
currentTestTimeStarted_ = (size_t) GetPlatformSpecificTimeInMillis();
}
void TestResult::print(const char* text)
{
output_.print(text);
}
void TestResult::printVeryVerbose(const char* text)
{
output_.printVeryVerbose(text);
}
void TestResult::currentTestEnded(UtestShell* /*test*/)
{
currentTestTotalExecutionTime_ = (size_t) GetPlatformSpecificTimeInMillis() - currentTestTimeStarted_;
output_.printCurrentTestEnded(*this);
}
void TestResult::addFailure(const TestFailure& failure)
{
output_.printFailure(failure);
failureCount_++;
}
void TestResult::countTest()
{
testCount_++;
}
void TestResult::countRun()
{
runCount_++;
}
void TestResult::countCheck()
{
checkCount_++;
}
void TestResult::countFilteredOut()
{
filteredOutCount_++;
}
void TestResult::countIgnored()
{
ignoredCount_++;
}
void TestResult::testsStarted()
{
timeStarted_ = (size_t) GetPlatformSpecificTimeInMillis();
output_.printTestsStarted();
}
void TestResult::testsEnded()
{
size_t timeEnded = (size_t) GetPlatformSpecificTimeInMillis();
totalExecutionTime_ = timeEnded - timeStarted_;
output_.printTestsEnded(*this);
}
size_t TestResult::getTotalExecutionTime() const
{
return totalExecutionTime_;
}
void TestResult::setTotalExecutionTime(size_t exTime)
{
totalExecutionTime_ = exTime;
}
size_t TestResult::getCurrentTestTotalExecutionTime() const
{
return currentTestTotalExecutionTime_;
}
size_t TestResult::getCurrentGroupTotalExecutionTime() const
{
return currentGroupTotalExecutionTime_;
}

View file

@ -0,0 +1,194 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestTestingFixture.h"
bool TestTestingFixture::lineOfCodeExecutedAfterCheck = false;
TestTestingFixture::TestTestingFixture()
{
output_ = new StringBufferTestOutput();
result_ = new TestResult(*output_);
genTest_ = new ExecFunctionTestShell();
registry_ = new TestRegistry();
ownsExecFunction_ = false;
registry_->setCurrentRegistry(registry_);
registry_->addTest(genTest_);
lineOfCodeExecutedAfterCheck = false;
}
void TestTestingFixture::flushOutputAndResetResult()
{
output_->flush();
delete result_;
result_ = new TestResult(*output_);
}
TestTestingFixture::~TestTestingFixture()
{
registry_->setCurrentRegistry(NULLPTR);
clearExecFunction();
delete registry_;
delete result_;
delete output_;
delete genTest_;
}
void TestTestingFixture::clearExecFunction()
{
if (genTest_->testFunction_ && ownsExecFunction_)
delete genTest_->testFunction_;
}
void TestTestingFixture::addTest(UtestShell * test)
{
registry_->addTest(test);
}
void TestTestingFixture::setTestFunction(void(*testFunction)())
{
clearExecFunction();
genTest_->testFunction_ = new ExecFunctionWithoutParameters(testFunction);
ownsExecFunction_ = true;
}
void TestTestingFixture::setTestFunction(ExecFunction* testFunction)
{
clearExecFunction();
genTest_->testFunction_ = testFunction;
ownsExecFunction_ = false;
}
void TestTestingFixture::setSetup(void(*setupFunction)())
{
genTest_->setup_ = setupFunction;
}
void TestTestingFixture::setTeardown(void(*teardownFunction)())
{
genTest_->teardown_ = teardownFunction;
}
void TestTestingFixture::installPlugin(TestPlugin* plugin)
{
registry_->installPlugin(plugin);
}
void TestTestingFixture::setRunTestsInSeperateProcess()
{
registry_->setRunTestsInSeperateProcess();
}
void TestTestingFixture::setOutputVerbose()
{
output_->verbose(TestOutput::level_verbose);
}
void TestTestingFixture::runTestWithMethod(void(*method)())
{
setTestFunction(method);
runAllTests();
}
void TestTestingFixture::runAllTests()
{
registry_->runAllTests(*result_);
}
size_t TestTestingFixture::getFailureCount()
{
return result_->getFailureCount();
}
size_t TestTestingFixture::getCheckCount()
{
return result_->getCheckCount();
}
size_t TestTestingFixture::getTestCount()
{
return result_->getTestCount();
}
size_t TestTestingFixture::getIgnoreCount()
{
return result_->getIgnoredCount();
}
TestRegistry* TestTestingFixture::getRegistry()
{
return registry_;
}
bool TestTestingFixture::hasTestFailed()
{
return genTest_->hasFailed();
}
void TestTestingFixture::assertPrintContains(const SimpleString& contains)
{
STRCMP_CONTAINS(contains.asCharString(), getOutput().asCharString());
}
void TestTestingFixture::assertPrintContainsNot(const SimpleString& contains)
{
CHECK(! getOutput().contains(contains));
}
const SimpleString& TestTestingFixture::getOutput()
{
return output_->getOutput();
}
size_t TestTestingFixture::getRunCount()
{
return result_->getRunCount();
}
void TestTestingFixture::lineExecutedAfterCheck()
{
lineOfCodeExecutedAfterCheck = true;
}
void TestTestingFixture::checkTestFailsWithProperTestLocation(const char* text, const char* file, size_t line)
{
if (getFailureCount() != 1)
FAIL_LOCATION(StringFromFormat("Expected one test failure, but got %d amount of test failures", (int) getFailureCount()).asCharString(), file, line);
STRCMP_CONTAINS_LOCATION(text, output_->getOutput().asCharString(), "", file, line);
if (lineOfCodeExecutedAfterCheck)
FAIL_LOCATION("The test should jump/throw on failure and not execute the next line. However, the next line was executed.", file, line);
}

View file

@ -0,0 +1,899 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/PlatformSpecificFunctions.h"
#include "CppUTest/TestOutput.h"
bool doubles_equal(double d1, double d2, double threshold)
{
if (PlatformSpecificIsNan(d1) || PlatformSpecificIsNan(d2) || PlatformSpecificIsNan(threshold))
return false;
if (PlatformSpecificIsInf(d1) && PlatformSpecificIsInf(d2))
{
return true;
}
return PlatformSpecificFabs(d1 - d2) <= threshold;
}
/* Sometimes stubs use the CppUTest assertions.
* Its not correct to do so, but this small helper class will prevent a segmentation fault and instead
* will give an error message and also the file/line of the check that was executed outside the tests.
*/
class OutsideTestRunnerUTest: public UtestShell
{
public:
static OutsideTestRunnerUTest& instance();
virtual TestResult& getTestResult()
{
return defaultTestResult;
}
virtual ~OutsideTestRunnerUTest() _destructor_override
{
}
private:
OutsideTestRunnerUTest() :
UtestShell("\n\t NOTE: Assertion happened without being in a test run (perhaps in main?)", "\n\t Something is very wrong. Check this assertion and fix", "unknown file", 0),
defaultTestResult(defaultOutput)
{
}
ConsoleTestOutput defaultOutput;
TestResult defaultTestResult;
};
OutsideTestRunnerUTest& OutsideTestRunnerUTest::instance()
{
static OutsideTestRunnerUTest instance_;
return instance_;
}
/*
* Below helpers are used for the PlatformSpecificSetJmp and LongJmp. They pass a method for what needs to happen after
* the jump, so that the stack stays right.
*
*/
extern "C" {
static void helperDoTestSetup(void* data)
{
((Utest*)data)->setup();
}
static void helperDoTestBody(void* data)
{
((Utest*)data)->testBody();
}
static void helperDoTestTeardown(void* data)
{
((Utest*)data)->teardown();
}
struct HelperTestRunInfo
{
HelperTestRunInfo(UtestShell* shell, TestPlugin* plugin, TestResult* result) : shell_(shell), plugin_(plugin), result_(result){}
UtestShell* shell_;
TestPlugin* plugin_;
TestResult* result_;
};
static void helperDoRunOneTestInCurrentProcess(void* data)
{
HelperTestRunInfo* runInfo = (HelperTestRunInfo*) data;
UtestShell* shell = runInfo->shell_;
TestPlugin* plugin = runInfo->plugin_;
TestResult* result = runInfo->result_;
shell->runOneTestInCurrentProcess(plugin, *result);
}
static void helperDoRunOneTestSeperateProcess(void* data)
{
HelperTestRunInfo* runInfo = (HelperTestRunInfo*) data;
UtestShell* shell = runInfo->shell_;
TestPlugin* plugin = runInfo->plugin_;
TestResult* result = runInfo->result_;
PlatformSpecificRunTestInASeperateProcess(shell, plugin, result);
}
}
/******************************** */
static const NormalTestTerminator normalTestTerminator;
static const CrashingTestTerminator crashingTestTerminator;
const TestTerminator *UtestShell::currentTestTerminator_ = &normalTestTerminator;
/******************************** */
UtestShell::UtestShell() :
group_("UndefinedTestGroup"), name_("UndefinedTest"), file_("UndefinedFile"), lineNumber_(0), next_(NULLPTR), isRunAsSeperateProcess_(false), hasFailed_(false)
{
}
UtestShell::UtestShell(const char* groupName, const char* testName, const char* fileName, size_t lineNumber) :
group_(groupName), name_(testName), file_(fileName), lineNumber_(lineNumber), next_(NULLPTR), isRunAsSeperateProcess_(false), hasFailed_(false)
{
}
UtestShell::UtestShell(const char* groupName, const char* testName, const char* fileName, size_t lineNumber, UtestShell* nextTest) :
group_(groupName), name_(testName), file_(fileName), lineNumber_(lineNumber), next_(nextTest), isRunAsSeperateProcess_(false), hasFailed_(false)
{
}
UtestShell::~UtestShell()
{
}
// LCOV_EXCL_START - actually covered but not in .gcno due to race condition
static void defaultCrashMethod()
{
UtestShell* ptr = (UtestShell*) NULLPTR; ptr->countTests();
}
// LCOV_EXCL_STOP
static void (*pleaseCrashMeRightNow) () = defaultCrashMethod;
void UtestShell::setCrashMethod(void (*crashme)())
{
pleaseCrashMeRightNow = crashme;
}
void UtestShell::resetCrashMethod()
{
pleaseCrashMeRightNow = defaultCrashMethod;
}
void UtestShell::crash()
{
pleaseCrashMeRightNow();
}
void UtestShell::runOneTest(TestPlugin* plugin, TestResult& result)
{
hasFailed_ = false;
result.countRun();
HelperTestRunInfo runInfo(this, plugin, &result);
if (isRunInSeperateProcess())
PlatformSpecificSetJmp(helperDoRunOneTestSeperateProcess, &runInfo);
else
PlatformSpecificSetJmp(helperDoRunOneTestInCurrentProcess, &runInfo);
}
Utest* UtestShell::createTest()
{
return new Utest();
}
void UtestShell::destroyTest(Utest* test)
{
delete test;
}
void UtestShell::runOneTestInCurrentProcess(TestPlugin* plugin, TestResult& result)
{
result.printVeryVerbose("\n-- before runAllPreTestAction: ");
plugin->runAllPreTestAction(*this, result);
result.printVeryVerbose("\n-- after runAllPreTestAction: ");
//save test context, so that test class can be tested
UtestShell* savedTest = UtestShell::getCurrent();
TestResult* savedResult = UtestShell::getTestResult();
UtestShell::setTestResult(&result);
UtestShell::setCurrentTest(this);
result.printVeryVerbose("\n---- before createTest: ");
Utest* testToRun = createTest();
result.printVeryVerbose("\n---- after createTest: ");
result.printVeryVerbose("\n------ before runTest: ");
testToRun->run();
result.printVeryVerbose("\n------ after runTest: ");
UtestShell::setCurrentTest(savedTest);
UtestShell::setTestResult(savedResult);
result.printVeryVerbose("\n---- before destroyTest: ");
destroyTest(testToRun);
result.printVeryVerbose("\n---- after destroyTest: ");
result.printVeryVerbose("\n-- before runAllPostTestAction: ");
plugin->runAllPostTestAction(*this, result);
result.printVeryVerbose("\n-- after runAllPostTestAction: ");
}
UtestShell *UtestShell::getNext() const
{
return next_;
}
UtestShell* UtestShell::addTest(UtestShell *test)
{
next_ = test;
return this;
}
size_t UtestShell::countTests()
{
return next_ ? next_->countTests() + 1 : 1;
}
SimpleString UtestShell::getMacroName() const
{
return "TEST";
}
const SimpleString UtestShell::getName() const
{
return SimpleString(name_);
}
const SimpleString UtestShell::getGroup() const
{
return SimpleString(group_);
}
SimpleString UtestShell::getFormattedName() const
{
SimpleString formattedName(getMacroName());
formattedName += "(";
formattedName += group_;
formattedName += ", ";
formattedName += name_;
formattedName += ")";
return formattedName;
}
bool UtestShell::hasFailed() const
{
return hasFailed_;
}
void UtestShell::countCheck()
{
getTestResult()->countCheck();
}
bool UtestShell::willRun() const
{
return true;
}
bool UtestShell::isRunInSeperateProcess() const
{
return isRunAsSeperateProcess_;
}
void UtestShell::setRunInSeperateProcess()
{
isRunAsSeperateProcess_ = true;
}
void UtestShell::setRunIgnored()
{
}
void UtestShell::setFileName(const char* fileName)
{
file_ = fileName;
}
void UtestShell::setLineNumber(size_t lineNumber)
{
lineNumber_ = lineNumber;
}
void UtestShell::setGroupName(const char* groupName)
{
group_ = groupName;
}
void UtestShell::setTestName(const char* testName)
{
name_ = testName;
}
const SimpleString UtestShell::getFile() const
{
return SimpleString(file_);
}
size_t UtestShell::getLineNumber() const
{
return lineNumber_;
}
bool UtestShell::match(const char* target, const TestFilter* filters) const
{
if(filters == NULLPTR) return true;
for(; filters != NULLPTR; filters = filters->getNext())
if(filters->match(target)) return true;
return false;
}
bool UtestShell::shouldRun(const TestFilter* groupFilters, const TestFilter* nameFilters) const
{
return match(group_, groupFilters) && match(name_, nameFilters);
}
void UtestShell::failWith(const TestFailure& failure)
{
failWith(failure, getCurrentTestTerminator());
} // LCOV_EXCL_LINE
void UtestShell::failWith(const TestFailure& failure, const TestTerminator& terminator)
{
hasFailed_ = true;
getTestResult()->addFailure(failure);
terminator.exitCurrentTest();
} // LCOV_EXCL_LINE
void UtestShell::exitTest(const TestTerminator& terminator)
{
terminator.exitCurrentTest();
} // LCOV_EXCL_LINE
void UtestShell::assertTrue(bool condition, const char *checkString, const char *conditionString, const char* text, const char *fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if (!condition)
failWith(CheckFailure(this, fileName, lineNumber, checkString, conditionString, text), testTerminator);
}
void UtestShell::fail(const char *text, const char* fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
failWith(FailFailure(this, fileName, lineNumber, text), testTerminator);
} // LCOV_EXCL_LINE
void UtestShell::assertCstrEqual(const char* expected, const char* actual, const char* text, const char* fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if (actual == NULLPTR && expected == NULLPTR) return;
if (actual == NULLPTR || expected == NULLPTR)
failWith(StringEqualFailure(this, fileName, lineNumber, expected, actual, text), testTerminator);
if (SimpleString::StrCmp(expected, actual) != 0)
failWith(StringEqualFailure(this, fileName, lineNumber, expected, actual, text), testTerminator);
}
void UtestShell::assertCstrNEqual(const char* expected, const char* actual, size_t length, const char* text, const char* fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if (actual == NULLPTR && expected == NULLPTR) return;
if (actual == NULLPTR || expected == NULLPTR)
failWith(StringEqualFailure(this, fileName, lineNumber, expected, actual, text), testTerminator);
if (SimpleString::StrNCmp(expected, actual, length) != 0)
failWith(StringEqualFailure(this, fileName, lineNumber, expected, actual, text), testTerminator);
}
void UtestShell::assertCstrNoCaseEqual(const char* expected, const char* actual, const char* text, const char* fileName, size_t lineNumber)
{
getTestResult()->countCheck();
if (actual == NULLPTR && expected == NULLPTR) return;
if (actual == NULLPTR || expected == NULLPTR)
failWith(StringEqualNoCaseFailure(this, fileName, lineNumber, expected, actual, text));
if (!SimpleString(expected).equalsNoCase(actual))
failWith(StringEqualNoCaseFailure(this, fileName, lineNumber, expected, actual, text));
}
void UtestShell::assertCstrContains(const char* expected, const char* actual, const char* text, const char* fileName, size_t lineNumber)
{
getTestResult()->countCheck();
if (actual == NULLPTR && expected == NULLPTR) return;
if (actual == NULLPTR || expected == NULLPTR)
failWith(ContainsFailure(this, fileName, lineNumber, expected, actual, text));
if (!SimpleString(actual).contains(expected))
failWith(ContainsFailure(this, fileName, lineNumber, expected, actual, text));
}
void UtestShell::assertCstrNoCaseContains(const char* expected, const char* actual, const char* text, const char* fileName, size_t lineNumber)
{
getTestResult()->countCheck();
if (actual == NULLPTR && expected == NULLPTR) return;
if (actual == NULLPTR || expected == NULLPTR)
failWith(ContainsFailure(this, fileName, lineNumber, expected, actual, text));
if (!SimpleString(actual).containsNoCase(expected))
failWith(ContainsFailure(this, fileName, lineNumber, expected, actual, text));
}
void UtestShell::assertLongsEqual(long expected, long actual, const char* text, const char* fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if (expected != actual)
failWith(LongsEqualFailure (this, fileName, lineNumber, expected, actual, text), testTerminator);
}
void UtestShell::assertUnsignedLongsEqual(unsigned long expected, unsigned long actual, const char* text, const char* fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if (expected != actual)
failWith(UnsignedLongsEqualFailure (this, fileName, lineNumber, expected, actual, text), testTerminator);
}
void UtestShell::assertLongLongsEqual(cpputest_longlong expected, cpputest_longlong actual, const char* text, const char* fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
#ifdef CPPUTEST_USE_LONG_LONG
if (expected != actual)
failWith(LongLongsEqualFailure(this, fileName, lineNumber, expected, actual, text), testTerminator);
#else
(void)expected;
(void)actual;
failWith(FeatureUnsupportedFailure(this, fileName, lineNumber, "CPPUTEST_USE_LONG_LONG", text), testTerminator);
#endif
}
void UtestShell::assertUnsignedLongLongsEqual(cpputest_ulonglong expected, cpputest_ulonglong actual, const char* text, const char* fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
#ifdef CPPUTEST_USE_LONG_LONG
if (expected != actual)
failWith(UnsignedLongLongsEqualFailure(this, fileName, lineNumber, expected, actual, text), testTerminator);
#else
(void)expected;
(void)actual;
failWith(FeatureUnsupportedFailure(this, fileName, lineNumber, "CPPUTEST_USE_LONG_LONG", text), testTerminator);
#endif
}
void UtestShell::assertSignedBytesEqual(signed char expected, signed char actual, const char* text, const char *fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if (expected != actual)
failWith(SignedBytesEqualFailure (this, fileName, lineNumber, expected, actual, text), testTerminator);
}
void UtestShell::assertPointersEqual(const void* expected, const void* actual, const char* text, const char* fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if (expected != actual)
failWith(EqualsFailure(this, fileName, lineNumber, StringFrom(expected), StringFrom(actual), text), testTerminator);
}
void UtestShell::assertFunctionPointersEqual(void (*expected)(), void (*actual)(), const char* text, const char* fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if (expected != actual)
failWith(EqualsFailure(this, fileName, lineNumber, StringFrom(expected), StringFrom(actual), text), testTerminator);
}
void UtestShell::assertDoublesEqual(double expected, double actual, double threshold, const char* text, const char* fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if (!doubles_equal(expected, actual, threshold))
failWith(DoublesEqualFailure(this, fileName, lineNumber, expected, actual, threshold, text), testTerminator);
}
void UtestShell::assertBinaryEqual(const void *expected, const void *actual, size_t length, const char* text, const char *fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if (length == 0) return;
if (actual == NULLPTR && expected == NULLPTR) return;
if (actual == NULLPTR || expected == NULLPTR)
failWith(BinaryEqualFailure(this, fileName, lineNumber, (const unsigned char *) expected, (const unsigned char *) actual, length, text), testTerminator);
if (SimpleString::MemCmp(expected, actual, length) != 0)
failWith(BinaryEqualFailure(this, fileName, lineNumber, (const unsigned char *) expected, (const unsigned char *) actual, length, text), testTerminator);
}
void UtestShell::assertBitsEqual(unsigned long expected, unsigned long actual, unsigned long mask, size_t byteCount, const char* text, const char *fileName, size_t lineNumber, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if ((expected & mask) != (actual & mask))
failWith(BitsEqualFailure(this, fileName, lineNumber, expected, actual, mask, byteCount, text), testTerminator);
}
void UtestShell::assertEquals(bool failed, const char* expected, const char* actual, const char* text, const char* file, size_t line, const TestTerminator& testTerminator)
{
getTestResult()->countCheck();
if (failed)
failWith(CheckEqualFailure(this, file, line, expected, actual, text), testTerminator);
}
void UtestShell::assertCompare(bool comparison, const char *checkString, const char *comparisonString, const char *text, const char *fileName, size_t lineNumber, const TestTerminator &testTerminator)
{
getTestResult()->countCheck();
if (!comparison)
failWith(ComparisonFailure(this, fileName, lineNumber, checkString, comparisonString, text), testTerminator);
}
void UtestShell::print(const char *text, const char* fileName, size_t lineNumber)
{
SimpleString stringToPrint = "\n";
stringToPrint += fileName;
stringToPrint += ":";
stringToPrint += StringFrom(lineNumber);
stringToPrint += " ";
stringToPrint += text;
getTestResult()->print(stringToPrint.asCharString());
}
void UtestShell::print(const SimpleString& text, const char* fileName, size_t lineNumber)
{
print(text.asCharString(), fileName, lineNumber);
}
void UtestShell::printVeryVerbose(const char* text)
{
getTestResult()->printVeryVerbose(text);
}
TestResult* UtestShell::testResult_ = NULLPTR;
UtestShell* UtestShell::currentTest_ = NULLPTR;
void UtestShell::setTestResult(TestResult* result)
{
testResult_ = result;
}
void UtestShell::setCurrentTest(UtestShell* test)
{
currentTest_ = test;
}
TestResult* UtestShell::getTestResult()
{
if (testResult_ == NULLPTR)
return &OutsideTestRunnerUTest::instance().getTestResult();
return testResult_;
}
UtestShell* UtestShell::getCurrent()
{
if (currentTest_ == NULLPTR)
return &OutsideTestRunnerUTest::instance();
return currentTest_;
}
const TestTerminator &UtestShell::getCurrentTestTerminator()
{
return *currentTestTerminator_;
}
void UtestShell::setCrashOnFail()
{
currentTestTerminator_ = &crashingTestTerminator;
}
void UtestShell::restoreDefaultTestTerminator()
{
currentTestTerminator_ = &normalTestTerminator;
}
ExecFunctionTestShell::~ExecFunctionTestShell()
{
}
////////////// Utest ////////////
Utest::Utest()
{
}
Utest::~Utest()
{
}
#if CPPUTEST_USE_STD_CPP_LIB
void Utest::run()
{
UtestShell* current = UtestShell::getCurrent();
int jumpResult = 0;
try {
current->printVeryVerbose("\n-------- before setup: ");
jumpResult = PlatformSpecificSetJmp(helperDoTestSetup, this);
current->printVeryVerbose("\n-------- after setup: ");
if (jumpResult) {
current->printVeryVerbose("\n---------- before body: ");
PlatformSpecificSetJmp(helperDoTestBody, this);
current->printVeryVerbose("\n---------- after body: ");
}
}
catch (CppUTestFailedException&)
{
PlatformSpecificRestoreJumpBuffer();
}
try {
current->printVeryVerbose("\n-------- before teardown: ");
PlatformSpecificSetJmp(helperDoTestTeardown, this);
current->printVeryVerbose("\n-------- after teardown: ");
}
catch (CppUTestFailedException&)
{
PlatformSpecificRestoreJumpBuffer();
}
}
#else
void Utest::run()
{
if (PlatformSpecificSetJmp(helperDoTestSetup, this)) {
PlatformSpecificSetJmp(helperDoTestBody, this);
}
PlatformSpecificSetJmp(helperDoTestTeardown, this);
}
#endif
void Utest::setup()
{
}
void Utest::testBody()
{
}
void Utest::teardown()
{
}
/////////////////// Terminators
TestTerminator::~TestTerminator()
{
}
void NormalTestTerminator::exitCurrentTest() const
{
#if CPPUTEST_USE_STD_CPP_LIB
throw CppUTestFailedException();
#else
TestTerminatorWithoutExceptions().exitCurrentTest();
#endif
}
NormalTestTerminator::~NormalTestTerminator()
{
}
void TestTerminatorWithoutExceptions::exitCurrentTest() const
{
PlatformSpecificLongJmp();
} // LCOV_EXCL_LINE
TestTerminatorWithoutExceptions::~TestTerminatorWithoutExceptions()
{
}
void CrashingTestTerminator::exitCurrentTest() const
{
UtestShell::crash();
NormalTestTerminator::exitCurrentTest();
}
CrashingTestTerminator::~CrashingTestTerminator()
{
}
//////////////////// ExecFunction
//
ExecFunction::ExecFunction()
{
}
ExecFunction::~ExecFunction()
{
}
ExecFunctionWithoutParameters::ExecFunctionWithoutParameters(void(*testFunction)())
: testFunction_(testFunction)
{
}
ExecFunctionWithoutParameters::~ExecFunctionWithoutParameters()
{
}
void ExecFunctionWithoutParameters::exec()
{
if (testFunction_)
testFunction_();
}
//////////////////// ExecFunctionTest
ExecFunctionTest::ExecFunctionTest(ExecFunctionTestShell* shell)
: shell_(shell)
{
}
void ExecFunctionTest::testBody()
{
if (shell_->testFunction_) shell_->testFunction_->exec();
}
void ExecFunctionTest::setup()
{
if (shell_->setup_) shell_->setup_();
}
void ExecFunctionTest::teardown()
{
if (shell_->teardown_) shell_->teardown_();
}
/////////////// IgnoredUtestShell /////////////
IgnoredUtestShell::IgnoredUtestShell(): runIgnored_(false)
{
}
IgnoredUtestShell::IgnoredUtestShell(const char* groupName, const char* testName, const char* fileName, size_t lineNumber) :
UtestShell(groupName, testName, fileName, lineNumber), runIgnored_(false)
{
}
IgnoredUtestShell::~IgnoredUtestShell()
{
}
bool IgnoredUtestShell::willRun() const
{
if (runIgnored_) return UtestShell::willRun();
return false;
}
SimpleString IgnoredUtestShell::getMacroName() const
{
if (runIgnored_) return "TEST";
return "IGNORE_TEST";
}
void IgnoredUtestShell::runOneTest(TestPlugin* plugin, TestResult& result)
{
if (runIgnored_)
{
UtestShell::runOneTest(plugin, result);
return;
}
result.countIgnored();
}
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(size_t seed)
{
if (count_ == 0) return;
PlatformSpecificSrand((unsigned int) 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(size_t index) const
{
if (index >= count_) return NULLPTR;
return arrayOfTests_[index];
}
////////////// TestInstaller ////////////
TestInstaller::TestInstaller(UtestShell& shell, const char* groupName, const char* testName, const char* fileName, size_t lineNumber)
{
shell.setGroupName(groupName);
shell.setTestName(testName);
shell.setFileName(fileName);
shell.setLineNumber(lineNumber);
TestRegistry::getCurrentRegistry()->addTest(&shell);
}
TestInstaller::~TestInstaller()
{
}
void TestInstaller::unDo()
{
TestRegistry::getCurrentRegistry()->unDoLastAddTest();
}

View file

@ -0,0 +1,60 @@
set(CppUTestExt_src
CodeMemoryReportFormatter.cpp
GTest.cpp
IEEE754ExceptionsPlugin.cpp
MemoryReporterPlugin.cpp
MockFailure.cpp
MockSupportPlugin.cpp
MockActualCall.cpp
MockSupport_c.cpp
MemoryReportAllocator.cpp
MockExpectedCall.cpp
MockNamedValue.cpp
OrderedTest.cpp
MemoryReportFormatter.cpp
MockExpectedCallsList.cpp
MockSupport.cpp
)
set(CppUTestExt_headers
${CppUTestRootDirectory}/include/CppUTestExt/CodeMemoryReportFormatter.h
${CppUTestRootDirectory}/include/CppUTestExt/IEEE754ExceptionsPlugin.h
${CppUTestRootDirectory}/include/CppUTestExt/MemoryReportAllocator.h
${CppUTestRootDirectory}/include/CppUTestExt/MockExpectedCall.h
${CppUTestRootDirectory}/include/CppUTestExt/MockCheckedExpectedCall.h
${CppUTestRootDirectory}/include/CppUTestExt/MockExpectedCallsList.h
${CppUTestRootDirectory}/include/CppUTestExt/MockSupportPlugin.h
${CppUTestRootDirectory}/include/CppUTestExt/MemoryReportFormatter.h
${CppUTestRootDirectory}/include/CppUTestExt/MockFailure.h
${CppUTestRootDirectory}/include/CppUTestExt/MockSupport.h
${CppUTestRootDirectory}/include/CppUTestExt/MockSupport_c.h
${CppUTestRootDirectory}/include/CppUTestExt/GMock.h
${CppUTestRootDirectory}/include/CppUTestExt/GTest.h
${CppUTestRootDirectory}/include/CppUTestExt/GTestSupport.h
${CppUTestRootDirectory}/include/CppUTestExt/MemoryReporterPlugin.h
${CppUTestRootDirectory}/include/CppUTestExt/OrderedTest.h
${CppUTestRootDirectory}/include/CppUTestExt/GTestConvertor.h
${CppUTestRootDirectory}/include/CppUTestExt/MockActualCall.h
${CppUTestRootDirectory}/include/CppUTestExt/MockCheckedActualCall.h
${CppUTestRootDirectory}/include/CppUTestExt/MockNamedValue.h
${CppUTestRootDirectory}/include/CppUTestExt/MockSupport.h
)
add_library(CppUTestExt STATIC ${CppUTestExt_src} ${CppUTestExt_headers})
target_link_libraries(CppUTestExt ${CPPUNIT_EXTERNAL_LIBRARIES})
#[[Arrange for the include directory to be added to the include paths of any CMake target depending on CppUTestExt.]]
target_include_directories(CppUTestExt
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../include>
$<INSTALL_INTERFACE:include>
)
set_target_properties(CppUTestExt PROPERTIES
PUBLIC_HEADER "${CppUTestExt_headers}")
install(TARGETS CppUTestExt
EXPORT CppUTestTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/CppUTestExt"
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/CppUTestExt")

View file

@ -0,0 +1,172 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/CodeMemoryReportFormatter.h"
#include "CppUTestExt/MemoryReportAllocator.h"
#include "CppUTest/PlatformSpecificFunctions.h"
#define MAX_VARIABLE_NAME_LINE_PART 10
#define MAX_VARIABLE_NAME_FILE_PART 53
#define MAX_VARIABLE_NAME_SEPERATOR_PART 1
#define MAX_VARIABLE_NAME_LENGTH MAX_VARIABLE_NAME_FILE_PART + MAX_VARIABLE_NAME_SEPERATOR_PART + MAX_VARIABLE_NAME_LINE_PART
struct CodeReportingAllocationNode
{
char variableName_[MAX_VARIABLE_NAME_LENGTH + 1];
void* memory_;
CodeReportingAllocationNode* next_;
};
CodeMemoryReportFormatter::CodeMemoryReportFormatter(TestMemoryAllocator* internalAllocator)
: codeReportingList_(NULLPTR), internalAllocator_(internalAllocator)
{
}
CodeMemoryReportFormatter::~CodeMemoryReportFormatter()
{
clearReporting();
}
void CodeMemoryReportFormatter::clearReporting()
{
while (codeReportingList_) {
CodeReportingAllocationNode* oldNode = codeReportingList_;
codeReportingList_ = codeReportingList_->next_;
internalAllocator_->free_memory((char*) oldNode, 0, __FILE__, __LINE__);
}
}
void CodeMemoryReportFormatter::addNodeToList(const char* variableName, void* memory, CodeReportingAllocationNode* next)
{
CodeReportingAllocationNode* newNode = (CodeReportingAllocationNode*) (void*) internalAllocator_->alloc_memory(sizeof(CodeReportingAllocationNode), __FILE__, __LINE__);
newNode->memory_ = memory;
newNode->next_ = next;
SimpleString::StrNCpy(newNode->variableName_, variableName, MAX_VARIABLE_NAME_LENGTH);
codeReportingList_ = newNode;
}
CodeReportingAllocationNode* CodeMemoryReportFormatter::findNode(void* memory)
{
CodeReportingAllocationNode* current = codeReportingList_;
while (current && current->memory_ != memory) {
current = current->next_;
}
return current;
}
static SimpleString extractFileNameFromPath(const char* file)
{
const char* fileNameOnly = file + SimpleString::StrLen(file);
while (fileNameOnly != file && *fileNameOnly != '/')
fileNameOnly--;
if (*fileNameOnly == '/') fileNameOnly++;
return fileNameOnly;
}
SimpleString CodeMemoryReportFormatter::createVariableNameFromFileLineInfo(const char *file, size_t line)
{
SimpleString fileNameOnly = extractFileNameFromPath(file);
fileNameOnly.replace(".", "_");
for (int i = 1; i < 100; i++) {
SimpleString variableName = StringFromFormat("%s_%d_%d", fileNameOnly.asCharString(), (int) line, i);
if (!variableExists(variableName))
return variableName;
}
return "";
}
bool CodeMemoryReportFormatter::isNewAllocator(TestMemoryAllocator* allocator)
{
return SimpleString::StrCmp(allocator->alloc_name(), defaultNewAllocator()->alloc_name()) == 0 || SimpleString::StrCmp(allocator->alloc_name(), defaultNewArrayAllocator()->alloc_name()) == 0;
}
bool CodeMemoryReportFormatter::variableExists(const SimpleString& variableName)
{
CodeReportingAllocationNode* current = codeReportingList_;
while (current) {
if (variableName == current->variableName_)
return true;
current = current->next_;
}
return false;
}
SimpleString CodeMemoryReportFormatter::getAllocationString(TestMemoryAllocator* allocator, const SimpleString& variableName, size_t size)
{
if (isNewAllocator(allocator))
return StringFromFormat("char* %s = new char[%lu]; /* using %s */", variableName.asCharString(), (unsigned long) size, allocator->alloc_name());
else
return StringFromFormat("void* %s = malloc(%lu);", variableName.asCharString(), (unsigned long) size);
}
SimpleString CodeMemoryReportFormatter::getDeallocationString(TestMemoryAllocator* allocator, const SimpleString& variableName, const char* file, size_t line)
{
if (isNewAllocator(allocator))
return StringFromFormat("delete [] %s; /* using %s at %s:%d */", variableName.asCharString(), allocator->free_name(), file, (int) line);
else
return StringFromFormat("free(%s); /* at %s:%d */", variableName.asCharString(), file, (int) line);
}
void CodeMemoryReportFormatter::report_test_start(TestResult* result, UtestShell& test)
{
clearReporting();
result->print(StringFromFormat("*/\nTEST(%s_memoryReport, %s)\n{ /* at %s:%d */\n",
test.getGroup().asCharString(), test.getName().asCharString(), test.getFile().asCharString(), (int) test.getLineNumber()).asCharString());
}
void CodeMemoryReportFormatter::report_test_end(TestResult* result, UtestShell&)
{
result->print("}/*");
}
void CodeMemoryReportFormatter::report_testgroup_start(TestResult* result, UtestShell& test)
{
result->print(StringFromFormat("*/TEST_GROUP(%s_memoryReport)\n{\n};\n/*",
test.getGroup().asCharString()).asCharString());
}
void CodeMemoryReportFormatter::report_alloc_memory(TestResult* result, TestMemoryAllocator* allocator, size_t size, char* memory, const char* file, size_t line)
{
SimpleString variableName = createVariableNameFromFileLineInfo(file, line);
result->print(StringFromFormat("\t%s\n", getAllocationString(allocator, variableName, size).asCharString()).asCharString());
addNodeToList(variableName.asCharString(), memory, codeReportingList_);
}
void CodeMemoryReportFormatter::report_free_memory(TestResult* result, TestMemoryAllocator* allocator, char* memory, const char* file, size_t line)
{
SimpleString variableName;
CodeReportingAllocationNode* node = findNode(memory);
if (memory == NULLPTR) variableName = "NULL";
else variableName = node->variableName_;
result->print(StringFromFormat("\t%s\n", getDeallocationString(allocator, variableName, file, line).asCharString()).asCharString());
}

View file

@ -0,0 +1,9 @@
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/GTestSupport.h"
void CppuTestGTestIgnoreLeaksInTest()
{
IGNORE_ALL_LEAKS_IN_TEST();
}

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2015, Michael Feathers, James Grenning, Bas Vodde
* and Arnd R. Strube. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/IEEE754ExceptionsPlugin.h"
#ifdef CPPUTEST_HAVE_FENV
extern "C" {
#include <fenv.h>
}
#define IEEE754_CHECK_CLEAR(test, result, flag) ieee754Check(test, result, flag, #flag)
bool IEEE754ExceptionsPlugin::inexactDisabled_ = true;
IEEE754ExceptionsPlugin::IEEE754ExceptionsPlugin(const SimpleString& name)
: TestPlugin(name)
{
}
void IEEE754ExceptionsPlugin::preTestAction(UtestShell&, TestResult&)
{
CHECK(!feclearexcept(FE_ALL_EXCEPT));
}
void IEEE754ExceptionsPlugin::postTestAction(UtestShell& test, TestResult& result)
{
if(!test.hasFailed()) {
IEEE754_CHECK_CLEAR(test, result, FE_DIVBYZERO);
IEEE754_CHECK_CLEAR(test, result, FE_OVERFLOW);
IEEE754_CHECK_CLEAR(test, result, FE_UNDERFLOW);
IEEE754_CHECK_CLEAR(test, result, FE_INVALID); // LCOV_EXCL_LINE (not all platforms support this)
IEEE754_CHECK_CLEAR(test, result, FE_INEXACT);
}
}
void IEEE754ExceptionsPlugin::disableInexact()
{
inexactDisabled_ = true;
}
void IEEE754ExceptionsPlugin::enableInexact()
{
inexactDisabled_ = false;
}
bool IEEE754ExceptionsPlugin::checkIeee754OverflowExceptionFlag()
{
return fetestexcept(FE_OVERFLOW) != 0;
}
bool IEEE754ExceptionsPlugin::checkIeee754UnderflowExceptionFlag()
{
return fetestexcept(FE_UNDERFLOW) != 0;
}
bool IEEE754ExceptionsPlugin::checkIeee754InexactExceptionFlag()
{
return fetestexcept(FE_INEXACT) != 0;
}
bool IEEE754ExceptionsPlugin::checkIeee754DivByZeroExceptionFlag()
{
return fetestexcept(FE_DIVBYZERO) != 0;
}
void IEEE754ExceptionsPlugin::ieee754Check(UtestShell& test, TestResult& result, int flag, const char* text)
{
result.countCheck();
if(inexactDisabled_) CHECK(!feclearexcept(FE_INEXACT));
if(fetestexcept(flag)) {
CHECK(!feclearexcept(FE_ALL_EXCEPT));
CheckFailure failure(&test, __FILE__, __LINE__, "IEEE754_CHECK_CLEAR", text);
result.addFailure(failure);
}
}
#else
bool IEEE754ExceptionsPlugin::inexactDisabled_ = true;
IEEE754ExceptionsPlugin::IEEE754ExceptionsPlugin(const SimpleString& name)
: TestPlugin(name)
{
}
void IEEE754ExceptionsPlugin::preTestAction(UtestShell&, TestResult&)
{
}
void IEEE754ExceptionsPlugin::postTestAction(UtestShell&, TestResult&)
{
}
void IEEE754ExceptionsPlugin::disableInexact()
{
}
void IEEE754ExceptionsPlugin::enableInexact()
{
}
bool IEEE754ExceptionsPlugin::checkIeee754OverflowExceptionFlag()
{
return false;
}
bool IEEE754ExceptionsPlugin::checkIeee754UnderflowExceptionFlag()
{
return false;
}
bool IEEE754ExceptionsPlugin::checkIeee754InexactExceptionFlag()
{
return false;
}
bool IEEE754ExceptionsPlugin::checkIeee754DivByZeroExceptionFlag()
{
return false;
}
void IEEE754ExceptionsPlugin::ieee754Check(UtestShell&, TestResult&, int, const char*)
{
}
#endif

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MemoryReportAllocator.h"
#include "CppUTestExt/MemoryReportFormatter.h"
MemoryReportAllocator::MemoryReportAllocator() : result_(NULLPTR), realAllocator_(NULLPTR), formatter_(NULLPTR)
{
}
MemoryReportAllocator::~MemoryReportAllocator()
{
}
const char* MemoryReportAllocator::name() const
{
return "MemoryReporterAllocator";
}
const char* MemoryReportAllocator::alloc_name() const
{
return realAllocator_->alloc_name();
}
const char* MemoryReportAllocator::free_name() const
{
return realAllocator_->free_name();
}
void MemoryReportAllocator::setRealAllocator(TestMemoryAllocator* allocator)
{
realAllocator_ = allocator;
}
TestMemoryAllocator* MemoryReportAllocator::getRealAllocator()
{
return realAllocator_;
}
TestMemoryAllocator* MemoryReportAllocator::actualAllocator()
{
return realAllocator_->actualAllocator();
}
void MemoryReportAllocator::setTestResult(TestResult* result)
{
result_ = result;
}
void MemoryReportAllocator::setFormatter(MemoryReportFormatter* formatter)
{
formatter_ = formatter;
}
char* MemoryReportAllocator::alloc_memory(size_t size, const char* file, size_t line)
{
char* memory = realAllocator_->alloc_memory(size, file, line);
if (result_ && formatter_)
formatter_->report_alloc_memory(result_, this, size, memory, file, line);
return memory;
}
void MemoryReportAllocator::free_memory(char* memory, size_t size, const char* file, size_t line)
{
realAllocator_->free_memory(memory, size, file, line);
if (result_ && formatter_)
formatter_->report_free_memory(result_, this, memory, file, line);
}

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MemoryReportAllocator.h"
#include "CppUTestExt/MemoryReportFormatter.h"
NormalMemoryReportFormatter::NormalMemoryReportFormatter()
{
}
NormalMemoryReportFormatter::~NormalMemoryReportFormatter()
{
}
void NormalMemoryReportFormatter::report_test_start(TestResult* result, UtestShell& test)
{
result->print(StringFromFormat("TEST(%s, %s)\n", test.getGroup().asCharString(), test.getName().asCharString()).asCharString());
}
void NormalMemoryReportFormatter::report_test_end(TestResult* result, UtestShell& test)
{
result->print(StringFromFormat("ENDTEST(%s, %s)\n", test.getGroup().asCharString(), test.getName().asCharString()).asCharString());
}
void NormalMemoryReportFormatter::report_alloc_memory(TestResult* result, TestMemoryAllocator* allocator, size_t size, char* memory, const char* file, size_t line)
{
result->print(StringFromFormat("\tAllocation using %s of size: %lu pointer: %p at %s:%d\n", allocator->alloc_name(), (unsigned long) size, (void*) memory, file, (int) line).asCharString());
}
void NormalMemoryReportFormatter::report_free_memory(TestResult* result, TestMemoryAllocator* allocator, char* memory, const char* file, size_t line)
{
result->print(StringFromFormat("\tDeallocation using %s of pointer: %p at %s:%d\n", allocator->free_name(), (void*) memory, file, (int) line).asCharString());
}
void NormalMemoryReportFormatter::report_testgroup_start(TestResult* result, UtestShell& test)
{
const size_t line_size = 80;
SimpleString groupName = StringFromFormat("TEST GROUP(%s)", test.getGroup().asCharString());
size_t beginPos = (line_size/2) - (groupName.size()/2);
SimpleString line("-", beginPos);
line += groupName;
line += SimpleString("-", line_size - line.size());
line += "\n";
result->print(line.asCharString());
}

View file

@ -0,0 +1,146 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MemoryReporterPlugin.h"
#include "CppUTestExt/MemoryReportFormatter.h"
#include "CppUTestExt/CodeMemoryReportFormatter.h"
MemoryReporterPlugin::MemoryReporterPlugin()
: TestPlugin("MemoryReporterPlugin"), formatter_(NULLPTR)
{
}
MemoryReporterPlugin::~MemoryReporterPlugin()
{
removeGlobalMemoryReportAllocators();
destroyMemoryFormatter(formatter_);
}
bool MemoryReporterPlugin::parseArguments(int /* ac */, const char *const *av, int index)
{
SimpleString argument (av[index]);
if (argument.contains("-pmemoryreport=")) {
argument.replace("-pmemoryreport=", "");
destroyMemoryFormatter(formatter_);
formatter_ = createMemoryFormatter(argument);
return true;
}
return false;
}
MemoryReportFormatter* MemoryReporterPlugin::createMemoryFormatter(const SimpleString& type)
{
if (type == "normal") {
return new NormalMemoryReportFormatter;
}
else if (type == "code") {
return new CodeMemoryReportFormatter(defaultMallocAllocator());
}
return NULLPTR;
}
void MemoryReporterPlugin::destroyMemoryFormatter(MemoryReportFormatter* formatter)
{
delete formatter;
}
void MemoryReporterPlugin::setGlobalMemoryReportAllocators()
{
mallocAllocator.setRealAllocator(getCurrentMallocAllocator());
setCurrentMallocAllocator(&mallocAllocator);
newAllocator.setRealAllocator(getCurrentNewAllocator());
setCurrentNewAllocator(&newAllocator);
newArrayAllocator.setRealAllocator(getCurrentNewArrayAllocator());
setCurrentNewArrayAllocator(&newArrayAllocator);
}
void MemoryReporterPlugin::removeGlobalMemoryReportAllocators()
{
if (getCurrentNewAllocator() == &newAllocator)
setCurrentNewAllocator(newAllocator.getRealAllocator());
if (getCurrentNewArrayAllocator() == &newArrayAllocator)
setCurrentNewArrayAllocator(newArrayAllocator.getRealAllocator());
if (getCurrentMallocAllocator() == &mallocAllocator)
setCurrentMallocAllocator(mallocAllocator.getRealAllocator());
}
MemoryReportAllocator* MemoryReporterPlugin::getMallocAllocator()
{
return &mallocAllocator;
}
MemoryReportAllocator* MemoryReporterPlugin::getNewAllocator()
{
return &newAllocator;
}
MemoryReportAllocator* MemoryReporterPlugin::getNewArrayAllocator()
{
return &newArrayAllocator;
}
void MemoryReporterPlugin::initializeAllocator(MemoryReportAllocator* allocator, TestResult & result)
{
allocator->setFormatter(formatter_);
allocator->setTestResult((&result));
}
void MemoryReporterPlugin::preTestAction(UtestShell& test, TestResult& result)
{
if (formatter_ == NULLPTR) return;
initializeAllocator(&mallocAllocator, result);
initializeAllocator(&newAllocator, result);
initializeAllocator(&newArrayAllocator, result);
setGlobalMemoryReportAllocators();
if (test.getGroup() != currentTestGroup_) {
formatter_->report_testgroup_start(&result, test);
currentTestGroup_ = test.getGroup();
}
formatter_->report_test_start(&result, test);
}
void MemoryReporterPlugin::postTestAction(UtestShell& test, TestResult& result)
{
if (formatter_ == NULLPTR) return;
removeGlobalMemoryReportAllocators();
formatter_->report_test_end(&result, test);
if (test.getNext() == NULLPTR || test.getNext()->getGroup() != currentTestGroup_)
formatter_->report_testgroup_end(&result, test);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,618 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockCheckedExpectedCall.h"
MockExpectedCall::MockExpectedCall()
{
}
MockExpectedCall::~MockExpectedCall()
{
}
SimpleString StringFrom(const MockNamedValue& parameter)
{
return parameter.toString();
}
void MockCheckedExpectedCall::setName(const SimpleString& name)
{
functionName_ = name;
}
SimpleString MockCheckedExpectedCall::getName() const
{
return functionName_;
}
MockCheckedExpectedCall::MockCheckedExpectedCall()
: ignoreOtherParameters_(false), isActualCallMatchFinalized_(false),
initialExpectedCallOrder_(NO_EXPECTED_CALL_ORDER), finalExpectedCallOrder_(NO_EXPECTED_CALL_ORDER),
outOfOrder_(false), returnValue_(""), objectPtr_(NULLPTR), isSpecificObjectExpected_(false), wasPassedToObject_(true),
actualCalls_(0), expectedCalls_(1)
{
inputParameters_ = new MockNamedValueList();
outputParameters_ = new MockNamedValueList();
}
MockCheckedExpectedCall::MockCheckedExpectedCall(unsigned int numCalls)
: ignoreOtherParameters_(false), isActualCallMatchFinalized_(false),
initialExpectedCallOrder_(NO_EXPECTED_CALL_ORDER), finalExpectedCallOrder_(NO_EXPECTED_CALL_ORDER),
outOfOrder_(false), returnValue_(""), objectPtr_(NULLPTR), isSpecificObjectExpected_(false), wasPassedToObject_(true),
actualCalls_(0), expectedCalls_(numCalls)
{
inputParameters_ = new MockNamedValueList();
outputParameters_ = new MockNamedValueList();
}
MockCheckedExpectedCall::~MockCheckedExpectedCall()
{
inputParameters_->clear();
delete inputParameters_;
outputParameters_->clear();
delete outputParameters_;
}
MockExpectedCall& MockCheckedExpectedCall::withName(const SimpleString& name)
{
setName(name);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withBoolParameter(const SimpleString& name, bool value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withUnsignedIntParameter(const SimpleString& name, unsigned int value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withIntParameter(const SimpleString& name, int value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withLongIntParameter(const SimpleString& name, long int value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withUnsignedLongIntParameter(const SimpleString& name, unsigned long int value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
#ifdef CPPUTEST_USE_LONG_LONG
MockExpectedCall& MockCheckedExpectedCall::withLongLongIntParameter(const SimpleString& name, cpputest_longlong value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withUnsignedLongLongIntParameter(const SimpleString& name, cpputest_ulonglong value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
#else
MockExpectedCall& MockCheckedExpectedCall::withLongLongIntParameter(const SimpleString&, cpputest_longlong)
{
FAIL("Long Long type is not supported");
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withUnsignedLongLongIntParameter(const SimpleString&, cpputest_ulonglong)
{
FAIL("Unsigned Long Long type is not supported");
return *this;
}
#endif
MockExpectedCall& MockCheckedExpectedCall::withDoubleParameter(const SimpleString& name, double value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withDoubleParameter(const SimpleString& name, double value, double tolerance)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value, tolerance);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withStringParameter(const SimpleString& name, const char* value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withPointerParameter(const SimpleString& name, void* value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withConstPointerParameter(const SimpleString& name, const void* value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withFunctionPointerParameter(const SimpleString& name, void (*value)())
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withMemoryBufferParameter(const SimpleString& name, const unsigned char* value, size_t size)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setMemoryBuffer(value, size);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withParameterOfType(const SimpleString& type, const SimpleString& name, const void* value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
inputParameters_->add(newParameter);
newParameter->setConstObjectPointer(type, value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withOutputParameterReturning(const SimpleString& name, const void* value, size_t size)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
outputParameters_->add(newParameter);
newParameter->setValue(value);
newParameter->setSize(size);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withOutputParameterOfTypeReturning(const SimpleString& type, const SimpleString& name, const void* value)
{
MockNamedValue* newParameter = new MockExpectedFunctionParameter(name);
outputParameters_->add(newParameter);
newParameter->setConstObjectPointer(type, value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::withUnmodifiedOutputParameter(const SimpleString& name)
{
return withOutputParameterReturning(name, NULLPTR, 0);
}
SimpleString MockCheckedExpectedCall::getInputParameterType(const SimpleString& name)
{
MockNamedValue * p = inputParameters_->getValueByName(name);
return (p) ? p->getType() : "";
}
bool MockCheckedExpectedCall::hasInputParameterWithName(const SimpleString& name)
{
MockNamedValue * p = inputParameters_->getValueByName(name);
return p != NULLPTR;
}
bool MockCheckedExpectedCall::hasOutputParameterWithName(const SimpleString& name)
{
MockNamedValue * p = outputParameters_->getValueByName(name);
return p != NULLPTR;
}
MockNamedValue MockCheckedExpectedCall::getInputParameter(const SimpleString& name)
{
MockNamedValue * p = inputParameters_->getValueByName(name);
return (p) ? *p : MockNamedValue("");
}
MockNamedValue MockCheckedExpectedCall::getOutputParameter(const SimpleString& name)
{
MockNamedValue * p = outputParameters_->getValueByName(name);
return (p) ? *p : MockNamedValue("");
}
bool MockCheckedExpectedCall::areParametersMatchingActualCall()
{
MockNamedValueListNode* p;
for (p = inputParameters_->begin(); p; p = p->next())
if (! item(p)->isMatchingActualCall())
return false;
for (p = outputParameters_->begin(); p; p = p->next())
if (! item(p)->isMatchingActualCall())
return false;
return true;
}
MockExpectedCall& MockCheckedExpectedCall::ignoreOtherParameters()
{
ignoreOtherParameters_ = true;
return *this;
}
bool MockCheckedExpectedCall::isFulfilled()
{
return (actualCalls_ == expectedCalls_);
}
bool MockCheckedExpectedCall::canMatchActualCalls()
{
return (actualCalls_ < expectedCalls_);
}
bool MockCheckedExpectedCall::isMatchingActualCallAndFinalized()
{
return isMatchingActualCall() && (!ignoreOtherParameters_ || isActualCallMatchFinalized_);
}
bool MockCheckedExpectedCall::isMatchingActualCall()
{
return areParametersMatchingActualCall() && wasPassedToObject_;
}
void MockCheckedExpectedCall::callWasMade(unsigned int callOrder)
{
actualCalls_++;
if ( (initialExpectedCallOrder_ != NO_EXPECTED_CALL_ORDER) &&
((callOrder < initialExpectedCallOrder_) || (callOrder > finalExpectedCallOrder_)) ) {
outOfOrder_ = true;
}
resetActualCallMatchingState();
}
void MockCheckedExpectedCall::finalizeActualCallMatch()
{
isActualCallMatchFinalized_ = true;
}
void MockCheckedExpectedCall::wasPassedToObject()
{
wasPassedToObject_ = true;
}
void MockCheckedExpectedCall::resetActualCallMatchingState()
{
wasPassedToObject_ = !isSpecificObjectExpected_;
isActualCallMatchFinalized_ = false;
MockNamedValueListNode* p;
for (p = inputParameters_->begin(); p; p = p->next())
item(p)->setMatchesActualCall(false);
for (p = outputParameters_->begin(); p; p = p->next())
item(p)->setMatchesActualCall(false);
}
void MockCheckedExpectedCall::inputParameterWasPassed(const SimpleString& name)
{
for (MockNamedValueListNode* p = inputParameters_->begin(); p; p = p->next()) {
if (p->getName() == name)
item(p)->setMatchesActualCall(true);
}
}
void MockCheckedExpectedCall::outputParameterWasPassed(const SimpleString& name)
{
for (MockNamedValueListNode* p = outputParameters_->begin(); p; p = p->next()) {
if (p->getName() == name)
item(p)->setMatchesActualCall(true);
}
}
SimpleString MockCheckedExpectedCall::getInputParameterValueString(const SimpleString& name)
{
MockNamedValue * p = inputParameters_->getValueByName(name);
return (p) ? StringFrom(*p) : "failed";
}
bool MockCheckedExpectedCall::hasInputParameter(const MockNamedValue& parameter)
{
MockNamedValue * p = inputParameters_->getValueByName(parameter.getName());
return (p) ? p->equals(parameter) : ignoreOtherParameters_;
}
bool MockCheckedExpectedCall::hasOutputParameter(const MockNamedValue& parameter)
{
MockNamedValue * p = outputParameters_->getValueByName(parameter.getName());
return (p) ? p->compatibleForCopying(parameter) : ignoreOtherParameters_;
}
SimpleString MockCheckedExpectedCall::callToString()
{
SimpleString str;
if (isSpecificObjectExpected_)
str = StringFromFormat("(object address: %p)::", objectPtr_);
str += getName();
str += " -> ";
if (initialExpectedCallOrder_ != NO_EXPECTED_CALL_ORDER) {
if (initialExpectedCallOrder_ == finalExpectedCallOrder_) {
str += StringFromFormat("expected call order: <%u> -> ", initialExpectedCallOrder_);
} else {
str += StringFromFormat("expected calls order: <%u..%u> -> ", initialExpectedCallOrder_, finalExpectedCallOrder_);
}
}
if (inputParameters_->begin() == NULLPTR && outputParameters_->begin() == NULLPTR) {
str += (ignoreOtherParameters_) ? "all parameters ignored" : "no parameters";
} else {
MockNamedValueListNode* p;
for (p = inputParameters_->begin(); p; p = p->next()) {
str += StringFromFormat("%s %s: <%s>", p->getType().asCharString(), p->getName().asCharString(), getInputParameterValueString(p->getName()).asCharString());
if (p->next()) str += ", ";
}
if (inputParameters_->begin() && outputParameters_->begin())
{
str += ", ";
}
for (p = outputParameters_->begin(); p; p = p->next()) {
str += StringFromFormat("%s %s: <output>", p->getType().asCharString(), p->getName().asCharString());
if (p->next()) str += ", ";
}
if (ignoreOtherParameters_)
str += ", other parameters are ignored";
}
str += StringFromFormat(" (expected %d call%s, called %d time%s)",
expectedCalls_, (expectedCalls_ == 1) ? "" : "s", actualCalls_, (actualCalls_ == 1) ? "" : "s" );
return str;
}
SimpleString MockCheckedExpectedCall::missingParametersToString()
{
SimpleString str;
MockNamedValueListNode* p;
for (p = inputParameters_->begin(); p; p = p->next()) {
if (! item(p)->isMatchingActualCall()) {
if (str != "") str += ", ";
str += StringFromFormat("%s %s", p->getType().asCharString(), p->getName().asCharString());
}
}
for (p = outputParameters_->begin(); p; p = p->next()) {
if (! item(p)->isMatchingActualCall()) {
if (str != "") str += ", ";
str += StringFromFormat("%s %s", p->getType().asCharString(), p->getName().asCharString());
}
}
return str;
}
bool MockCheckedExpectedCall::relatesTo(const SimpleString& functionName)
{
return functionName == getName();
}
bool MockCheckedExpectedCall::relatesToObject(const void* objectPtr) const
{
return (!isSpecificObjectExpected_) || (objectPtr_ == objectPtr);
}
MockCheckedExpectedCall::MockExpectedFunctionParameter* MockCheckedExpectedCall::item(MockNamedValueListNode* node)
{
return (MockExpectedFunctionParameter*) node->item();
}
MockCheckedExpectedCall::MockExpectedFunctionParameter::MockExpectedFunctionParameter(const SimpleString& name)
: MockNamedValue(name), matchesActualCall_(false)
{
}
void MockCheckedExpectedCall::MockExpectedFunctionParameter::setMatchesActualCall(bool b)
{
matchesActualCall_ = b;
}
bool MockCheckedExpectedCall::MockExpectedFunctionParameter::isMatchingActualCall() const
{
return matchesActualCall_;
}
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(bool value)
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(unsigned int value)
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(int value)
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(long int value)
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(unsigned long int value)
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
#ifdef CPPUTEST_USE_LONG_LONG
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(cpputest_longlong value)
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(cpputest_ulonglong value)
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
#else
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(cpputest_longlong)
{
FAIL("Long Long type is not supported");
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(cpputest_ulonglong)
{
FAIL("Unsigned Long Long type is not supported");
return *this;
}
#endif
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(const char* value)
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(double value)
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(void* value)
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(const void* value)
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::andReturnValue(void (*value)())
{
returnValue_.setName("returnValue");
returnValue_.setValue(value);
return *this;
}
MockExpectedCall& MockCheckedExpectedCall::onObject(void* objectPtr)
{
isSpecificObjectExpected_ = true;
wasPassedToObject_ = false;
objectPtr_ = objectPtr;
return *this;
}
MockNamedValue MockCheckedExpectedCall::returnValue()
{
return returnValue_;
}
MockExpectedCall& MockCheckedExpectedCall::withCallOrder(unsigned int initialCallOrder, unsigned int finalCallOrder)
{
initialExpectedCallOrder_ = initialCallOrder;
finalExpectedCallOrder_ = finalCallOrder;
return *this;
}
bool MockCheckedExpectedCall::isOutOfOrder() const
{
return outOfOrder_;
}
unsigned int MockCheckedExpectedCall::getActualCallsFulfilled() const
{
return actualCalls_;
}
MockExpectedCall& MockIgnoredExpectedCall::instance()
{
static MockIgnoredExpectedCall call;
return call;
}

View file

@ -0,0 +1,364 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockExpectedCallsList.h"
#include "CppUTestExt/MockCheckedExpectedCall.h"
MockExpectedCallsList::MockExpectedCallsList() : head_(NULLPTR)
{
}
MockExpectedCallsList::~MockExpectedCallsList()
{
while (head_) {
MockExpectedCallsListNode* next = head_->next_;
delete head_;
head_ = next;
}
}
bool MockExpectedCallsList::hasCallsOutOfOrder() const
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (p->expectedCall_->isOutOfOrder())
return true;
return false;
}
unsigned int MockExpectedCallsList::size() const
{
unsigned int count = 0;
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
count++;
return count;
}
bool MockExpectedCallsList::isEmpty() const
{
return head_ == NULLPTR;
}
unsigned int MockExpectedCallsList::amountOfActualCallsFulfilledFor(const SimpleString& name) const
{
unsigned int count = 0;
for (MockExpectedCallsListNode* p = head_; p; p = p->next_) {
if (p->expectedCall_->relatesTo(name)) {
count += p->expectedCall_->getActualCallsFulfilled();
}
}
return count;
}
unsigned int MockExpectedCallsList::amountOfUnfulfilledExpectations() const
{
unsigned int count = 0;
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (! p->expectedCall_->isFulfilled()) count++;
return count;
}
bool MockExpectedCallsList::hasFinalizedMatchingExpectations() const
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_) {
if (p->expectedCall_->isMatchingActualCallAndFinalized()) {
return true;
}
}
return false;
}
bool MockExpectedCallsList::hasUnfulfilledExpectations() const
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_) {
if (!p->expectedCall_->isFulfilled()) {
return true;
}
}
return false;
}
bool MockExpectedCallsList::hasExpectationWithName(const SimpleString& name) const
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (p->expectedCall_->relatesTo(name))
return true;
return false;
}
void MockExpectedCallsList::addExpectedCall(MockCheckedExpectedCall* call)
{
MockExpectedCallsListNode* newCall = new MockExpectedCallsListNode(call);
if (head_ == NULLPTR)
head_ = newCall;
else {
MockExpectedCallsListNode* lastCall = head_;
while (lastCall->next_) lastCall = lastCall->next_;
lastCall->next_ = newCall;
}
}
void MockExpectedCallsList::addPotentiallyMatchingExpectations(const MockExpectedCallsList& list)
{
for (MockExpectedCallsListNode* p = list.head_; p; p = p->next_)
if (p->expectedCall_->canMatchActualCalls())
addExpectedCall(p->expectedCall_);
}
void MockExpectedCallsList::addExpectationsRelatedTo(const SimpleString& name, const MockExpectedCallsList& list)
{
for (MockExpectedCallsListNode* p = list.head_; p; p = p->next_)
if (p->expectedCall_->relatesTo(name))
addExpectedCall(p->expectedCall_);
}
void MockExpectedCallsList::addExpectations(const MockExpectedCallsList& list)
{
for (MockExpectedCallsListNode* p = list.head_; p; p = p->next_)
addExpectedCall(p->expectedCall_);
}
void MockExpectedCallsList::onlyKeepExpectationsRelatedTo(const SimpleString& name)
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (! p->expectedCall_->relatesTo(name))
p->expectedCall_ = NULLPTR;
pruneEmptyNodeFromList();
}
void MockExpectedCallsList::onlyKeepOutOfOrderExpectations()
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (!p->expectedCall_->isOutOfOrder())
p->expectedCall_ = NULLPTR;
pruneEmptyNodeFromList();
}
void MockExpectedCallsList::onlyKeepUnmatchingExpectations()
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (p->expectedCall_->isMatchingActualCallAndFinalized())
{
p->expectedCall_->resetActualCallMatchingState();
p->expectedCall_ = NULLPTR;
}
pruneEmptyNodeFromList();
}
void MockExpectedCallsList::onlyKeepExpectationsWithInputParameterName(const SimpleString& name)
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (! p->expectedCall_->hasInputParameterWithName(name))
p->expectedCall_ = NULLPTR;
pruneEmptyNodeFromList();
}
void MockExpectedCallsList::onlyKeepExpectationsWithOutputParameterName(const SimpleString& name)
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (! p->expectedCall_->hasOutputParameterWithName(name))
p->expectedCall_ = NULLPTR;
pruneEmptyNodeFromList();
}
void MockExpectedCallsList::onlyKeepExpectationsWithInputParameter(const MockNamedValue& parameter)
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (! p->expectedCall_->hasInputParameter(parameter))
p->expectedCall_ = NULLPTR;
pruneEmptyNodeFromList();
}
void MockExpectedCallsList::onlyKeepExpectationsWithOutputParameter(const MockNamedValue& parameter)
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (! p->expectedCall_->hasOutputParameter(parameter))
p->expectedCall_ = NULLPTR;
pruneEmptyNodeFromList();
}
void MockExpectedCallsList::onlyKeepExpectationsOnObject(const void* objectPtr)
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (! p->expectedCall_->relatesToObject(objectPtr))
p->expectedCall_ = NULLPTR;
pruneEmptyNodeFromList();
}
MockCheckedExpectedCall* MockExpectedCallsList::removeFirstFinalizedMatchingExpectation()
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_) {
if (p->expectedCall_->isMatchingActualCallAndFinalized()) {
MockCheckedExpectedCall* matchingCall = p->expectedCall_;
p->expectedCall_ = NULLPTR;
pruneEmptyNodeFromList();
return matchingCall;
}
}
return NULLPTR;
}
MockCheckedExpectedCall* MockExpectedCallsList::getFirstMatchingExpectation()
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_) {
if (p->expectedCall_->isMatchingActualCall()) {
return p->expectedCall_;
}
}
return NULLPTR;
}
MockCheckedExpectedCall* MockExpectedCallsList::removeFirstMatchingExpectation()
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_) {
if (p->expectedCall_->isMatchingActualCall()) {
MockCheckedExpectedCall* matchingCall = p->expectedCall_;
p->expectedCall_ = NULLPTR;
pruneEmptyNodeFromList();
return matchingCall;
}
}
return NULLPTR;
}
void MockExpectedCallsList::pruneEmptyNodeFromList()
{
MockExpectedCallsListNode* current = head_;
MockExpectedCallsListNode* previous = NULLPTR;
MockExpectedCallsListNode* toBeDeleted = NULLPTR;
while (current) {
if (current->expectedCall_ == NULLPTR) {
toBeDeleted = current;
if (previous == NULLPTR)
head_ = current = current->next_;
else
current = previous->next_ = current->next_;
delete toBeDeleted;
}
else {
previous = current;
current = current->next_;
}
}
}
void MockExpectedCallsList::deleteAllExpectationsAndClearList()
{
while (head_) {
MockExpectedCallsListNode* next = head_->next_;
delete head_->expectedCall_;
delete head_;
head_ = next;
}
}
void MockExpectedCallsList::resetActualCallMatchingState()
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
p->expectedCall_->resetActualCallMatchingState();
}
void MockExpectedCallsList::wasPassedToObject()
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
p->expectedCall_->wasPassedToObject();
}
void MockExpectedCallsList::parameterWasPassed(const SimpleString& parameterName)
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
p->expectedCall_->inputParameterWasPassed(parameterName);
}
void MockExpectedCallsList::outputParameterWasPassed(const SimpleString& parameterName)
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
p->expectedCall_->outputParameterWasPassed(parameterName);
}
static SimpleString stringOrNoneTextWhenEmpty(const SimpleString& inputString, const SimpleString& linePrefix)
{
SimpleString str = inputString;
if (str == "") {
str += linePrefix;
str += "<none>";
}
return str;
}
static SimpleString appendStringOnANewLine(const SimpleString& inputString, const SimpleString& linePrefix, const SimpleString& stringToAppend)
{
SimpleString str = inputString;
if (str != "") str += "\n";
str += linePrefix;
str += stringToAppend;
return str;
}
SimpleString MockExpectedCallsList::unfulfilledCallsToString(const SimpleString& linePrefix) const
{
SimpleString str;
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (!p->expectedCall_->isFulfilled())
str = appendStringOnANewLine(str, linePrefix, p->expectedCall_->callToString());
return stringOrNoneTextWhenEmpty(str, linePrefix);
}
SimpleString MockExpectedCallsList::fulfilledCallsToString(const SimpleString& linePrefix) const
{
SimpleString str;
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (p->expectedCall_->isFulfilled())
str = appendStringOnANewLine(str, linePrefix, p->expectedCall_->callToString());
return stringOrNoneTextWhenEmpty(str, linePrefix);
}
SimpleString MockExpectedCallsList::missingParametersToString() const
{
SimpleString str;
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (! p->expectedCall_->isMatchingActualCall())
str = appendStringOnANewLine(str, "", p->expectedCall_->missingParametersToString());
return stringOrNoneTextWhenEmpty(str, "");
}
bool MockExpectedCallsList::hasUnmatchingExpectationsBecauseOfMissingParameters() const
{
for (MockExpectedCallsListNode* p = head_; p; p = p->next_)
if (! p->expectedCall_->areParametersMatchingActualCall())
return true;
return false;
}

View file

@ -0,0 +1,241 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockFailure.h"
#include "CppUTestExt/MockExpectedCall.h"
#include "CppUTestExt/MockExpectedCallsList.h"
#include "CppUTestExt/MockNamedValue.h"
class MockFailureReporterTestTerminator : public TestTerminator
{
public:
MockFailureReporterTestTerminator(bool crashOnFailure) : crashOnFailure_(crashOnFailure)
{
}
virtual void exitCurrentTest() const _override
{
if (crashOnFailure_)
UT_CRASH();
UtestShell::getCurrentTestTerminator().exitCurrentTest();
} // LCOV_EXCL_LINE
virtual ~MockFailureReporterTestTerminator() _destructor_override
{
}
private:
bool crashOnFailure_;
};
void MockFailureReporter::failTest(const MockFailure& failure)
{
if (!getTestToFail()->hasFailed())
getTestToFail()->failWith(failure, MockFailureReporterTestTerminator(crashOnFailure_));
} // LCOV_EXCL_LINE
UtestShell* MockFailureReporter::getTestToFail()
{
return UtestShell::getCurrent();
}
MockFailure::MockFailure(UtestShell* test) : TestFailure(test, "Test failed with MockFailure without an error! Something went seriously wrong.")
{
}
void MockFailure::addExpectationsAndCallHistory(const MockExpectedCallsList& expectations)
{
message_ += "\tEXPECTED calls that WERE NOT fulfilled:\n";
message_ += expectations.unfulfilledCallsToString("\t\t");
message_ += "\n\tEXPECTED calls that WERE fulfilled:\n";
message_ += expectations.fulfilledCallsToString("\t\t");
}
void MockFailure::addExpectationsAndCallHistoryRelatedTo(const SimpleString& name, const MockExpectedCallsList& expectations)
{
MockExpectedCallsList expectationsForFunction;
expectationsForFunction.addExpectationsRelatedTo(name, expectations);
message_ += "\tEXPECTED calls that WERE NOT fulfilled related to function: ";
message_ += name;
message_ += "\n";
message_ += expectationsForFunction.unfulfilledCallsToString("\t\t");
message_ += "\n\tEXPECTED calls that WERE fulfilled related to function: ";
message_ += name;
message_ += "\n";
message_ += expectationsForFunction.fulfilledCallsToString("\t\t");
}
MockExpectedCallsDidntHappenFailure::MockExpectedCallsDidntHappenFailure(UtestShell* test, const MockExpectedCallsList& expectations) : MockFailure(test)
{
message_ = "Mock Failure: Expected call WAS NOT fulfilled.\n";
addExpectationsAndCallHistory(expectations);
}
MockUnexpectedCallHappenedFailure::MockUnexpectedCallHappenedFailure(UtestShell* test, const SimpleString& name, const MockExpectedCallsList& expectations) : MockFailure(test)
{
unsigned int amountOfActualCalls = expectations.amountOfActualCallsFulfilledFor(name);
if (amountOfActualCalls > 0) {
SimpleString ordinalNumber = StringFromOrdinalNumber(amountOfActualCalls + 1);
message_ = StringFromFormat("Mock Failure: Unexpected additional (%s) call to function: ", ordinalNumber.asCharString());
} else {
message_ = "Mock Failure: Unexpected call to function: ";
}
message_ += name;
message_ += "\n";
addExpectationsAndCallHistory(expectations);
}
MockCallOrderFailure::MockCallOrderFailure(UtestShell* test, const MockExpectedCallsList& expectations) : MockFailure(test)
{
MockExpectedCallsList expectationsForOutOfOrder;
expectationsForOutOfOrder.addExpectations(expectations);
expectationsForOutOfOrder.onlyKeepOutOfOrderExpectations();
message_ = "Mock Failure: Out of order calls";
message_ += "\n";
addExpectationsAndCallHistory(expectationsForOutOfOrder);
}
MockUnexpectedInputParameterFailure::MockUnexpectedInputParameterFailure(UtestShell* test, const SimpleString& functionName, const MockNamedValue& parameter, const MockExpectedCallsList& expectations) : MockFailure(test)
{
MockExpectedCallsList expectationsForFunctionWithParameterName;
expectationsForFunctionWithParameterName.addExpectationsRelatedTo(functionName, expectations);
expectationsForFunctionWithParameterName.onlyKeepExpectationsWithInputParameterName(parameter.getName());
if (expectationsForFunctionWithParameterName.isEmpty()) {
message_ = "Mock Failure: Unexpected parameter name to function \"";
message_ += functionName;
message_ += "\": ";
message_ += parameter.getName();
}
else {
message_ = "Mock Failure: Unexpected parameter value to parameter \"";
message_ += parameter.getName();
message_ += "\" to function \"";
message_ += functionName;
message_ += "\": <";
message_ += StringFrom(parameter);
message_ += ">";
}
message_ += "\n";
addExpectationsAndCallHistoryRelatedTo(functionName, expectations);
message_ += "\n\tACTUAL unexpected parameter passed to function: ";
message_ += functionName;
message_ += "\n";
message_ += "\t\t";
message_ += parameter.getType();
message_ += " ";
message_ += parameter.getName();
message_ += ": <";
message_ += StringFrom(parameter);
message_ += ">";
}
MockUnexpectedOutputParameterFailure::MockUnexpectedOutputParameterFailure(UtestShell* test, const SimpleString& functionName, const MockNamedValue& parameter, const MockExpectedCallsList& expectations) : MockFailure(test)
{
MockExpectedCallsList expectationsForFunctionWithParameterName;
expectationsForFunctionWithParameterName.addExpectationsRelatedTo(functionName, expectations);
expectationsForFunctionWithParameterName.onlyKeepExpectationsWithOutputParameterName(parameter.getName());
if (expectationsForFunctionWithParameterName.isEmpty()) {
message_ = "Mock Failure: Unexpected output parameter name to function \"";
message_ += functionName;
message_ += "\": ";
message_ += parameter.getName();
}
else {
message_ = "Mock Failure: Unexpected parameter type \"";
message_ += parameter.getType();
message_ += "\" to output parameter \"";
message_ += parameter.getName();
message_ += "\" to function \"";
message_ += functionName;
message_ += "\"";
}
message_ += "\n";
addExpectationsAndCallHistoryRelatedTo(functionName, expectations);
message_ += "\n\tACTUAL unexpected output parameter passed to function: ";
message_ += functionName;
message_ += "\n";
message_ += "\t\t";
message_ += parameter.getType();
message_ += " ";
message_ += parameter.getName();
}
MockExpectedParameterDidntHappenFailure::MockExpectedParameterDidntHappenFailure(UtestShell* test, const SimpleString& functionName, const MockExpectedCallsList& expectations) : MockFailure(test)
{
MockExpectedCallsList expectationsForFunction;
expectationsForFunction.addExpectationsRelatedTo(functionName, expectations);
message_ = "Mock Failure: Expected parameter for function \"";
message_ += functionName;
message_ += "\" did not happen.\n";
addExpectationsAndCallHistoryRelatedTo(functionName, expectations);
message_ += "\n\tMISSING parameters that didn't happen:\n";
message_ += "\t\t";
message_ += expectationsForFunction.missingParametersToString();
}
MockNoWayToCompareCustomTypeFailure::MockNoWayToCompareCustomTypeFailure(UtestShell* test, const SimpleString& typeName) : MockFailure(test)
{
message_ = StringFromFormat("MockFailure: No way to compare type <%s>. Please install a MockNamedValueComparator.", typeName.asCharString());
}
MockNoWayToCopyCustomTypeFailure::MockNoWayToCopyCustomTypeFailure(UtestShell* test, const SimpleString& typeName) : MockFailure(test)
{
message_ = StringFromFormat("MockFailure: No way to copy type <%s>. Please install a MockNamedValueCopier.", typeName.asCharString());
}
MockUnexpectedObjectFailure::MockUnexpectedObjectFailure(UtestShell* test, const SimpleString& functionName, const void* actual, const MockExpectedCallsList& expectations) : MockFailure(test)
{
message_ = StringFromFormat ("MockFailure: Function called on an unexpected object: %s\n"
"\tActual object for call has address: <%p>\n", functionName.asCharString(),actual);
addExpectationsAndCallHistoryRelatedTo(functionName, expectations);
}
MockExpectedObjectDidntHappenFailure::MockExpectedObjectDidntHappenFailure(UtestShell* test, const SimpleString& functionName, const MockExpectedCallsList& expectations) : MockFailure(test)
{
message_ = StringFromFormat("Mock Failure: Expected call on object for function \"%s\" but it did not happen.\n", functionName.asCharString());
addExpectationsAndCallHistoryRelatedTo(functionName, expectations);
}

View file

@ -0,0 +1,660 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockNamedValue.h"
#include "CppUTest/PlatformSpecificFunctions.h"
MockNamedValueComparatorsAndCopiersRepository* MockNamedValue::defaultRepository_ = NULLPTR;
const double MockNamedValue::defaultDoubleTolerance = 0.005;
void MockNamedValue::setDefaultComparatorsAndCopiersRepository(MockNamedValueComparatorsAndCopiersRepository* repository)
{
defaultRepository_ = repository;
}
MockNamedValueComparatorsAndCopiersRepository* MockNamedValue::getDefaultComparatorsAndCopiersRepository()
{
return defaultRepository_;
}
MockNamedValue::MockNamedValue(const SimpleString& name) : name_(name), type_("int"), size_(0), comparator_(NULLPTR), copier_(NULLPTR)
{
value_.intValue_ = 0;
}
MockNamedValue::~MockNamedValue()
{
}
void MockNamedValue::setValue(bool value)
{
type_ = "bool";
value_.boolValue_ = value;
}
void MockNamedValue::setValue(unsigned int value)
{
type_ = "unsigned int";
value_.unsignedIntValue_ = value;
}
void MockNamedValue::setValue(int value)
{
type_ = "int";
value_.intValue_ = value;
}
void MockNamedValue::setValue(long int value)
{
type_ = "long int";
value_.longIntValue_ = value;
}
void MockNamedValue::setValue(unsigned long int value)
{
type_ = "unsigned long int";
value_.unsignedLongIntValue_ = value;
}
#ifdef CPPUTEST_USE_LONG_LONG
void MockNamedValue::setValue(cpputest_longlong value)
{
type_ = "long long int";
value_.longLongIntValue_ = value;
}
void MockNamedValue::setValue(cpputest_ulonglong value)
{
type_ = "unsigned long long int";
value_.unsignedLongLongIntValue_ = value;
}
#else
void MockNamedValue::setValue(cpputest_longlong)
{
FAIL("Long Long type is not supported");
}
void MockNamedValue::setValue(cpputest_ulonglong)
{
FAIL("Unsigned Long Long type is not supported");
}
#endif
void MockNamedValue::setValue(double value)
{
setValue(value, defaultDoubleTolerance);
}
void MockNamedValue::setValue(double value, double tolerance)
{
type_ = "double";
value_.doubleValue_.value = value;
value_.doubleValue_.tolerance = tolerance;
}
void MockNamedValue::setValue(void* value)
{
type_ = "void*";
value_.pointerValue_ = value;
}
void MockNamedValue::setValue(const void* value)
{
type_ = "const void*";
value_.constPointerValue_ = value;
}
void MockNamedValue::setValue(void (*value)())
{
type_ = "void (*)()";
value_.functionPointerValue_ = value;
}
void MockNamedValue::setValue(const char* value)
{
type_ = "const char*";
value_.stringValue_ = value;
}
void MockNamedValue::setMemoryBuffer(const unsigned char* value, size_t size)
{
type_ = "const unsigned char*";
value_.memoryBufferValue_ = value;
size_ = size;
}
void MockNamedValue::setConstObjectPointer(const SimpleString& type, const void* objectPtr)
{
type_ = type;
value_.constObjectPointerValue_ = objectPtr;
if (defaultRepository_)
{
comparator_ = defaultRepository_->getComparatorForType(type);
copier_ = defaultRepository_->getCopierForType(type);
}
}
void MockNamedValue::setObjectPointer(const SimpleString& type, void* objectPtr)
{
type_ = type;
value_.objectPointerValue_ = objectPtr;
if (defaultRepository_)
{
comparator_ = defaultRepository_->getComparatorForType(type);
copier_ = defaultRepository_->getCopierForType(type);
}
}
void MockNamedValue::setSize(size_t size)
{
size_ = size;
}
void MockNamedValue::setName(const char* name)
{
name_ = name;
}
SimpleString MockNamedValue::getName() const
{
return name_;
}
SimpleString MockNamedValue::getType() const
{
return type_;
}
bool MockNamedValue::getBoolValue() const
{
STRCMP_EQUAL("bool", type_.asCharString());
return value_.boolValue_;
}
unsigned int MockNamedValue::getUnsignedIntValue() const
{
if(type_ == "int" && value_.intValue_ >= 0)
return (unsigned int)value_.intValue_;
else
{
STRCMP_EQUAL("unsigned int", type_.asCharString());
return value_.unsignedIntValue_;
}
}
int MockNamedValue::getIntValue() const
{
STRCMP_EQUAL("int", type_.asCharString());
return value_.intValue_;
}
long int MockNamedValue::getLongIntValue() const
{
if(type_ == "int")
return value_.intValue_;
else if(type_ == "unsigned int")
return (long int)value_.unsignedIntValue_;
else
{
STRCMP_EQUAL("long int", type_.asCharString());
return value_.longIntValue_;
}
}
unsigned long int MockNamedValue::getUnsignedLongIntValue() const
{
if(type_ == "unsigned int")
return value_.unsignedIntValue_;
else if(type_ == "int" && value_.intValue_ >= 0)
return (unsigned long int)value_.intValue_;
else if(type_ == "long int" && value_.longIntValue_ >= 0)
return (unsigned long int)value_.longIntValue_;
else
{
STRCMP_EQUAL("unsigned long int", type_.asCharString());
return value_.unsignedLongIntValue_;
}
}
#ifdef CPPUTEST_USE_LONG_LONG
cpputest_longlong MockNamedValue::getLongLongIntValue() const
{
if(type_ == "int")
return value_.intValue_;
else if(type_ == "unsigned int")
return (long long int)value_.unsignedIntValue_;
else if(type_ == "long int")
return value_.longIntValue_;
else if(type_ == "unsigned long int")
return (long long int)value_.unsignedLongIntValue_;
else
{
STRCMP_EQUAL("long long int", type_.asCharString());
return value_.longLongIntValue_;
}
}
cpputest_ulonglong MockNamedValue::getUnsignedLongLongIntValue() const
{
if(type_ == "unsigned int")
return value_.unsignedIntValue_;
else if(type_ == "int" && value_.intValue_ >= 0)
return (unsigned long long int)value_.intValue_;
else if(type_ == "long int" && value_.longIntValue_ >= 0)
return (unsigned long long int)value_.longIntValue_;
else if(type_ == "unsigned long int")
return value_.unsignedLongIntValue_;
else if(type_ == "long long int" && value_.longLongIntValue_ >= 0)
return (unsigned long long int)value_.longLongIntValue_;
else
{
STRCMP_EQUAL("unsigned long long int", type_.asCharString());
return value_.unsignedLongLongIntValue_;
}
}
#else
cpputest_longlong MockNamedValue::getLongLongIntValue() const
{
FAIL("Long Long type is not supported");
return cpputest_longlong(0);
}
cpputest_ulonglong MockNamedValue::getUnsignedLongLongIntValue() const
{
FAIL("Unsigned Long Long type is not supported");
return cpputest_ulonglong(0);
}
#endif
double MockNamedValue::getDoubleValue() const
{
STRCMP_EQUAL("double", type_.asCharString());
return value_.doubleValue_.value;
}
double MockNamedValue::getDoubleTolerance() const
{
STRCMP_EQUAL("double", type_.asCharString());
return value_.doubleValue_.tolerance;
}
const char* MockNamedValue::getStringValue() const
{
STRCMP_EQUAL("const char*", type_.asCharString());
return value_.stringValue_;
}
void* MockNamedValue::getPointerValue() const
{
STRCMP_EQUAL("void*", type_.asCharString());
return value_.pointerValue_;
}
const void* MockNamedValue::getConstPointerValue() const
{
STRCMP_EQUAL("const void*", type_.asCharString());
return value_.pointerValue_;
}
void (*MockNamedValue::getFunctionPointerValue() const)()
{
STRCMP_EQUAL("void (*)()", type_.asCharString());
return value_.functionPointerValue_;
}
const unsigned char* MockNamedValue::getMemoryBuffer() const
{
STRCMP_EQUAL("const unsigned char*", type_.asCharString());
return value_.memoryBufferValue_;
}
const void* MockNamedValue::getConstObjectPointer() const
{
return value_.constObjectPointerValue_;
}
void* MockNamedValue::getObjectPointer() const
{
return value_.objectPointerValue_;
}
size_t MockNamedValue::getSize() const
{
return size_;
}
MockNamedValueComparator* MockNamedValue::getComparator() const
{
return comparator_;
}
MockNamedValueCopier* MockNamedValue::getCopier() const
{
return copier_;
}
bool MockNamedValue::equals(const MockNamedValue& p) const
{
if((type_ == "long int") && (p.type_ == "int"))
return value_.longIntValue_ == p.value_.intValue_;
else if((type_ == "int") && (p.type_ == "long int"))
return value_.intValue_ == p.value_.longIntValue_;
else if((type_ == "unsigned int") && (p.type_ == "int"))
return (p.value_.intValue_ >= 0) && (value_.unsignedIntValue_ == (unsigned int)p.value_.intValue_);
else if((type_ == "int") && (p.type_ == "unsigned int"))
return (value_.intValue_ >= 0) && ((unsigned int)value_.intValue_ == p.value_.unsignedIntValue_);
else if((type_ == "unsigned long int") && (p.type_ == "int"))
return (p.value_.intValue_ >= 0) && (value_.unsignedLongIntValue_ == (unsigned long)p.value_.intValue_);
else if((type_ == "int") && (p.type_ == "unsigned long int"))
return (value_.intValue_ >= 0) && ((unsigned long)value_.intValue_ == p.value_.unsignedLongIntValue_);
else if((type_ == "unsigned int") && (p.type_ == "long int"))
return (p.value_.longIntValue_ >= 0) && (value_.unsignedIntValue_ == (unsigned long)p.value_.longIntValue_);
else if((type_ == "long int") && (p.type_ == "unsigned int"))
return (value_.longIntValue_ >= 0) && ((unsigned long)value_.longIntValue_ == p.value_.unsignedIntValue_);
else if((type_ == "unsigned int") && (p.type_ == "unsigned long int"))
return value_.unsignedIntValue_ == p.value_.unsignedLongIntValue_;
else if((type_ == "unsigned long int") && (p.type_ == "unsigned int"))
return value_.unsignedLongIntValue_ == p.value_.unsignedIntValue_;
else if((type_ == "long int") && (p.type_ == "unsigned long int"))
return (value_.longIntValue_ >= 0) && ((unsigned long)value_.longIntValue_ == p.value_.unsignedLongIntValue_);
else if((type_ == "unsigned long int") && (p.type_ == "long int"))
return (p.value_.longIntValue_ >= 0) && (value_.unsignedLongIntValue_ == (unsigned long) p.value_.longIntValue_);
#ifdef CPPUTEST_USE_LONG_LONG
else if ((type_ == "long long int") && (p.type_ == "int"))
return value_.longLongIntValue_ == p.value_.intValue_;
else if ((type_ == "int") && (p.type_ == "long long int"))
return value_.intValue_ == p.value_.longLongIntValue_;
else if ((type_ == "long long int") && (p.type_ == "long int"))
return value_.longLongIntValue_ == p.value_.longIntValue_;
else if ((type_ == "long int") && (p.type_ == "long long int"))
return value_.longIntValue_ == p.value_.longLongIntValue_;
else if ((type_ == "long long int") && (p.type_ == "unsigned int"))
return (value_.longLongIntValue_ >= 0) && ((unsigned long long)value_.longLongIntValue_ == p.value_.unsignedIntValue_);
else if ((type_ == "unsigned int") && (p.type_ == "long long int"))
return (p.value_.longLongIntValue_ >= 0) && (value_.unsignedIntValue_ == (unsigned long long)p.value_.longLongIntValue_);
else if ((type_ == "long long int") && (p.type_ == "unsigned long int"))
return (value_.longLongIntValue_ >= 0) && ((unsigned long long)value_.longLongIntValue_ == p.value_.unsignedLongIntValue_);
else if ((type_ == "unsigned long int") && (p.type_ == "long long int"))
return (p.value_.longLongIntValue_ >= 0) && (value_.unsignedLongIntValue_ == (unsigned long long)p.value_.longLongIntValue_);
else if ((type_ == "long long int") && (p.type_ == "unsigned long long int"))
return (value_.longLongIntValue_ >= 0) && ((unsigned long long)value_.longLongIntValue_ == p.value_.unsignedLongLongIntValue_);
else if ((type_ == "unsigned long long int") && (p.type_ == "long long int"))
return (p.value_.longLongIntValue_ >= 0) && (value_.unsignedLongLongIntValue_ == (unsigned long long)p.value_.longLongIntValue_);
else if ((type_ == "unsigned long long int") && (p.type_ == "int"))
return (p.value_.intValue_ >= 0) && (value_.unsignedLongLongIntValue_ == (unsigned long long)p.value_.intValue_);
else if ((type_ == "int") && (p.type_ == "unsigned long long int"))
return (value_.intValue_ >= 0) && ((unsigned long long)value_.intValue_ == p.value_.unsignedLongLongIntValue_);
else if ((type_ == "unsigned long long int") && (p.type_ == "unsigned int"))
return value_.unsignedLongLongIntValue_ == p.value_.unsignedIntValue_;
else if ((type_ == "unsigned int") && (p.type_ == "unsigned long long int"))
return value_.unsignedIntValue_ == p.value_.unsignedLongLongIntValue_;
else if ((type_ == "unsigned long long int") && (p.type_ == "long int"))
return (p.value_.longIntValue_ >= 0) && (value_.unsignedLongLongIntValue_ == (unsigned long long)p.value_.longIntValue_);
else if ((type_ == "long int") && (p.type_ == "unsigned long long int"))
return (value_.longIntValue_ >= 0) && ((unsigned long long)value_.longIntValue_ == p.value_.unsignedLongLongIntValue_);
else if ((type_ == "unsigned long long int") && (p.type_ == "unsigned long int"))
return value_.unsignedLongLongIntValue_ == p.value_.unsignedLongIntValue_;
else if ((type_ == "unsigned long int") && (p.type_ == "unsigned long long int"))
return value_.unsignedLongIntValue_ == p.value_.unsignedLongLongIntValue_;
#endif
if (type_ != p.type_) return false;
if (type_ == "bool")
return value_.boolValue_ == p.value_.boolValue_;
else if (type_ == "int")
return value_.intValue_ == p.value_.intValue_;
else if (type_ == "unsigned int")
return value_.unsignedIntValue_ == p.value_.unsignedIntValue_;
else if (type_ == "long int")
return value_.longIntValue_ == p.value_.longIntValue_;
else if (type_ == "unsigned long int")
return value_.unsignedLongIntValue_ == p.value_.unsignedLongIntValue_;
#ifdef CPPUTEST_USE_LONG_LONG
else if (type_ == "long long int")
return value_.longLongIntValue_ == p.value_.longLongIntValue_;
else if (type_ == "unsigned long long int")
return value_.unsignedLongLongIntValue_ == p.value_.unsignedLongLongIntValue_;
#endif
else if (type_ == "const char*")
return SimpleString(value_.stringValue_) == SimpleString(p.value_.stringValue_);
else if (type_ == "void*")
return value_.pointerValue_ == p.value_.pointerValue_;
else if (type_ == "const void*")
return value_.constPointerValue_ == p.value_.constPointerValue_;
else if (type_ == "void (*)()")
return value_.functionPointerValue_ == p.value_.functionPointerValue_;
else if (type_ == "double")
return (doubles_equal(value_.doubleValue_.value, p.value_.doubleValue_.value, value_.doubleValue_.tolerance));
else if (type_ == "const unsigned char*")
{
if (size_ != p.size_) {
return false;
}
return SimpleString::MemCmp(value_.memoryBufferValue_, p.value_.memoryBufferValue_, size_) == 0;
}
if (comparator_)
return comparator_->isEqual(value_.constObjectPointerValue_, p.value_.constObjectPointerValue_);
return false;
}
bool MockNamedValue::compatibleForCopying(const MockNamedValue& p) const
{
if (type_ == p.type_) return true;
if ((type_ == "const void*") && (p.type_ == "void*"))
return true;
return false;
}
SimpleString MockNamedValue::toString() const
{
if (type_ == "bool")
return StringFrom(value_.boolValue_);
else if (type_ == "int")
return StringFrom(value_.intValue_) + " " + BracketsFormattedHexStringFrom(value_.intValue_);
else if (type_ == "unsigned int")
return StringFrom(value_.unsignedIntValue_) + " " + BracketsFormattedHexStringFrom(value_.unsignedIntValue_);
else if (type_ == "long int")
return StringFrom(value_.longIntValue_) + " " + BracketsFormattedHexStringFrom(value_.longIntValue_);
else if (type_ == "unsigned long int")
return StringFrom(value_.unsignedLongIntValue_) + " " + BracketsFormattedHexStringFrom(value_.unsignedLongIntValue_);
#ifdef CPPUTEST_USE_LONG_LONG
else if (type_ == "long long int")
return StringFrom(value_.longLongIntValue_) + " " + BracketsFormattedHexStringFrom(value_.longLongIntValue_);
else if (type_ == "unsigned long long int")
return StringFrom(value_.unsignedLongLongIntValue_) + " " + BracketsFormattedHexStringFrom(value_.unsignedLongLongIntValue_);
#endif
else if (type_ == "const char*")
return value_.stringValue_;
else if (type_ == "void*")
return StringFrom(value_.pointerValue_);
else if (type_ == "void (*)()")
return StringFrom(value_.functionPointerValue_);
else if (type_ == "const void*")
return StringFrom(value_.constPointerValue_);
else if (type_ == "double")
return StringFrom(value_.doubleValue_.value);
else if (type_ == "const unsigned char*")
return StringFromBinaryWithSizeOrNull(value_.memoryBufferValue_, size_);
if (comparator_)
return comparator_->valueToString(value_.constObjectPointerValue_);
return StringFromFormat("No comparator found for type: \"%s\"", type_.asCharString());
}
void MockNamedValueListNode::setNext(MockNamedValueListNode* node)
{
next_ = node;
}
MockNamedValueListNode* MockNamedValueListNode::next()
{
return next_;
}
MockNamedValue* MockNamedValueListNode::item()
{
return data_;
}
void MockNamedValueListNode::destroy()
{
delete data_;
}
MockNamedValueListNode::MockNamedValueListNode(MockNamedValue* newValue)
: data_(newValue), next_(NULLPTR)
{
}
SimpleString MockNamedValueListNode::getName() const
{
return data_->getName();
}
SimpleString MockNamedValueListNode::getType() const
{
return data_->getType();
}
MockNamedValueList::MockNamedValueList() : head_(NULLPTR)
{
}
void MockNamedValueList::clear()
{
while (head_) {
MockNamedValueListNode* n = head_->next();
head_->destroy();
delete head_;
head_ = n;
}
}
void MockNamedValueList::add(MockNamedValue* newValue)
{
MockNamedValueListNode* newNode = new MockNamedValueListNode(newValue);
if (head_ == NULLPTR)
head_ = newNode;
else {
MockNamedValueListNode* lastNode = head_;
while (lastNode->next()) lastNode = lastNode->next();
lastNode->setNext(newNode);
}
}
MockNamedValue* MockNamedValueList::getValueByName(const SimpleString& name)
{
for (MockNamedValueListNode * p = head_; p; p = p->next())
if (p->getName() == name)
return p->item();
return NULLPTR;
}
MockNamedValueListNode* MockNamedValueList::begin()
{
return head_;
}
struct MockNamedValueComparatorsAndCopiersRepositoryNode
{
MockNamedValueComparatorsAndCopiersRepositoryNode(const SimpleString& name, MockNamedValueComparator* comparator, MockNamedValueComparatorsAndCopiersRepositoryNode* next)
: name_(name), comparator_(comparator), copier_(NULLPTR), next_(next) {}
MockNamedValueComparatorsAndCopiersRepositoryNode(const SimpleString& name, MockNamedValueCopier* copier, MockNamedValueComparatorsAndCopiersRepositoryNode* next)
: name_(name), comparator_(NULLPTR), copier_(copier), next_(next) {}
MockNamedValueComparatorsAndCopiersRepositoryNode(const SimpleString& name, MockNamedValueComparator* comparator, MockNamedValueCopier* copier, MockNamedValueComparatorsAndCopiersRepositoryNode* next)
: name_(name), comparator_(comparator), copier_(copier), next_(next) {}
SimpleString name_;
MockNamedValueComparator* comparator_;
MockNamedValueCopier* copier_;
MockNamedValueComparatorsAndCopiersRepositoryNode* next_;
};
MockNamedValueComparatorsAndCopiersRepository::MockNamedValueComparatorsAndCopiersRepository() : head_(NULLPTR)
{
}
MockNamedValueComparatorsAndCopiersRepository::~MockNamedValueComparatorsAndCopiersRepository()
{
clear();
}
void MockNamedValueComparatorsAndCopiersRepository::clear()
{
while (head_) {
MockNamedValueComparatorsAndCopiersRepositoryNode* next = head_->next_;
delete head_;
head_ = next;
}
}
void MockNamedValueComparatorsAndCopiersRepository::installComparator(const SimpleString& name, MockNamedValueComparator& comparator)
{
head_ = new MockNamedValueComparatorsAndCopiersRepositoryNode(name, &comparator, head_);
}
void MockNamedValueComparatorsAndCopiersRepository::installCopier(const SimpleString& name, MockNamedValueCopier& copier)
{
head_ = new MockNamedValueComparatorsAndCopiersRepositoryNode(name, &copier, head_);
}
MockNamedValueComparator* MockNamedValueComparatorsAndCopiersRepository::getComparatorForType(const SimpleString& name)
{
for (MockNamedValueComparatorsAndCopiersRepositoryNode* p = head_; p; p = p->next_)
if (p->name_ == name && p->comparator_) return p->comparator_;
return NULLPTR;
}
MockNamedValueCopier* MockNamedValueComparatorsAndCopiersRepository::getCopierForType(const SimpleString& name)
{
for (MockNamedValueComparatorsAndCopiersRepositoryNode* p = head_; p; p = p->next_)
if (p->name_ == name && p->copier_) return p->copier_;
return NULLPTR;
}
void MockNamedValueComparatorsAndCopiersRepository::installComparatorsAndCopiers(const MockNamedValueComparatorsAndCopiersRepository& repository)
{
for (MockNamedValueComparatorsAndCopiersRepositoryNode* p = repository.head_; p; p = p->next_)
head_ = new MockNamedValueComparatorsAndCopiersRepositoryNode(p->name_, p->comparator_, p->copier_, head_);
}

View file

@ -0,0 +1,658 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockSupport.h"
#include "CppUTestExt/MockActualCall.h"
#include "CppUTestExt/MockExpectedCall.h"
#include "CppUTestExt/MockFailure.h"
#define MOCK_SUPPORT_SCOPE_PREFIX "!!!$$$MockingSupportScope$$$!!!"
static MockSupport global_mock;
MockSupport& mock(const SimpleString& mockName, MockFailureReporter* failureReporterForThisCall)
{
MockSupport& mock_support = (mockName != "") ? *global_mock.getMockSupportScope(mockName) : global_mock;
mock_support.setActiveReporter(failureReporterForThisCall);
mock_support.setDefaultComparatorsAndCopiersRepository();
return mock_support;
}
MockSupport::MockSupport(const SimpleString& mockName)
: actualCallOrder_(0), expectedCallOrder_(0), strictOrdering_(false), standardReporter_(&defaultReporter_), ignoreOtherCalls_(false), enabled_(true), lastActualFunctionCall_(NULLPTR), mockName_(mockName), tracing_(false)
{
setActiveReporter(NULLPTR);
}
MockSupport::~MockSupport()
{
}
void MockSupport::crashOnFailure(bool shouldCrash)
{
activeReporter_->crashOnFailure(shouldCrash);
}
void MockSupport::setMockFailureStandardReporter(MockFailureReporter* reporter)
{
standardReporter_ = (reporter != NULLPTR) ? reporter : &defaultReporter_;
if (lastActualFunctionCall_)
lastActualFunctionCall_->setMockFailureReporter(standardReporter_);
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p)) getMockSupport(p)->setMockFailureStandardReporter(standardReporter_);
}
void MockSupport::setActiveReporter(MockFailureReporter* reporter)
{
activeReporter_ = (reporter) ? reporter : standardReporter_;
}
void MockSupport::setDefaultComparatorsAndCopiersRepository()
{
MockNamedValue::setDefaultComparatorsAndCopiersRepository(&comparatorsAndCopiersRepository_);
}
void MockSupport::installComparator(const SimpleString& typeName, MockNamedValueComparator& comparator)
{
comparatorsAndCopiersRepository_.installComparator(typeName, comparator);
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p)) getMockSupport(p)->installComparator(typeName, comparator);
}
void MockSupport::installCopier(const SimpleString& typeName, MockNamedValueCopier& copier)
{
comparatorsAndCopiersRepository_.installCopier(typeName, copier);
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p)) getMockSupport(p)->installCopier(typeName, copier);
}
void MockSupport::installComparatorsAndCopiers(const MockNamedValueComparatorsAndCopiersRepository& repository)
{
comparatorsAndCopiersRepository_.installComparatorsAndCopiers(repository);
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p)) getMockSupport(p)->installComparatorsAndCopiers(repository);
}
void MockSupport::removeAllComparatorsAndCopiers()
{
comparatorsAndCopiersRepository_.clear();
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p)) getMockSupport(p)->removeAllComparatorsAndCopiers();
}
void MockSupport::clear()
{
delete lastActualFunctionCall_;
lastActualFunctionCall_ = NULLPTR;
tracing_ = false;
MockActualCallTrace::clearInstance();
expectations_.deleteAllExpectationsAndClearList();
ignoreOtherCalls_ = false;
enabled_ = true;
actualCallOrder_ = 0;
expectedCallOrder_ = 0;
strictOrdering_ = false;
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next()) {
MockSupport* support = getMockSupport(p);
if (support) {
support->clear();
delete support;
}
}
data_.clear();
}
void MockSupport::strictOrder()
{
strictOrdering_ = true;
}
SimpleString MockSupport::appendScopeToName(const SimpleString& functionName)
{
if (mockName_.isEmpty()) return functionName;
return mockName_ + "::" + functionName;
}
MockExpectedCall& MockSupport::expectOneCall(const SimpleString& functionName)
{
return expectNCalls(1, functionName);
}
void MockSupport::expectNoCall(const SimpleString& functionName)
{
expectNCalls(0, functionName);
}
MockExpectedCall& MockSupport::expectNCalls(unsigned int amount, const SimpleString& functionName)
{
if (!enabled_) return MockIgnoredExpectedCall::instance();
countCheck();
MockCheckedExpectedCall* call = new MockCheckedExpectedCall(amount);
call->withName(appendScopeToName(functionName));
if (strictOrdering_) {
call->withCallOrder(expectedCallOrder_ + 1, expectedCallOrder_ + amount);
expectedCallOrder_ += amount;
}
expectations_.addExpectedCall(call);
return *call;
}
MockCheckedActualCall* MockSupport::createActualCall()
{
lastActualFunctionCall_ = new MockCheckedActualCall(++actualCallOrder_, activeReporter_, expectations_);
return lastActualFunctionCall_;
}
bool MockSupport::callIsIgnored(const SimpleString& functionName)
{
return ignoreOtherCalls_ && !expectations_.hasExpectationWithName(functionName);
}
MockActualCall& MockSupport::actualCall(const SimpleString& functionName)
{
const SimpleString scopeFunctionName = appendScopeToName(functionName);
if (lastActualFunctionCall_) {
lastActualFunctionCall_->checkExpectations();
delete lastActualFunctionCall_;
lastActualFunctionCall_ = NULLPTR;
}
if (!enabled_) return MockIgnoredActualCall::instance();
if (tracing_) return MockActualCallTrace::instance().withName(scopeFunctionName);
if (callIsIgnored(scopeFunctionName)) {
return MockIgnoredActualCall::instance();
}
MockCheckedActualCall* call = createActualCall();
call->withName(scopeFunctionName);
return *call;
}
void MockSupport::ignoreOtherCalls()
{
ignoreOtherCalls_ = true;
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p)) getMockSupport(p)->ignoreOtherCalls();
}
void MockSupport::disable()
{
enabled_ = false;
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p)) getMockSupport(p)->disable();
}
void MockSupport::enable()
{
enabled_ = true;
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p)) getMockSupport(p)->enable();
}
void MockSupport::tracing(bool enabled)
{
tracing_ = enabled;
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p)) getMockSupport(p)->tracing(enabled);
}
const char* MockSupport::getTraceOutput()
{
return MockActualCallTrace::instance().getTraceOutput();
}
bool MockSupport::expectedCallsLeft()
{
int callsLeft = expectations_.hasUnfulfilledExpectations();
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p)) callsLeft += getMockSupport(p)->expectedCallsLeft();
return callsLeft != 0;
}
bool MockSupport::wasLastActualCallFulfilled()
{
if (lastActualFunctionCall_ && !lastActualFunctionCall_->isFulfilled())
return false;
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p) && !getMockSupport(p)->wasLastActualCallFulfilled())
return false;
return true;
}
void MockSupport::failTestWithExpectedCallsNotFulfilled()
{
MockExpectedCallsList expectationsList;
expectationsList.addExpectations(expectations_);
for(MockNamedValueListNode *p = data_.begin();p;p = p->next())
if(getMockSupport(p))
expectationsList.addExpectations(getMockSupport(p)->expectations_);
MockExpectedCallsDidntHappenFailure failure(activeReporter_->getTestToFail(), expectationsList);
failTest(failure);
}
void MockSupport::failTestWithOutOfOrderCalls()
{
MockExpectedCallsList expectationsList;
expectationsList.addExpectations(expectations_);
for(MockNamedValueListNode *p = data_.begin();p;p = p->next())
if(getMockSupport(p))
expectationsList.addExpectations(getMockSupport(p)->expectations_);
MockCallOrderFailure failure(activeReporter_->getTestToFail(), expectationsList);
failTest(failure);
}
void MockSupport::failTest(MockFailure& failure)
{
clear();
activeReporter_->failTest(failure);
}
void MockSupport::countCheck()
{
UtestShell::getCurrent()->countCheck();
}
void MockSupport::checkExpectationsOfLastActualCall()
{
if(lastActualFunctionCall_)
lastActualFunctionCall_->checkExpectations();
for(MockNamedValueListNode *p = data_.begin();p;p = p->next())
if(getMockSupport(p) && getMockSupport(p)->lastActualFunctionCall_)
getMockSupport(p)->lastActualFunctionCall_->checkExpectations();
}
bool MockSupport::hasCallsOutOfOrder()
{
if (expectations_.hasCallsOutOfOrder())
{
return true;
}
for (MockNamedValueListNode* p = data_.begin(); p; p = p->next())
if (getMockSupport(p) && getMockSupport(p)->hasCallsOutOfOrder())
{
return true;
}
return false;
}
void MockSupport::checkExpectations()
{
checkExpectationsOfLastActualCall();
if (wasLastActualCallFulfilled() && expectedCallsLeft())
failTestWithExpectedCallsNotFulfilled();
if (hasCallsOutOfOrder())
failTestWithOutOfOrderCalls();
}
bool MockSupport::hasData(const SimpleString& name)
{
return data_.getValueByName(name) != NULLPTR;
}
MockNamedValue* MockSupport::retrieveDataFromStore(const SimpleString& name)
{
MockNamedValue* newData = data_.getValueByName(name);
if (newData == NULLPTR) {
newData = new MockNamedValue(name);
data_.add(newData);
}
return newData;
}
void MockSupport::setData(const SimpleString& name, bool value)
{
MockNamedValue* newData = retrieveDataFromStore(name);
newData->setValue(value);
}
void MockSupport::setData(const SimpleString& name, unsigned int value)
{
MockNamedValue* newData = retrieveDataFromStore(name);
newData->setValue(value);
}
void MockSupport::setData(const SimpleString& name, int value)
{
MockNamedValue* newData = retrieveDataFromStore(name);
newData->setValue(value);
}
void MockSupport::setData(const SimpleString& name, const char* value)
{
MockNamedValue* newData = retrieveDataFromStore(name);
newData->setValue(value);
}
void MockSupport::setData(const SimpleString& name, double value)
{
MockNamedValue* newData = retrieveDataFromStore(name);
newData->setValue(value);
}
void MockSupport::setData(const SimpleString& name, void* value)
{
MockNamedValue* newData = retrieveDataFromStore(name);
newData->setValue(value);
}
void MockSupport::setData(const SimpleString& name, const void* value)
{
MockNamedValue* newData = retrieveDataFromStore(name);
newData->setValue(value);
}
void MockSupport::setData(const SimpleString& name, void (*value)())
{
MockNamedValue* newData = retrieveDataFromStore(name);
newData->setValue(value);
}
void MockSupport::setDataObject(const SimpleString& name, const SimpleString& type, void* value)
{
MockNamedValue* newData = retrieveDataFromStore(name);
newData->setObjectPointer(type, value);
}
void MockSupport::setDataConstObject(const SimpleString& name, const SimpleString& type, const void* value)
{
MockNamedValue* newData = retrieveDataFromStore(name);
newData->setConstObjectPointer(type, value);
}
MockNamedValue MockSupport::getData(const SimpleString& name)
{
MockNamedValue* value = data_.getValueByName(name);
if (value == NULLPTR)
return MockNamedValue("");
return *value;
}
MockSupport* MockSupport::clone(const SimpleString& mockName)
{
MockSupport* newMock = new MockSupport(mockName);
newMock->setMockFailureStandardReporter(standardReporter_);
if (ignoreOtherCalls_) newMock->ignoreOtherCalls();
if (!enabled_) newMock->disable();
if (strictOrdering_) newMock->strictOrder();
newMock->tracing(tracing_);
newMock->installComparatorsAndCopiers(comparatorsAndCopiersRepository_);
return newMock;
}
MockSupport* MockSupport::getMockSupportScope(const SimpleString& name)
{
SimpleString mockingSupportName = MOCK_SUPPORT_SCOPE_PREFIX;
mockingSupportName += name;
if (hasData(mockingSupportName)) {
STRCMP_EQUAL("MockSupport", getData(mockingSupportName).getType().asCharString());
return (MockSupport*) getData(mockingSupportName).getObjectPointer();
}
MockSupport *newMock = clone(name);
setDataObject(mockingSupportName, "MockSupport", newMock);
return newMock;
}
MockSupport* MockSupport::getMockSupport(MockNamedValueListNode* node)
{
if (node->getType() == "MockSupport" && node->getName().contains(MOCK_SUPPORT_SCOPE_PREFIX))
return (MockSupport*) node->item()->getObjectPointer();
return NULLPTR;
}
MockNamedValue MockSupport::returnValue()
{
if (lastActualFunctionCall_) return lastActualFunctionCall_->returnValue();
return MockNamedValue("");
}
bool MockSupport::boolReturnValue()
{
return returnValue().getBoolValue();
}
unsigned int MockSupport::unsignedIntReturnValue()
{
return returnValue().getUnsignedIntValue();
}
int MockSupport::intReturnValue()
{
return returnValue().getIntValue();
}
const char * MockSupport::returnStringValueOrDefault(const char * defaultValue)
{
if (hasReturnValue()) {
return stringReturnValue();
}
return defaultValue;
}
double MockSupport::returnDoubleValueOrDefault(double defaultValue)
{
if (hasReturnValue()) {
return doubleReturnValue();
}
return defaultValue;
}
long int MockSupport::returnLongIntValueOrDefault(long int defaultValue)
{
if (hasReturnValue()) {
return longIntReturnValue();
}
return defaultValue;
}
bool MockSupport::returnBoolValueOrDefault(bool defaultValue)
{
if (hasReturnValue()) {
return boolReturnValue();
}
return defaultValue;
}
int MockSupport::returnIntValueOrDefault(int defaultValue)
{
if (hasReturnValue()) {
return intReturnValue();
}
return defaultValue;
}
unsigned int MockSupport::returnUnsignedIntValueOrDefault(unsigned int defaultValue)
{
if (hasReturnValue()) {
return unsignedIntReturnValue();
}
return defaultValue;
}
unsigned long int MockSupport::returnUnsignedLongIntValueOrDefault(unsigned long int defaultValue)
{
if (hasReturnValue()) {
return unsignedLongIntReturnValue();
}
return defaultValue;
}
long int MockSupport::longIntReturnValue()
{
return returnValue().getLongIntValue();
}
unsigned long int MockSupport::unsignedLongIntReturnValue()
{
return returnValue().getUnsignedLongIntValue();
}
#ifdef CPPUTEST_USE_LONG_LONG
cpputest_longlong MockSupport::longLongIntReturnValue()
{
return returnValue().getLongLongIntValue();
}
cpputest_ulonglong MockSupport::unsignedLongLongIntReturnValue()
{
return returnValue().getUnsignedLongLongIntValue();
}
cpputest_longlong MockSupport::returnLongLongIntValueOrDefault(cpputest_longlong defaultValue)
{
if (hasReturnValue()) {
return longLongIntReturnValue();
}
return defaultValue;
}
cpputest_ulonglong MockSupport::returnUnsignedLongLongIntValueOrDefault(cpputest_ulonglong defaultValue)
{
if (hasReturnValue()) {
return unsignedLongLongIntReturnValue();
}
return defaultValue;
}
#else
cpputest_longlong MockSupport::longLongIntReturnValue()
{
FAIL("Long Long type is not supported");
return cpputest_longlong(0);
}
cpputest_ulonglong MockSupport::unsignedLongLongIntReturnValue()
{
FAIL("Unsigned Long Long type is not supported");
return cpputest_ulonglong(0);
}
cpputest_longlong MockSupport::returnLongLongIntValueOrDefault(cpputest_longlong defaultValue)
{
FAIL("Long Long type is not supported");
return defaultValue;
}
cpputest_ulonglong MockSupport::returnUnsignedLongLongIntValueOrDefault(cpputest_ulonglong defaultValue)
{
FAIL("Unsigned Long Long type is not supported");
return defaultValue;
}
#endif
const char* MockSupport::stringReturnValue()
{
return returnValue().getStringValue();
}
double MockSupport::doubleReturnValue()
{
return returnValue().getDoubleValue();
}
void * MockSupport::returnPointerValueOrDefault(void * defaultValue)
{
if (hasReturnValue()) {
return pointerReturnValue();
}
return defaultValue;
}
const void* MockSupport::returnConstPointerValueOrDefault(const void * defaultValue)
{
if (hasReturnValue()) {
return constPointerReturnValue();
}
return defaultValue;
}
void (*MockSupport::returnFunctionPointerValueOrDefault(void (*defaultValue)()))()
{
if (hasReturnValue()) {
return functionPointerReturnValue();
}
return defaultValue;
}
void* MockSupport::pointerReturnValue()
{
return returnValue().getPointerValue();
}
const void* MockSupport::constPointerReturnValue()
{
return returnValue().getConstPointerValue();
}
void (*MockSupport::functionPointerReturnValue())()
{
return returnValue().getFunctionPointerValue();
}
bool MockSupport::hasReturnValue()
{
if (lastActualFunctionCall_) return lastActualFunctionCall_->hasReturnValue();
return false;
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockSupport.h"
#include "CppUTestExt/MockSupportPlugin.h"
class MockSupportPluginReporter : public MockFailureReporter
{
UtestShell& test_;
TestResult& result_;
public:
MockSupportPluginReporter(UtestShell& test, TestResult& result)
: test_(test), result_(result)
{
}
virtual void failTest(const MockFailure& failure) _override
{
result_.addFailure(failure);
}
virtual UtestShell* getTestToFail() _override
{
return &test_;
}
};
MockSupportPlugin::MockSupportPlugin(const SimpleString& name)
: TestPlugin(name)
{
}
MockSupportPlugin::~MockSupportPlugin()
{
clear();
}
void MockSupportPlugin::clear()
{
repository_.clear();
}
void MockSupportPlugin::preTestAction(UtestShell&, TestResult&)
{
mock().installComparatorsAndCopiers(repository_);
}
void MockSupportPlugin::postTestAction(UtestShell& test, TestResult& result)
{
MockSupportPluginReporter reporter(test, result);
mock().setMockFailureStandardReporter(&reporter);
if (!test.hasFailed())
mock().checkExpectations();
mock().clear();
mock().setMockFailureStandardReporter(NULLPTR);
mock().removeAllComparatorsAndCopiers();
}
void MockSupportPlugin::installComparator(const SimpleString& name, MockNamedValueComparator& comparator)
{
repository_.installComparator(name, comparator);
}
void MockSupportPlugin::installCopier(const SimpleString& name, MockNamedValueCopier& copier)
{
repository_.installCopier(name, copier);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,137 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTestExt/OrderedTest.h"
OrderedTestShell* OrderedTestShell::_orderedTestsHead = NULLPTR;
OrderedTestShell::OrderedTestShell() :
_nextOrderedTest(NULLPTR), _level(0)
{
}
OrderedTestShell::~OrderedTestShell()
{
}
int OrderedTestShell::getLevel()
{
return _level;
}
void OrderedTestShell::setLevel(int level)
{
_level = level;
}
void OrderedTestShell::setOrderedTestHead(OrderedTestShell* test)
{
_orderedTestsHead = test;
}
OrderedTestShell* OrderedTestShell::getOrderedTestHead()
{
return _orderedTestsHead;
}
bool OrderedTestShell::firstOrderedTest()
{
return (getOrderedTestHead() == NULLPTR);
}
OrderedTestShell* OrderedTestShell::addOrderedTest(OrderedTestShell* test)
{
UtestShell::addTest(test);
_nextOrderedTest = test;
return this;
}
void OrderedTestShell::addOrderedTestToHead(OrderedTestShell* test)
{
TestRegistry *reg = TestRegistry::getCurrentRegistry();
UtestShell* head = getOrderedTestHead();
if (NULLPTR == reg->getFirstTest() || head == reg->getFirstTest()) {
reg->addTest(test);
}
else {
reg->getTestWithNext(head)->addTest(test);
test->addTest(head);
}
test->_nextOrderedTest = getOrderedTestHead();
setOrderedTestHead(test);
}
OrderedTestShell* OrderedTestShell::getNextOrderedTest()
{
return _nextOrderedTest;
}
OrderedTestInstaller::OrderedTestInstaller(OrderedTestShell& test,
const char* groupName, const char* testName, const char* fileName,
size_t lineNumber, int level)
{
test.setTestName(testName);
test.setGroupName(groupName);
test.setFileName(fileName);
test.setLineNumber(lineNumber);
test.setLevel(level);
if (OrderedTestShell::firstOrderedTest()) OrderedTestShell::addOrderedTestToHead(&test);
else addOrderedTestInOrder(&test);
}
void OrderedTestInstaller::addOrderedTestInOrder(OrderedTestShell* test)
{
if (test->getLevel() < OrderedTestShell::getOrderedTestHead()->getLevel())
OrderedTestShell::addOrderedTestToHead(test);
else addOrderedTestInOrderNotAtHeadPosition(test);
}
void OrderedTestInstaller::addOrderedTestInOrderNotAtHeadPosition(
OrderedTestShell* test)
{
OrderedTestShell* current = OrderedTestShell::getOrderedTestHead();
while (current->getNextOrderedTest()) {
if (current->getNextOrderedTest()->getLevel() > test->getLevel()) {
test->addOrderedTest(current->getNextOrderedTest());
current->addOrderedTest(test);
return;
}
current = current->getNextOrderedTest();
}
test->addOrderedTest(current->getNextOrderedTest());
current->addOrderedTest(test);
}
OrderedTestInstaller::~OrderedTestInstaller()
{
}

View file

@ -0,0 +1,254 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Un-comment to use buffer instead of std out */
// #define USE_BUFFER_OUTPUT 1
#include <cstdlib>
#include "CppUTest/TestHarness.h"
#undef malloc
#undef free
#undef calloc
#undef realloc
#undef strdup
#undef strndup
#define far // eliminate "meaningless type qualifier" warning
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <setjmp.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#undef far
#include "CppUTest/PlatformSpecificFunctions.h"
static jmp_buf test_exit_jmp_buf[10];
static int jmp_buf_index = 0;
#if USE_BUFFER_OUTPUT
// Buffer for crude output routine
#define BUFFER_SIZE 4096
static char buffer [BUFFER_SIZE]; /* "never used" warning is OK */
static int idx = 0;
#endif
TestOutput::WorkingEnvironment PlatformSpecificGetWorkingEnvironment()
{
return TestOutput::eclipse;
}
static void C2000RunTestInASeperateProcess(UtestShell* shell, TestPlugin* plugin, TestResult* result)
{
result->addFailure(TestFailure(shell, "-p doesn't work on this platform, as it is lacking fork.\b"));
}
void (*PlatformSpecificRunTestInASeperateProcess)(UtestShell*, TestPlugin*, TestResult*) =
C2000RunTestInASeperateProcess;
extern "C" {
static int C2000SetJmp(void (*function) (void* data), void* data)
{
if (0 == setjmp(test_exit_jmp_buf[jmp_buf_index])) {
jmp_buf_index++;
function(data);
jmp_buf_index--;
return 1;
}
return 0;
}
static void C2000LongJmp()
{
jmp_buf_index--;
longjmp(test_exit_jmp_buf[jmp_buf_index], 1);
}
static void C2000RestoreJumpBuffer()
{
jmp_buf_index--;
}
int (*PlatformSpecificSetJmp)(void (*function) (void*), void*) = C2000SetJmp;
void (*PlatformSpecificLongJmp)(void) = C2000LongJmp;
void (*PlatformSpecificRestoreJumpBuffer)(void) = C2000RestoreJumpBuffer;
static long C2000TimeInMillis()
{
/* The TI c2000 platform does not have Posix support and thus lacks struct timespec.
* Also, clock() always returns 0 in the simulator. Hence we work with struct tm.tm_hour
* This has two consequences:
* (1) We need to sum up the part in order to get an "elapsed since" time value,
* rather than just using tm_sec.
* (2) There is a possibility of overflow, since we stop at the hour
* (3) Resolution is 1 s, even though we return ms.
*/
time_t t = time((time_t*)0);
struct tm * ptm = gmtime(&t);
long result = (long)
((ptm->tm_sec + ptm->tm_min * (time_t)60 + ptm->tm_hour * (time_t)3600) * (time_t)1000);
return result;
}
static const char* TimeStringImplementation()
{
time_t tm = time(NULL);
return ctime(&tm);
}
long (*GetPlatformSpecificTimeInMillis)() = C2000TimeInMillis;
const char* (*GetPlatformSpecificTimeString)() = TimeStringImplementation;
extern int vsnprintf(char*, size_t, const char*, va_list); // not std::vsnprintf()
extern int (*PlatformSpecificVSNprintf)(char *, size_t, const char*, va_list) = vsnprintf;
PlatformSpecificFile C2000FOpen(const char* filename, const char* flag)
{
return fopen(filename, flag);
}
static void C2000FPuts(const char* str, PlatformSpecificFile file)
{
fputs(str, (FILE*)file);
}
static void C2000FClose(PlatformSpecificFile file)
{
fclose((FILE*)file);
}
PlatformSpecificFile (*PlatformSpecificFOpen)(const char* filename, const char* flag) = C2000FOpen;
void (*PlatformSpecificFPuts)(const char* str, PlatformSpecificFile file) = C2000FPuts;
void (*PlatformSpecificFClose)(PlatformSpecificFile file) = C2000FClose;
static int CL2000Putchar(int c)
{
#if USE_BUFFER_OUTPUT
if(idx < BUFFER_SIZE) {
buffer[idx] = (char) c;
idx++;
/* "buffer[idx]" instead of "c" eliminates "never used" warning */
return (buffer[idx]);
}
else {
return EOF;
}
#else
return putchar(c);
#endif
}
static void CL2000Flush()
{
fflush(stdout);
}
extern int (*PlatformSpecificPutchar)(int c) = CL2000Putchar;
extern void (*PlatformSpecificFlush)(void) = CL2000Flush;
static void* C2000Malloc(size_t size)
{
return (void*)far_malloc((unsigned long)size);
}
static void* C2000Realloc (void* memory, size_t size)
{
return (void*)far_realloc((long)memory, (unsigned long)size);
}
static void C2000Free(void* memory)
{
far_free((long)memory);
}
static void* C2000MemCpy(void* s1, const void* s2, size_t size)
{
return (void*)far_memlcpy((long)s1, (long)s2, size);
}
static void* C2000Memset(void* mem, int c, size_t size)
{
register unsigned long i = size;
register long p = (long) mem;
while (i--) *__farptr_to_word(p++) = c;
return mem;
}
void* (*PlatformSpecificMalloc)(size_t size) = C2000Malloc;
void* (*PlatformSpecificRealloc)(void* memory, size_t size) = C2000Realloc;
void (*PlatformSpecificFree)(void* memory) = C2000Free;
void* (*PlatformSpecificMemCpy)(void* s1, const void* s2, size_t size) = C2000MemCpy;
void* (*PlatformSpecificMemset)(void* mem, int c, size_t size) = C2000Memset;
/*
double PlatformSpecificFabs(double d)
{
return fabs(d);
}
*/
double (*PlatformSpecificFabs)(double) = fabs;
static int IsNanImplementation(double d)
{
return 0;
}
static int IsInfImplementation(double d)
{
return 0;
}
int (*PlatformSpecificIsNan)(double d) = IsNanImplementation;
int (*PlatformSpecificIsInf)(double d) = IsInfImplementation;
static PlatformSpecificMutex DummyMutexCreate(void)
{
return 0;
}
static void DummyMutexLock(PlatformSpecificMutex mtx)
{
}
static void DummyMutexUnlock(PlatformSpecificMutex mtx)
{
}
static void DummyMutexDestroy(PlatformSpecificMutex mtx)
{
}
PlatformSpecificMutex (*PlatformSpecificMutexCreate)(void) = DummyMutexCreate;
void (*PlatformSpecificMutexLock)(PlatformSpecificMutex) = DummyMutexLock;
void (*PlatformSpecificMutexUnlock)(PlatformSpecificMutex) = DummyMutexUnlock;
void (*PlatformSpecificMutexDestroy)(PlatformSpecificMutex) = DummyMutexDestroy;
}

View file

@ -0,0 +1,242 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Un-comment to use buffer instead of std out */
// #define USE_BUFFER_OUTPUT 1
#include <cstdlib>
#include "CppUTest/TestHarness.h"
#undef malloc
#undef free
#undef calloc
#undef realloc
#undef strdup
#undef strndup
#define far // eliminate "meaningless type qualifier" warning
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <setjmp.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#undef far
#include "CppUTest/PlatformSpecificFunctions.h"
static jmp_buf test_exit_jmp_buf[10];
static int jmp_buf_index = 0;
TestOutput::WorkingEnvironment PlatformSpecificGetWorkingEnvironment()
{
return TestOutput::eclipse;
}
static void DummyRunTestInASeperateProcess(UtestShell* shell, TestPlugin* plugin, TestResult* result)
{
result->addFailure(TestFailure(shell, "-p doesn't work on this platform, as it is lacking fork.\b"));
}
static int DummyPlatformSpecificFork(void)
{
return 0;
}
static int DummyPlatformSpecificWaitPid(int, int*, int)
{
return 0;
}
void (*PlatformSpecificRunTestInASeperateProcess)(UtestShell*, TestPlugin*, TestResult*) = DummyRunTestInASeperateProcess;
int (*PlatformSpecificFork)() = DummyPlatformSpecificFork;
int (*PlatformSpecificWaitPid)(int, int*, int) = DummyPlatformSpecificWaitPid;
extern "C" {
static int DosSetJmp(void (*function) (void* data), void* data)
{
if (0 == setjmp(test_exit_jmp_buf[jmp_buf_index])) {
jmp_buf_index++;
function(data);
jmp_buf_index--;
return 1;
}
return 0;
}
static void DosLongJmp()
{
jmp_buf_index--;
longjmp(test_exit_jmp_buf[jmp_buf_index], 1);
}
static void DosRestoreJumpBuffer()
{
jmp_buf_index--;
}
int (*PlatformSpecificSetJmp)(void (*function) (void*), void*) = DosSetJmp;
void (*PlatformSpecificLongJmp)(void) = DosLongJmp;
void (*PlatformSpecificRestoreJumpBuffer)(void) = DosRestoreJumpBuffer;
static long DosTimeInMillis()
{
return clock() * 1000 / CLOCKS_PER_SEC;
}
static const char* DosTimeString()
{
time_t tm = time(NULL);
return ctime(&tm);
}
static int DosVSNprintf(char* str, size_t size, const char* format, va_list args) {
return vsnprintf(str, size, format, args);
}
long (*GetPlatformSpecificTimeInMillis)() = DosTimeInMillis;
const char* (*GetPlatformSpecificTimeString)() = DosTimeString;
int (*PlatformSpecificVSNprintf)(char *, size_t, const char*, va_list) = DosVSNprintf;
PlatformSpecificFile DosFOpen(const char* filename, const char* flag)
{
return fopen(filename, flag);
}
static void DosFPuts(const char* str, PlatformSpecificFile file)
{
fputs(str, (FILE*)file);
}
static void DosFClose(PlatformSpecificFile file)
{
fclose((FILE*)file);
}
PlatformSpecificFile (*PlatformSpecificFOpen)(const char* filename, const char* flag) = DosFOpen;
void (*PlatformSpecificFPuts)(const char* str, PlatformSpecificFile file) = DosFPuts;
void (*PlatformSpecificFClose)(PlatformSpecificFile file) = DosFClose;
static int DosPutchar(int c)
{
return putchar(c);
}
static void DosFlush()
{
fflush(stdout);
}
extern int (*PlatformSpecificPutchar)(int c) = DosPutchar;
extern void (*PlatformSpecificFlush)(void) = DosFlush;
static void* DosMalloc(size_t size)
{
return malloc(size);
}
static void* DosRealloc (void* memory, size_t size)
{
return realloc(memory, size);
}
static void DosFree(void* memory)
{
free(memory);
}
static void* DosMemCpy(void* s1, const void* s2, size_t size)
{
return memcpy(s1, s2, size);
}
static void* DosMemset(void* mem, int c, size_t size)
{
return memset(mem, c, size);
}
void* (*PlatformSpecificMalloc)(size_t size) = DosMalloc;
void* (*PlatformSpecificRealloc)(void* memory, size_t size) = DosRealloc;
void (*PlatformSpecificFree)(void* memory) = DosFree;
void* (*PlatformSpecificMemCpy)(void* s1, const void* s2, size_t size) = DosMemCpy;
void* (*PlatformSpecificMemset)(void* mem, int c, size_t size) = DosMemset;
static void DosSrand(unsigned int seed)
{
srand(seed);
}
static int DosRand()
{
return rand();
}
static double DosFabs(double d)
{
return fabs(d);
}
static int DosIsNan(double d)
{
return isnan(d);
}
static int DosIsInf(double d)
{
return isinf(d);
}
void (*PlatformSpecificSrand)(unsigned int) = DosSrand;
int (*PlatformSpecificRand)(void) = DosRand;
double (*PlatformSpecificFabs)(double) = DosFabs;
int (*PlatformSpecificIsNan)(double d) = DosIsNan;
int (*PlatformSpecificIsInf)(double d) = DosIsInf;
static PlatformSpecificMutex DummyMutexCreate(void)
{
return 0;
}
static void DummyMutexLock(PlatformSpecificMutex mtx)
{
}
static void DummyMutexUnlock(PlatformSpecificMutex mtx)
{
}
static void DummyMutexDestroy(PlatformSpecificMutex mtx)
{
}
PlatformSpecificMutex (*PlatformSpecificMutexCreate)(void) = DummyMutexCreate;
void (*PlatformSpecificMutexLock)(PlatformSpecificMutex) = DummyMutexLock;
void (*PlatformSpecificMutexUnlock)(PlatformSpecificMutex) = DummyMutexUnlock;
void (*PlatformSpecificMutexDestroy)(PlatformSpecificMutex) = DummyMutexDestroy;
}

View file

@ -0,0 +1,356 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include "CppUTest/TestHarness.h"
#undef malloc
#undef free
#undef calloc
#undef realloc
#undef strdup
#undef strndup
#ifdef CPPUTEST_HAVE_GETTIMEOFDAY
#include <sys/time.h>
#endif
#ifdef CPPUTEST_HAVE_FORK
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#endif
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <setjmp.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <signal.h>
#ifdef CPPUTEST_HAVE_PTHREAD_MUTEX_LOCK
#include <pthread.h>
#endif
#include "CppUTest/PlatformSpecificFunctions.h"
static jmp_buf test_exit_jmp_buf[10];
static int jmp_buf_index = 0;
#ifndef CPPUTEST_HAVE_FORK
static void GccPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin*, TestResult* result)
{
result->addFailure(TestFailure(shell, "-p doesn't work on this platform, as it is lacking fork.\b"));
}
static int PlatformSpecificForkImplementation(void)
{
return 0;
}
static int PlatformSpecificWaitPidImplementation(int, int*, int)
{
return 0;
}
#else
static void SetTestFailureByStatusCode(UtestShell* shell, TestResult* result, int status)
{
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
result->addFailure(TestFailure(shell, "Failed in separate process"));
} else if (WIFSIGNALED(status)) {
SimpleString message("Failed in separate process - killed by signal ");
message += StringFrom(WTERMSIG(status));
result->addFailure(TestFailure(shell, message));
} else if (WIFSTOPPED(status)) {
result->addFailure(TestFailure(shell, "Stopped in separate process - continuing"));
}
}
static void GccPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin* plugin, TestResult* result)
{
const pid_t syscallError = -1;
pid_t cpid;
pid_t w;
int status = 0;
cpid = PlatformSpecificFork();
if (cpid == syscallError) {
result->addFailure(TestFailure(shell, "Call to fork() failed"));
return;
}
if (cpid == 0) { /* Code executed by child */
const size_t initialFailureCount = result->getFailureCount(); // LCOV_EXCL_LINE
shell->runOneTestInCurrentProcess(plugin, *result); // LCOV_EXCL_LINE
_exit(initialFailureCount < result->getFailureCount()); // LCOV_EXCL_LINE
} else { /* Code executed by parent */
size_t amountOfRetries = 0;
do {
w = PlatformSpecificWaitPid(cpid, &status, WUNTRACED);
if (w == syscallError) {
// OS X debugger causes EINTR
if (EINTR == errno) {
if (amountOfRetries > 30) {
result->addFailure(TestFailure(shell, "Call to waitpid() failed with EINTR. Tried 30 times and giving up! Sometimes happens in debugger"));
return;
}
amountOfRetries++;
}
else {
result->addFailure(TestFailure(shell, "Call to waitpid() failed"));
return;
}
} else {
SetTestFailureByStatusCode(shell, result, status);
if (WIFSTOPPED(status)) kill(w, SIGCONT);
}
} while ((w == syscallError) || (!WIFEXITED(status) && !WIFSIGNALED(status)));
}
}
static pid_t PlatformSpecificForkImplementation(void)
{
return fork();
}
static pid_t PlatformSpecificWaitPidImplementation(int pid, int* status, int options)
{
return waitpid(pid, status, options);
}
#endif
TestOutput::WorkingEnvironment PlatformSpecificGetWorkingEnvironment()
{
return TestOutput::eclipse;
}
void (*PlatformSpecificRunTestInASeperateProcess)(UtestShell* shell, TestPlugin* plugin, TestResult* result) =
GccPlatformSpecificRunTestInASeperateProcess;
int (*PlatformSpecificFork)(void) = PlatformSpecificForkImplementation;
int (*PlatformSpecificWaitPid)(int, int*, int) = PlatformSpecificWaitPidImplementation;
extern "C" {
static int PlatformSpecificSetJmpImplementation(void (*function) (void* data), void* data)
{
if (0 == setjmp(test_exit_jmp_buf[jmp_buf_index])) {
jmp_buf_index++;
function(data);
jmp_buf_index--;
return 1;
}
return 0;
}
/*
* MacOSX clang 3.0 doesn't seem to recognize longjmp and thus complains about _no_return_.
* The later clang compilers complain when it isn't there. So only way is to check the clang compiler here :(
*/
#ifdef __clang__
#if !((__clang_major__ == 3) && (__clang_minor__ == 0))
_no_return_
#endif
#endif
static void PlatformSpecificLongJmpImplementation()
{
jmp_buf_index--;
longjmp(test_exit_jmp_buf[jmp_buf_index], 1);
}
static void PlatformSpecificRestoreJumpBufferImplementation()
{
jmp_buf_index--;
}
void (*PlatformSpecificLongJmp)() = PlatformSpecificLongJmpImplementation;
int (*PlatformSpecificSetJmp)(void (*)(void*), void*) = PlatformSpecificSetJmpImplementation;
void (*PlatformSpecificRestoreJumpBuffer)() = PlatformSpecificRestoreJumpBufferImplementation;
///////////// Time in millis
static long TimeInMillisImplementation()
{
#ifdef CPPUTEST_HAVE_GETTIMEOFDAY
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
return (tv.tv_sec * 1000) + (long)((double)tv.tv_usec * 0.001);
#else
return 0;
#endif
}
static const char* TimeStringImplementation()
{
time_t theTime = time(NULLPTR);
static char dateTime[80];
#if defined(_WIN32) && defined(MINGW_HAS_SECURE_API)
static struct tm lastlocaltime;
localtime_s(&lastlocaltime, &theTime);
struct tm *tmp = &lastlocaltime;
#else
struct tm *tmp = localtime(&theTime);
#endif
strftime(dateTime, 80, "%Y-%m-%dT%H:%M:%S", tmp);
return dateTime;
}
long (*GetPlatformSpecificTimeInMillis)() = TimeInMillisImplementation;
const char* (*GetPlatformSpecificTimeString)() = TimeStringImplementation;
/* Wish we could add an attribute to the format for discovering mis-use... but the __attribute__(format) seems to not work on va_list */
#ifdef __clang__
#pragma clang diagnostic ignored "-Wformat-nonliteral"
#endif
#ifdef __clang__
#pragma clang diagnostic ignored "-Wused-but-marked-unused"
#endif
int (*PlatformSpecificVSNprintf)(char *str, size_t size, const char* format, va_list va_args_list) = vsnprintf;
static PlatformSpecificFile PlatformSpecificFOpenImplementation(const char* filename, const char* flag)
{
#if defined(_WIN32) && defined(MINGW_HAS_SECURE_API)
FILE* file;
fopen_s(&file, filename, flag);
return file;
#else
return fopen(filename, flag);
#endif
}
static void PlatformSpecificFPutsImplementation(const char* str, PlatformSpecificFile file)
{
fputs(str, (FILE*)file);
}
static void PlatformSpecificFCloseImplementation(PlatformSpecificFile file)
{
fclose((FILE*)file);
}
static void PlatformSpecificFlushImplementation()
{
fflush(stdout);
}
PlatformSpecificFile (*PlatformSpecificFOpen)(const char*, const char*) = PlatformSpecificFOpenImplementation;
void (*PlatformSpecificFPuts)(const char*, PlatformSpecificFile) = PlatformSpecificFPutsImplementation;
void (*PlatformSpecificFClose)(PlatformSpecificFile) = PlatformSpecificFCloseImplementation;
int (*PlatformSpecificPutchar)(int) = putchar;
void (*PlatformSpecificFlush)() = PlatformSpecificFlushImplementation;
void* (*PlatformSpecificMalloc)(size_t size) = malloc;
void* (*PlatformSpecificRealloc)(void*, size_t) = realloc;
void (*PlatformSpecificFree)(void* memory) = free;
void* (*PlatformSpecificMemCpy)(void*, const void*, size_t) = memcpy;
void* (*PlatformSpecificMemset)(void*, int, size_t) = memset;
/* GCC 4.9.x introduces -Wfloat-conversion, which causes a warning / error
* in GCC's own (macro) implementation of isnan() and isinf().
*/
#if defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ > 8))
#pragma GCC diagnostic ignored "-Wfloat-conversion"
#endif
static int IsNanImplementation(double d)
{
return isnan(d);
}
static int IsInfImplementation(double d)
{
return isinf(d);
}
double (*PlatformSpecificFabs)(double) = fabs;
void (*PlatformSpecificSrand)(unsigned int) = srand;
int (*PlatformSpecificRand)(void) = rand;
int (*PlatformSpecificIsNan)(double) = IsNanImplementation;
int (*PlatformSpecificIsInf)(double) = IsInfImplementation;
int (*PlatformSpecificAtExit)(void(*func)(void)) = atexit; /// this was undefined before
static PlatformSpecificMutex PThreadMutexCreate(void)
{
#ifdef CPPUTEST_HAVE_PTHREAD_MUTEX_LOCK
pthread_mutex_t *mutex = new pthread_mutex_t;
pthread_mutex_init(mutex, NULLPTR);
return (PlatformSpecificMutex)mutex;
#else
return NULLPTR;
#endif
}
#ifdef CPPUTEST_HAVE_PTHREAD_MUTEX_LOCK
static void PThreadMutexLock(PlatformSpecificMutex mtx)
{
pthread_mutex_lock((pthread_mutex_t *)mtx);
}
#else
static void PThreadMutexLock(PlatformSpecificMutex)
{
}
#endif
#ifdef CPPUTEST_HAVE_PTHREAD_MUTEX_LOCK
static void PThreadMutexUnlock(PlatformSpecificMutex mtx)
{
pthread_mutex_unlock((pthread_mutex_t *)mtx);
}
#else
static void PThreadMutexUnlock(PlatformSpecificMutex)
{
}
#endif
#ifdef CPPUTEST_HAVE_PTHREAD_MUTEX_LOCK
static void PThreadMutexDestroy(PlatformSpecificMutex mtx)
{
pthread_mutex_t *mutex = (pthread_mutex_t *)mtx;
pthread_mutex_destroy(mutex);
delete mutex;
}
#else
static void PThreadMutexDestroy(PlatformSpecificMutex)
{
}
#endif
PlatformSpecificMutex (*PlatformSpecificMutexCreate)(void) = PThreadMutexCreate;
void (*PlatformSpecificMutexLock)(PlatformSpecificMutex) = PThreadMutexLock;
void (*PlatformSpecificMutexUnlock)(PlatformSpecificMutex) = PThreadMutexUnlock;
void (*PlatformSpecificMutexDestroy)(PlatformSpecificMutex) = PThreadMutexDestroy;
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#undef malloc
#undef free
#undef calloc
#undef realloc
#undef strdup
#undef strndup
#include "CppUTest/PlatformSpecificFunctions.h"
void (*PlatformSpecificRunTestInASeperateProcess)(UtestShell*, TestPlugin*, TestResult*) = NULLPTR;
int (*PlatformSpecificFork)() = NULLPTR;
int (*PlatformSpecificWaitPid)(int, int*, int) = NULLPTR;
TestOutput::WorkingEnvironment PlatformSpecificGetWorkingEnvironment()
{
return TestOutput::eclipse;
}
void (*PlatformSpecificLongJmp)() = NULLPTR;
int (*PlatformSpecificSetJmp)(void (*)(void*), void*) = NULLPTR;
void (*PlatformSpecificRestoreJumpBuffer)() = NULLPTR;
long (*GetPlatformSpecificTimeInMillis)() = NULLPTR;
const char* (*GetPlatformSpecificTimeString)() = NULLPTR;
/* IO operations */
PlatformSpecificFile (*PlatformSpecificFOpen)(const char* filename, const char* flag) = NULLPTR;
void (*PlatformSpecificFPuts)(const char* str, PlatformSpecificFile file) = NULLPTR;
void (*PlatformSpecificFClose)(PlatformSpecificFile file) = NULLPTR;
int (*PlatformSpecificPutchar)(int c) = NULLPTR;
void (*PlatformSpecificFlush)(void) = NULLPTR;
int (*PlatformSpecificVSNprintf)(char *str, size_t size, const char* format, va_list va_args_list) = NULLPTR;
/* Dynamic Memory operations */
void* (*PlatformSpecificMalloc)(size_t) = NULLPTR;
void* (*PlatformSpecificRealloc)(void*, size_t) = NULLPTR;
void (*PlatformSpecificFree)(void*) = NULLPTR;
void* (*PlatformSpecificMemCpy)(void*, const void*, size_t) = NULLPTR;
void* (*PlatformSpecificMemset)(void*, int, size_t) = NULLPTR;
double (*PlatformSpecificFabs)(double) = NULLPTR;
int (*PlatformSpecificIsNan)(double) = NULLPTR;
int (*PlatformSpecificIsInf)(double) = NULLPTR;
int (*PlatformSpecificAtExit)(void(*func)(void)) = NULLPTR;
PlatformSpecificMutex (*PlatformSpecificMutexCreate)(void) = NULLPTR;
void (*PlatformSpecificMutexLock)(PlatformSpecificMutex mtx) = NULLPTR;
void (*PlatformSpecificMutexUnlock)(PlatformSpecificMutex mtx) = NULLPTR;
void (*PlatformSpecificMutexDestroy)(PlatformSpecificMutex mtx) = NULLPTR;
void (*PlatformSpecificSrand)(unsigned int) = NULLPTR;
int (*PlatformSpecificRand)(void) = NULLPTR;

View file

@ -0,0 +1,205 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "CppUTest/TestHarness.h"
#undef malloc
#undef calloc
#undef realloc
#undef free
#undef strdup
#undef strndup
#include "CppUTest/PlatformSpecificFunctions.h"
static jmp_buf test_exit_jmp_buf[10];
static int jmp_buf_index = 0;
TestOutput::WorkingEnvironment PlatformSpecificGetWorkingEnvironment()
{
return TestOutput::eclipse;
}
static void DummyPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin*, TestResult* result)
{
result->addFailure(TestFailure(shell, "-p doesn't work on this platform, as it is lacking fork.\b"));
}
static int DummyPlatformSpecificFork(void)
{
return 0;
}
static int DummyPlatformSpecificWaitPid(int, int*, int)
{
return 0;
}
void (*PlatformSpecificRunTestInASeperateProcess)(UtestShell* shell, TestPlugin* plugin, TestResult* result) =
DummyPlatformSpecificRunTestInASeperateProcess;
int (*PlatformSpecificFork)(void) = DummyPlatformSpecificFork;
int (*PlatformSpecificWaitPid)(int, int*, int) = DummyPlatformSpecificWaitPid;
extern "C" {
static int PlatformSpecificSetJmpImplementation(void (*function) (void* data), void* data)
{
if (0 == setjmp(test_exit_jmp_buf[jmp_buf_index])) {
jmp_buf_index++;
function(data);
jmp_buf_index--;
return 1;
}
return 0;
}
static void PlatformSpecificLongJmpImplementation()
{
jmp_buf_index--;
longjmp(test_exit_jmp_buf[jmp_buf_index], 1);
}
static void PlatformSpecificRestoreJumpBufferImplementation()
{
jmp_buf_index--;
}
void (*PlatformSpecificLongJmp)() = PlatformSpecificLongJmpImplementation;
int (*PlatformSpecificSetJmp)(void (*)(void*), void*) = PlatformSpecificSetJmpImplementation;
void (*PlatformSpecificRestoreJumpBuffer)() = PlatformSpecificRestoreJumpBufferImplementation;
///////////// Time in millis
static long TimeInMillisImplementation()
{
clock_t t = clock();
t = t * 10;
return t;
}
///////////// Time in String
static const char* TimeStringImplementation()
{
time_t tm = time(NULL);
char* pTimeStr = ctime(&tm);
char* newlineChar = strchr(pTimeStr, '\n'); // Find the terminating newline character.
if(newlineChar != NULL) *newlineChar = '\0'; //If newline is found replace it with the string terminator.
return (pTimeStr);
}
long (*GetPlatformSpecificTimeInMillis)() = TimeInMillisImplementation;
const char* (*GetPlatformSpecificTimeString)() = TimeStringImplementation;
int (*PlatformSpecificVSNprintf)(char *str, size_t size, const char* format, va_list args) = vsnprintf;
static PlatformSpecificFile PlatformSpecificFOpenImplementation(const char* filename, const char* flag)
{
static int fileNo = 0;
(void)filename;
(void)flag;
fileNo++;
return (void*)fileNo;
}
static void PlatformSpecificFPutsImplementation(const char* str, PlatformSpecificFile file)
{
(void)str;
(void)file;
printf("FILE%d:%s",(int)file, str);
}
static void PlatformSpecificFCloseImplementation(PlatformSpecificFile file)
{
(void)file;
}
static void PlatformSpecificFlushImplementation()
{
}
PlatformSpecificFile (*PlatformSpecificFOpen)(const char*, const char*) = PlatformSpecificFOpenImplementation;
void (*PlatformSpecificFPuts)(const char*, PlatformSpecificFile) = PlatformSpecificFPutsImplementation;
void (*PlatformSpecificFClose)(PlatformSpecificFile) = PlatformSpecificFCloseImplementation;
int (*PlatformSpecificPutchar)(int) = putchar;
void (*PlatformSpecificFlush)() = PlatformSpecificFlushImplementation;
void* (*PlatformSpecificMalloc)(size_t size) = malloc;
void* (*PlatformSpecificRealloc)(void*, size_t) = realloc;
void (*PlatformSpecificFree)(void* memory) = free;
void* (*PlatformSpecificMemCpy)(void*, const void*, size_t) = memcpy;
void* (*PlatformSpecificMemset)(void*, int, size_t) = memset;
static int IsNanImplementation(double d)
{
return isnan(d);
}
static int IsInfImplementation(double d)
{
return isinf(d);
}
double (*PlatformSpecificFabs)(double) = fabs;
int (*PlatformSpecificIsNan)(double) = IsNanImplementation;
int (*PlatformSpecificIsInf)(double) = IsInfImplementation;
int (*PlatformSpecificAtExit)(void(*func)(void)) = atexit; /// this was undefined before
static PlatformSpecificMutex DummyMutexCreate(void)
{
return 0;
}
static void DummyMutexLock(PlatformSpecificMutex)
{
}
static void DummyMutexUnlock(PlatformSpecificMutex)
{
}
static void DummyMutexDestroy(PlatformSpecificMutex)
{
}
PlatformSpecificMutex (*PlatformSpecificMutexCreate)(void) = DummyMutexCreate;
void (*PlatformSpecificMutexLock)(PlatformSpecificMutex) = DummyMutexLock;
void (*PlatformSpecificMutexUnlock)(PlatformSpecificMutex) = DummyMutexUnlock;
void (*PlatformSpecificMutexDestroy)(PlatformSpecificMutex) = DummyMutexDestroy;
void (*PlatformSpecificSrand)(unsigned int) = srand;
int (*PlatformSpecificRand)(void) = rand;
}

View file

@ -0,0 +1,220 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include "CppUTest/TestHarness.h"
#undef malloc
#undef free
#undef calloc
#undef realloc
#undef strdup
#undef strndup
#define far // eliminate "meaningless type qualifier" warning
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <setjmp.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include "CppUTest/PlatformSpecificFunctions.h"
static jmp_buf test_exit_jmp_buf[10];
static int jmp_buf_index = 0;
TestOutput::WorkingEnvironment PlatformSpecificGetWorkingEnvironment()
{
return TestOutput::eclipse;
}
static void DummyRunTestInASeperateProcess(UtestShell* shell, TestPlugin* plugin, TestResult* result)
{
result->addFailure(TestFailure(shell, "-p doesn't work on this platform, as it is lacking fork.\b"));
}
static int DummyPlatformSpecificFork(void)
{
return 0;
}
static int DummyPlatformSpecificWaitPid(int, int*, int)
{
return 0;
}
void (*PlatformSpecificRunTestInASeperateProcess)(UtestShell*, TestPlugin*, TestResult*) = DummyRunTestInASeperateProcess;
int (*PlatformSpecificFork)() = DummyPlatformSpecificFork;
int (*PlatformSpecificWaitPid)(int, int*, int) = DummyPlatformSpecificWaitPid;
extern "C"
{
static int PlatformSpecificSetJmpImplementation(void (*function) (void* data), void* data)
{
if (0 == setjmp(test_exit_jmp_buf[jmp_buf_index])) {
jmp_buf_index++;
function(data);
jmp_buf_index--;
return 1;
}
return 0;
}
static void PlatformSpecificLongJmpImplementation()
{
jmp_buf_index--;
longjmp(test_exit_jmp_buf[jmp_buf_index], 1);
}
static void PlatformSpecificRestoreJumpBufferImplementation()
{
jmp_buf_index--;
}
void (*PlatformSpecificLongJmp)() = PlatformSpecificLongJmpImplementation;
int (*PlatformSpecificSetJmp)(void (*function)(void*), void*) = PlatformSpecificSetJmpImplementation;
void (*PlatformSpecificRestoreJumpBuffer)() = PlatformSpecificRestoreJumpBufferImplementation;
///////////// Time in millis
/*
* In Keil MDK-ARM, clock() default implementation used semihosting.
* Resolutions is user adjustable (1 ms for now)
*/
static long TimeInMillisImplementation()
{
clock_t t = clock();
t = t * 10;
return t;
}
long (*GetPlatformSpecificTimeInMillis)() = TimeInMillisImplementation;
static const char* TimeStringImplementation()
{
time_t tm = 0;//time(NULL); // todo
return ctime(&tm);
}
const char* (*GetPlatformSpecificTimeString)() = TimeStringImplementation;
int PlatformSpecificAtoI(const char* str)
{
return atoi(str);
}
/* The ARMCC compiler will compile this function with C++ linkage, unless
* we specifically tell it to use C linkage again, in the function definiton.
*/
extern int (*PlatformSpecificVSNprintf)(char *str, size_t size, const char* format, va_list args) = vsnprintf;
static PlatformSpecificFile PlatformSpecificFOpenImplementation(const char* filename, const char* flag)
{
return 0;
}
static void PlatformSpecificFPutsImplementation(const char* str, PlatformSpecificFile file)
{
printf("%s", str);
}
static void PlatformSpecificFCloseImplementation(PlatformSpecificFile file)
{
}
static void PlatformSpecificFlushImplementation()
{
}
PlatformSpecificFile (*PlatformSpecificFOpen)(const char*, const char*) = PlatformSpecificFOpenImplementation;
void (*PlatformSpecificFPuts)(const char*, PlatformSpecificFile) = PlatformSpecificFPutsImplementation;
void (*PlatformSpecificFClose)(PlatformSpecificFile) = PlatformSpecificFCloseImplementation;
int (*PlatformSpecificPutchar)(int) = putchar;
void (*PlatformSpecificFlush)() = PlatformSpecificFlushImplementation;
void* (*PlatformSpecificMalloc)(size_t) = malloc;
void* (*PlatformSpecificRealloc) (void*, size_t) = realloc;
void (*PlatformSpecificFree)(void*) = free;
void* (*PlatformSpecificMemCpy)(void* s1, const void* s2, size_t size) = memcpy;
void* (*PlatformSpecificMemset)(void*, int, size_t) = memset;
static int IsNanImplementation(double d)
{
# ifdef __MICROLIB
return 0;
# else
return isnan(d);
# endif
}
static int IsInfImplementation(double d)
{
# ifdef __MICROLIB
return 0;
# else
return isinf(d);
# endif
}
int DummyAtExit(void(*)(void))
{
return 0;
}
double (*PlatformSpecificFabs)(double) = abs;
int (*PlatformSpecificIsNan)(double) = IsNanImplementation;
int (*PlatformSpecificIsInf)(double) = IsInfImplementation;
int (*PlatformSpecificAtExit)(void(*func)(void)) = DummyAtExit;
static PlatformSpecificMutex DummyMutexCreate(void)
{
return 0;
}
static void DummyMutexLock(PlatformSpecificMutex mtx)
{
}
static void DummyMutexUnlock(PlatformSpecificMutex mtx)
{
}
static void DummyMutexDestroy(PlatformSpecificMutex mtx)
{
}
PlatformSpecificMutex (*PlatformSpecificMutexCreate)(void) = DummyMutexCreate;
void (*PlatformSpecificMutexLock)(PlatformSpecificMutex) = DummyMutexLock;
void (*PlatformSpecificMutexUnlock)(PlatformSpecificMutex) = DummyMutexUnlock;
void (*PlatformSpecificMutexDestroy)(PlatformSpecificMutex) = DummyMutexDestroy;
}

View file

@ -0,0 +1,36 @@
CppUTest on Symbian
Compliling
To compile CppUTest you need to have Symbian Posix libraries installed. On S60 it's
recommended to use S60 Open C. On other platforms one can use Symbian PIPS. Compiling is
in standard way, by issuing from command line commands bldmake bldfiles && abld build in
build-directory. You can also import the project's bld.inf file into Carbide in normal way.
Writing tests
CppUTest exports the needed header files into \epoc32\include\CppUTest -directory. Add the directory
to the include-path of the test project. One needs to include TestHarness.h file into test source
file. The test project must link against cpputest.lib using STATICLIBRARY statement in MMP-file.
CppUTest depends also on standard C-library so the tests must be linked against libc as well.
The entry point file of the tests is normally the following:
#include <CppUTest/CommandLineTestRunner.h>
#include <stdio.h>
// This is a GCCE toolchain workaround needed when compiling with GCCE
// and using main() entry point
#ifdef __GCCE__
#include <staticlibinit_gcce.h>
#endif
int main(int argc, char** argv)
{
CommandLineTestRunner::RunAllTests(argc, argv);
}
The test must be statically linked against libcrt0.lib if standard main (not E32Main) is used as above.
For the further example, please consult alltests.mmp in build directory.

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning, Bas Vodde and Timo Puronen
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "MemoryLeakWarning.h"
#include <e32base.h>
MemoryLeakWarning* MemoryLeakWarning::_latest = NULL;
// naming convention due to CppUTest generic class name
class MemoryLeakWarningData : public CBase {
public:
TInt iInitialAllocCells;
TInt iExpectedLeaks;
TInt iInitialThreadHandleCount;
TInt iInitialProcessHandleCount;
};
MemoryLeakWarning::MemoryLeakWarning()
{
_latest = this;
CreateData();
}
MemoryLeakWarning::~MemoryLeakWarning()
{
DestroyData();
}
void MemoryLeakWarning::Enable()
{
}
const char* MemoryLeakWarning::FinalReport(int toBeDeletedLeaks)
{
TInt cellDifference(User::CountAllocCells() - _impl->iInitialAllocCells);
if( cellDifference != toBeDeletedLeaks ) {
return "Heap imbalance after test\n";
}
TInt processHandles;
TInt threadHandles;
RThread().HandleCount(processHandles, threadHandles);
if(_impl->iInitialProcessHandleCount != processHandles ||
_impl->iInitialThreadHandleCount != threadHandles) {
return "Handle count imbalance after test\n";
}
return "";
}
void MemoryLeakWarning::CheckPointUsage()
{
_impl->iInitialAllocCells = User::CountAllocCells();
RThread().HandleCount(_impl->iInitialProcessHandleCount, _impl->iInitialThreadHandleCount);
}
bool MemoryLeakWarning::UsageIsNotBalanced()
{
TInt allocatedCells(User::CountAllocCells());
if(_impl->iExpectedLeaks != 0) {
TInt difference(Abs(_impl->iInitialAllocCells - allocatedCells));
return difference != _impl->iExpectedLeaks;
}
return allocatedCells != _impl->iInitialAllocCells;
}
const char* MemoryLeakWarning::Message()
{
return "";
}
void MemoryLeakWarning::ExpectLeaks(int n)
{
_impl->iExpectedLeaks = n;
}
// this method leaves (no naming convention followed due to CppUTest framework
void MemoryLeakWarning::CreateData()
{
_impl = new(ELeave) MemoryLeakWarningData();
}
void MemoryLeakWarning::DestroyData()
{
delete _impl;
_impl = NULL;
}
MemoryLeakWarning* MemoryLeakWarning::GetLatest()
{
return _latest;
}
void MemoryLeakWarning::SetLatest(MemoryLeakWarning* latest)
{
_latest = latest;
}

View file

@ -0,0 +1,182 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning, Bas Vodde and Timo Puronen
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CppUTest/TestHarness.h"
#include <e32def.h>
#include <e32std.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include "CppUTest/PlatformSpecificFunctions.h"
static jmp_buf test_exit_jmp_buf[10];
static int jmp_buf_index = 0;
int PlatformSpecificSetJmp(void (*function) (void* data), void* data)
{
if (0 == setjmp(test_exit_jmp_buf[jmp_buf_index])) {
jmp_buf_index++;
function(data);
jmp_buf_index--;
return 1;
}
return 0;
}
void PlatformSpecificLongJmp()
{
jmp_buf_index--;
longjmp(test_exit_jmp_buf[jmp_buf_index], 1);
}
void PlatformSpecificRestoreJumpBuffer()
{
jmp_buf_index--;
}
void PlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin* plugin, TestResult* result)
{
printf("-p doesn't work on this platform as it is not implemented. Running inside the process\b");
shell->runOneTest(plugin, *result);
}
static long TimeInMillisImplementation() {
struct timeval tv;
struct timezone tz;
::gettimeofday(&tv, &tz);
return (tv.tv_sec * 1000) + (long)(tv.tv_usec * 0.001);
}
long (*GetPlatformSpecificTimeInMillis)() = TimeInMillisImplementation;
TestOutput::WorkingEnvironment PlatformSpecificGetWorkingEnvironment()
{
return TestOutput::eclipse;
}
static SimpleString TimeStringImplementation() {
time_t tm = time(NULL);
return ctime(&tm);
}
SimpleString GetPlatformSpecificTimeString() = TimeStringImplementation;
int PlatformSpecificVSNprintf(char* str, size_t size, const char* format, va_list args) {
return vsnprintf(str, size, format, args);
}
void PlatformSpecificFlush() {
fflush(stdout);
}
int PlatformSpecificPutchar(int c) {
return putchar(c);
}
double PlatformSpecificFabs(double d) {
return fabs(d);
}
void* PlatformSpecificMalloc(size_t size) {
return malloc(size);
}
void* PlatformSpecificRealloc (void* memory, size_t size) {
return realloc(memory, size);
}
void PlatformSpecificFree(void* memory) {
free(memory);
}
void* PlatformSpecificMemCpy(void* s1, const void* s2, size_t size) {
return memcpy(s1, s2, size);
}
void* PlatformSpecificMemset(void* mem, int c, size_t size)
{
return memset(mem, c, size);
}
PlatformSpecificFile PlatformSpecificFOpen(const char* filename, const char* flag) {
return fopen(filename, flag);
}
void PlatformSpecificFPuts(const char* str, PlatformSpecificFile file) {
fputs(str, (FILE*)file);
}
void PlatformSpecificFClose(PlatformSpecificFile file) {
fclose((FILE*)file);
}
extern "C" {
static int IsNanImplementation(double d)
{
return isnan(d);
}
static int IsInfImplementation(double d)
{
return isinf(d);
}
int (*PlatformSpecificIsNan)(double) = IsNanImplementation;
int (*PlatformSpecificIsInf)(double) = IsInfImplementation;
}
static PlatformSpecificMutex DummyMutexCreate(void)
{
FAIL("PlatformSpecificMutexCreate is not implemented");
return 0;
}
static void DummyMutexLock(PlatformSpecificMutex mtx)
{
FAIL("PlatformSpecificMutexLock is not implemented");
}
static void DummyMutexUnlock(PlatformSpecificMutex mtx)
{
FAIL("PlatformSpecificMutexUnlock is not implemented");
}
static void DummyMutexDestroy(PlatformSpecificMutex mtx)
{
FAIL("PlatformSpecificMutexDestroy is not implemented");
}
PlatformSpecificMutex (*PlatformSpecificMutexCreate)(void) = DummyMutexCreate;
void (*PlatformSpecificMutexLock)(PlatformSpecificMutex) = DummyMutexLock;
void (*PlatformSpecificMutexUnlock)(PlatformSpecificMutex) = DummyMutexUnlock;
void (*PlatformSpecificMutexDestroy)(PlatformSpecificMutex) = DummyMutexDestroy;

View file

@ -0,0 +1,233 @@
#include <stdlib.h>
#include "CppUTest/TestHarness.h"
#undef malloc
#undef free
#undef calloc
#undef realloc
#undef strdup
#undef strndup
#include <stdio.h>
#include <stdarg.h>
#include <setjmp.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include <time.h>
#include "CppUTest/PlatformSpecificFunctions.h"
#include <windows.h>
#include <mmsystem.h>
#include <setjmp.h>
#ifdef STDC_WANT_SECURE_LIB
#define FOPEN(fp, filename, flag) fopen_s((fp), (filename), (flag))
#define _VSNPRINTF(str, size, trunc, format, args) _vsnprintf_s((str), (size), (trunc), (format), (args))
#define LOCALTIME(_tm, timer) localtime_s((_tm), (timer))
#else
#define FOPEN(fp, filename, flag) *(fp) = fopen((filename), (flag))
#define _VSNPRINTF(str, size, trunc, format, args) _vsnprintf((str), (size), (format), (args))
#define LOCALTIME(_tm, timer) memcpy(_tm, localtime(timer), sizeof(tm));
#endif
static jmp_buf test_exit_jmp_buf[10];
static int jmp_buf_index = 0;
static int VisualCppSetJmp(void (*function) (void* data), void* data)
{
if (0 == setjmp(test_exit_jmp_buf[jmp_buf_index])) {
jmp_buf_index++;
function(data);
jmp_buf_index--;
return 1;
}
return 0;
}
static void VisualCppLongJmp()
{
jmp_buf_index--;
longjmp(test_exit_jmp_buf[jmp_buf_index], 1);
}
static void VisualCppRestoreJumpBuffer()
{
jmp_buf_index--;
}
int (*PlatformSpecificSetJmp)(void (*function) (void*), void* data) = VisualCppSetJmp;
void (*PlatformSpecificLongJmp)(void) = VisualCppLongJmp;
void (*PlatformSpecificRestoreJumpBuffer)(void) = VisualCppRestoreJumpBuffer;
static void VisualCppRunTestInASeperateProcess(UtestShell* shell, TestPlugin* plugin, TestResult* result)
{
result->addFailure(TestFailure(shell, "-p doesn't work on this platform, as it is lacking fork.\b"));
}
void (*PlatformSpecificRunTestInASeperateProcess)(UtestShell* shell, TestPlugin* plugin, TestResult* result) =
VisualCppRunTestInASeperateProcess;
TestOutput::WorkingEnvironment PlatformSpecificGetWorkingEnvironment()
{
return TestOutput::visualStudio;
}
///////////// Time in millis
static long VisualCppTimeInMillis()
{
static LARGE_INTEGER s_frequency;
static const BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
if (s_use_qpc)
{
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
return (long)((now.QuadPart * 1000) / s_frequency.QuadPart);
}
else
{
#ifdef TIMERR_NOERROR
return (long)timeGetTime();
#else
#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || (_WIN32_WINNT < _WIN32_WINNT_VISTA)
return (long)GetTickCount();
#else
return (long)GetTickCount64();
#endif
#endif
}
}
long (*GetPlatformSpecificTimeInMillis)() = VisualCppTimeInMillis;
///////////// Time in String
static const char* VisualCppTimeString()
{
time_t the_time = time(NULL);
struct tm the_local_time;
static char dateTime[80];
LOCALTIME(&the_local_time, &the_time);
strftime(dateTime, 80, "%Y-%m-%dT%H:%M:%S", &the_local_time);
return dateTime;
}
const char* (*GetPlatformSpecificTimeString)() = VisualCppTimeString;
////// taken from gcc
static int VisualCppVSNprintf(char *str, size_t size, const char* format, va_list args)
{
char* buf = 0;
size_t sizeGuess = size;
int result = _VSNPRINTF( str, size, _TRUNCATE, format, args);
str[size-1] = 0;
while (result == -1)
{
if (buf != 0)
free(buf);
sizeGuess += 10;
buf = (char*)malloc(sizeGuess);
result = _VSNPRINTF( buf, sizeGuess, _TRUNCATE, format, args);
}
if (buf != 0)
free(buf);
return result;
}
int (*PlatformSpecificVSNprintf)(char *str, size_t size, const char* format, va_list va_args_list) = VisualCppVSNprintf;
static PlatformSpecificFile VisualCppFOpen(const char* filename, const char* flag)
{
FILE* file;
FOPEN(&file, filename, flag);
return file;
}
static void VisualCppFPuts(const char* str, PlatformSpecificFile file)
{
fputs(str, (FILE*)file);
}
static void VisualCppFClose(PlatformSpecificFile file)
{
fclose((FILE*)file);
}
PlatformSpecificFile (*PlatformSpecificFOpen)(const char* filename, const char* flag) = VisualCppFOpen;
void (*PlatformSpecificFPuts)(const char* str, PlatformSpecificFile file) = VisualCppFPuts;
void (*PlatformSpecificFClose)(PlatformSpecificFile file) = VisualCppFClose;
static void VisualCppFlush()
{
fflush(stdout);
}
int (*PlatformSpecificPutchar)(int c) = putchar;
void (*PlatformSpecificFlush)(void) = VisualCppFlush;
static void* VisualCppMalloc(size_t size)
{
return malloc(size);
}
static void* VisualCppReAlloc(void* memory, size_t size)
{
return realloc(memory, size);
}
static void VisualCppFree(void* memory)
{
free(memory);
}
void (*PlatformSpecificSrand)(unsigned int) = srand;
int (*PlatformSpecificRand)(void) = rand;
void* (*PlatformSpecificMalloc)(size_t size) = VisualCppMalloc;
void* (*PlatformSpecificRealloc)(void* memory, size_t size) = VisualCppReAlloc;
void (*PlatformSpecificFree)(void* memory) = VisualCppFree;
void* (*PlatformSpecificMemCpy)(void* s1, const void* s2, size_t size) = memcpy;
void* (*PlatformSpecificMemset)(void* mem, int c, size_t size) = memset;
static int IsInfImplementation(double d)
{
return !_finite(d);
}
double (*PlatformSpecificFabs)(double d) = fabs;
extern "C" int (*PlatformSpecificIsNan)(double) = _isnan;
extern "C" int (*PlatformSpecificIsInf)(double) = IsInfImplementation;
int (*PlatformSpecificAtExit)(void(*func)(void)) = atexit;
static PlatformSpecificMutex VisualCppMutexCreate(void)
{
CRITICAL_SECTION *critical_section = new CRITICAL_SECTION;
InitializeCriticalSection(critical_section);
return (PlatformSpecificMutex)critical_section;
}
static void VisualCppMutexLock(PlatformSpecificMutex mutex)
{
EnterCriticalSection((CRITICAL_SECTION*)mutex);
}
static void VisualCppMutexUnlock(PlatformSpecificMutex mutex)
{
LeaveCriticalSection((CRITICAL_SECTION*)mutex);
}
static void VisualCppMutexDestroy(PlatformSpecificMutex mutex)
{
CRITICAL_SECTION *critical_section = (CRITICAL_SECTION*)mutex;
DeleteCriticalSection(critical_section);
delete critical_section;
}
PlatformSpecificMutex (*PlatformSpecificMutexCreate)(void) = VisualCppMutexCreate;
void (*PlatformSpecificMutexLock)(PlatformSpecificMutex) = VisualCppMutexLock;
void (*PlatformSpecificMutexUnlock)(PlatformSpecificMutex) = VisualCppMutexUnlock;
void (*PlatformSpecificMutexDestroy)(PlatformSpecificMutex) = VisualCppMutexDestroy;

View file

@ -0,0 +1,207 @@
/*
* Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "CppUTest/TestHarness.h"
#undef malloc
#undef calloc
#undef realloc
#undef free
#undef strdup
#undef strndup
#define far // eliminate "meaningless type qualifier" warning
#include "CppUTest/PlatformSpecificFunctions.h"
static jmp_buf test_exit_jmp_buf[10];
static int jmp_buf_index = 0;
TestOutput::WorkingEnvironment PlatformSpecificGetWorkingEnvironment()
{
return TestOutput::eclipse;
}
static void DummyPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin*, TestResult* result)
{
result->addFailure(TestFailure(shell, "-p doesn't work on this platform, as it is lacking fork.\b"));
}
static int DummyPlatformSpecificFork(void)
{
return 0;
}
static int DummyPlatformSpecificWaitPid(int, int*, int)
{
return 0;
}
void (*PlatformSpecificRunTestInASeperateProcess)(UtestShell* shell, TestPlugin* plugin, TestResult* result) =
DummyPlatformSpecificRunTestInASeperateProcess;
int (*PlatformSpecificFork)(void) = DummyPlatformSpecificFork;
int (*PlatformSpecificWaitPid)(int, int*, int) = DummyPlatformSpecificWaitPid;
extern "C" {
static int PlatformSpecificSetJmpImplementation(void (*function) (void* data), void* data)
{
if (0 == setjmp(test_exit_jmp_buf[jmp_buf_index])) {
jmp_buf_index++;
function(data);
jmp_buf_index--;
return 1;
}
return 0;
}
static void PlatformSpecificLongJmpImplementation()
{
jmp_buf_index--;
longjmp(test_exit_jmp_buf[jmp_buf_index], 1);
}
static void PlatformSpecificRestoreJumpBufferImplementation()
{
jmp_buf_index--;
}
void (*PlatformSpecificLongJmp)() = PlatformSpecificLongJmpImplementation;
int (*PlatformSpecificSetJmp)(void (*)(void*), void*) = PlatformSpecificSetJmpImplementation;
void (*PlatformSpecificRestoreJumpBuffer)() = PlatformSpecificRestoreJumpBufferImplementation;
///////////// Time in millis
/*
* In Keil MDK-ARM, clock() default implementation used semihosting.
* Resolutions is user adjustable (1 ms for now)
*/
static long TimeInMillisImplementation()
{
clock_t t = clock();
return t;
}
///////////// Time in String
static const char* DummyTimeStringImplementation()
{
time_t tm = 0;
return ctime(&tm);
}
long (*GetPlatformSpecificTimeInMillis)() = TimeInMillisImplementation;
const char* (*GetPlatformSpecificTimeString)() = DummyTimeStringImplementation;
int (*PlatformSpecificVSNprintf)(char *str, size_t size, const char* format, va_list args) = vsnprintf;
static PlatformSpecificFile PlatformSpecificFOpenImplementation(const char* filename, const char* flag)
{
return fopen(filename, flag);
}
static void PlatformSpecificFPutsImplementation(const char* str, PlatformSpecificFile file)
{
fputs(str, (FILE*)file);
}
static void PlatformSpecificFCloseImplementation(PlatformSpecificFile file)
{
fclose((FILE*)file);
}
static void PlatformSpecificFlushImplementation()
{
fflush(stdout);
}
PlatformSpecificFile (*PlatformSpecificFOpen)(const char*, const char*) = PlatformSpecificFOpenImplementation;
void (*PlatformSpecificFPuts)(const char*, PlatformSpecificFile) = PlatformSpecificFPutsImplementation;
void (*PlatformSpecificFClose)(PlatformSpecificFile) = PlatformSpecificFCloseImplementation;
int (*PlatformSpecificPutchar)(int) = putchar;
void (*PlatformSpecificFlush)() = PlatformSpecificFlushImplementation;
void* (*PlatformSpecificMalloc)(size_t size) = malloc;
void* (*PlatformSpecificRealloc)(void*, size_t) = realloc;
void (*PlatformSpecificFree)(void* memory) = free;
void* (*PlatformSpecificMemCpy)(void*, const void*, size_t) = memcpy;
void* (*PlatformSpecificMemset)(void*, int, size_t) = memset;
void (*PlatformSpecificSrand)(unsigned int) = srand;
int (*PlatformSpecificRand)(void) = rand;
static int IsNanImplementation(double d)
{
return isnan(d);
}
static int IsInfImplementation(double d)
{
return isinf(d);
}
static int AtExitImplementation(void(*func)(void))
{
return atexit(func);
}
double (*PlatformSpecificFabs)(double) = fabs;
int (*PlatformSpecificIsNan)(double) = IsNanImplementation;
int (*PlatformSpecificIsInf)(double) = IsInfImplementation;
int (*PlatformSpecificAtExit)(void(*func)(void)) = AtExitImplementation;
static PlatformSpecificMutex DummyMutexCreate(void)
{
return 0;
}
static void DummyMutexLock(PlatformSpecificMutex)
{
}
static void DummyMutexUnlock(PlatformSpecificMutex)
{
}
static void DummyMutexDestroy(PlatformSpecificMutex)
{
}
PlatformSpecificMutex (*PlatformSpecificMutexCreate)(void) = DummyMutexCreate;
void (*PlatformSpecificMutexLock)(PlatformSpecificMutex) = DummyMutexLock;
void (*PlatformSpecificMutexUnlock)(PlatformSpecificMutex) = DummyMutexUnlock;
void (*PlatformSpecificMutexDestroy)(PlatformSpecificMutex) = DummyMutexDestroy;
}