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,59 @@
/*
* 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/CommandLineTestRunner.h"
#include "CppUTest/TestMemoryAllocator.h"
#include "CppUTest/SimpleStringInternalCache.h"
#define SHOW_MEMORY_REPORT 0
int main(int ac, char **av)
{
int returnValue = 0;
GlobalSimpleStringCache stringCache;
{
/* These checks are here to make sure assertions outside test runs don't crash */
CHECK(true);
LONGS_EQUAL(1, 1);
#if SHOW_MEMORY_REPORT
GlobalMemoryAccountant accountant;
accountant.start();
#endif
returnValue = CommandLineTestRunner::RunAllTests(ac, av); /* cover alternate method */
#if SHOW_MEMORY_REPORT
accountant.stop();
printf("%s", accountant.report().asCharString());
#endif
}
return returnValue;
}

View file

@ -0,0 +1,43 @@
/*
* 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 this in the test main to execute these tests
IMPORT_TEST_GROUP( Utest);
IMPORT_TEST_GROUP( Failure);
IMPORT_TEST_GROUP( TestOutput);
IMPORT_TEST_GROUP( SimpleString);
IMPORT_TEST_GROUP( TestInstaller);
IMPORT_TEST_GROUP( NullTest);
IMPORT_TEST_GROUP( MemoryLeakWarningTest);
IMPORT_TEST_GROUP( TestHarness_c);
IMPORT_TEST_GROUP( CommandLineTestRunner);
IMPORT_TEST_GROUP( JUnitOutputTest);
IMPORT_TEST_GROUP( MemoryLeakDetectorTest);
/* In allTest.cpp */
IMPORT_TEST_GROUP(CheatSheet);

View file

@ -0,0 +1,28 @@
#include "CppUTest/StandardCLibrary.h"
#if CPPUTEST_USE_STD_C_LIB
#include "AllocLetTestFree.h"
typedef struct AllocLetTestFreeStruct
{
int placeHolderForHiddenStructElements;
} AllocLetTestFreeStruct;
AllocLetTestFree AllocLetTestFree_Create(void)
{
size_t count = 1;
AllocLetTestFree self = (AllocLetTestFree)calloc(count, sizeof(AllocLetTestFreeStruct));
return self;
}
void AllocLetTestFree_Destroy(AllocLetTestFree self)
{
AllocLetTestFree no_use = self;
self = NULL;
self = no_use;
(void)self;
}
#endif

View file

@ -0,0 +1,19 @@
#ifndef D_AllocLetTestFree_H
#define D_AllocLetTestFree_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct AllocLetTestFreeStruct * AllocLetTestFree;
AllocLetTestFree AllocLetTestFree_Create(void);
void AllocLetTestFree_Destroy(AllocLetTestFree);
#ifdef __cplusplus
}
#endif
#endif /* D_FakeAllocLetTestFree_H */

View file

@ -0,0 +1,35 @@
#include "CppUTest/StandardCLibrary.h"
extern "C"
{
#include "AllocLetTestFree.h"
}
#include "CppUTest/TestHarness.h"
#if CPPUTEST_USE_STD_C_LIB
/*
* This test makes sure that memory leak malloc macros are forced into .cpp and .c files
*/
TEST_GROUP(AllocLetTestFree)
{
AllocLetTestFree allocLetTestFree;
void setup() _override
{
allocLetTestFree = AllocLetTestFree_Create();
}
void teardown() _override
{
AllocLetTestFree_Destroy(allocLetTestFree);
}
};
TEST(AllocLetTestFree, Create)
{
free(allocLetTestFree);
}
#endif

View file

@ -0,0 +1,42 @@
#include "AllocationInCFile.h"
#include "CppUTest/MemoryLeakDetectorMallocMacros.h"
#include "CppUTest/StandardCLibrary.h"
/* This file is for simulating overloads of malloc */
char* mallocAllocation()
{
return (char*) malloc(10UL);
}
char* strdupAllocation()
{
#ifdef CPPUTEST_USE_STRDUP_MACROS
return strdup("0123456789");
#else
return NULL;
#endif
}
char* strndupAllocation()
{
#ifdef CPPUTEST_USE_STRDUP_MACROS
return strndup("0123456789", 10);
#else
return NULL;
#endif
}
void freeAllocation(void* memory)
{
free(memory);
}
#undef free
void freeAllocationWithoutMacro(void* memory)
{
free(memory);
}

View file

@ -0,0 +1,18 @@
#ifndef ALLOCATIONINCFILE_H
#define ALLOCATIONINCFILE_H
#ifdef __cplusplus
extern "C" {
#endif
extern char* mallocAllocation(void);
extern char* strdupAllocation(void);
extern char* strndupAllocation(void);
extern void freeAllocation(void* memory);
extern void freeAllocationWithoutMacro(void* memory);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,37 @@
/* This file is for emulating allocations in a C++ file.
* It is used simulating the use of the memory leak detector on production code in C++
*/
#undef new
#include "CppUTest/MemoryLeakDetectorNewMacros.h"
#include "AllocationInCppFile.h"
char* newAllocation()
{
return new char;
}
char* newArrayAllocation()
{
return new char[100];
}
#undef new
char* newAllocationWithoutMacro()
{
return new char;
}
char* newArrayAllocationWithoutMacro()
{
return new char[100];
}
#if CPPUTEST_USE_STD_CPP_LIB
ClassThatThrowsAnExceptionInTheConstructor::ClassThatThrowsAnExceptionInTheConstructor()
{
throw 1;
}
#endif

View file

@ -0,0 +1,20 @@
#ifndef ALLOCATIONINCPPFILE_H
#define ALLOCATIONINCPPFILE_H
char* newAllocation();
char* newArrayAllocation();
char* newAllocationWithoutMacro();
char* newArrayAllocationWithoutMacro();
#if CPPUTEST_USE_STD_CPP_LIB
class ClassThatThrowsAnExceptionInTheConstructor
{
public:
ClassThatThrowsAnExceptionInTheConstructor() _no_return_;
};
#endif
#endif

View file

@ -0,0 +1,61 @@
set(CppUTestTests_src
AllTests.cpp
SetPluginTest.cpp
CheatSheetTest.cpp
SimpleStringTest.cpp
SimpleStringCacheTest.cpp
CompatabilityTests.cpp
CommandLineArgumentsTest.cpp
TestFailureTest.cpp
TestFailureNaNTest.cpp
CommandLineTestRunnerTest.cpp
TestFilterTest.cpp
TestHarness_cTest.cpp
JUnitOutputTest.cpp
TestHarness_cTestCFile.c
DummyMemoryLeakDetector.cpp
MemoryLeakDetectorTest.cpp
TestInstallerTest.cpp
AllocLetTestFree.c
MemoryOperatorOverloadTest.cpp
TestMemoryAllocatorTest.cpp
MemoryLeakWarningTest.cpp
TestOutputTest.cpp
AllocLetTestFreeTest.cpp
TestRegistryTest.cpp
AllocationInCFile.c
PluginTest.cpp
TestResultTest.cpp
PreprocessorTest.cpp
TestUTestMacro.cpp
TestUTestStringMacro.cpp
AllocationInCppFile.cpp
UtestTest.cpp
SimpleMutexTest.cpp
UtestPlatformTest.cpp
TeamCityOutputTest.cpp
)
if (MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4723")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4723")
endif (MSVC)
if (MINGW)
find_package (Threads REQUIRED)
set(THREAD_LIB "pthread")
endif (MINGW)
if (${CMAKE_HOST_SYSTEM_NAME} MATCHES "OpenBSD")
set (THREADS_HAVE_PTHREAD_ARG 1)
find_package (Threads REQUIRED)
set (THREAD_LIB "pthread")
endif ()
add_executable(CppUTestTests ${CppUTestTests_src})
cpputest_normalize_test_output_location(CppUTestTests)
target_link_libraries(CppUTestTests CppUTest ${THREAD_LIB})
if (TESTS_BUILD_DISCOVER)
cpputest_buildtime_discover_tests(CppUTestTests)
endif()

View file

@ -0,0 +1,35 @@
static void (*real_one) ();
static void stub(){}
/* in CheatSheetTest.cpp */
#include "CppUTest/TestHarness.h"
/* Declare TestGroup with name CheatSheet */
TEST_GROUP(CheatSheet)
{
/* declare a setup method for the test group. Optional. */
void setup() _override
{
/* Set method real_one to stub. Automatically restore in teardown */
UT_PTR_SET(real_one, stub);
}
/* Declare a teardown method for the test group. Optional */
void teardown() _override
{
}
}; /* Do not forget semicolumn */
/* Declare one test within the test group */
TEST(CheatSheet, TestName)
{
/* Check two longs are equal */
LONGS_EQUAL(1, 1);
/* Check a condition */
CHECK(true == true);
/* Check a string */
STRCMP_EQUAL("HelloWorld", "HelloWorld");
}

View file

@ -0,0 +1,552 @@
/*
* 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/TestRegistry.h"
class OptionsPlugin: public TestPlugin
{
public:
OptionsPlugin(const SimpleString& name) :
TestPlugin(name)
{
}
~OptionsPlugin() _destructor_override
{
}
bool parseArguments(int /*ac*/, const char *const * /*av*/, int /*index*/) _override
{
return true;
}
};
TEST_GROUP(CommandLineArguments)
{
CommandLineArguments* args;
OptionsPlugin* plugin;
void setup() _override
{
plugin = new OptionsPlugin("options");
args = NULLPTR;
}
void teardown() _override
{
delete args;
delete plugin;
}
bool newArgumentParser(int argc, const char *const *argv)
{
args = new CommandLineArguments(argc, argv);
return args->parse(plugin);
}
};
TEST(CommandLineArguments, Create)
{
}
TEST(CommandLineArguments, verboseSetMultipleParameters)
{
const char* argv[] = { "tests.exe", "-v" };
CHECK(newArgumentParser(2, argv));
CHECK(args->isVerbose());
}
TEST(CommandLineArguments, veryVerbose)
{
const char* argv[] = { "tests.exe", "-vv" };
CHECK(newArgumentParser(2, argv));
CHECK(args->isVeryVerbose());
}
TEST(CommandLineArguments, setColor)
{
const char* argv[] = { "tests.exe", "-c" };
CHECK(newArgumentParser(2, argv));
CHECK(args->isColor());
}
TEST(CommandLineArguments, repeatSet)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-r3" };
CHECK(newArgumentParser(argc, argv));
LONGS_EQUAL(3, args->getRepeatCount());
}
TEST(CommandLineArguments, repeatSetDifferentParameter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-r", "4" };
CHECK(newArgumentParser(argc, argv));
LONGS_EQUAL(4, args->getRepeatCount());
}
TEST(CommandLineArguments, repeatSetDefaultsToTwoAndShuffleDisabled)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-r" };
CHECK(newArgumentParser(argc, argv));
LONGS_EQUAL(2, args->getRepeatCount());
}
TEST(CommandLineArguments, reverseEnabled)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-b" };
CHECK(newArgumentParser(argc, argv));
CHECK_TRUE(args->isReversing());
}
TEST(CommandLineArguments, shuffleDisabledByDefault)
{
int argc = 1;
const char* argv[] = { "tests.exe" };
CHECK(newArgumentParser(argc, argv));
CHECK_FALSE(args->isShuffling());
}
TEST(CommandLineArguments, shuffleEnabled)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-s" };
CHECK(newArgumentParser(argc, argv));
CHECK_TRUE(args->isShuffling());
}
TEST(CommandLineArguments, shuffleWithSeedZeroIsOk)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-s0" };
CHECK_FALSE(newArgumentParser(argc, argv));
CHECK_EQUAL(0, args->getShuffleSeed());
}
TEST(CommandLineArguments, shuffleEnabledSpecificSeedCase1)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-s999"};
CHECK(newArgumentParser(argc, argv));
CHECK_EQUAL(999, args->getShuffleSeed());
}
TEST(CommandLineArguments, shuffleEnabledSpecificSeedCase2)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-s 888"};
CHECK(newArgumentParser(argc, argv));
CHECK_EQUAL(888, args->getShuffleSeed());
}
TEST(CommandLineArguments, shuffleEnabledSpecificSeedCase3)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-s", "777"};
CHECK(newArgumentParser(argc, argv));
CHECK_EQUAL(777, args->getShuffleSeed());
}
TEST(CommandLineArguments, shuffleBeforeDoesNotDisturbOtherSwitch)
{
int argc = 4;
const char* argv[] = { "tests.exe", "-s", "-sg", "group" };
CHECK(newArgumentParser(argc, argv));
TestFilter groupFilter("group");
groupFilter.strictMatching();
CHECK_EQUAL(groupFilter, *args->getGroupFilters());
CHECK_TRUE(args->isShuffling());
}
TEST(CommandLineArguments, runningTestsInSeperateProcesses)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-p" };
CHECK(newArgumentParser(argc, argv));
CHECK(args->runTestsInSeperateProcess());
}
TEST(CommandLineArguments, setGroupFilter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-g", "group" };
CHECK(newArgumentParser(argc, argv));
CHECK_EQUAL(TestFilter("group"), *args->getGroupFilters());
}
TEST(CommandLineArguments, setCompleteGroupDotNameFilterInvalidArgument)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-t", "groupname" };
CHECK_FALSE(newArgumentParser(argc, argv));
}
TEST(CommandLineArguments, setCompleteGroupDotNameFilter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-t", "group.name" };
CHECK(newArgumentParser(argc, argv));
CHECK_EQUAL(TestFilter("group"), *args->getGroupFilters());
CHECK_EQUAL(TestFilter("name"), *args->getNameFilters());
}
TEST(CommandLineArguments, setGroupFilterSameParameter)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-ggroup" };
CHECK(newArgumentParser(argc, argv));
CHECK_EQUAL(TestFilter("group"), *args->getGroupFilters());
}
TEST(CommandLineArguments, setStrictGroupFilter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-sg", "group" };
CHECK(newArgumentParser(argc, argv));
TestFilter groupFilter("group");
groupFilter.strictMatching();
CHECK_EQUAL(groupFilter, *args->getGroupFilters());
}
TEST(CommandLineArguments, setStrictGroupFilterSameParameter)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-sggroup" };
CHECK(newArgumentParser(argc, argv));
TestFilter groupFilter("group");
groupFilter.strictMatching();
CHECK_EQUAL(groupFilter, *args->getGroupFilters());
}
TEST(CommandLineArguments, setExcludeGroupFilter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-xg", "group" };
CHECK(newArgumentParser(argc, argv));
TestFilter groupFilter("group");
groupFilter.invertMatching();
CHECK_EQUAL(groupFilter, *args->getGroupFilters());
}
TEST(CommandLineArguments, setExcludeGroupFilterSameParameter)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-xggroup" };
CHECK(newArgumentParser(argc, argv));
TestFilter groupFilter("group");
groupFilter.invertMatching();
CHECK_EQUAL(groupFilter, *args->getGroupFilters());
}
TEST(CommandLineArguments, setExcludeStrictGroupFilter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-xsg", "group" };
CHECK(newArgumentParser(argc, argv));
TestFilter groupFilter("group");
groupFilter.invertMatching();
groupFilter.strictMatching();
CHECK_EQUAL(groupFilter, *args->getGroupFilters());
}
TEST(CommandLineArguments, setExcludeStrictGroupFilterSameParameter)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-xsggroup" };
CHECK(newArgumentParser(argc, argv));
TestFilter groupFilter("group");
groupFilter.invertMatching();
groupFilter.strictMatching();
CHECK_EQUAL(groupFilter, *args->getGroupFilters());
}
TEST(CommandLineArguments, setNameFilter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-n", "name" };
CHECK(newArgumentParser(argc, argv));
CHECK_EQUAL(TestFilter("name"), *args->getNameFilters());
}
TEST(CommandLineArguments, setNameFilterSameParameter)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-nname" };
CHECK(newArgumentParser(argc, argv));
CHECK_EQUAL(TestFilter("name"), *args->getNameFilters());
}
TEST(CommandLineArguments, setStrictNameFilter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-sn", "name" };
CHECK(newArgumentParser(argc, argv));
TestFilter nameFilter("name");
nameFilter.strictMatching();
CHECK_EQUAL(nameFilter, *args->getNameFilters());
}
TEST(CommandLineArguments, setStrictNameFilterSameParameter)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-snname" };
CHECK(newArgumentParser(argc, argv));
TestFilter nameFilter("name");
nameFilter.strictMatching();
CHECK_EQUAL(nameFilter, *args->getNameFilters());
}
TEST(CommandLineArguments, setExcludeNameFilter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-xn", "name" };
CHECK(newArgumentParser(argc, argv));
TestFilter nameFilter("name");
nameFilter.invertMatching();
CHECK_EQUAL(nameFilter, *args->getNameFilters());
}
TEST(CommandLineArguments, setExcludeNameFilterSameParameter)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-xnname" };
CHECK(newArgumentParser(argc, argv));
TestFilter nameFilter("name");
nameFilter.invertMatching();
CHECK_EQUAL(nameFilter, *args->getNameFilters());
}
TEST(CommandLineArguments, setExcludeStrictNameFilter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-xsn", "name" };
CHECK(newArgumentParser(argc, argv));
TestFilter nameFilter("name");
nameFilter.invertMatching();
nameFilter.strictMatching();
CHECK_EQUAL(nameFilter, *args->getNameFilters());
}
TEST(CommandLineArguments, setExcludeStrictNameFilterSameParameter)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-xsnname" };
CHECK(newArgumentParser(argc, argv));
TestFilter nameFilter("name");
nameFilter.invertMatching();
nameFilter.strictMatching();
CHECK_EQUAL(nameFilter, *args->getNameFilters());
}
TEST(CommandLineArguments, setTestToRunUsingVerboseOutput)
{
int argc = 2;
const char* argv[] = { "tests.exe", "TEST(testgroup, testname) - stuff" };
CHECK(newArgumentParser(argc, argv));
TestFilter nameFilter("testname");
TestFilter groupFilter("testgroup");
nameFilter.strictMatching();
groupFilter.strictMatching();
CHECK_EQUAL(nameFilter, *args->getNameFilters());
CHECK_EQUAL(groupFilter, *args->getGroupFilters());
}
TEST(CommandLineArguments, setTestToRunUsingVerboseOutputOfIgnoreTest)
{
int argc = 2;
const char* argv[] = { "tests.exe", "IGNORE_TEST(testgroup, testname) - stuff" };
CHECK(newArgumentParser(argc, argv));
TestFilter nameFilter("testname");
TestFilter groupFilter("testgroup");
nameFilter.strictMatching();
groupFilter.strictMatching();
CHECK_EQUAL(nameFilter, *args->getNameFilters());
CHECK_EQUAL(groupFilter, *args->getGroupFilters());
}
TEST(CommandLineArguments, setNormalOutput)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-onormal" };
CHECK(newArgumentParser(argc, argv));
CHECK(args->isEclipseOutput());
}
TEST(CommandLineArguments, setEclipseOutput)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-oeclipse" };
CHECK(newArgumentParser(argc, argv));
CHECK(args->isEclipseOutput());
}
TEST(CommandLineArguments, setNormalOutputDifferentParameter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-o", "normal" };
CHECK(newArgumentParser(argc, argv));
CHECK(args->isEclipseOutput());
}
TEST(CommandLineArguments, setJUnitOutputDifferentParameter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-o", "junit" };
CHECK(newArgumentParser(argc, argv));
CHECK(args->isJUnitOutput());
}
TEST(CommandLineArguments, setTeamCityOutputDifferentParameter)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-o", "teamcity" };
CHECK(newArgumentParser(argc, argv));
CHECK(args->isTeamCityOutput());
}
TEST(CommandLineArguments, setOutputToGarbage)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-o", "garbage" };
CHECK(!newArgumentParser(argc, argv));
}
TEST(CommandLineArguments, setPrintGroups)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-lg" };
CHECK(newArgumentParser(argc, argv));
CHECK(args->isListingTestGroupNames());
}
TEST(CommandLineArguments, setPrintGroupsAndNames)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-ln" };
CHECK(newArgumentParser(argc, argv));
CHECK(args->isListingTestGroupAndCaseNames());
}
TEST(CommandLineArguments, weirdParamatersReturnsFalse)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-SomethingWeird" };
CHECK(!newArgumentParser(argc, argv));
}
TEST(CommandLineArguments, printUsage)
{
STRCMP_EQUAL(
"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",
args->usage());
}
TEST(CommandLineArguments, helpPrintsTheHelp)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-h" };
CHECK(!newArgumentParser(argc, argv));
CHECK(args->needHelp());
}
TEST(CommandLineArguments, pluginKnowsOption)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-pPluginOption" };
TestRegistry::getCurrentRegistry()->installPlugin(plugin);
CHECK(newArgumentParser(argc, argv));
TestRegistry::getCurrentRegistry()->removePluginByName("options");
}
TEST(CommandLineArguments, checkDefaultArguments)
{
int argc = 1;
const char* argv[] = { "tests.exe" };
CHECK(newArgumentParser(argc, argv));
CHECK(!args->isVerbose());
LONGS_EQUAL(1, args->getRepeatCount());
CHECK(NULLPTR == args->getGroupFilters());
CHECK(NULLPTR == args->getNameFilters());
CHECK(args->isEclipseOutput());
CHECK(SimpleString("") == args->getPackageName());
CHECK(!args->isCrashingOnFail());
}
TEST(CommandLineArguments, setPackageName)
{
int argc = 3;
const char* argv[] = { "tests.exe", "-k", "package" };
CHECK(newArgumentParser(argc, argv));
CHECK_EQUAL(SimpleString("package"), args->getPackageName());
}
TEST(CommandLineArguments, lotsOfGroupsAndTests)
{
int argc = 10;
const char* argv[] = { "tests.exe", "-sggroup1", "-xntest1", "-sggroup2", "-sntest2", "-sntest3", "-sggroup3", "-sntest4", "-sggroup4", "-sntest5" };
CHECK(newArgumentParser(argc, argv));
TestFilter nameFilter("test1");
nameFilter.invertMatching();
TestFilter groupFilter("group1");
groupFilter.strictMatching();
CHECK_EQUAL(nameFilter, *args->getNameFilters()->getNext()->getNext()->getNext()->getNext());
CHECK_EQUAL(groupFilter, *args->getGroupFilters()->getNext()->getNext()->getNext());
}
TEST(CommandLineArguments, lastParameterFieldMissing)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-k"};
CHECK(newArgumentParser(argc, argv));
CHECK_EQUAL(SimpleString(""), args->getPackageName());
}
TEST(CommandLineArguments, setOptRun)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-ri"};
CHECK(newArgumentParser(argc, argv));
CHECK(args->isRunIgnored());
}
TEST(CommandLineArguments, setOptCrashOnFail)
{
int argc = 2;
const char* argv[] = { "tests.exe", "-f"};
CHECK(newArgumentParser(argc, argv));
CHECK(args->isCrashingOnFail());
}

View file

@ -0,0 +1,455 @@
/*
* 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/TestRegistry.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/TestPlugin.h"
#include "CppUTest/JUnitTestOutput.h"
#include "CppUTest/PlatformSpecificFunctions.h"
#include "CppUTestExt/MockSupport.h"
class DummyPluginWhichCountsThePlugins : public TestPlugin
{
public:
bool returnValue;
int amountOfPlugins;
DummyPluginWhichCountsThePlugins(const SimpleString& name, TestRegistry* registry) :
TestPlugin(name), returnValue(true), amountOfPlugins(0), registry_(registry)
{
}
virtual bool parseArguments(int, const char *const *, int) _override
{
/* Remove ourselves from the count */
amountOfPlugins = registry_->countPlugins() - 1;
return returnValue;
}
private:
TestRegistry* registry_;
};
class CommandLineTestRunnerWithStringBufferOutput : public CommandLineTestRunner
{
public:
StringBufferTestOutput* fakeJUnitOutputWhichIsReallyABuffer_;
StringBufferTestOutput* fakeConsoleOutputWhichIsReallyABuffer;
StringBufferTestOutput* fakeTCOutputWhichIsReallyABuffer;
CommandLineTestRunnerWithStringBufferOutput(int argc, const char *const *argv, TestRegistry* registry)
: CommandLineTestRunner(argc, argv, registry), fakeJUnitOutputWhichIsReallyABuffer_(NULLPTR),
fakeConsoleOutputWhichIsReallyABuffer(NULLPTR), fakeTCOutputWhichIsReallyABuffer(NULLPTR)
{}
TestOutput* createConsoleOutput() _override
{
fakeConsoleOutputWhichIsReallyABuffer = new StringBufferTestOutput;
return fakeConsoleOutputWhichIsReallyABuffer;
}
TestOutput* createJUnitOutput(const SimpleString&) _override
{
fakeJUnitOutputWhichIsReallyABuffer_ = new StringBufferTestOutput;
return fakeJUnitOutputWhichIsReallyABuffer_;
}
TestOutput* createTeamCityOutput() _override
{
fakeTCOutputWhichIsReallyABuffer = new StringBufferTestOutput;
return fakeTCOutputWhichIsReallyABuffer;
}
};
TEST_GROUP(CommandLineTestRunner)
{
TestRegistry registry;
UtestShell *test1;
UtestShell *test2;
DummyPluginWhichCountsThePlugins* pluginCountingPlugin;
void setup() _override
{
test1 = new UtestShell("group1", "test1", "file1", 1);
test2 = new UtestShell("group2", "test2", "file2", 2);
registry.addTest(test1);
pluginCountingPlugin = new DummyPluginWhichCountsThePlugins("PluginCountingPlugin", &registry);
}
void teardown() _override
{
delete pluginCountingPlugin;
delete test2;
delete test1;
}
SimpleString runAndGetOutput(const int argc, const char* argv[])
{
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(argc, argv, &registry);
commandLineTestRunner.runAllTestsMain();
return commandLineTestRunner.fakeConsoleOutputWhichIsReallyABuffer->getOutput();
}
};
TEST(CommandLineTestRunner, OnePluginGetsInstalledDuringTheRunningTheTests)
{
const char* argv[] = { "tests.exe", "-psomething"};
registry.installPlugin(pluginCountingPlugin);
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
commandLineTestRunner.runAllTestsMain();
registry.removePluginByName("PluginCountingPlugin");
LONGS_EQUAL(0, registry.countPlugins());
LONGS_EQUAL(1, pluginCountingPlugin->amountOfPlugins);
}
TEST(CommandLineTestRunner, NoPluginsAreInstalledAtTheEndOfARunWhenTheArgumentsAreInvalid)
{
const char* argv[] = { "tests.exe", "-fdskjnfkds"};
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
commandLineTestRunner.runAllTestsMain();
LONGS_EQUAL(0, registry.countPlugins());
}
TEST(CommandLineTestRunner, ReturnsOneWhenTheArgumentsAreInvalid)
{
const char* argv[] = { "tests.exe", "-some-invalid=parameter" };
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
int returned = commandLineTestRunner.runAllTestsMain();
LONGS_EQUAL(1, returned);
}
TEST(CommandLineTestRunner, ReturnsOnePrintsHelpOnHelp)
{
const char* argv[] = { "tests.exe", "-h" };
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
int returned = commandLineTestRunner.runAllTestsMain();
LONGS_EQUAL(1, returned);
STRCMP_CONTAINS("Thanks for using CppUTest.", commandLineTestRunner.fakeConsoleOutputWhichIsReallyABuffer->getOutput().asCharString());
}
TEST(CommandLineTestRunner, ReturnsZeroWhenNoErrors)
{
const char* argv[] = { "tests.exe" };
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(1, argv, &registry);
int returned = commandLineTestRunner.runAllTestsMain();
LONGS_EQUAL(0, returned);
}
TEST(CommandLineTestRunner, ReturnsOneWhenNoTestsMatchProvidedFilter)
{
const char* argv[] = { "tests.exe", "-g", "NoSuchGroup"};
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(3, argv, &registry);
int returned = commandLineTestRunner.runAllTestsMain();
LONGS_EQUAL(1, returned);
}
TEST(CommandLineTestRunner, TeamcityOutputEnabled)
{
const char* argv[] = {"tests.exe", "-oteamcity"};
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
commandLineTestRunner.runAllTestsMain();
CHECK(commandLineTestRunner.fakeTCOutputWhichIsReallyABuffer != NULLPTR);
}
TEST(CommandLineTestRunner, JunitOutputEnabled)
{
const char* argv[] = { "tests.exe", "-ojunit"};
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
commandLineTestRunner.runAllTestsMain();
CHECK(commandLineTestRunner.fakeJUnitOutputWhichIsReallyABuffer_ != NULLPTR);
}
TEST(CommandLineTestRunner, JunitOutputAndVerboseEnabled)
{
const char* argv[] = { "tests.exe", "-ojunit", "-v"};
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(3, argv, &registry);
commandLineTestRunner.runAllTestsMain();
STRCMP_CONTAINS("TEST(group1, test1)", commandLineTestRunner.fakeJUnitOutputWhichIsReallyABuffer_->getOutput().asCharString());
STRCMP_CONTAINS("TEST(group1, test1)", commandLineTestRunner.fakeConsoleOutputWhichIsReallyABuffer->getOutput().asCharString());
}
TEST(CommandLineTestRunner, veryVerboseSetOnOutput)
{
const char* argv[] = { "tests.exe", "-vv"};
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
commandLineTestRunner.runAllTestsMain();
STRCMP_CONTAINS("TEST(group1, test1)", commandLineTestRunner.fakeConsoleOutputWhichIsReallyABuffer->getOutput().asCharString());
STRCMP_CONTAINS("destroyTest", commandLineTestRunner.fakeConsoleOutputWhichIsReallyABuffer->getOutput().asCharString());
}
TEST(CommandLineTestRunner, defaultTestsAreRunInOrderTheyAreInRepository)
{
const char* argv[] = { "tests.exe", "-v"};
registry.addTest(test2);
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
commandLineTestRunner.runAllTestsMain();
SimpleStringCollection stringCollection;
commandLineTestRunner.fakeConsoleOutputWhichIsReallyABuffer->getOutput().split("\n", stringCollection);
STRCMP_CONTAINS("test2", stringCollection[0].asCharString());
STRCMP_CONTAINS("test1", stringCollection[1].asCharString());
}
TEST(CommandLineTestRunner, testsCanBeRunInReverseOrder)
{
const char* argv[] = { "tests.exe", "-v", "-b"};
registry.addTest(test2);
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(3, argv, &registry);
commandLineTestRunner.runAllTestsMain();
SimpleStringCollection stringCollection;
commandLineTestRunner.fakeConsoleOutputWhichIsReallyABuffer->getOutput().split("\n", stringCollection);
STRCMP_CONTAINS("test1", stringCollection[0].asCharString());
STRCMP_CONTAINS("test2", stringCollection[1].asCharString());
}
TEST(CommandLineTestRunner, listTestGroupNamesShouldWorkProperly)
{
const char* argv[] = { "tests.exe", "-lg" };
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
commandLineTestRunner.runAllTestsMain();
STRCMP_CONTAINS("group", commandLineTestRunner.fakeConsoleOutputWhichIsReallyABuffer->getOutput().asCharString());
}
TEST(CommandLineTestRunner, listTestGroupAndCaseNamesShouldWorkProperly)
{
const char* argv[] = { "tests.exe", "-ln" };
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
commandLineTestRunner.runAllTestsMain();
STRCMP_CONTAINS("group1.test1", commandLineTestRunner.fakeConsoleOutputWhichIsReallyABuffer->getOutput().asCharString());
}
TEST(CommandLineTestRunner, randomShuffleSeedIsPrintedAndRandFuncIsExercised)
{
// more than 1 item in test list ensures that shuffle algorithm calls rand_()
UtestShell *anotherTest = new UtestShell("group", "test2", "file", 1);
registry.addTest(anotherTest);
const char* argv[] = { "tests.exe", "-s"};
SimpleString text = runAndGetOutput(2, argv);
STRCMP_CONTAINS("shuffling enabled with seed:", text.asCharString());
delete anotherTest;
}
TEST(CommandLineTestRunner, specificShuffleSeedIsPrintedVerbose)
{
const char* argv[] = { "tests.exe", "-s2", "-v"};
SimpleString text = runAndGetOutput(3, argv);
STRCMP_CONTAINS("shuffling enabled with seed: 2", text.asCharString());
}
extern "C" {
typedef PlatformSpecificFile (*FOpenFunc)(const char*, const char*);
typedef void (*FPutsFunc)(const char*, PlatformSpecificFile);
typedef void (*FCloseFunc)(PlatformSpecificFile);
typedef int (*PutcharFunc)(int);
}
struct FakeOutput
{
FakeOutput() : SaveFOpen(PlatformSpecificFOpen), SaveFPuts(PlatformSpecificFPuts),
SaveFClose(PlatformSpecificFClose), SavePutchar(PlatformSpecificPutchar)
{
installFakes();
currentFake = this;
}
~FakeOutput()
{
currentFake = NULLPTR;
restoreOriginals();
}
void installFakes()
{
PlatformSpecificFOpen = (FOpenFunc)fopen_fake;
PlatformSpecificFPuts = (FPutsFunc)fputs_fake;
PlatformSpecificFClose = (FCloseFunc)fclose_fake;
PlatformSpecificPutchar = (PutcharFunc)putchar_fake;
}
void restoreOriginals()
{
PlatformSpecificPutchar = SavePutchar;
PlatformSpecificFOpen = SaveFOpen;
PlatformSpecificFPuts = SaveFPuts;
PlatformSpecificFClose = SaveFClose;
}
static PlatformSpecificFile fopen_fake(const char*, const char*)
{
return (PlatformSpecificFile) NULLPTR;
}
static void fputs_fake(const char* str, PlatformSpecificFile)
{
currentFake->file += str;
}
static void fclose_fake(PlatformSpecificFile)
{
}
static int putchar_fake(int c)
{
currentFake->console += StringFrom((char)c);
return c;
}
SimpleString file;
SimpleString console;
static FakeOutput* currentFake;
private:
FOpenFunc SaveFOpen;
FPutsFunc SaveFPuts;
FCloseFunc SaveFClose;
PutcharFunc SavePutchar;
};
FakeOutput* FakeOutput::currentFake = NULLPTR;
TEST(CommandLineTestRunner, realJunitOutputShouldBeCreatedAndWorkProperly)
{
const char* argv[] = { "tests.exe", "-ojunit", "-v", "-kpackage", };
FakeOutput fakeOutput; /* UT_PTR_SET() is not reentrant */
CommandLineTestRunner commandLineTestRunner(4, argv, &registry);
commandLineTestRunner.runAllTestsMain();
fakeOutput.restoreOriginals();
STRCMP_CONTAINS("<testcase classname=\"package.group1\" name=\"test1\"", fakeOutput.file.asCharString());
STRCMP_CONTAINS("TEST(group1, test1)", fakeOutput.console.asCharString());
}
TEST(CommandLineTestRunner, realTeamCityOutputShouldBeCreatedAndWorkProperly)
{
const char* argv[] = { "tests.exe", "-oteamcity", "-v", "-kpackage", };
FakeOutput fakeOutput; /* UT_PTR_SET() is not reentrant */
CommandLineTestRunner commandLineTestRunner(4, argv, &registry);
commandLineTestRunner.runAllTestsMain();
fakeOutput.restoreOriginals();
STRCMP_CONTAINS("##teamcity[testSuiteStarted name='group1'", fakeOutput.console.asCharString());
STRCMP_CONTAINS("##teamcity[testStarted name='test1'", fakeOutput.console.asCharString());
STRCMP_CONTAINS("##teamcity[testFinished name='test1'", fakeOutput.console.asCharString());
STRCMP_CONTAINS("##teamcity[testSuiteFinished name='group1'", fakeOutput.console.asCharString());
}
class RunIgnoredUtest : public Utest
{
public:
static bool Checker;
void testBody() _override
{
Checker = true;
}
};
bool RunIgnoredUtest::Checker = false;
class RunIgnoredUtestShell : public IgnoredUtestShell
{
public:
RunIgnoredUtestShell(const char* groupName, const char* testName, const char* fileName, size_t lineNumber)
: IgnoredUtestShell(groupName, testName, fileName, lineNumber) {}
virtual Utest* createTest() _override { return new RunIgnoredUtest; }
};
TEST_GROUP(RunIgnoredTest)
{
TestRegistry registry;
RunIgnoredUtestShell *runIgnoredTest;
DummyPluginWhichCountsThePlugins* pluginCountingPlugin;
void setup() _override
{
runIgnoredTest = new RunIgnoredUtestShell("group", "test", "file", 1);
registry.addTest(runIgnoredTest);
pluginCountingPlugin = new DummyPluginWhichCountsThePlugins("PluginCountingPlugin", &registry);
}
void teardown() _override
{
delete pluginCountingPlugin;
delete runIgnoredTest;
RunIgnoredUtest::Checker = false;
}
};
TEST(RunIgnoredTest, IgnoreTestWillBeIgnoredIfNoOptionSpecified)
{
const char* argv[] = { "tests.exe" };
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(1, argv, &registry);
commandLineTestRunner.runAllTestsMain();
CHECK_FALSE( RunIgnoredUtest::Checker );
}
TEST(RunIgnoredTest, IgnoreTestWillGetRunIfOptionSpecified)
{
const char* argv[] = { "tests.exe", "-ri" };
CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
commandLineTestRunner.runAllTestsMain();
CHECK_TRUE( RunIgnoredUtest::Checker );
}

View file

@ -0,0 +1,26 @@
#include "CppUTest/TestHarness.h"
#if CPPUTEST_USE_STD_CPP_LIB
#include <memory>
TEST_GROUP(StandardCppLibrary)
{
};
#if defined(__cplusplus) && __cplusplus >= 201402L
TEST(StandardCppLibrary, UniquePtrConversationToBool)
{
auto const aNull = std::unique_ptr<int>(nullptr);
CHECK_FALSE(aNull);
auto const notNull = std::make_unique<int>(1);
CHECK_TRUE(notNull);
}
#endif
#endif

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 "CppUTest/MemoryLeakDetector.h"
#include "DummyMemoryLeakDetector.h"
DummyMemoryLeakDetector::DummyMemoryLeakDetector(MemoryLeakFailure* reporter) : MemoryLeakDetector(reporter)
{
memoryLeakDetectorWasDeleted = false;
}
DummyMemoryLeakDetector::~DummyMemoryLeakDetector()
{
memoryLeakDetectorWasDeleted = true;
}
bool DummyMemoryLeakDetector::wasDeleted()
{
return memoryLeakDetectorWasDeleted;
}
bool DummyMemoryLeakDetector::memoryLeakDetectorWasDeleted = false;
DummyMemoryLeakFailure::DummyMemoryLeakFailure()
: MemoryLeakFailure()
{
memoryLeakFailureWasDelete = false;
}
DummyMemoryLeakFailure::~DummyMemoryLeakFailure()
{
memoryLeakFailureWasDelete = true;
}
bool DummyMemoryLeakFailure::wasDeleted()
{
return memoryLeakFailureWasDelete;
}
void DummyMemoryLeakFailure::fail(char*)
{
}
bool DummyMemoryLeakFailure::memoryLeakFailureWasDelete = false;

View file

@ -0,0 +1,51 @@
/*
* 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.
*/
class DummyMemoryLeakDetector : public MemoryLeakDetector
{
public:
DummyMemoryLeakDetector(MemoryLeakFailure* reporter);
virtual ~DummyMemoryLeakDetector() _destructor_override;
static bool wasDeleted();
private:
static bool memoryLeakDetectorWasDeleted;
};
class DummyMemoryLeakFailure : public MemoryLeakFailure
{
public:
DummyMemoryLeakFailure();
virtual ~DummyMemoryLeakFailure() _destructor_override;
static bool wasDeleted();
virtual void fail(char*) _override;
private:
static bool memoryLeakFailureWasDelete;
};

View file

@ -0,0 +1,759 @@
/*
* 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/PlatformSpecificFunctions.h"
#include "CppUTest/SimpleString.h"
class FileForJUnitOutputTests
{
SimpleString name_;
bool isOpen_;
SimpleString buffer_;
FileForJUnitOutputTests* next_;
SimpleStringCollection linesOfFile_;
public:
FileForJUnitOutputTests(const SimpleString& filename, FileForJUnitOutputTests* next) :
name_(filename), isOpen_(true), next_(next) {}
FileForJUnitOutputTests* nextFile()
{
return next_;
}
SimpleString name()
{
return name_;
}
void write(const SimpleString& buffer)
{
buffer_ += buffer;
}
void close()
{
isOpen_ = false;
}
const char* line(size_t lineNumber)
{
buffer_.split("\n", linesOfFile_);
return linesOfFile_[lineNumber-1].asCharString();
}
const char* lineFromTheBack(size_t lineNumberFromTheBack)
{
return line(amountOfLines() - (lineNumberFromTheBack - 1));
}
size_t amountOfLines()
{
buffer_.split("\n", linesOfFile_);
return linesOfFile_.size();
}
SimpleString content()
{
return buffer_;
}
};
class FileSystemForJUnitTestOutputTests
{
FileForJUnitOutputTests* firstFile_;
public:
FileSystemForJUnitTestOutputTests() : firstFile_(NULLPTR) {}
~FileSystemForJUnitTestOutputTests() { clear(); }
void clear(void)
{
while (firstFile_) {
FileForJUnitOutputTests* fileToBeDeleted = firstFile_;
firstFile_ = firstFile_->nextFile();
delete fileToBeDeleted;
}
}
FileForJUnitOutputTests* openFile(const SimpleString& filename)
{
firstFile_ = new FileForJUnitOutputTests(filename, firstFile_);
return firstFile_;
}
int amountOfFiles() {
int totalAmountOfFiles = 0;
for (FileForJUnitOutputTests* current = firstFile_; current != NULLPTR; current = current->nextFile())
totalAmountOfFiles++;
return totalAmountOfFiles;
}
bool fileExists(const char* filename)
{
FileForJUnitOutputTests *searchedFile = file(filename);
return (searchedFile != NULLPTR);
}
FileForJUnitOutputTests* file(const char* filename)
{
for (FileForJUnitOutputTests* current = firstFile_; current != NULLPTR; current = current->nextFile())
if (current->name() == filename)
return current;
return NULLPTR;
}
};
extern "C" {
static long millisTime = 0;
static const char* theTime = "";
static long MockGetPlatformSpecificTimeInMillis()
{
return millisTime;
}
static const char* MockGetPlatformSpecificTimeString()
{
return theTime;
}
}
class JUnitTestOutputTestRunner
{
TestResult result_;
const char* currentGroupName_;
UtestShell* currentTest_;
bool firstTestInGroup_;
int timeTheTestTakes_;
unsigned int numberOfChecksInTest_;
TestFailure* testFailure_;
public:
explicit JUnitTestOutputTestRunner(const TestResult& result) :
result_(result), currentGroupName_(NULLPTR), currentTest_(NULLPTR), firstTestInGroup_(true), timeTheTestTakes_(0), numberOfChecksInTest_(0), testFailure_(NULLPTR)
{
millisTime = 0;
theTime = "1978-10-03T00:00:00";
UT_PTR_SET(GetPlatformSpecificTimeInMillis, MockGetPlatformSpecificTimeInMillis);
UT_PTR_SET(GetPlatformSpecificTimeString, MockGetPlatformSpecificTimeString);
}
JUnitTestOutputTestRunner& start()
{
result_.testsStarted();
return *this;
}
JUnitTestOutputTestRunner& end()
{
endOfPreviousTestGroup();
delete currentTest_;
result_.testsEnded();
return *this;
}
JUnitTestOutputTestRunner& endGroupAndClearTest()
{
endOfPreviousTestGroup();
delete currentTest_;
currentTest_ = NULLPTR;
return *this;
}
void endOfPreviousTestGroup()
{
runPreviousTest();
if (currentTest_) {
result_.currentGroupEnded(currentTest_);
firstTestInGroup_ = true;
}
currentGroupName_ = NULLPTR;
}
JUnitTestOutputTestRunner& withGroup(const char* groupName)
{
runPreviousTest();
endOfPreviousTestGroup();
currentGroupName_ = groupName;
return *this;
}
JUnitTestOutputTestRunner& withTest(const char* testName)
{
runPreviousTest();
delete currentTest_;
currentTest_ = new UtestShell(currentGroupName_, testName, "file", 1);
return *this;
}
JUnitTestOutputTestRunner& withIgnoredTest(const char* testName)
{
runPreviousTest();
delete currentTest_;
currentTest_ = new IgnoredUtestShell(currentGroupName_, testName, "file", 1);
return *this;
}
JUnitTestOutputTestRunner& inFile(const char* fileName)
{
if(currentTest_) {
currentTest_->setFileName(fileName);
}
return *this;
}
JUnitTestOutputTestRunner& onLine(size_t lineNumber)
{
if(currentTest_) {
currentTest_->setLineNumber(lineNumber);
}
return *this;
}
void runPreviousTest()
{
if (currentTest_ == NULLPTR) return;
if (firstTestInGroup_) {
result_.currentGroupStarted(currentTest_);
firstTestInGroup_ = false;
}
result_.currentTestStarted(currentTest_);
millisTime += timeTheTestTakes_;
for(unsigned int i = 0; i < numberOfChecksInTest_; i++) {
result_.countCheck();
}
numberOfChecksInTest_ = 0;
if (testFailure_) {
result_.addFailure(*testFailure_);
delete testFailure_;
testFailure_ = NULLPTR;
}
result_.currentTestEnded(currentTest_);
}
JUnitTestOutputTestRunner& thatHasChecks(unsigned int numOfChecks)
{
numberOfChecksInTest_ = numOfChecks;
return *this;
}
JUnitTestOutputTestRunner& thatTakes(int timeElapsed)
{
timeTheTestTakes_ = timeElapsed;
return *this;
}
JUnitTestOutputTestRunner& seconds()
{
return *this;
}
JUnitTestOutputTestRunner& thatFails(const char* message, const char* file, size_t line)
{
testFailure_ = new TestFailure( currentTest_, file, line, message);
return *this;
}
JUnitTestOutputTestRunner& atTime(const char* newTime)
{
theTime = newTime;
return *this;
}
JUnitTestOutputTestRunner& thatPrints(const char* output)
{
runPreviousTest();
result_.print(output);
return *this;
}
};
extern "C" {
static FileSystemForJUnitTestOutputTests fileSystem;
static PlatformSpecificFile mockFOpen(const char* filename, const char*)
{
return fileSystem.openFile(filename);
}
static void mockFPuts(const char* str, PlatformSpecificFile file)
{
((FileForJUnitOutputTests*)file)->write(str);
}
static void mockFClose(PlatformSpecificFile file)
{
((FileForJUnitOutputTests*)file)->close();
}
}
TEST_GROUP(JUnitOutputTest)
{
JUnitTestOutput *junitOutput;
TestResult *result;
JUnitTestOutputTestRunner *testCaseRunner;
FileForJUnitOutputTests* outputFile;
void setup() _override
{
UT_PTR_SET(PlatformSpecificFOpen, mockFOpen);
UT_PTR_SET(PlatformSpecificFPuts, mockFPuts);
UT_PTR_SET(PlatformSpecificFClose, mockFClose);
junitOutput = new JUnitTestOutput();
result = new TestResult(*junitOutput);
testCaseRunner = new JUnitTestOutputTestRunner(*result);
}
void teardown() _override
{
delete testCaseRunner;
delete result;
delete junitOutput;
fileSystem.clear();
}
};
TEST(JUnitOutputTest, withOneTestGroupAndOneTestOnlyWriteToOneFile)
{
testCaseRunner->start()
.withGroup("groupname").withTest("testname")
.end();
LONGS_EQUAL(1, fileSystem.amountOfFiles());
CHECK(fileSystem.fileExists("cpputest_groupname.xml"));
}
TEST(JUnitOutputTest, withReservedCharactersInPackageOrTestGroupUsesUnderscoresForFileName)
{
junitOutput->setPackageName("p/a\\c?k%a*g:e|n\"a<m>e.");
testCaseRunner->start()
.withGroup("g/r\\o?u%p*n:a|m\"e<h>ere").withTest("testname")
.end();
CHECK(fileSystem.fileExists("cpputest_p_a_c_k_a_g_e_n_a_m_e._g_r_o_u_p_n_a_m_e_h_ere.xml"));
}
TEST(JUnitOutputTest, withOneTestGroupAndOneTestOutputsValidXMLFiles)
{
testCaseRunner->start()
.withGroup("groupname").withTest("testname")
.end();
outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n", outputFile->line(1));
}
TEST(JUnitOutputTest, withOneTestGroupAndOneTestOutputsTestSuiteStartAndEndBlocks)
{
testCaseRunner->start()
.withGroup("groupname").withTest("testname")
.end();
outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<testsuite errors=\"0\" failures=\"0\" hostname=\"localhost\" name=\"groupname\" tests=\"1\" time=\"0.000\" timestamp=\"1978-10-03T00:00:00\">\n", outputFile->line(2));
STRCMP_EQUAL("</testsuite>\n", outputFile->lineFromTheBack(1));
}
TEST(JUnitOutputTest, withOneTestGroupAndOneTestFileShouldContainAnEmptyPropertiesBlock)
{
testCaseRunner->start()
.withGroup("groupname").withTest("testname")
.end();
outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<properties>\n", outputFile->line(3));
STRCMP_EQUAL("</properties>\n", outputFile->line(4));
}
TEST(JUnitOutputTest, withOneTestGroupAndOneTestFileShouldContainAnEmptyStdoutBlock)
{
testCaseRunner->start()
.withGroup("groupname").withTest("testname")
.end();
outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<system-out></system-out>\n", outputFile->lineFromTheBack(3));
}
TEST(JUnitOutputTest, withOneTestGroupAndOneTestFileShouldContainAnEmptyStderrBlock)
{
testCaseRunner->start()
.withGroup("groupname").withTest("testname")
.end();
outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<system-err></system-err>\n", outputFile->lineFromTheBack(2));
}
TEST(JUnitOutputTest, withOneTestGroupAndOneTestFileShouldContainsATestCaseBlock)
{
testCaseRunner->start()
.withGroup("groupname").withTest("testname")
.end();
outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<testcase classname=\"groupname\" name=\"testname\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
STRCMP_EQUAL("</testcase>\n", outputFile->line(6));
}
TEST(JUnitOutputTest, withOneTestGroupAndTwoTestCasesCreateCorrectTestgroupBlockAndCorrectTestCaseBlock)
{
testCaseRunner->start()
.withGroup("twoTestsGroup").withTest("firstTestName").withTest("secondTestName")
.end();
outputFile = fileSystem.file("cpputest_twoTestsGroup.xml");
STRCMP_EQUAL("<testsuite errors=\"0\" failures=\"0\" hostname=\"localhost\" name=\"twoTestsGroup\" tests=\"2\" time=\"0.000\" timestamp=\"1978-10-03T00:00:00\">\n", outputFile->line(2));
STRCMP_EQUAL("<testcase classname=\"twoTestsGroup\" name=\"firstTestName\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
STRCMP_EQUAL("</testcase>\n", outputFile->line(6));
STRCMP_EQUAL("<testcase classname=\"twoTestsGroup\" name=\"secondTestName\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(7));
STRCMP_EQUAL("</testcase>\n", outputFile->line(8));
}
TEST(JUnitOutputTest, withOneTestGroupAndTimeHasElapsedAndTimestampChanged)
{
testCaseRunner->start().atTime("2013-07-04T22:28:00")
.withGroup("timeGroup").withTest("Dummy").thatTakes(10).seconds()
.end();
outputFile = fileSystem.file("cpputest_timeGroup.xml");
STRCMP_EQUAL("<testsuite errors=\"0\" failures=\"0\" hostname=\"localhost\" name=\"timeGroup\" tests=\"1\" time=\"0.010\" timestamp=\"2013-07-04T22:28:00\">\n", outputFile->line(2));
}
TEST(JUnitOutputTest, withOneTestGroupAndMultipleTestCasesWithElapsedTime)
{
testCaseRunner->start()
.withGroup("twoTestsGroup")
.withTest("firstTestName").thatTakes(10).seconds()
.withTest("secondTestName").thatTakes(50).seconds()
.end();
outputFile = fileSystem.file("cpputest_twoTestsGroup.xml");
STRCMP_EQUAL("<testsuite errors=\"0\" failures=\"0\" hostname=\"localhost\" name=\"twoTestsGroup\" tests=\"2\" time=\"0.060\" timestamp=\"1978-10-03T00:00:00\">\n", outputFile->line(2));
STRCMP_EQUAL("<testcase classname=\"twoTestsGroup\" name=\"firstTestName\" assertions=\"0\" time=\"0.010\" file=\"file\" line=\"1\">\n", outputFile->line(5));
STRCMP_EQUAL("</testcase>\n", outputFile->line(6));
STRCMP_EQUAL("<testcase classname=\"twoTestsGroup\" name=\"secondTestName\" assertions=\"0\" time=\"0.050\" file=\"file\" line=\"1\">\n", outputFile->line(7));
STRCMP_EQUAL("</testcase>\n", outputFile->line(8));
}
TEST(JUnitOutputTest, withOneTestGroupAndOneFailingTest)
{
testCaseRunner->start()
.withGroup("testGroupWithFailingTest")
.withTest("FailingTestName").thatFails("Test failed", "thisfile", 10)
.end();
outputFile = fileSystem.file("cpputest_testGroupWithFailingTest.xml");
STRCMP_EQUAL("<testsuite errors=\"0\" failures=\"1\" hostname=\"localhost\" name=\"testGroupWithFailingTest\" tests=\"1\" time=\"0.000\" timestamp=\"1978-10-03T00:00:00\">\n", outputFile->line(2));
STRCMP_EQUAL("<testcase classname=\"testGroupWithFailingTest\" name=\"FailingTestName\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
STRCMP_EQUAL("<failure message=\"thisfile:10: Test failed\" type=\"AssertionFailedError\">\n", outputFile->line(6));
STRCMP_EQUAL("</failure>\n", outputFile->line(7));
STRCMP_EQUAL("</testcase>\n", outputFile->line(8));
}
TEST(JUnitOutputTest, withTwoTestGroupAndOneFailingTest)
{
testCaseRunner->start()
.withGroup("testGroupWithFailingTest")
.withTest("FirstTest")
.withTest("FailingTestName").thatFails("Test failed", "thisfile", 10)
.end();
outputFile = fileSystem.file("cpputest_testGroupWithFailingTest.xml");
STRCMP_EQUAL("<testsuite errors=\"0\" failures=\"1\" hostname=\"localhost\" name=\"testGroupWithFailingTest\" tests=\"2\" time=\"0.000\" timestamp=\"1978-10-03T00:00:00\">\n", outputFile->line(2));
STRCMP_EQUAL("<testcase classname=\"testGroupWithFailingTest\" name=\"FailingTestName\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(7));
STRCMP_EQUAL("<failure message=\"thisfile:10: Test failed\" type=\"AssertionFailedError\">\n", outputFile->line(8));
}
TEST(JUnitOutputTest, testFailureWithLessThanAndGreaterThanInsideIt)
{
testCaseRunner->start()
.withGroup("testGroupWithFailingTest")
.withTest("FailingTestName").thatFails("Test <failed>", "thisfile", 10)
.end();
outputFile = fileSystem.file("cpputest_testGroupWithFailingTest.xml");
STRCMP_EQUAL("<failure message=\"thisfile:10: Test &lt;failed&gt;\" type=\"AssertionFailedError\">\n", outputFile->line(6));
}
TEST(JUnitOutputTest, testFailureWithQuotesInIt)
{
testCaseRunner->start()
.withGroup("testGroupWithFailingTest")
.withTest("FailingTestName").thatFails("Test \"failed\"", "thisfile", 10)
.end();
outputFile = fileSystem.file("cpputest_testGroupWithFailingTest.xml");
STRCMP_EQUAL("<failure message=\"thisfile:10: Test &quot;failed&quot;\" type=\"AssertionFailedError\">\n", outputFile->line(6));
}
TEST(JUnitOutputTest, testFailureWithNewlineInIt)
{
testCaseRunner->start()
.withGroup("testGroupWithFailingTest")
.withTest("FailingTestName").thatFails("Test \nfailed", "thisfile", 10)
.end();
outputFile = fileSystem.file("cpputest_testGroupWithFailingTest.xml");
STRCMP_EQUAL("<failure message=\"thisfile:10: Test {newline}failed\" type=\"AssertionFailedError\">\n", outputFile->line(6));
}
TEST(JUnitOutputTest, testFailureWithDifferentFileAndLine)
{
testCaseRunner->start()
.withGroup("testGroupWithFailingTest")
.withTest("FailingTestName").thatFails("Test failed", "importantFile", 999)
.end();
outputFile = fileSystem.file("cpputest_testGroupWithFailingTest.xml");
STRCMP_EQUAL("<failure message=\"importantFile:999: Test failed\" type=\"AssertionFailedError\">\n", outputFile->line(6));
}
TEST(JUnitOutputTest, testFailureWithAmpersandsAndLessThan)
{
testCaseRunner->start()
.withGroup("testGroupWithFailingTest")
.withTest("FailingTestName").thatFails("&object1 < &object2", "importantFile", 999)
.end();
outputFile = fileSystem.file("cpputest_testGroupWithFailingTest.xml");
STRCMP_EQUAL("<failure message=\"importantFile:999: &amp;object1 &lt; &amp;object2\" type=\"AssertionFailedError\">\n", outputFile->line(6));
}
TEST(JUnitOutputTest, testFailureWithAmpersands)
{
testCaseRunner->start()
.withGroup("testGroupWithFailingTest")
.withTest("FailingTestName").thatFails("&object1 != &object2", "importantFile", 999)
.end();
outputFile = fileSystem.file("cpputest_testGroupWithFailingTest.xml");
STRCMP_EQUAL("<failure message=\"importantFile:999: &amp;object1 != &amp;object2\" type=\"AssertionFailedError\">\n", outputFile->line(6));
}
TEST(JUnitOutputTest, aCoupleOfTestFailures)
{
testCaseRunner->start()
.withGroup("testGroup")
.withTest("passingOne")
.withTest("FailingTest").thatFails("Failure", "file", 99)
.withTest("passingTwo")
.withTest("passingThree")
.withTest("AnotherFailingTest").thatFails("otherFailure", "anotherFile", 10)
.end();
outputFile = fileSystem.file("cpputest_testGroup.xml");
STRCMP_EQUAL("<failure message=\"file:99: Failure\" type=\"AssertionFailedError\">\n", outputFile->line(8));
STRCMP_EQUAL("<failure message=\"anotherFile:10: otherFailure\" type=\"AssertionFailedError\">\n", outputFile->line(16));
}
TEST(JUnitOutputTest, testFailuresInSeparateGroups)
{
testCaseRunner->start()
.withGroup("testGroup")
.withTest("passingOne")
.withTest("FailingTest").thatFails("Failure", "file", 99)
.withGroup("AnotherGroup")
.withTest("AnotherFailingTest").thatFails("otherFailure", "anotherFile", 10)
.end();
outputFile = fileSystem.file("cpputest_testGroup.xml");
STRCMP_EQUAL("<failure message=\"file:99: Failure\" type=\"AssertionFailedError\">\n", outputFile->line(8));
outputFile = fileSystem.file("cpputest_AnotherGroup.xml");
STRCMP_EQUAL("<failure message=\"anotherFile:10: otherFailure\" type=\"AssertionFailedError\">\n", outputFile->line(8));
}
TEST(JUnitOutputTest, twoTestGroupsWriteToTwoDifferentFiles)
{
testCaseRunner->start()
.withGroup("firstTestGroup")
.withTest("testName")
.withGroup("secondTestGroup")
.withTest("testName")
.end();
CHECK(fileSystem.file("cpputest_firstTestGroup.xml") != NULLPTR);
CHECK(fileSystem.file("cpputest_secondTestGroup.xml") != NULLPTR);
}
TEST(JUnitOutputTest, testGroupWithWeirdName)
{
STRCMP_EQUAL("cpputest_group_weird_name.xml", junitOutput->createFileName("group/weird/name").asCharString());
}
TEST(JUnitOutputTest, TestCaseBlockWithAPackageName)
{
junitOutput->setPackageName("packagename");
testCaseRunner->start()
.withGroup("groupname").withTest("testname")
.end();
outputFile = fileSystem.file("cpputest_packagename_groupname.xml");
STRCMP_EQUAL("<testcase classname=\"packagename.groupname\" name=\"testname\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
STRCMP_EQUAL("</testcase>\n", outputFile->line(6));
}
TEST(JUnitOutputTest, TestCaseBlockForIgnoredTest)
{
junitOutput->setPackageName("packagename");
testCaseRunner->start()
.withGroup("groupname").withIgnoredTest("testname")
.end();
outputFile = fileSystem.file("cpputest_packagename_groupname.xml");
STRCMP_EQUAL("<testcase classname=\"packagename.groupname\" name=\"testname\" assertions=\"0\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
STRCMP_EQUAL("<skipped />\n", outputFile->line(6));
STRCMP_EQUAL("</testcase>\n", outputFile->line(7));
}
TEST(JUnitOutputTest, TestCaseWithTestLocation)
{
junitOutput->setPackageName("packagename");
testCaseRunner->start()
.withGroup("groupname")
.withTest("testname").inFile("MySource.c").onLine(159)
.end();
outputFile = fileSystem.file("cpputest_packagename_groupname.xml");
STRCMP_EQUAL("<testcase classname=\"packagename.groupname\" name=\"testname\" assertions=\"0\" time=\"0.000\" file=\"MySource.c\" line=\"159\">\n", outputFile->line(5));
}
TEST(JUnitOutputTest, MultipleTestCaseWithTestLocations)
{
testCaseRunner->start()
.withGroup("twoTestsGroup")
.withTest("firstTestName").inFile("MyFirstSource.c").onLine(846)
.withTest("secondTestName").inFile("MySecondSource.c").onLine(513)
.end();
outputFile = fileSystem.file("cpputest_twoTestsGroup.xml");
STRCMP_EQUAL("<testcase classname=\"twoTestsGroup\" name=\"firstTestName\" assertions=\"0\" time=\"0.000\" file=\"MyFirstSource.c\" line=\"846\">\n", outputFile->line(5));
STRCMP_EQUAL("<testcase classname=\"twoTestsGroup\" name=\"secondTestName\" assertions=\"0\" time=\"0.000\" file=\"MySecondSource.c\" line=\"513\">\n", outputFile->line(7));
}
TEST(JUnitOutputTest, TestCaseBlockWithAssertions)
{
junitOutput->setPackageName("packagename");
testCaseRunner->start()
.withGroup("groupname")
.withTest("testname")
.thatHasChecks(24)
.end();
outputFile = fileSystem.file("cpputest_packagename_groupname.xml");
STRCMP_EQUAL("<testcase classname=\"packagename.groupname\" name=\"testname\" assertions=\"24\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
}
TEST(JUnitOutputTest, MultipleTestCaseBlocksWithAssertions)
{
testCaseRunner->start()
.withGroup("twoTestsGroup")
.withTest("firstTestName").thatHasChecks(456)
.withTest("secondTestName").thatHasChecks(567)
.end();
outputFile = fileSystem.file("cpputest_twoTestsGroup.xml");
STRCMP_EQUAL("<testcase classname=\"twoTestsGroup\" name=\"firstTestName\" assertions=\"456\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
STRCMP_EQUAL("<testcase classname=\"twoTestsGroup\" name=\"secondTestName\" assertions=\"567\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(7));
}
TEST(JUnitOutputTest, MultipleTestCasesInDifferentGroupsWithAssertions)
{
testCaseRunner->start()
.withGroup("groupOne")
.withTest("testA").thatHasChecks(456)
.endGroupAndClearTest()
.withGroup("groupTwo")
.withTest("testB").thatHasChecks(678)
.end();
outputFile = fileSystem.file("cpputest_groupOne.xml");
STRCMP_EQUAL("<testcase classname=\"groupOne\" name=\"testA\" assertions=\"456\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
outputFile = fileSystem.file("cpputest_groupTwo.xml");
STRCMP_EQUAL("<testcase classname=\"groupTwo\" name=\"testB\" assertions=\"678\" time=\"0.000\" file=\"file\" line=\"1\">\n", outputFile->line(5));
}
TEST(JUnitOutputTest, UTPRINTOutputInJUnitOutput)
{
testCaseRunner->start()
.withGroup("groupname")
.withTest("testname").thatPrints("someoutput")
.end();
outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<system-out>someoutput</system-out>\n", outputFile->lineFromTheBack(3));
}
TEST(JUnitOutputTest, UTPRINTOutputInJUnitOutputWithSpecials)
{
testCaseRunner->start()
.withGroup("groupname")
.withTest("testname").thatPrints("The <rain> in \"Spain\"\nGoes \\mainly\\ down the Dr&in\n")
.end();
outputFile = fileSystem.file("cpputest_groupname.xml");
STRCMP_EQUAL("<system-out>The &lt;rain&gt; in &quot;Spain&quot;{newline}Goes \\mainly\\ down the Dr&amp;in{newline}</system-out>\n", outputFile->lineFromTheBack(3));
}

View file

@ -0,0 +1,692 @@
/*
* 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"
class MemoryLeakFailureForTest: public MemoryLeakFailure
{
public:
virtual ~MemoryLeakFailureForTest() _destructor_override
{
}
virtual void fail(char* fail_string) _override
{
*message = fail_string;
}
SimpleString *message;
};
class NewAllocatorForMemoryLeakDetectionTest: public TestMemoryAllocator
{
public:
NewAllocatorForMemoryLeakDetectionTest() :
TestMemoryAllocator("Standard New Allocator", "new", "delete"),
alloc_called(0), free_called(0)
{
}
int alloc_called;
int free_called;
char* alloc_memory(size_t size, const char*, size_t) _override
{
alloc_called++;
return TestMemoryAllocator::alloc_memory(size, "file", 1);
}
void free_memory(char* memory, size_t size, const char* file, size_t line) _override
{
free_called++;
TestMemoryAllocator::free_memory(memory, size, file, line);
}
};
class AllocatorForMemoryLeakDetectionTest: public TestMemoryAllocator
{
public:
AllocatorForMemoryLeakDetectionTest() :
alloc_called(0), free_called(0), allocMemoryLeakNodeCalled(0), freeMemoryLeakNodeCalled(0)
{
}
int alloc_called;
int free_called;
int allocMemoryLeakNodeCalled;
int freeMemoryLeakNodeCalled;
char* alloc_memory(size_t size, const char* file, size_t line) _override
{
alloc_called++;
return TestMemoryAllocator::alloc_memory(size, file, line);
}
void free_memory(char* memory, size_t size, const char* file, size_t line) _override
{
free_called++;
TestMemoryAllocator::free_memory(memory, size, file, line);
}
char* allocMemoryLeakNode(size_t size) _override
{
allocMemoryLeakNodeCalled++;
return TestMemoryAllocator::alloc_memory(size, __FILE__, __LINE__);
}
void freeMemoryLeakNode(char* memory) _override
{
freeMemoryLeakNodeCalled++;
TestMemoryAllocator::free_memory(memory, 0, __FILE__, __LINE__);
}
};
TEST_GROUP(MemoryLeakDetectorTest)
{
MemoryLeakDetector* detector;
MemoryLeakFailureForTest *reporter;
AllocatorForMemoryLeakDetectionTest* testAllocator;
void setup() _override
{
reporter = new MemoryLeakFailureForTest;
detector = new MemoryLeakDetector(reporter);
testAllocator = new AllocatorForMemoryLeakDetectionTest;
detector->enable();
detector->startChecking();
reporter->message = new SimpleString();
}
void teardown() _override
{
delete reporter->message;
delete detector;
delete reporter;
delete testAllocator;
}
};
TEST(MemoryLeakDetectorTest, OneLeak)
{
char* mem = detector->allocMemory(testAllocator, 3);
detector->stopChecking();
SimpleString output = detector->report(mem_leak_period_checking);
STRCMP_CONTAINS("Memory leak(s) found", output.asCharString());
STRCMP_CONTAINS("size: 3", output.asCharString());
STRCMP_CONTAINS("alloc", output.asCharString());
STRCMP_CONTAINS(StringFromFormat("%p", (void*) mem).asCharString(), output.asCharString());
STRCMP_CONTAINS("Total number of leaks", output.asCharString());
PlatformSpecificFree(mem);
LONGS_EQUAL(1, testAllocator->alloc_called);
LONGS_EQUAL(0, testAllocator->free_called);
}
TEST(MemoryLeakDetectorTest, sequenceNumbersOfMemoryLeaks)
{
char* mem = detector->allocMemory(defaultNewAllocator(), 1);
char* mem2 = detector->allocMemory(defaultNewAllocator(), 2);
char* mem3 = detector->allocMemory(defaultNewAllocator(), 3);
SimpleString output = detector->report(mem_leak_period_checking);
STRCMP_CONTAINS("Alloc num (1)", output.asCharString());
STRCMP_CONTAINS("Alloc num (2)", output.asCharString());
STRCMP_CONTAINS("Alloc num (3)", output.asCharString());
PlatformSpecificFree(mem);
PlatformSpecificFree(mem2);
PlatformSpecificFree(mem3);
}
TEST(MemoryLeakDetectorTest, memoryDumpOutput)
{
char* mem = detector->allocMemory(defaultNewAllocator(), 6);
SimpleString::StrNCpy(mem, "test1", 6);
SimpleString output = detector->report(mem_leak_period_checking);
STRCMP_CONTAINS("Alloc num (1)", output.asCharString());
STRCMP_CONTAINS("Leak size: 6 Allocated at", output.asCharString());
STRCMP_CONTAINS("Content:", output.asCharString());
STRCMP_CONTAINS("0000: 74 65 73 74 31 00 |test1.|", output.asCharString());
PlatformSpecificFree(mem);
}
TEST(MemoryLeakDetectorTest, OneHundredLeaks)
{
const int amount_alloc = 100;
char *mem[amount_alloc];
for (int i = 0; i < amount_alloc; i++)
mem[i] = detector->allocMemory(defaultMallocAllocator(), 3);
detector->stopChecking();
SimpleString output = detector->report(mem_leak_period_checking);
STRCMP_CONTAINS("Memory leak(s) found", output.asCharString());
STRCMP_CONTAINS("Total number of leaks", output.asCharString());
STRCMP_CONTAINS("Memory leak reports about malloc and free", output.asCharString());
//don't reuse i for vc6 compatibility
for (int j = 0; j < amount_alloc; j++)
PlatformSpecificFree(mem[j]);
}
TEST(MemoryLeakDetectorTest, OneLeakOutsideCheckingPeriod)
{
detector->stopChecking();
char* mem = detector->allocMemory(defaultNewAllocator(), 4);
SimpleString output = detector->report(mem_leak_period_all);
CHECK(output.contains("Memory leak(s) found"));
CHECK(output.contains("size: 4"));
CHECK(output.contains("new"));
CHECK(output.contains("Total number of leaks"));
PlatformSpecificFree(mem);
}
TEST(MemoryLeakDetectorTest, NoLeaksWhatsoever)
{
detector->stopChecking();
STRCMP_CONTAINS("No memory leaks", detector->report(mem_leak_period_checking));
STRCMP_CONTAINS("No memory leaks", detector->report(mem_leak_period_all));
}
TEST(MemoryLeakDetectorTest, TwoLeaksUsingOperatorNew)
{
char* mem = detector->allocMemory(defaultNewAllocator(), 4);
char* mem2 = detector->allocMemory(defaultNewAllocator(), 8);
detector->stopChecking();
SimpleString output = detector->report(mem_leak_period_checking);
LONGS_EQUAL(2, detector->totalMemoryLeaks(mem_leak_period_checking));
CHECK(output.contains("size: 8"));
CHECK(output.contains("size: 4"));
PlatformSpecificFree(mem);
PlatformSpecificFree(mem2);
}
TEST(MemoryLeakDetectorTest, OneAllocButNoLeak)
{
char* mem = detector->allocMemory(testAllocator, 4);
detector->deallocMemory(testAllocator, mem);
detector->stopChecking();
STRCMP_CONTAINS("No memory leaks", detector->report(mem_leak_period_checking));
LONGS_EQUAL(1, testAllocator->alloc_called);
LONGS_EQUAL(1, testAllocator->free_called);
}
TEST(MemoryLeakDetectorTest, TwoAllocOneFreeOneLeak)
{
char* mem = detector->allocMemory(testAllocator, 4);
char* mem2 = detector->allocMemory(testAllocator, 12);
detector->deallocMemory(testAllocator, mem);
detector->stopChecking();
SimpleString output = detector->report(mem_leak_period_checking);
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_checking));
CHECK(output.contains("Leak size: 12"));
CHECK(!output.contains("Leak size: 4"));
PlatformSpecificFree(mem2);
LONGS_EQUAL(2, testAllocator->alloc_called);
LONGS_EQUAL(1, testAllocator->free_called);
}
TEST(MemoryLeakDetectorTest, TwoAllocOneFreeOneLeakReverseOrder)
{
char* mem = detector->allocMemory(defaultNewAllocator(), 4);
char* mem2 = detector->allocMemory(defaultNewAllocator(), 12);
detector->deallocMemory(defaultNewAllocator(), mem2);
detector->stopChecking();
SimpleString output = detector->report(mem_leak_period_checking);
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_checking));
CHECK(!output.contains("size: 12"));
CHECK(output.contains("size: 4"));
PlatformSpecificFree(mem);
}
TEST(MemoryLeakDetectorTest, DeleteNonAlocatedMemory)
{
char a;
char* pa = &a;
detector->deallocMemory(defaultMallocAllocator(), pa, "FREE.c", 100);
detector->stopChecking();
CHECK(reporter->message->contains("Deallocating non-allocated memory"));
CHECK(reporter->message->contains(" allocated at file: <unknown> line: 0 size: 0 type: unknown"));
CHECK(reporter->message->contains(" deallocated at file: FREE.c line: 100 type: free"));
}
TEST(MemoryLeakDetectorTest, IgnoreMemoryAllocatedOutsideCheckingPeriod)
{
detector->stopChecking();
char* mem = detector->allocMemory(defaultNewAllocator(), 4);
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_checking));
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_all));
detector->deallocMemory(defaultNewAllocator(), mem);
}
TEST(MemoryLeakDetectorTest, IgnoreMemoryAllocatedOutsideCheckingPeriodComplicatedCase)
{
char* mem = detector->allocMemory(defaultNewAllocator(), 4);
detector->stopChecking();
char* mem2 = detector->allocMemory(defaultNewAllocator(), 8);
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_checking));
detector->clearAllAccounting(mem_leak_period_checking);
PlatformSpecificFree(mem);
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_checking));
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_all));
detector->startChecking();
char* mem3 = detector->allocMemory(defaultNewAllocator(), 4);
detector->stopChecking();
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_checking));
LONGS_EQUAL(2, detector->totalMemoryLeaks(mem_leak_period_all));
detector->clearAllAccounting(mem_leak_period_checking);
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_checking));
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_all));
detector->clearAllAccounting(mem_leak_period_all);
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_all));
PlatformSpecificFree(mem2);
PlatformSpecificFree(mem3);
}
TEST(MemoryLeakDetectorTest, OneLeakUsingOperatorNewWithFileLine)
{
char* mem = detector->allocMemory(defaultNewAllocator(), 4, "file.cpp", 1234);
detector->stopChecking();
SimpleString output = detector->report(mem_leak_period_checking);
CHECK(output.contains("file.cpp"));
CHECK(output.contains("1234"));
PlatformSpecificFree(mem);
}
TEST(MemoryLeakDetectorTest, OneAllocAndFreeUsingArrayNew)
{
char* mem = detector->allocMemory(defaultNewArrayAllocator(), 10, "file.cpp", 1234);
char* mem2 = detector->allocMemory(defaultNewArrayAllocator(), 12);
LONGS_EQUAL(2, detector->totalMemoryLeaks(mem_leak_period_all));
SimpleString output = detector->report(mem_leak_period_checking);
CHECK(output.contains("new []"));
detector->deallocMemory(defaultNewArrayAllocator(), mem);
detector->deallocMemory(defaultNewArrayAllocator(), mem2);
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_all));
detector->stopChecking();
}
TEST(MemoryLeakDetectorTest, OneAllocAndFree)
{
char* mem = detector->allocMemory(defaultMallocAllocator(), 10, "file.cpp", 1234);
char* mem2 = detector->allocMemory(defaultMallocAllocator(), 12);
LONGS_EQUAL(2, detector->totalMemoryLeaks(mem_leak_period_checking));
SimpleString output = detector->report(mem_leak_period_checking);
CHECK(output.contains("malloc"));
detector->deallocMemory(defaultMallocAllocator(), mem);
detector->deallocMemory(defaultMallocAllocator(), mem2, "file.c", 5678);
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_all));
detector->stopChecking();
}
TEST(MemoryLeakDetectorTest, OneRealloc)
{
char* mem1 = detector->allocMemory(testAllocator, 10, "file.cpp", 1234, true);
char* mem2 = detector->reallocMemory(testAllocator, mem1, 1000, "other.cpp", 5678, true);
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_checking));
SimpleString output = detector->report(mem_leak_period_checking);
CHECK(output.contains("other.cpp"));
detector->deallocMemory(testAllocator, mem2, true);
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_all));
detector->stopChecking();
LONGS_EQUAL(1, testAllocator->alloc_called);
LONGS_EQUAL(1, testAllocator->free_called);
LONGS_EQUAL(2, testAllocator->allocMemoryLeakNodeCalled);
LONGS_EQUAL(2, testAllocator->freeMemoryLeakNodeCalled);
}
TEST(MemoryLeakDetectorTest, ReallocNonAllocatedMemory)
{
char mem1;
char* mem2 = detector->reallocMemory(testAllocator, &mem1, 5, "other.cpp", 13, true);
detector->deallocMemory(testAllocator, mem2, true);
detector->stopChecking();
CHECK(reporter->message->contains("Deallocating non-allocated memory\n"));
CHECK(reporter->message->contains(" deallocated at file: other.cpp line: 13"));
}
TEST(MemoryLeakDetectorTest, AllocOneTypeFreeAnotherType)
{
char* mem = detector->allocMemory(defaultNewArrayAllocator(), 100, "ALLOC.c", 10);
detector->deallocMemory(defaultMallocAllocator(), mem, "FREE.c", 100);
detector->stopChecking();
CHECK(reporter->message->contains("Allocation/deallocation type mismatch"));
CHECK(reporter->message->contains(" allocated at file: ALLOC.c line: 10 size: 100 type: new []"));
CHECK(reporter->message->contains(" deallocated at file: FREE.c line: 100 type: free"));
}
TEST(MemoryLeakDetectorTest, AllocOneTypeFreeAnotherTypeWithCheckingDisabled)
{
detector->disableAllocationTypeChecking();
char* mem = detector->allocMemory(defaultNewArrayAllocator(), 100, "ALLOC.c", 10);
detector->deallocMemory(defaultNewAllocator(), mem, "FREE.c", 100);
detector->stopChecking();
STRCMP_EQUAL("", reporter->message->asCharString());
detector->enableAllocationTypeChecking();
}
TEST(MemoryLeakDetectorTest, mallocLeakGivesAdditionalWarning)
{
char* mem = detector->allocMemory(defaultMallocAllocator(), 100, "ALLOC.c", 10);
detector->stopChecking();
SimpleString output = detector->report(mem_leak_period_checking);
STRCMP_CONTAINS("Memory leak reports about malloc and free can be caused by allocating using the cpputest version of malloc", output.asCharString());
PlatformSpecificFree(mem);
}
TEST(MemoryLeakDetectorTest, newLeakDoesNotGiveAdditionalWarning)
{
char* mem = detector->allocMemory(defaultNewAllocator(), 100, "ALLOC.c", 10);
detector->stopChecking();
SimpleString output = detector->report(mem_leak_period_checking);
CHECK(! output.contains("Memory leak reports about malloc and free"));
PlatformSpecificFree(mem);
}
TEST(MemoryLeakDetectorTest, MarkCheckingPeriodLeaksAsNonCheckingPeriod)
{
char* mem = detector->allocMemory(defaultNewArrayAllocator(), 100);
char* mem2 = detector->allocMemory(defaultNewArrayAllocator(), 100);
detector->stopChecking();
LONGS_EQUAL(2, detector->totalMemoryLeaks(mem_leak_period_checking));
LONGS_EQUAL(2, detector->totalMemoryLeaks(mem_leak_period_all));
detector->markCheckingPeriodLeaksAsNonCheckingPeriod();
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_checking));
LONGS_EQUAL(2, detector->totalMemoryLeaks(mem_leak_period_all));
PlatformSpecificFree(mem);
PlatformSpecificFree(mem2);
}
TEST(MemoryLeakDetectorTest, memoryCorruption)
{
char* mem = detector->allocMemory(defaultMallocAllocator(), 10, "ALLOC.c", 10);
mem[10] = 'O';
mem[11] = 'H';
detector->deallocMemory(defaultMallocAllocator(), mem, "FREE.c", 100);
detector->stopChecking();
CHECK(reporter->message->contains("Memory corruption"));
CHECK(reporter->message->contains(" allocated at file: ALLOC.c line: 10 size: 10 type: malloc"));
CHECK(reporter->message->contains(" deallocated at file: FREE.c line: 100 type: free"));
}
TEST(MemoryLeakDetectorTest, safelyDeleteNULL)
{
detector->deallocMemory(defaultNewAllocator(), NULLPTR);
STRCMP_EQUAL("", reporter->message->asCharString());
}
TEST(MemoryLeakDetectorTest, periodDisabled)
{
detector->disable();
char* mem = detector->allocMemory(defaultMallocAllocator(), 2);
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_all));
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_disabled));
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_enabled));
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_checking));
detector->deallocMemory(defaultMallocAllocator(), mem);
}
TEST(MemoryLeakDetectorTest, periodEnabled)
{
detector->enable();
char* mem = detector->allocMemory(defaultMallocAllocator(), 2);
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_all));
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_disabled));
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_enabled));
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_checking));
detector->deallocMemory(defaultMallocAllocator(), mem);
}
TEST(MemoryLeakDetectorTest, periodChecking)
{
char* mem = detector->allocMemory(defaultMallocAllocator(), 2);
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_all));
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_disabled));
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_enabled));
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_checking));
detector->deallocMemory(defaultMallocAllocator(), mem);
}
TEST(MemoryLeakDetectorTest, defaultAllocationStageIsZero)
{
LONGS_EQUAL(0, detector->getCurrentAllocationStage());
}
TEST(MemoryLeakDetectorTest, canFreeNoAllocations)
{
detector->deallocAllMemoryInCurrentAllocationStage();
LONGS_EQUAL(0, detector->getCurrentAllocationStage());
}
TEST(MemoryLeakDetectorTest, increaseAllocationStage)
{
detector->increaseAllocationStage();
LONGS_EQUAL(1, detector->getCurrentAllocationStage());
}
TEST(MemoryLeakDetectorTest, decreaseAllocationStage)
{
detector->increaseAllocationStage();
detector->decreaseAllocationStage();
LONGS_EQUAL(0, detector->getCurrentAllocationStage());
}
TEST(MemoryLeakDetectorTest, freeAllMemoryInCurrentAllocationStage)
{
detector->increaseAllocationStage();
detector->allocMemory(defaultMallocAllocator(), 2);
detector->allocMemory(defaultMallocAllocator(), 2);
detector->deallocAllMemoryInCurrentAllocationStage();
LONGS_EQUAL(0, detector->totalMemoryLeaks(mem_leak_period_all));
}
TEST(MemoryLeakDetectorTest, freeOnlyTheMemoryInTheAllocationStage)
{
char* mem = detector->allocMemory(defaultMallocAllocator(), 2);
detector->increaseAllocationStage();
detector->allocMemory(defaultMallocAllocator(), 2);
detector->deallocAllMemoryInCurrentAllocationStage();
LONGS_EQUAL(1, detector->totalMemoryLeaks(mem_leak_period_all));
detector->deallocMemory(defaultMallocAllocator(), mem);
}
TEST(MemoryLeakDetectorTest, allocateWithANullAllocatorCausesNoProblems)
{
char* mem = detector->allocMemory(NullUnknownAllocator::defaultAllocator(), 2);
detector->deallocMemory(NullUnknownAllocator::defaultAllocator(), mem);
}
TEST(MemoryLeakDetectorTest, invalidateMemory)
{
unsigned char* mem = (unsigned char*)detector->allocMemory(defaultMallocAllocator(), 2);
detector->invalidateMemory((char*)mem);
CHECK(mem[0] == 0xCD);
CHECK(mem[1] == 0xCD);
detector->deallocMemory(defaultMallocAllocator(), mem);
}
TEST(MemoryLeakDetectorTest, invalidateMemoryNULLShouldWork)
{
detector->invalidateMemory(NULLPTR);
}
TEST_GROUP(MemoryLeakDetectorListTest)
{
};
TEST(MemoryLeakDetectorListTest, clearAllAccountingIsWorkingProperly)
{
MemoryLeakDetectorList listForTesting;
MemoryLeakDetectorNode node1, node2, node3;
node3.period_ = mem_leak_period_disabled;
listForTesting.addNewNode(&node1);
listForTesting.addNewNode(&node2);
listForTesting.addNewNode(&node3);
listForTesting.clearAllAccounting(mem_leak_period_enabled);
POINTERS_EQUAL(NULLPTR, listForTesting.getFirstLeak(mem_leak_period_enabled));
CHECK(&node3 == listForTesting.getFirstLeak(mem_leak_period_disabled));
}
TEST_GROUP(SimpleStringBuffer)
{
};
TEST(SimpleStringBuffer, initialStringIsEmpty)
{
SimpleStringBuffer buffer;
STRCMP_EQUAL("", buffer.toString());
}
TEST(SimpleStringBuffer, simpleTest)
{
SimpleStringBuffer buffer;
buffer.add("Hello");
buffer.add(" World");
STRCMP_EQUAL("Hello World", buffer.toString());
}
TEST(SimpleStringBuffer, writePastLimit)
{
SimpleStringBuffer buffer;
for (int i = 0; i < SimpleStringBuffer::SIMPLE_STRING_BUFFER_LEN * 2; i++)
buffer.add("h");
SimpleString str("h", SimpleStringBuffer::SIMPLE_STRING_BUFFER_LEN-1);
STRCMP_EQUAL(str.asCharString(), buffer.toString());
}
TEST(SimpleStringBuffer, setWriteLimit)
{
SimpleStringBuffer buffer;
buffer.setWriteLimit(10);
for (int i = 0; i < SimpleStringBuffer::SIMPLE_STRING_BUFFER_LEN ; i++)
buffer.add("h");
SimpleString str("h", 10);
STRCMP_EQUAL(str.asCharString(), buffer.toString());
}
TEST(SimpleStringBuffer, setWriteLimitTooHighIsIgnored)
{
SimpleStringBuffer buffer;
buffer.setWriteLimit(SimpleStringBuffer::SIMPLE_STRING_BUFFER_LEN+10);
for (int i = 0; i < SimpleStringBuffer::SIMPLE_STRING_BUFFER_LEN+10; i++)
buffer.add("h");
SimpleString str("h", SimpleStringBuffer::SIMPLE_STRING_BUFFER_LEN-1);
STRCMP_EQUAL(str.asCharString(), buffer.toString());
}
TEST(SimpleStringBuffer, resetWriteLimit)
{
SimpleStringBuffer buffer;
buffer.setWriteLimit(10);
for (int i = 0; i < SimpleStringBuffer::SIMPLE_STRING_BUFFER_LEN ; i++)
buffer.add("h");
buffer.resetWriteLimit();
buffer.add("%s", SimpleString("h", 10).asCharString());
SimpleString str("h", 20);
STRCMP_EQUAL(str.asCharString(), buffer.toString());
}
TEST(SimpleStringBuffer, addMemoryDumpOneLinePlusOnePartial)
{
SimpleStringBuffer buffer;
buffer.addMemoryDump("deadbeefdeadbeefhopsxx", 22);
STRCMP_EQUAL(" 0000: 64 65 61 64 62 65 65 66 64 65 61 64 62 65 65 66 |deadbeefdeadbeef|\n"
" 0010: 68 6f 70 73 78 78 |hopsxx|\n",
buffer.toString());
}
TEST(SimpleStringBuffer, addMemoryDumpNonPrintable)
{
SimpleStringBuffer buffer;
// Ensure we test edge cases - NUL, 0x1F, 0x7F, 0xFF
buffer.addMemoryDump("\x15\x7f\xff\x00\x1ftdd", 8);
STRCMP_EQUAL(" 0000: 15 7f ff 00 1f 74 64 64 |.....tdd|\n",
buffer.toString());
}
TEST(SimpleStringBuffer, addMemoryDumpOneLine)
{
SimpleStringBuffer buffer;
buffer.addMemoryDump("deadbeefdeadbeef", 16);
STRCMP_EQUAL(" 0000: 64 65 61 64 62 65 65 66 64 65 61 64 62 65 65 66 |deadbeefdeadbeef|\n",
buffer.toString());
}
TEST(SimpleStringBuffer, addMemoryDumpOneHalfLine)
{
SimpleStringBuffer buffer;
buffer.addMemoryDump("deadbeef", 8);
STRCMP_EQUAL(" 0000: 64 65 61 64 62 65 65 66 |deadbeef|\n",
buffer.toString());
}
TEST(SimpleStringBuffer, addMemoryDumpOneByte)
{
SimpleStringBuffer buffer;
buffer.addMemoryDump("Z", 1);
STRCMP_EQUAL(" 0000: 5a |Z|\n",
buffer.toString());
}
TEST(SimpleStringBuffer, addMemoryDumpZeroBytes)
{
SimpleStringBuffer buffer;
buffer.addMemoryDump("", 0);
STRCMP_EQUAL("", buffer.toString());
}
TEST_GROUP(ReallocBugReported)
{
MemoryLeakFailureForTest reporter;
};
TEST(ReallocBugReported, CanSafelyDoAReallocWithANewAllocator)
{
MemoryLeakDetector detector(&reporter);
char* mem = detector.allocMemory(defaultNewAllocator(), 5, "file", 1);
mem = detector.reallocMemory(defaultNewAllocator(), mem, 19, "file", 1);
detector.deallocMemory(defaultNewAllocator(), mem);
}
TEST(ReallocBugReported, CanSafelyDoAReallocWithAMallocAllocator)
{
MemoryLeakDetector detector(&reporter);
char* mem = detector.allocMemory(defaultMallocAllocator(), 5, "file", 1, true);
mem = detector.reallocMemory(defaultMallocAllocator(), mem, 19, "file", 1, true);
detector.deallocMemory(defaultMallocAllocator(), mem, true);
}

View file

@ -0,0 +1,520 @@
/*
* 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/TestOutput.h"
#include "CppUTest/MemoryLeakWarningPlugin.h"
#include "CppUTest/MemoryLeakDetector.h"
#include "CppUTest/TestMemoryAllocator.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/TestHarness_c.h"
#include "CppUTest/SimpleMutex.h"
#include "DummyMemoryLeakDetector.h"
TEST_GROUP(MemoryLeakWarningLocalDetectorTest)
{
DummyMemoryLeakFailure dummy;
};
TEST(MemoryLeakWarningLocalDetectorTest, localDetectorReturnsNewGlobalWhenNoneWasSet)
{
MemoryLeakWarningPlugin memoryLeakWarningPlugin("TestMemoryLeakWarningPlugin", NULLPTR);
CHECK(NULLPTR != memoryLeakWarningPlugin.getMemoryLeakDetector());
}
TEST(MemoryLeakWarningLocalDetectorTest, localDetectorIsTheOneSpecifiedInConstructor)
{
MemoryLeakDetector localDetector(&dummy);
MemoryLeakWarningPlugin memoryLeakWarningPlugin("TestMemoryLeakWarningPlugin", &localDetector);
POINTERS_EQUAL(&localDetector, memoryLeakWarningPlugin.getMemoryLeakDetector());
}
TEST(MemoryLeakWarningLocalDetectorTest, localDetectorIsGlobalDetector)
{
MemoryLeakDetector* globalDetector = MemoryLeakWarningPlugin::getGlobalDetector();
MemoryLeakWarningPlugin memoryLeakWarningPlugin("TestMemoryLeakWarningPlugin", NULLPTR);
MemoryLeakDetector* localDetector = memoryLeakWarningPlugin.getMemoryLeakDetector();
POINTERS_EQUAL(globalDetector, localDetector);
}
static char* leak1;
static long* leak2;
static MemoryLeakDetector* detector;
static MemoryLeakWarningPlugin* memPlugin;
static TestMemoryAllocator* allocator;
TEST_GROUP(MemoryLeakWarningTest)
{
DummyMemoryLeakFailure dummy;
TestTestingFixture* fixture;
void setup() _override
{
fixture = new TestTestingFixture();
detector = new MemoryLeakDetector(&dummy);
allocator = new TestMemoryAllocator;
memPlugin = new MemoryLeakWarningPlugin("TestMemoryLeakWarningPlugin", detector);
fixture->installPlugin(memPlugin);
memPlugin->enable();
leak1 = NULLPTR;
leak2 = NULLPTR;
}
void teardown() _override
{
detector->deallocMemory(allocator, leak1);
detector->deallocMemory(allocator, leak2);
delete fixture;
delete memPlugin;
delete detector;
delete allocator;
}
};
static void _testTwoLeaks()
{
leak1 = detector->allocMemory(allocator, 10);
leak2 = (long*) (void*) detector->allocMemory(allocator, 4);
}
#if CPPUTEST_USE_MEM_LEAK_DETECTION
TEST(MemoryLeakWarningTest, TwoLeaks)
{
fixture->setTestFunction(_testTwoLeaks);
fixture->runAllTests();
LONGS_EQUAL(1, fixture->getFailureCount());
}
#else
TEST(MemoryLeakWarningTest, TwoLeaks)
{
fixture->setTestFunction(_testTwoLeaks);
fixture->runAllTests();
LONGS_EQUAL(0, fixture->getFailureCount());
}
#endif
static void _testLeakWarningWithPluginDisabled()
{
memPlugin->expectLeaksInTest(1);
leak1 = (char*) cpputest_malloc_location_with_leak_detection(10, __FILE__, __LINE__);
}
TEST(MemoryLeakWarningTest, LeakWarningWithPluginDisabled)
{
fixture->setTestFunction(_testLeakWarningWithPluginDisabled);
MemoryLeakWarningPlugin::saveAndDisableNewDeleteOverloads();
fixture->runAllTests();
LONGS_EQUAL(0, fixture->getFailureCount());
fixture->assertPrintContains("Warning: Expected 1 leak(s), but leak detection was disabled");
cpputest_free_location_with_leak_detection(leak1, __FILE__, __LINE__);
leak1 = NULLPTR;
MemoryLeakWarningPlugin::restoreNewDeleteOverloads();
}
static void _testIgnore2()
{
memPlugin->expectLeaksInTest(2);
leak1 = detector->allocMemory(allocator, 10);
leak2 = (long*) (void*) detector->allocMemory(allocator, 4);
}
TEST(MemoryLeakWarningTest, Ignore2)
{
fixture->setTestFunction(_testIgnore2);
fixture->runAllTests();
LONGS_EQUAL(0, fixture->getFailureCount());
}
static void _failAndLeakMemory()
{
leak1 = detector->allocMemory(allocator, 10);
FAIL("");
}
TEST(MemoryLeakWarningTest, FailingTestDoesNotReportMemoryLeaks)
{
fixture->setTestFunction(_failAndLeakMemory);
fixture->runAllTests();
LONGS_EQUAL(1, fixture->getFailureCount());
}
static bool cpputestHasCrashed;
TEST_GROUP(MemoryLeakWarningGlobalDetectorTest)
{
MemoryLeakDetector* detector;
MemoryLeakFailure* failureReporter;
DummyMemoryLeakDetector * dummyDetector;
MemoryLeakFailure* dummyReporter;
GlobalMemoryAllocatorStash memoryAllocatorStash;
static void crashMethod()
{
cpputestHasCrashed = true;
}
void setup() _override
{
memoryAllocatorStash.save();
detector = MemoryLeakWarningPlugin::getGlobalDetector();
failureReporter = MemoryLeakWarningPlugin::getGlobalFailureReporter();
MemoryLeakWarningPlugin::saveAndDisableNewDeleteOverloads();
dummyReporter = new DummyMemoryLeakFailure;
dummyDetector = new DummyMemoryLeakDetector(dummyReporter);
UtestShell::setCrashMethod(crashMethod);
cpputestHasCrashed = false;
}
void teardown() _override
{
MemoryLeakWarningPlugin::restoreNewDeleteOverloads();
MemoryLeakWarningPlugin::saveAndDisableNewDeleteOverloads();
if (!DummyMemoryLeakDetector::wasDeleted()) delete dummyDetector;
if (!DummyMemoryLeakFailure::wasDeleted()) delete dummyReporter;
MemoryLeakWarningPlugin::setGlobalDetector(detector, failureReporter);
MemoryLeakWarningPlugin::restoreNewDeleteOverloads();
UtestShell::resetCrashMethod();
memoryAllocatorStash.restore();
}
};
TEST(MemoryLeakWarningGlobalDetectorTest, turnOffNewOverloadsCausesNoAdditionalLeaks)
{
size_t storedAmountOfLeaks = detector->totalMemoryLeaks(mem_leak_period_all);
char* arrayMemory = new char[100];
char* nonArrayMemory = new char;
char* mallocMemory = (char*) cpputest_malloc_location_with_leak_detection(10, "file", 10);
char* reallocMemory = (char*) cpputest_realloc_location_with_leak_detection(NULLPTR, 10, "file", 10);
LONGS_EQUAL(storedAmountOfLeaks, detector->totalMemoryLeaks(mem_leak_period_all));
cpputest_free_location_with_leak_detection(mallocMemory, "file", 10);
cpputest_free_location_with_leak_detection(reallocMemory, "file", 10);
delete [] arrayMemory;
delete nonArrayMemory;
}
TEST(MemoryLeakWarningGlobalDetectorTest, destroyGlobalDetector)
{
MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);
MemoryLeakWarningPlugin::destroyGlobalDetector();
CHECK(DummyMemoryLeakDetector::wasDeleted());
CHECK(DummyMemoryLeakFailure::wasDeleted());
}
TEST(MemoryLeakWarningGlobalDetectorTest, MemoryWarningPluginCanBeSetToDestroyTheGlobalDetector)
{
MemoryLeakWarningPlugin* plugin = new MemoryLeakWarningPlugin("dummy");
plugin->destroyGlobalDetectorAndTurnOffMemoryLeakDetectionInDestructor(true);
MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);
delete plugin;
CHECK(DummyMemoryLeakDetector::wasDeleted());
}
#if CPPUTEST_USE_MEM_LEAK_DETECTION
TEST(MemoryLeakWarningGlobalDetectorTest, crashOnLeakWithOperatorNew)
{
MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);
MemoryLeakWarningPlugin::restoreNewDeleteOverloads();
crash_on_allocation_number(1);
char* memory = new char[100];
CHECK(cpputestHasCrashed);
delete [] memory;
MemoryLeakWarningPlugin::saveAndDisableNewDeleteOverloads();
}
TEST(MemoryLeakWarningGlobalDetectorTest, crashOnLeakWithOperatorNewArray)
{
MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);
MemoryLeakWarningPlugin::restoreNewDeleteOverloads();
crash_on_allocation_number(1);
char* memory = new char;
CHECK(cpputestHasCrashed);
delete memory;
MemoryLeakWarningPlugin::saveAndDisableNewDeleteOverloads();
}
TEST(MemoryLeakWarningGlobalDetectorTest, crashOnLeakWithOperatorMalloc)
{
MemoryLeakWarningPlugin::setGlobalDetector(dummyDetector, dummyReporter);
MemoryLeakWarningPlugin::restoreNewDeleteOverloads();
crash_on_allocation_number(1);
char* memory = (char*) cpputest_malloc(10);
CHECK(cpputestHasCrashed);
cpputest_free(memory);
MemoryLeakWarningPlugin::saveAndDisableNewDeleteOverloads();
}
TEST(MemoryLeakWarningGlobalDetectorTest, gettingTheGlobalDetectorDoesNotRestoreTheMemoryLeakOverloadsWhenTheyWereAlreadyOff)
{
MemoryLeakWarningPlugin::setGlobalDetector(NULLPTR, NULLPTR);
MemoryLeakDetector* temporaryDetector = MemoryLeakWarningPlugin::getGlobalDetector();
MemoryLeakFailure* temporaryReporter = MemoryLeakWarningPlugin::getGlobalFailureReporter();
MemoryLeakWarningPlugin::saveAndDisableNewDeleteOverloads();
bool areNewDeleteOverloaded = MemoryLeakWarningPlugin::areNewDeleteOverloaded();
MemoryLeakWarningPlugin::restoreNewDeleteOverloads();
CHECK(!areNewDeleteOverloaded);
delete temporaryReporter;
delete temporaryDetector;
MemoryLeakWarningPlugin::setGlobalDetector(NULLPTR, NULLPTR);
}
TEST(MemoryLeakWarningGlobalDetectorTest, checkIfTheMemoryLeakOverloadsAreOn)
{
MemoryLeakWarningPlugin::turnOnDefaultNotThreadSafeNewDeleteOverloads();
CHECK(MemoryLeakWarningPlugin::areNewDeleteOverloaded());
MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
}
TEST(MemoryLeakWarningGlobalDetectorTest, checkIfTheMemoryLeakOverloadsAreOff)
{
MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
bool areNewDeleteOverloaded = MemoryLeakWarningPlugin::areNewDeleteOverloaded();
MemoryLeakWarningPlugin::turnOnDefaultNotThreadSafeNewDeleteOverloads();
CHECK(!areNewDeleteOverloaded);
}
TEST(MemoryLeakWarningGlobalDetectorTest, checkIfTheMemoryLeakOverloadsAreOnWithRestore)
{
MemoryLeakWarningPlugin::restoreNewDeleteOverloads();
CHECK(MemoryLeakWarningPlugin::areNewDeleteOverloaded());
MemoryLeakWarningPlugin::saveAndDisableNewDeleteOverloads();
}
TEST(MemoryLeakWarningGlobalDetectorTest, checkIfTheMemoryLeakOverloadsAreOffWithSaveDisable)
{
MemoryLeakWarningPlugin::saveAndDisableNewDeleteOverloads();
CHECK(!MemoryLeakWarningPlugin::areNewDeleteOverloaded());
MemoryLeakWarningPlugin::restoreNewDeleteOverloads();
}
TEST(MemoryLeakWarningGlobalDetectorTest, threadSafeMemoryLeakDetectorOverloadsAreAlsoOverloaded)
{
MemoryLeakWarningPlugin::restoreNewDeleteOverloads();
MemoryLeakWarningPlugin::turnOnThreadSafeNewDeleteOverloads();
CHECK(MemoryLeakWarningPlugin::areNewDeleteOverloaded());
MemoryLeakWarningPlugin::turnOnDefaultNotThreadSafeNewDeleteOverloads();
MemoryLeakWarningPlugin::saveAndDisableNewDeleteOverloads();
}
#endif
#if CPPUTEST_USE_STD_CPP_LIB
TEST(MemoryLeakWarningGlobalDetectorTest, turnOffNewOverloadsNoThrowCausesNoAdditionalLeaks)
{
#undef new
size_t storedAmountOfLeaks = detector->totalMemoryLeaks(mem_leak_period_all);
char* nonMemoryNoThrow = new (std::nothrow) char;
char* nonArrayMemoryNoThrow = new (std::nothrow) char[10];
char* nonArrayMemoryThrow = new char[10];
LONGS_EQUAL(storedAmountOfLeaks, detector->totalMemoryLeaks(mem_leak_period_all));
::operator delete(nonMemoryNoThrow, std::nothrow);
::operator delete[](nonArrayMemoryNoThrow, std::nothrow);
::operator delete[](nonArrayMemoryThrow, std::nothrow);
#ifdef CPPUTEST_USE_NEW_MACROS
#include "CppUTest/MemoryLeakDetectorNewMacros.h"
#endif
}
#if CPPUTEST_USE_MEM_LEAK_DETECTION
static int mutexLockCount = 0;
static int mutexUnlockCount = 0;
static void StubMutexLock(PlatformSpecificMutex)
{
mutexLockCount++;
}
static void StubMutexUnlock(PlatformSpecificMutex)
{
mutexUnlockCount++;
}
TEST_GROUP(MemoryLeakWarningThreadSafe)
{
void setup() _override
{
UT_PTR_SET(PlatformSpecificMutexLock, StubMutexLock);
UT_PTR_SET(PlatformSpecificMutexUnlock, StubMutexUnlock);
mutexLockCount = 0;
mutexUnlockCount = 0;
}
void teardown() _override
{
}
};
TEST(MemoryLeakWarningThreadSafe, turnOnThreadSafeMallocFreeReallocOverloadsDebug)
{
size_t storedAmountOfLeaks = MemoryLeakWarningPlugin::getGlobalDetector()->totalMemoryLeaks(mem_leak_period_all);
MemoryLeakWarningPlugin::turnOnThreadSafeNewDeleteOverloads();
int *n = (int*) cpputest_malloc(sizeof(int));
LONGS_EQUAL(storedAmountOfLeaks + 1, MemoryLeakWarningPlugin::getGlobalDetector()->totalMemoryLeaks(mem_leak_period_all));
CHECK_EQUAL(1, mutexLockCount);
CHECK_EQUAL(1, mutexUnlockCount);
n = (int*) cpputest_realloc(n, sizeof(int)*3);
LONGS_EQUAL(storedAmountOfLeaks + 1, MemoryLeakWarningPlugin::getGlobalDetector()->totalMemoryLeaks(mem_leak_period_all));
CHECK_EQUAL(2, mutexLockCount);
CHECK_EQUAL(2, mutexUnlockCount);
cpputest_free(n);
LONGS_EQUAL(storedAmountOfLeaks, MemoryLeakWarningPlugin::getGlobalDetector()->totalMemoryLeaks(mem_leak_period_all));
CHECK_EQUAL(3, mutexLockCount);
CHECK_EQUAL(3, mutexUnlockCount);
MemoryLeakWarningPlugin::turnOnDefaultNotThreadSafeNewDeleteOverloads();
}
TEST(MemoryLeakWarningThreadSafe, turnOnThreadSafeNewDeleteOverloadsDebug)
{
size_t storedAmountOfLeaks = MemoryLeakWarningPlugin::getGlobalDetector()->totalMemoryLeaks(mem_leak_period_all);
MemoryLeakWarningPlugin::turnOnThreadSafeNewDeleteOverloads();
int *n = new int;
char *str = new char[20];
LONGS_EQUAL(storedAmountOfLeaks + 2, MemoryLeakWarningPlugin::getGlobalDetector()->totalMemoryLeaks(mem_leak_period_all));
CHECK_EQUAL(2, mutexLockCount);
CHECK_EQUAL(2, mutexUnlockCount);
delete [] str;
delete n;
LONGS_EQUAL(storedAmountOfLeaks, MemoryLeakWarningPlugin::getGlobalDetector()->totalMemoryLeaks(mem_leak_period_all));
CHECK_EQUAL(4, mutexLockCount);
CHECK_EQUAL(4, mutexUnlockCount);
MemoryLeakWarningPlugin::turnOnDefaultNotThreadSafeNewDeleteOverloads();
}
#ifdef __clang__
IGNORE_TEST(MemoryLeakWarningThreadSafe, turnOnThreadSafeNewDeleteOverloads)
{
/* Clang misbehaves with -O2 - it will not overload operator new or
* operator new[] no matter what. Therefore, this test is must be ignored.
*/
}
#else
TEST(MemoryLeakWarningThreadSafe, turnOnThreadSafeNewDeleteOverloads)
{
#undef new
size_t storedAmountOfLeaks = MemoryLeakWarningPlugin::getGlobalDetector()->totalMemoryLeaks(mem_leak_period_all);
MemoryLeakWarningPlugin::turnOnThreadSafeNewDeleteOverloads();
int *n = new int;
int *n_nothrow = new (std::nothrow) int;
char *str = new char[20];
char *str_nothrow = new (std::nothrow) char[20];
LONGS_EQUAL(storedAmountOfLeaks + 4, MemoryLeakWarningPlugin::getGlobalDetector()->totalMemoryLeaks(mem_leak_period_all));
CHECK_EQUAL(4, mutexLockCount);
CHECK_EQUAL(4, mutexUnlockCount);
delete [] str_nothrow;
delete [] str;
delete n;
delete n_nothrow;
LONGS_EQUAL(storedAmountOfLeaks, MemoryLeakWarningPlugin::getGlobalDetector()->totalMemoryLeaks(mem_leak_period_all));
CHECK_EQUAL(8, mutexLockCount);
CHECK_EQUAL(8, mutexUnlockCount);
MemoryLeakWarningPlugin::turnOnDefaultNotThreadSafeNewDeleteOverloads();
#ifdef CPPUTEST_USE_NEW_MACROS
#include "CppUTest/MemoryLeakDetectorNewMacros.h"
#endif
}
#endif
#endif
#endif

View file

@ -0,0 +1,506 @@
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestMemoryAllocator.h"
#include "CppUTest/MemoryLeakDetector.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/PlatformSpecificFunctions.h"
#include "CppUTest/TestTestingFixture.h"
#include "AllocationInCppFile.h"
#include "CppUTest/TestHarness_c.h"
#include "AllocationInCFile.h"
TEST_GROUP(BasicBehavior)
{
};
TEST(BasicBehavior, CanDeleteNullPointers)
{
delete (char*) NULLPTR;
delete [] (char*) NULLPTR;
}
#if CPPUTEST_USE_MEM_LEAK_DETECTION
CPPUTEST_DO_NOT_SANITIZE_ADDRESS
static void deleteArrayInvalidatesMemory()
{
unsigned char* memory = new unsigned char[10];
PlatformSpecificMemset(memory, 0xAB, 10);
delete [] memory;
CHECK(memory[5] != 0xCB);
}
TEST(BasicBehavior, deleteArrayInvalidatesMemory)
{
deleteArrayInvalidatesMemory();
}
CPPUTEST_DO_NOT_SANITIZE_ADDRESS
static void deleteInvalidatesMemory()
{
unsigned char* memory = new unsigned char;
*memory = 0xAD;
delete memory;
CHECK(*memory != 0xAD);
}
TEST(BasicBehavior, deleteInvalidatesMemory)
{
deleteInvalidatesMemory();
}
#if __cplusplus >= 201402L
TEST(BasicBehavior, DeleteWithSizeParameterWorks)
{
char* charMemory = new char;
char* charArrayMemory = new char[10];
::operator delete(charMemory, sizeof(char));
::operator delete[](charArrayMemory, sizeof(char)* 10);
}
#endif
static void deleteUnallocatedMemory()
{
delete (char*) 0x1234678;
FAIL("Should never come here"); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(BasicBehavior, deleteWillNotThrowAnExceptionWhenDeletingUnallocatedMemoryButCanStillCauseTestFailures)
{
/*
* Test failure might cause an exception. But according to C++ standard, you aren't allowed
* to throw exceptions in the delete function. If you do that, it will call std::terminate.
* Therefore, the delete will need to fail without exceptions.
*/
MemoryLeakFailure* defaultReporter = MemoryLeakWarningPlugin::getGlobalFailureReporter();
TestTestingFixture fixture;
fixture.setTestFunction(deleteUnallocatedMemory);
fixture.runAllTests();
LONGS_EQUAL(1, fixture.getFailureCount());
POINTERS_EQUAL(defaultReporter, MemoryLeakWarningPlugin::getGlobalFailureReporter());
}
#endif
#ifdef CPPUTEST_USE_MALLOC_MACROS
/* This include is added because *sometimes* the cstdlib does an #undef. This should have been prevented */
#if CPPUTEST_USE_STD_CPP_LIB
#include <cstdlib>
#endif
TEST(BasicBehavior, bothMallocAndFreeAreOverloaded)
{
void* memory = cpputest_malloc_location(sizeof(char), "file", 10);
free(memory);
memory = malloc(sizeof(unsigned char));
cpputest_free_location(memory, "file", 10);
}
#endif
#if CPPUTEST_USE_MEM_LEAK_DETECTION
CPPUTEST_DO_NOT_SANITIZE_ADDRESS
static void freeInvalidatesMemory()
{
unsigned char* memory = (unsigned char*) cpputest_malloc(sizeof(unsigned char));
*memory = 0xAD;
cpputest_free(memory);
CHECK(*memory != 0xAD);
}
TEST(BasicBehavior, freeInvalidatesMemory)
{
freeInvalidatesMemory();
}
#endif
TEST_GROUP(MemoryLeakOverridesToBeUsedInProductionCode)
{
MemoryLeakDetector* memLeakDetector;
void setup() _override
{
memLeakDetector = MemoryLeakWarningPlugin::getGlobalDetector();
}
};
#if ! defined CPPUTEST_MEM_LEAK_DETECTION_DISABLED || ! CPPUTEST_MEM_LEAK_DETECTION_DISABLED
#ifdef CPPUTEST_USE_NEW_MACROS
#undef new
#endif
TEST(MemoryLeakOverridesToBeUsedInProductionCode, newDeleteOverloadsWithIntLineWorks)
{
const int line = 42;
char* leak = new("TestFile.cpp", line) char;
size_t memLeaks = memLeakDetector->totalMemoryLeaks(mem_leak_period_checking);
STRCMP_NOCASE_CONTAINS("Allocated at: TestFile.cpp and line: 42.", memLeakDetector->report(mem_leak_period_checking));
::operator delete (leak, "TestFile.cpp", line);
LONGS_EQUAL(memLeaks-1, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
}
TEST(MemoryLeakOverridesToBeUsedInProductionCode, newDeleteOverloadsWithSizeTLineWorks)
{
const size_t line = 42;
char* leak = new("TestFile.cpp", line) char;
size_t memLeaks = memLeakDetector->totalMemoryLeaks(mem_leak_period_checking);
STRCMP_NOCASE_CONTAINS("Allocated at: TestFile.cpp and line: 42.", memLeakDetector->report(mem_leak_period_checking));
::operator delete (leak, "TestFile.cpp", line);
LONGS_EQUAL(memLeaks-1, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
}
TEST(MemoryLeakOverridesToBeUsedInProductionCode, newDeleteArrayOverloadsWithIntLineWorks)
{
const int line = 42;
char* leak = new("TestFile.cpp", line) char[10];
size_t memLeaks = memLeakDetector->totalMemoryLeaks(mem_leak_period_checking);
STRCMP_NOCASE_CONTAINS("Allocated at: TestFile.cpp and line: 42.", memLeakDetector->report(mem_leak_period_checking));
::operator delete [] (leak, "TestFile.cpp", line);
LONGS_EQUAL(memLeaks-1, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
}
TEST(MemoryLeakOverridesToBeUsedInProductionCode, newDeleteArrayOverloadsWithSizeTLineWorks)
{
const size_t line = 42;
char* leak = new("TestFile.cpp", line) char[10];
size_t memLeaks = memLeakDetector->totalMemoryLeaks(mem_leak_period_checking);
STRCMP_NOCASE_CONTAINS("Allocated at: TestFile.cpp and line: 42.", memLeakDetector->report(mem_leak_period_checking));
::operator delete [] (leak, "TestFile.cpp", line);
LONGS_EQUAL(memLeaks-1, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
}
#ifdef CPPUTEST_USE_NEW_MACROS
#include "CppUTest/MemoryLeakDetectorNewMacros.h" // redefine the 'new' macro
#endif
#endif
#ifdef CPPUTEST_USE_MALLOC_MACROS
TEST(MemoryLeakOverridesToBeUsedInProductionCode, MallocOverrideIsUsed)
{
size_t memLeaks = memLeakDetector->totalMemoryLeaks(mem_leak_period_checking);
void* memory = malloc(10);
LONGS_EQUAL(memLeaks+1, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
free (memory);
}
#ifdef CPPUTEST_USE_STRDUP_MACROS
TEST(MemoryLeakOverridesToBeUsedInProductionCode, StrdupOverrideIsUsed)
{
size_t memLeaks = memLeakDetector->totalMemoryLeaks(mem_leak_period_checking);
char* memory = strdup("0123456789");
LONGS_EQUAL(memLeaks+1, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
free (memory);
}
TEST(MemoryLeakOverridesToBeUsedInProductionCode, StrndupOverrideIsUsed)
{
size_t memLeaks = memLeakDetector->totalMemoryLeaks(mem_leak_period_checking);
char* memory = strndup("0123456789", 10);
LONGS_EQUAL(memLeaks+1, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
free (memory);
}
#endif
#endif
TEST(MemoryLeakOverridesToBeUsedInProductionCode, UseNativeMallocByTemporarlySwitchingOffMalloc)
{
size_t memLeaks = memLeakDetector->totalMemoryLeaks(mem_leak_period_checking);
#ifdef CPPUTEST_USE_MALLOC_MACROS
#undef malloc
#undef free
#endif
#if CPPUTEST_USE_STD_C_LIB
void* memory = malloc(10);
LONGS_EQUAL(memLeaks, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
free (memory);
#else
void* memory = PlatformSpecificMalloc(10);
LONGS_EQUAL(memLeaks, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
PlatformSpecificFree (memory);
#endif
#ifdef CPPUTEST_USE_MALLOC_MACROS
#include "CppUTest/MemoryLeakDetectorMallocMacros.h"
#endif
}
/* TEST... allowing for a new overload in a class */
class NewDummyClass
{
public:
static bool overloaded_new_called;
#ifdef CPPUTEST_USE_NEW_MACROS
#undef new
#endif
void* operator new (size_t size)
#ifdef CPPUTEST_USE_NEW_MACROS
#include "CppUTest/MemoryLeakDetectorNewMacros.h"
#endif
{
overloaded_new_called = true;
return malloc(size);
}
void dummyFunction()
{
char* memory = new char;
delete memory;
}
};
bool NewDummyClass::overloaded_new_called = false;
TEST(MemoryLeakOverridesToBeUsedInProductionCode, NoSideEffectsFromTurningOffNewMacros)
{
/*
* Interesting effect of wrapping the operator new around the macro is
* that the actual new that is called is a different one than expected.
*
* The overloaded operator new doesn't actually ever get called.
*
* This might come as a surprise, so it is important to realize!
*/
NewDummyClass dummy;
dummy.dummyFunction();
// CHECK(dummy.overloaded_new_called);
}
TEST(MemoryLeakOverridesToBeUsedInProductionCode, UseNativeNewByTemporarlySwitchingOffNew)
{
#ifdef CPPUTEST_USE_NEW_MACROS
#undef new
#undef delete
#endif
char* memory = new char[10];
delete [] memory;
#ifdef CPPUTEST_USE_NEW_MACROS
#include "CppUTest/MemoryLeakDetectorNewMacros.h"
#endif
}
#if CPPUTEST_USE_MEM_LEAK_DETECTION
TEST(MemoryLeakOverridesToBeUsedInProductionCode, OperatorNewMacroOverloadViaIncludeFileWorks)
{
char* leak = newAllocation();
STRCMP_NOCASE_CONTAINS("AllocationInCppFile.cpp", memLeakDetector->report(mem_leak_period_checking));
delete leak;
}
TEST(MemoryLeakOverridesToBeUsedInProductionCode, OperatorNewArrayMacroOverloadViaIncludeFileWorks)
{
char* leak = newArrayAllocation();
STRCMP_NOCASE_CONTAINS("AllocationInCppFile.cpp", memLeakDetector->report(mem_leak_period_checking));
delete[] leak;
}
TEST(MemoryLeakOverridesToBeUsedInProductionCode, MallocOverrideWorks)
{
char* leak = mallocAllocation();
STRCMP_NOCASE_CONTAINS("AllocationInCFile.c", memLeakDetector->report(mem_leak_period_checking));
freeAllocation(leak);
}
#ifdef CPPUTEST_USE_STRDUP_MACROS
TEST(MemoryLeakOverridesToBeUsedInProductionCode, StrdupOverrideWorks)
{
char* leak = strdupAllocation();
STRCMP_NOCASE_CONTAINS("AllocationInCFile.c", memLeakDetector->report(mem_leak_period_checking));
freeAllocation(leak);
}
TEST(MemoryLeakOverridesToBeUsedInProductionCode, StrndupOverrideWorks)
{
char* leak = strndupAllocation();
STRCMP_NOCASE_CONTAINS("AllocationInCFile.c", memLeakDetector->report(mem_leak_period_checking));
freeAllocation(leak);
}
#endif
TEST(MemoryLeakOverridesToBeUsedInProductionCode, MallocWithButFreeWithoutLeakDetectionDoesntCrash)
{
char* leak = mallocAllocation();
freeAllocationWithoutMacro(leak);
LONGS_EQUAL(2, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
memLeakDetector->removeMemoryLeakInformationWithoutCheckingOrDeallocatingTheMemoryButDeallocatingTheAccountInformation(getCurrentMallocAllocator(), leak, true);
}
TEST(MemoryLeakOverridesToBeUsedInProductionCode, OperatorNewOverloadingWithoutMacroWorks)
{
char* leak = newAllocationWithoutMacro();
STRCMP_CONTAINS("unknown", memLeakDetector->report(mem_leak_period_checking));
delete leak;
}
TEST(MemoryLeakOverridesToBeUsedInProductionCode, OperatorNewArrayOverloadingWithoutMacroWorks)
{
char* leak = newArrayAllocationWithoutMacro();
STRCMP_CONTAINS("unknown", memLeakDetector->report(mem_leak_period_checking));
delete[] leak;
}
#else
TEST(MemoryLeakOverridesToBeUsedInProductionCode, MemoryOverridesAreDisabled)
{
char* leak = newAllocation();
STRCMP_EQUAL("No memory leaks were detected.", memLeakDetector->report(mem_leak_period_checking));
delete leak;
}
#endif
TEST_GROUP(OutOfMemoryTestsForOperatorNew)
{
TestMemoryAllocator* no_memory_allocator;
GlobalMemoryAllocatorStash memoryAllocatorStash;
void setup() _override
{
memoryAllocatorStash.save();
no_memory_allocator = new NullUnknownAllocator;
setCurrentNewAllocator(no_memory_allocator);
setCurrentNewArrayAllocator(no_memory_allocator);
}
void teardown() _override
{
memoryAllocatorStash.restore();
delete no_memory_allocator;
}
};
#if CPPUTEST_USE_MEM_LEAK_DETECTION
#if CPPUTEST_USE_STD_CPP_LIB
TEST(OutOfMemoryTestsForOperatorNew, FailingNewOperatorThrowsAnExceptionWhenUsingStdCppNew)
{
CHECK_THROWS(std::bad_alloc, new char);
}
TEST(OutOfMemoryTestsForOperatorNew, FailingNewArrayOperatorThrowsAnExceptionWhenUsingStdCppNew)
{
CHECK_THROWS(std::bad_alloc, new char[10]);
}
TEST_GROUP(TestForExceptionsInConstructor)
{
};
TEST(TestForExceptionsInConstructor,ConstructorThrowsAnException)
{
CHECK_THROWS(int, new ClassThatThrowsAnExceptionInTheConstructor);
}
TEST(TestForExceptionsInConstructor,ConstructorThrowsAnExceptionAllocatedAsArray)
{
CHECK_THROWS(int, new ClassThatThrowsAnExceptionInTheConstructor[10]);
}
#else
TEST(OutOfMemoryTestsForOperatorNew, FailingNewOperatorReturnsNull)
{
POINTERS_EQUAL(NULLPTR, new char);
}
TEST(OutOfMemoryTestsForOperatorNew, FailingNewArrayOperatorReturnsNull)
{
POINTERS_EQUAL(NULLPTR, new char[10]);
}
#endif
#undef new
#if CPPUTEST_USE_STD_CPP_LIB
/*
* CLang 4.2 and memory allocation.
*
* Clang 4.2 has done some optimizations to their memory management that actually causes slightly different behavior than what the C++ Standard defines.
* Usually this is not a problem... but in this case, it is a problem.
*
* More information about the optimization can be found at: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3433.html
* We've done a bug-report to clang to fix some of this non-standard behavior, which is open at: http://llvm.org/bugs/show_bug.cgi?id=15541
*
* I very much hope that nobody would actually ever hit this bug/optimization as it is hard to figure out what is going on.
*
* The original test simply did "new char". Because the memory wasn't assigned to anything and is local in context, the optimization *doesn't* call
* the operator new overload. Because it doesn't call the operator new (optimizing away a call to operator new), therefore the method wouldn't throw an exception
* and therefore this test failed.
*
* The first attempt to fix this is to create a local variable and assigned the memory to that. Also this doesn't work as it still detects the allocation is
* local and optimizes away the memory call.
*
* Now, we assign the memory on some static global which fools the optimizer to believe that it isn't local and it stops optimizing the operator new call.
*
* We (Bas Vodde and Terry Yin) suspect that in a real product, you wouldn't be able to detect the optimization and it's breaking of Standard C++. Therefore,
* for now, we keep this hack in the test to fool the optimizer and hope nobody will ever notice this 'optimizer behavior' in a real product.
*
* Update 2020: The gcc compiler implemented the same optimization, but it seems to be slightly smarter and discovered that we assign to a static variable.
* Thus it still optimized away the call to operator new. Did another bug report, but it is unlikely to get fixed. You can find it at:
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94671
*
* Changed the variable to be external so it would definitively be a mistake to optimize the call.
*
*/
extern char* some_memory;
char* some_memory;
TEST(OutOfMemoryTestsForOperatorNew, FailingNewOperatorThrowsAnExceptionWhenUsingStdCppNewWithoutOverride)
{
CHECK_THROWS(std::bad_alloc, some_memory = new char);
}
TEST(OutOfMemoryTestsForOperatorNew, FailingNewArrayOperatorThrowsAnExceptionWhenUsingStdCppNewWithoutOverride)
{
CHECK_THROWS(std::bad_alloc, some_memory = new char[10]);
}
TEST(OutOfMemoryTestsForOperatorNew, FailingNewOperatorReturnsNullWithoutOverride)
{
POINTERS_EQUAL(NULLPTR, new (std::nothrow) char);
}
TEST(OutOfMemoryTestsForOperatorNew, FailingNewArrayOperatorReturnsNullWithoutOverride)
{
POINTERS_EQUAL(NULLPTR, new (std::nothrow) char[10]);
}
#else
TEST(OutOfMemoryTestsForOperatorNew, FailingNewOperatorReturnsNullWithoutOverride)
{
POINTERS_EQUAL(NULLPTR, new char);
}
TEST(OutOfMemoryTestsForOperatorNew, FailingNewArrayOperatorReturnsNullWithoutOverride)
{
POINTERS_EQUAL(NULLPTR, new char[10]);
}
#endif
#endif

View file

@ -0,0 +1,198 @@
/*
* 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/TestOutput.h"
#include "CppUTest/TestTestingFixture.h"
#define GENERIC_PLUGIN "GenericPlugin"
#define GENERIC_PLUGIN2 "GenericPlugin2"
#define GENERIC_PLUGIN3 "GenericPlugin3"
static int sequenceNumber;
class DummyPlugin: public TestPlugin
{
public:
DummyPlugin(const SimpleString& name) :
TestPlugin(name), preAction(0), preActionSequence(0), postAction(0), postActionSequence(0)
{
}
virtual void preTestAction(UtestShell&, TestResult&) _override
{
preAction++;
preActionSequence = sequenceNumber++;
}
virtual void postTestAction(UtestShell&, TestResult&) _override
{
postAction++;
postActionSequence = sequenceNumber++;
}
int preAction;
int preActionSequence;
int postAction;
int postActionSequence;
};
class DummyPluginWhichAcceptsParameters: public DummyPlugin
{
public:
DummyPluginWhichAcceptsParameters(const SimpleString& name) :
DummyPlugin(name)
{
}
virtual bool parseArguments(int ac, const char *const *av, int index) _override
{
SimpleString argument (av[index]);
if (argument == "-paccept")
return true;
return TestPlugin::parseArguments(ac, av, index);
}
};
TEST_GROUP(PluginTest)
{
DummyPlugin* firstPlugin;
DummyPluginWhichAcceptsParameters* secondPlugin;
DummyPlugin* thirdPlugin;
TestTestingFixture *genFixture;
TestRegistry* registry;
void setup() _override
{
firstPlugin = new DummyPlugin(GENERIC_PLUGIN);
secondPlugin = new DummyPluginWhichAcceptsParameters(GENERIC_PLUGIN2);
thirdPlugin = new DummyPlugin(GENERIC_PLUGIN3);
genFixture = new TestTestingFixture;
registry = genFixture->getRegistry();
registry->installPlugin(firstPlugin);
sequenceNumber = 1;
}
void teardown() _override
{
delete firstPlugin;
delete secondPlugin;
delete thirdPlugin;
delete genFixture;
}
};
#define GENERIC_PLUGIN "GenericPlugin"
TEST(PluginTest, PluginHasName)
{
STRCMP_EQUAL(GENERIC_PLUGIN, firstPlugin->getName().asCharString());
}
TEST(PluginTest, InstallPlugin)
{
CHECK_EQUAL(firstPlugin, registry->getFirstPlugin());
CHECK_EQUAL(firstPlugin, registry->getPluginByName(GENERIC_PLUGIN));
LONGS_EQUAL(1, registry->countPlugins());
}
TEST(PluginTest, InstallMultiplePlugins)
{
registry->installPlugin(thirdPlugin);
CHECK_EQUAL(firstPlugin, registry->getPluginByName(GENERIC_PLUGIN));
CHECK_EQUAL(thirdPlugin, registry->getPluginByName(GENERIC_PLUGIN3));
POINTERS_EQUAL(NULLPTR, registry->getPluginByName("I do not exist"));
}
TEST(PluginTest, ActionsAllRun)
{
genFixture->runAllTests();
genFixture->runAllTests();
CHECK_EQUAL(2, firstPlugin->preAction);
CHECK_EQUAL(2, firstPlugin->postAction);
}
TEST(PluginTest, Sequence)
{
registry->installPlugin(thirdPlugin);
genFixture->runAllTests();
CHECK_EQUAL(1, thirdPlugin->preActionSequence);
CHECK_EQUAL(2, firstPlugin->preActionSequence);
CHECK_EQUAL(3, firstPlugin->postActionSequence);
CHECK_EQUAL(4, thirdPlugin->postActionSequence);
LONGS_EQUAL(2, registry->countPlugins());
}
TEST(PluginTest, RemovePluginByName)
{
registry->installPlugin(secondPlugin);
registry->installPlugin(thirdPlugin);
LONGS_EQUAL(3, registry->countPlugins());
registry->removePluginByName(GENERIC_PLUGIN2);
LONGS_EQUAL(2, registry->countPlugins());
}
struct DefaultPlugin : public TestPlugin
{
DefaultPlugin() : TestPlugin("default") {}
};
TEST(PluginTest, DefaultPostTestActionDoesntDoAnything)
{
DefaultPlugin defaultPlugin;
registry->installPlugin(&defaultPlugin);
genFixture->runAllTests();
}
TEST(PluginTest, DisablesPluginsDontRun)
{
registry->installPlugin(thirdPlugin);
thirdPlugin->disable();
genFixture->runAllTests();
CHECK(!thirdPlugin->isEnabled());
thirdPlugin->enable();
genFixture->runAllTests();
CHECK_EQUAL(2, firstPlugin->preAction);
CHECK_EQUAL(1, thirdPlugin->preAction);
CHECK(thirdPlugin->isEnabled());
}
TEST(PluginTest, ParseArgumentsForUnknownArgumentsFails)
{
registry->installPlugin(secondPlugin);
const char *cmd_line[] = {"nonsense", "andmorenonsense"};
CHECK(registry->getFirstPlugin()->parseAllArguments(2, const_cast<char**>(cmd_line), 0) == false); /* cover non-const wrapper, too */
}
TEST(PluginTest, ParseArgumentsContinuesAndSucceedsWhenAPluginCanParse)
{
registry->installPlugin(secondPlugin);
const char *cmd_line[] = {"-paccept", "andmorenonsense"};
CHECK(registry->getFirstPlugin()->parseAllArguments(2, const_cast<char**>(cmd_line), 0)); /* cover non-const wrapper, too */
}

View file

@ -0,0 +1,33 @@
/*
* 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"
TEST_GROUP(PreprocessorTest)
{
};

View file

@ -0,0 +1,171 @@
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/TestPlugin.h"
static void orig_func1()
{
}
static void stub_func1()
{
}
static void orig_func2()
{
}
static void stub_func2()
{
}
static void (*fp1)();
static void (*fp2)();
TEST_GROUP(SetPointerPluginTest)
{
SetPointerPlugin* plugin_;
TestRegistry* myRegistry_;
StringBufferTestOutput* output_;
TestResult* result_;
void setup() _override
{
myRegistry_ = new TestRegistry();
plugin_ = new SetPointerPlugin("TestSetPlugin");
myRegistry_->setCurrentRegistry(myRegistry_);
myRegistry_->installPlugin(plugin_);
output_ = new StringBufferTestOutput();
result_ = new TestResult(*output_);
}
void teardown() _override
{
myRegistry_->setCurrentRegistry(NULLPTR);
delete myRegistry_;
delete plugin_;
delete output_;
delete result_;
}
};
class FunctionPointerUtest : public Utest
{
public:
void setup() _override
{
UT_PTR_SET(fp1, stub_func1);
UT_PTR_SET(fp2, stub_func2);
UT_PTR_SET(fp2, stub_func2);
}
void testBody() _override
{
CHECK(fp1 == stub_func1);
CHECK(fp2 == stub_func2);
}
};
class FunctionPointerUtestShell: public UtestShell
{
public:
virtual Utest* createTest() _override
{
return new FunctionPointerUtest();
}
};
TEST(SetPointerPluginTest, installTwoFunctionPointer)
{
FunctionPointerUtestShell *tst = new FunctionPointerUtestShell();
fp1 = orig_func1;
fp2 = orig_func2;
myRegistry_->addTest(tst);
myRegistry_->runAllTests(*result_);
CHECK(fp1 == orig_func1);
CHECK(fp2 == orig_func2);
LONGS_EQUAL(0, result_->getFailureCount());
LONGS_EQUAL(2, result_->getCheckCount());
delete tst;
}
class MaxFunctionPointerUtest : public Utest
{
public:
int numOfFpSets;
MaxFunctionPointerUtest(int num) :
numOfFpSets(num)
{
}
void setup() _override
{
for (int i = 0; i < numOfFpSets; ++i)
{
UT_PTR_SET(fp1, stub_func1);
}
}
};
class MaxFunctionPointerUtestShell: public UtestShell
{
public:
int numOfFpSets;
MaxFunctionPointerUtestShell(int num) :
numOfFpSets(num)
{
}
virtual Utest* createTest() _override
{
return new MaxFunctionPointerUtest(numOfFpSets);
}
};
TEST(SetPointerPluginTest, installTooMuchFunctionPointer)
{
MaxFunctionPointerUtestShell *tst = new MaxFunctionPointerUtestShell(SetPointerPlugin::MAX_SET + 1);
myRegistry_->addTest(tst);
myRegistry_->runAllTests(*result_);
LONGS_EQUAL(1, result_->getFailureCount());
delete tst;
}
static double orig_double = 3.0;
static double* orig_double_ptr = &orig_double;
static double stub_double = 4.0;
class SetDoublePointerUtest : public Utest
{
public:
void setup() _override
{
UT_PTR_SET(orig_double_ptr, &stub_double);
}
void testBody() _override
{
CHECK(orig_double_ptr == &stub_double);
}
};
class SetDoublePointerUtestShell: public UtestShell
{
public:
Utest * createTest() _override
{
return new SetDoublePointerUtest();
}
};
TEST(SetPointerPluginTest, doublePointer)
{
SetDoublePointerUtestShell *doubletst = new SetDoublePointerUtestShell();
myRegistry_->addTest(doubletst);
myRegistry_->runAllTests(*result_);
CHECK(orig_double_ptr == &orig_double);
LONGS_EQUAL(1, result_->getCheckCount());
delete doubletst;
}

View file

@ -0,0 +1,104 @@
/*
* 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"
#include "CppUTest/PlatformSpecificFunctions.h"
static int mutexCreateCount = 0;
static int mutexLockCount = 0;
static int mutexUnlockCount = 0;
static int mutexDestroyCount = 0;
static PlatformSpecificMutex StubMutexCreate(void)
{
mutexCreateCount++;
return NULLPTR;
}
static void StubMutexLock(PlatformSpecificMutex)
{
mutexLockCount++;
}
static void StubMutexUnlock(PlatformSpecificMutex)
{
mutexUnlockCount++;
}
static void StubMutexDestroy(PlatformSpecificMutex)
{
mutexDestroyCount++;
}
TEST_GROUP(SimpleMutexTest)
{
void setup() _override
{
UT_PTR_SET(PlatformSpecificMutexCreate, StubMutexCreate);
UT_PTR_SET(PlatformSpecificMutexLock, StubMutexLock);
UT_PTR_SET(PlatformSpecificMutexUnlock, StubMutexUnlock);
UT_PTR_SET(PlatformSpecificMutexDestroy, StubMutexDestroy);
mutexCreateCount = 0;
mutexDestroyCount = 0;
mutexLockCount = 0;
mutexUnlockCount = 0;
}
void teardown() _override
{
}
};
TEST(SimpleMutexTest, CreateAndDestroy)
{
{
SimpleMutex mtx;
}
CHECK_EQUAL(1, mutexCreateCount);
CHECK_EQUAL(1, mutexDestroyCount);
CHECK_EQUAL(0, mutexLockCount);
CHECK_EQUAL(0, mutexUnlockCount);
}
TEST(SimpleMutexTest, LockUnlockTest)
{
{
SimpleMutex mtx;
mtx.Lock();
mtx.Unlock();
}
CHECK_EQUAL(1, mutexCreateCount);
CHECK_EQUAL(1, mutexLockCount);
CHECK_EQUAL(1, mutexUnlockCount);
CHECK_EQUAL(1, mutexDestroyCount);
}

View file

@ -0,0 +1,389 @@
/*
* 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"
#include "CppUTest/TestTestingFixture.h"
class TestFunctionWithCache : public ExecFunction
{
public:
void (*testFunction)(SimpleStringInternalCache*, size_t);
SimpleStringInternalCache* parameter;
size_t allocationSize;
void exec() _override
{
testFunction(parameter, allocationSize);
}
};
TEST_GROUP(SimpleStringInternalCache)
{
SimpleStringInternalCache cache;
MemoryAccountant accountant;
MemoryLeakAllocator* defaultAllocator;
AccountingTestMemoryAllocator* allocator;
TestFunctionWithCache testFunction;
TestTestingFixture fixture;
void setup() _override
{
fixture.setTestFunction(&testFunction);
testFunction.parameter = &cache;
defaultAllocator = new MemoryLeakAllocator(defaultMallocAllocator());
allocator = new AccountingTestMemoryAllocator(accountant, defaultAllocator);
cache.setAllocator(defaultAllocator);
}
void teardown() _override
{
cache.clearAllIncludingCurrentlyUsedMemory();
accountant.clear();
delete allocator;
delete defaultAllocator;
}
void createCacheForSize(size_t size, size_t amount)
{
for (size_t i = 0; i < amount; i++) {
char* memory = cache.alloc(size);
cache.dealloc(memory, size);
}
}
};
TEST(SimpleStringInternalCache, cacheHitWithOneEntry)
{
createCacheForSize(10, 1);
cache.setAllocator(allocator);
char* mem = cache.alloc(10);
mem[0] = 'B';
mem[3] = 'A';
mem[9] = 'S';
cache.setAllocator(allocator->originalAllocator());
LONGS_EQUAL(0, accountant.totalAllocationsOfSize(10));
CHECK(!cache.hasFreeBlocksOfSize(10));
cache.setAllocator(allocator);
}
TEST(SimpleStringInternalCache, cacheHitWithTwoEntries)
{
createCacheForSize(10, 2);
cache.setAllocator(allocator);
cache.alloc(10);
cache.alloc(10);
cache.setAllocator(allocator->originalAllocator());
LONGS_EQUAL(0, accountant.totalAllocationsOfSize(10));
CHECK(!cache.hasFreeBlocksOfSize(10));
cache.setAllocator(allocator);
}
TEST(SimpleStringInternalCache, allocatingMoreThanCacheAvailable)
{
createCacheForSize(10, 1);
cache.setAllocator(allocator);
cache.alloc(10);
cache.alloc(10);
cache.setAllocator(allocator->originalAllocator());
LONGS_EQUAL(1, accountant.totalAllocationsOfSize(32));
CHECK(!cache.hasFreeBlocksOfSize(10));
cache.setAllocator(allocator);
}
TEST(SimpleStringInternalCache, allocationWillReuseTheAllocatedBlocks)
{
cache.setAllocator(allocator);
char* mem = cache.alloc(10);
cache.dealloc(mem, 10);
mem = cache.alloc(10);
cache.dealloc(mem, 10);
LONGS_EQUAL(1, accountant.totalAllocationsOfSize(32));
}
TEST(SimpleStringInternalCache, multipleDifferentSizeAllocationsAndDeallocations)
{
cache.setAllocator(allocator);
char* mem10 = cache.alloc(10);
char* mem11 = cache.alloc(11);
char* mem100 = cache.alloc(100);
cache.dealloc(mem100, 100);
char* mem101 = cache.alloc(101);
char* mem102 = cache.alloc(102);
char* mem103 = cache.alloc(103);
cache.dealloc(mem101, 102);
cache.dealloc(mem102, 103);
cache.dealloc(mem103, 104);
cache.alloc(105);
cache.alloc(106);
cache.alloc(107);
cache.dealloc(mem10, 10);
cache.dealloc(mem11, 11);
LONGS_EQUAL(2, accountant.totalAllocationsOfSize(32));
LONGS_EQUAL(3, accountant.totalAllocationsOfSize(128));
}
TEST(SimpleStringInternalCache, deallocOfCachedMemoryWillNotDealloc)
{
cache.setAllocator(allocator);
char* mem = cache.alloc(10);
cache.dealloc(mem, 10);
LONGS_EQUAL(0, accountant.totalDeallocationsOfSize(32));
}
TEST(SimpleStringInternalCache, clearCacheWillRemoveAllCachedMemoryButNotAllUsedMemory)
{
cache.setAllocator(allocator);
char* mem = cache.alloc(10);
cache.dealloc(mem, 10);
mem = cache.alloc(60);
cache.clearCache();
LONGS_EQUAL(1, accountant.totalDeallocationsOfSize(32));
LONGS_EQUAL(0, accountant.totalDeallocationsOfSize(64));
}
TEST(SimpleStringInternalCache, clearAllIncludingCurrentlyUsedMemory)
{
cache.setAllocator(allocator);
cache.alloc(60);
cache.clearAllIncludingCurrentlyUsedMemory();
LONGS_EQUAL(1, accountant.totalDeallocationsOfSize(64));
}
TEST(SimpleStringInternalCache, allocatingLargerStringThanCached)
{
cache.setAllocator(allocator);
char* mem = cache.alloc(1234);
cache.dealloc(mem, 1234);
LONGS_EQUAL(1, accountant.totalAllocationsOfSize(1234));
LONGS_EQUAL(1, accountant.totalDeallocationsOfSize(1234));
}
TEST(SimpleStringInternalCache, allocatingMultipleLargerStringThanCached)
{
cache.setAllocator(allocator);
char* mem = cache.alloc(1234);
char* mem2 = cache.alloc(1234);
char* mem3 = cache.alloc(1234);
cache.dealloc(mem2, 1234);
cache.dealloc(mem, 1234);
cache.dealloc(mem3, 1234);
LONGS_EQUAL(3, accountant.totalAllocationsOfSize(1234));
LONGS_EQUAL(3, accountant.totalDeallocationsOfSize(1234));
}
TEST(SimpleStringInternalCache, clearAllIncludingCurrentlyUsedMemoryAlsoReleasesLargeNonCachesMemory)
{
cache.setAllocator(allocator);
cache.alloc(1234);
cache.alloc(1234);
cache.alloc(1234);
cache.clearAllIncludingCurrentlyUsedMemory();
LONGS_EQUAL(3, accountant.totalAllocationsOfSize(1234));
LONGS_EQUAL(3, accountant.totalDeallocationsOfSize(1234));
}
static void _deallocatingStringMemoryThatWasntAllocatedWithCache(SimpleStringInternalCache* cache, size_t allocationSize)
{
char* mem = defaultMallocAllocator()->alloc_memory(allocationSize, __FILE__, __LINE__);
mem[0] = 'B';
mem[1] = 'a';
mem[2] = 's';
mem[3] = '\0';
cache->dealloc(mem, allocationSize);
defaultMallocAllocator()->free_memory(mem, allocationSize, __FILE__, __LINE__);
}
TEST(SimpleStringInternalCache, deallocatingMemoryThatWasntAllocatedWhileCacheWasInPlaceProducesWarning)
{
testFunction.testFunction = _deallocatingStringMemoryThatWasntAllocatedWithCache;
testFunction.allocationSize = 123;
cache.setAllocator(allocator);
fixture.runAllTests();
fixture.assertPrintContains("\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: \"Bas\"\n");
}
static void _deallocatingStringMemoryTwiceThatWasntAllocatedWithCache(SimpleStringInternalCache* cache, size_t allocationSize)
{
char* mem = defaultMallocAllocator()->alloc_memory(allocationSize, __FILE__, __LINE__);
mem[0] = '\0';
cache->dealloc(mem, allocationSize);
cache->dealloc(mem, allocationSize);
defaultMallocAllocator()->free_memory(mem, allocationSize, __FILE__, __LINE__);
}
TEST(SimpleStringInternalCache, deallocatingMemoryThatWasntAllocatedWhileCacheWasInPlaceProducesWarningButOnlyOnce)
{
testFunction.testFunction = _deallocatingStringMemoryTwiceThatWasntAllocatedWithCache;
testFunction.allocationSize = 123;
cache.setAllocator(allocator);
fixture.runAllTests();
LONGS_EQUAL(1, fixture.getOutput().count("WARNING"));
}
TEST(SimpleStringInternalCache, deallocatingLargeMemoryThatWasntAllocatedWhileCacheWasInPlaceProducesWarning)
{
testFunction.testFunction = _deallocatingStringMemoryThatWasntAllocatedWithCache;
testFunction.allocationSize = 12345;
cache.setAllocator(allocator);
fixture.runAllTests();
fixture.assertPrintContains("\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: \"Bas\"\n");
}
TEST(SimpleStringInternalCache, deallocatingLargeMemoryThatWasntAllocatedWhileCacheWasInPlaceProducesWarningButOnlyOnce)
{
testFunction.testFunction = _deallocatingStringMemoryTwiceThatWasntAllocatedWithCache;
testFunction.allocationSize = 12345;
cache.setAllocator(allocator);
fixture.runAllTests();
LONGS_EQUAL(1, fixture.getOutput().count("WARNING"));
}
TEST_GROUP(SimpleStringCacheAllocator)
{
SimpleStringCacheAllocator* allocator;
SimpleStringInternalCache cache;
MemoryAccountant accountant;
AccountingTestMemoryAllocator* accountingAllocator;
void setup() _override
{
accountingAllocator = new AccountingTestMemoryAllocator(accountant, defaultMallocAllocator());
allocator = new SimpleStringCacheAllocator(cache, accountingAllocator);
}
void teardown() _override
{
cache.clearCache();
delete allocator;
delete accountingAllocator;
}
};
TEST(SimpleStringCacheAllocator, allocationIsCached)
{
char* mem = allocator->alloc_memory(10, __FILE__, __LINE__);
allocator->free_memory(mem, 10, __FILE__, __LINE__);
size_t totalAllocations = accountant.totalAllocations();
size_t totalDeallocations = accountant.totalDeallocations();
mem = allocator->alloc_memory(10, __FILE__, __LINE__);
allocator->free_memory(mem, 10, __FILE__, __LINE__);
LONGS_EQUAL(totalAllocations, accountant.totalAllocations());
LONGS_EQUAL(totalDeallocations, accountant.totalDeallocations());
}
TEST(SimpleStringCacheAllocator, originalAllocator)
{
POINTERS_EQUAL(defaultMallocAllocator(), allocator->actualAllocator());
STRCMP_EQUAL(defaultMallocAllocator()->alloc_name(), allocator->alloc_name());
STRCMP_EQUAL(defaultMallocAllocator()->free_name(), allocator->free_name());
}
TEST(SimpleStringCacheAllocator, name)
{
STRCMP_EQUAL("SimpleStringCacheAllocator", allocator->name());
}
TEST_GROUP(GlobalSimpleStringCache)
{
};
TEST(GlobalSimpleStringCache, installsAndRemovedCache)
{
TestMemoryAllocator* originalStringAllocator = SimpleString::getStringAllocator();
{
GlobalSimpleStringCache cache;
STRCMP_EQUAL("SimpleStringCacheAllocator", SimpleString::getStringAllocator()->name());
POINTERS_EQUAL(cache.getAllocator(), SimpleString::getStringAllocator());
}
POINTERS_EQUAL(originalStringAllocator, SimpleString::getStringAllocator());
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,226 @@
#include "CppUTest/TestHarness.h"
#include "CppUTest/TeamCityTestOutput.h"
#include "CppUTest/PlatformSpecificFunctions.h"
class TeamCityOutputToBuffer : public TeamCityTestOutput
{
public:
explicit TeamCityOutputToBuffer()
{
}
virtual ~TeamCityOutputToBuffer() _destructor_override
{
}
void printBuffer(const char* s) _override
{
output += s;
}
void flush() _override
{
output = "";
}
const SimpleString& getOutput()
{
return output;
}
private:
SimpleString output;
};
static long millisTime;
extern "C" {
static long MockGetPlatformSpecificTimeInMillis()
{
return millisTime;
}
}
TEST_GROUP(TeamCityOutputTest)
{
TeamCityTestOutput* tcout;
TeamCityOutputToBuffer* mock;
UtestShell* tst;
TestFailure *f, *f2, *f3;
TestResult* result;
void setup() _override
{
mock = new TeamCityOutputToBuffer();
tcout = mock;
tst = new UtestShell("group", "test", "file", 10);
f = new TestFailure(tst, "failfile", 20, "failure message");
f2 = new TestFailure(tst, "file", 20, "message");
f3 = new TestFailure(tst, "file", 30, "apos' pipe| [brackets]\r\nCRLF");
result = new TestResult(*mock);
result->setTotalExecutionTime(10);
millisTime = 0;
UT_PTR_SET(GetPlatformSpecificTimeInMillis, MockGetPlatformSpecificTimeInMillis);
}
void teardown() _override
{
delete tcout;
delete tst;
delete f;
delete f2;
delete f3;
delete result;
}
};
TEST(TeamCityOutputTest, PrintGroupStarted)
{
result->currentGroupStarted(tst);
STRCMP_EQUAL("##teamcity[testSuiteStarted name='group']\n", mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, PrintGroupStartedAndEnded)
{
const char* expected = "##teamcity[testSuiteStarted name='group']\n"
"##teamcity[testSuiteFinished name='group']\n";
result->currentGroupStarted(tst);
result->currentGroupEnded(tst);
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, PrintGroupEndedButNotStarted)
{
result->currentGroupEnded(tst);
STRCMP_EQUAL("", mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, PrintTestStarted)
{
tcout->printCurrentTestStarted(*tst);
STRCMP_EQUAL("##teamcity[testStarted name='test']\n", mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, PrintTestStartedAndEnded)
{
result->currentTestStarted(tst);
millisTime = 42;
result->currentTestEnded(tst);
STRCMP_EQUAL("##teamcity[testStarted name='test']\n##teamcity[testFinished name='test' duration='42']\n",
mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, PrintTestEndedButNotStarted)
{
result->currentTestEnded(tst);
STRCMP_EQUAL("", mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, PrintTestIgnored)
{
const char* expected =
"##teamcity[testStarted name='test']\n"
"##teamcity[testIgnored name='test']\n"
"##teamcity[testFinished name='test' duration='41']\n";
IgnoredUtestShell* itst = new IgnoredUtestShell("group", "test", "file", 10);
result->currentTestStarted(itst);
millisTime = 41;
result->currentTestEnded(itst);
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
delete itst;
}
TEST(TeamCityOutputTest, PrintWithFailureInSameFile)
{
tcout->printFailure(*f2);
const char* expected =
"##teamcity[testFailed name='test' message='file:20' "
"details='message']\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, PrintWithEscapedCharacters)
{
tcout->printFailure(*f3);
const char* expected =
"##teamcity[testFailed name='test' message='file:30' "
"details='apos|' pipe|| |[brackets|]"
"|r|nCRLF']\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, PrintFailureWithFailInDifferentFile)
{
tcout->printFailure(*f);
const char* expected =
"##teamcity[testFailed name='test' message='TEST failed (file:10): failfile:20' "
"details='failure message']\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, TestGroupEscaped_Start)
{
tst->setGroupName("'[]\n\r");
result->currentGroupStarted(tst);
const char* expected =
"##teamcity[testSuiteStarted name='|'|[|]|n|r']\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, TestGroupEscaped_End)
{
tst->setGroupName("'[]\n\r");
result->currentGroupStarted(tst);
result->currentGroupEnded(tst);
const char* expected =
"##teamcity[testSuiteStarted name='|'|[|]|n|r']\n"
"##teamcity[testSuiteFinished name='|'|[|]|n|r']\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, TestNameEscaped_Start)
{
tst->setTestName("'[]\n\r");
result->currentTestStarted(tst);
const char* expected =
"##teamcity[testStarted name='|'|[|]|n|r']\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, TestNameEscaped_End)
{
tst->setTestName("'[]\n\r");
result->currentTestStarted(tst);
result->currentTestEnded(tst);
const char* expected =
"##teamcity[testStarted name='|'|[|]|n|r']\n"
"##teamcity[testFinished name='|'|[|]|n|r' duration='0']\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, TestNameEscaped_Ignore)
{
IgnoredUtestShell itst("group", "'[]\n\r", "file", 10);
result->currentTestStarted(&itst);
const char* expected =
"##teamcity[testStarted name='|'|[|]|n|r']\n"
"##teamcity[testIgnored name='|'|[|]|n|r']\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TeamCityOutputTest, TestNameEscaped_Fail)
{
tst->setTestName("'[]\n\r");
TestFailure fail(tst, "failfile", 20, "failure message");
tcout->printFailure(fail);
const char* expected =
"##teamcity[testFailed name='|'|[|]|n|r' message='TEST failed (file:10): failfile:20' "
"details='failure message']\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
/* Todo:
* -Detect when running in TeamCity and switch output to -o teamcity automatically
*/

View file

@ -0,0 +1,117 @@
/*
* 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"
namespace
{
const int failLineNumber = 2;
const char* failFileName = "fail.cpp";
}
static double zero = 0.0;
static double one = 1.0;
static double not_a_number = zero / zero;
static double infinity = one / zero;
extern "C" {
static int IsNanForSystemsWithoutNan(double d) { return ((long)not_a_number == (long)d); }
static int IsInfForSystemsWithoutInf(double d) { return ((long)infinity == (long)d); }
}
TEST_GROUP(TestFailureNanAndInf)
{
UtestShell* test;
void setup() _override
{
test = new UtestShell("groupname", "testname", failFileName, failLineNumber-1);
if(PlatformSpecificIsNan(not_a_number) == false)
{
not_a_number = -1.0;
UT_PTR_SET(PlatformSpecificIsNan, IsNanForSystemsWithoutNan);
}
if(PlatformSpecificIsInf(infinity) == false)
{
infinity = -2.0;
UT_PTR_SET(PlatformSpecificIsInf, IsInfForSystemsWithoutInf);
}
}
void teardown() _override
{
delete test;
}
};
#define FAILURE_EQUAL(a, b) STRCMP_EQUAL_LOCATION(a, b.getMessage().asCharString(), "", __FILE__, __LINE__)
TEST(TestFailureNanAndInf, DoublesEqualExpectedIsNaN)
{
DoublesEqualFailure f(test, failFileName, failLineNumber, not_a_number, 2.0, 3.0, "");
FAILURE_EQUAL("expected <Nan - Not a number>\n"
"\tbut was <2> threshold used was <3>\n"
"\tCannot make comparisons with Nan", f);
}
TEST(TestFailureNanAndInf, DoublesEqualActualIsNaN)
{
DoublesEqualFailure f(test, failFileName, failLineNumber, 1.0, not_a_number, 3.0, "");
FAILURE_EQUAL("expected <1>\n"
"\tbut was <Nan - Not a number> threshold used was <3>\n"
"\tCannot make comparisons with Nan", f);
}
TEST(TestFailureNanAndInf, DoublesEqualThresholdIsNaN)
{
DoublesEqualFailure f(test, failFileName, failLineNumber, 1.0, 2.0, not_a_number, "");
FAILURE_EQUAL("expected <1>\n"
"\tbut was <2> threshold used was <Nan - Not a number>\n"
"\tCannot make comparisons with Nan", f);
}
TEST(TestFailureNanAndInf, DoublesEqualExpectedIsInf)
{
DoublesEqualFailure f(test, failFileName, failLineNumber, infinity, 2.0, 3.0, "");
FAILURE_EQUAL("expected <Inf - Infinity>\n"
"\tbut was <2> threshold used was <3>", f);
}
TEST(TestFailureNanAndInf, DoublesEqualActualIsInf)
{
DoublesEqualFailure f(test, failFileName, failLineNumber, 1.0, infinity, 3.0, "");
FAILURE_EQUAL("expected <1>\n"
"\tbut was <Inf - Infinity> threshold used was <3>", f);
}
TEST(TestFailureNanAndInf, DoublesEqualThresholdIsInf)
{
DoublesEqualFailure f(test, failFileName, failLineNumber, 1.0, not_a_number, infinity, "");
FAILURE_EQUAL("expected <1>\n"
"\tbut was <Nan - Not a number> threshold used was <Inf - Infinity>\n"
"\tCannot make comparisons with Nan", f);
}

View file

@ -0,0 +1,428 @@
/*
* 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"
namespace
{
const int failLineNumber = 2;
const char* failFileName = "fail.cpp";
}
TEST_GROUP(TestFailure)
{
UtestShell* test;
void setup() _override
{
test = new UtestShell("groupname", "testname", failFileName, failLineNumber-1);
}
void teardown() _override
{
delete test;
}
};
#define FAILURE_EQUAL(a, b) STRCMP_EQUAL_LOCATION(a, b.getMessage().asCharString(), "", __FILE__, __LINE__)
TEST(TestFailure, CreateFailure)
{
TestFailure f1(test, failFileName, failLineNumber, "the failure message");
TestFailure f2(test, "the failure message");
TestFailure f3(test, failFileName, failLineNumber);
}
TEST(TestFailure, GetTestFileAndLineFromFailure)
{
TestFailure f1(test, failFileName, failLineNumber, "the failure message");
STRCMP_EQUAL(failFileName, f1.getTestFileName().asCharString());
LONGS_EQUAL(1, f1.getTestLineNumber());
}
TEST(TestFailure, EqualsFailureWithText)
{
EqualsFailure f(test, failFileName, failLineNumber, "expected", "actual", "text");
FAILURE_EQUAL("Message: text\n"
"\texpected <expected>\n\tbut was <actual>", f);
}
TEST(TestFailure, EqualsFailure)
{
EqualsFailure f(test, failFileName, failLineNumber, "expected", "actual", "");
FAILURE_EQUAL("expected <expected>\n\tbut was <actual>", f);
}
TEST(TestFailure, EqualsFailureWithNullAsActual)
{
EqualsFailure f(test, failFileName, failLineNumber, "expected", NULLPTR, "");
FAILURE_EQUAL("expected <expected>\n\tbut was <(null)>", f);
}
TEST(TestFailure, EqualsFailureWithNullAsExpected)
{
EqualsFailure f(test, failFileName, failLineNumber, NULLPTR, "actual", "");
FAILURE_EQUAL("expected <(null)>\n\tbut was <actual>", f);
}
TEST(TestFailure, CheckEqualFailureWithText)
{
CheckEqualFailure f(test, failFileName, failLineNumber, "expected", "actual", "text");
FAILURE_EQUAL("Message: text\n"
"\texpected <expected>\n"
"\tbut was <actual>\n"
"\tdifference starts at position 0 at: < actual >\n"
"\t ^", f);
}
TEST(TestFailure, CheckEqualFailure)
{
CheckEqualFailure f(test, failFileName, failLineNumber, "expected", "actual", "");
FAILURE_EQUAL("expected <expected>\n"
"\tbut was <actual>\n"
"\tdifference starts at position 0 at: < actual >\n"
"\t ^", f);
}
TEST(TestFailure, CheckFailure)
{
CheckFailure f(test, failFileName, failLineNumber, "CHECK", "chk");
FAILURE_EQUAL("CHECK(chk) failed", f);
}
TEST(TestFailure, CheckFailureWithText)
{
CheckFailure f(test, failFileName, failLineNumber, "CHECK", "chk", "text");
FAILURE_EQUAL("Message: text\n"
"\tCHECK(chk) failed", f);
}
TEST(TestFailure, FailFailure)
{
FailFailure f(test, failFileName, failLineNumber, "chk");
FAILURE_EQUAL("chk", f);
}
TEST(TestFailure, LongsEqualFailureWithText)
{
LongsEqualFailure f(test, failFileName, failLineNumber, 1, 2, "text");
FAILURE_EQUAL("Message: text\n"
"\texpected <1 (0x1)>\n\tbut was <2 (0x2)>", f);
}
TEST(TestFailure, LongsEqualFailure)
{
LongsEqualFailure f(test, failFileName, failLineNumber, 1, 2, "");
FAILURE_EQUAL("expected <1 (0x1)>\n\tbut was <2 (0x2)>", f);
}
TEST(TestFailure, LongLongsEqualFailure)
{
#ifdef CPPUTEST_USE_LONG_LONG
LongLongsEqualFailure f(test, failFileName, failLineNumber, 1, 2, "");
FAILURE_EQUAL("expected <1 (0x1)>\n\tbut was <2 (0x2)>", f);
#else
cpputest_longlong dummy_longlong;
LongLongsEqualFailure f(test, failFileName, failLineNumber, dummy_longlong, dummy_longlong, "");
FAILURE_EQUAL("expected <<longlong_unsupported> >\n\tbut was <<longlong_unsupported> >", f);
#endif
}
TEST(TestFailure, UnsignedLongLongsEqualFailure)
{
#ifdef CPPUTEST_USE_LONG_LONG
UnsignedLongLongsEqualFailure f(test, failFileName, failLineNumber, 1, 2, "");
FAILURE_EQUAL("expected <1 (0x1)>\n\tbut was <2 (0x2)>", f);
#else
cpputest_ulonglong dummy_ulonglong;
UnsignedLongLongsEqualFailure f(test, failFileName, failLineNumber, dummy_ulonglong, dummy_ulonglong, "");
FAILURE_EQUAL("expected <<ulonglong_unsupported> >\n\tbut was <<ulonglong_unsupported> >", f);
#endif
}
TEST(TestFailure, SignedBytesEqualFailure)
{
SignedBytesEqualFailure f(test, failFileName, failLineNumber, (signed char)-1, (signed char)2, "");
FAILURE_EQUAL("expected <-1 (0xff)>\n\tbut was < 2 (0x2)>", f);
}
TEST(TestFailure, StringsEqualFailureWithText)
{
StringEqualFailure f(test, failFileName, failLineNumber, "abc", "abd", "text");
FAILURE_EQUAL("Message: text\n"
"\texpected <abc>\n"
"\tbut was <abd>\n"
"\tdifference starts at position 2 at: < abd >\n"
"\t ^", f);
}
TEST(TestFailure, StringsEqualFailure)
{
StringEqualFailure f(test, failFileName, failLineNumber, "abc", "abd", "");
FAILURE_EQUAL("expected <abc>\n"
"\tbut was <abd>\n"
"\tdifference starts at position 2 at: < abd >\n"
"\t ^", f);
}
TEST(TestFailure, StringsEqualFailureAtTheEnd)
{
StringEqualFailure f(test, failFileName, failLineNumber, "abc", "ab", "");
FAILURE_EQUAL("expected <abc>\n"
"\tbut was <ab>\n"
"\tdifference starts at position 2 at: < ab >\n"
"\t ^", f);
}
TEST(TestFailure, StringsEqualFailureNewVariantAtTheEnd)
{
StringEqualFailure f(test, failFileName, failLineNumber, "EndOfALongerString", "EndOfALongerStrinG", "");
FAILURE_EQUAL("expected <EndOfALongerString>\n"
"\tbut was <EndOfALongerStrinG>\n"
"\tdifference starts at position 17 at: <ongerStrinG >\n"
"\t ^", f);
}
TEST(TestFailure, StringsEqualFailureWithNewLinesAndTabs)
{
StringEqualFailure f(test, failFileName, failLineNumber,
"StringWith\t\nDifferentString",
"StringWith\t\ndifferentString", "");
FAILURE_EQUAL("expected <StringWith\\t\\nDifferentString>\n"
"\tbut was <StringWith\\t\\ndifferentString>\n"
"\tdifference starts at position 12 at: <ngWith\\t\\ndifferentS>\n"
"\t ^", f);
}
TEST(TestFailure, StringsEqualFailureInTheMiddle)
{
StringEqualFailure f(test, failFileName, failLineNumber, "aa", "ab", "");
FAILURE_EQUAL("expected <aa>\n"
"\tbut was <ab>\n"
"\tdifference starts at position 1 at: < ab >\n"
"\t ^", f);
}
TEST(TestFailure, StringsEqualFailureAtTheBeginning)
{
StringEqualFailure f(test, failFileName, failLineNumber, "aaa", "bbb", "");
FAILURE_EQUAL("expected <aaa>\n"
"\tbut was <bbb>\n"
"\tdifference starts at position 0 at: < bbb >\n"
"\t ^", f);
}
TEST(TestFailure, StringsEqualFailureWithNullAsActual)
{
StringEqualFailure f(test, failFileName, failLineNumber, "abc", NULLPTR, "");
FAILURE_EQUAL("expected <abc>\n"
"\tbut was <(null)>", f);
}
TEST(TestFailure, StringsEqualFailureWithNullAsExpected)
{
StringEqualFailure f(test, failFileName, failLineNumber, NULLPTR, "abd", "");
FAILURE_EQUAL("expected <(null)>\n"
"\tbut was <abd>", f);
}
TEST(TestFailure, StringsEqualNoCaseFailureWithText)
{
StringEqualNoCaseFailure f(test, failFileName, failLineNumber, "ABC", "abd", "text");
FAILURE_EQUAL("Message: text\n"
"\texpected <ABC>\n"
"\tbut was <abd>\n"
"\tdifference starts at position 2 at: < abd >\n"
"\t ^", f);
}
TEST(TestFailure, StringsEqualNoCaseFailure)
{
StringEqualNoCaseFailure f(test, failFileName, failLineNumber, "ABC", "abd", "");
FAILURE_EQUAL("expected <ABC>\n"
"\tbut was <abd>\n"
"\tdifference starts at position 2 at: < abd >\n"
"\t ^", f);
}
TEST(TestFailure, StringsEqualNoCaseFailureWithActualAsNull)
{
StringEqualNoCaseFailure f(test, failFileName, failLineNumber, "ABC", NULLPTR, "");
FAILURE_EQUAL("expected <ABC>\n"
"\tbut was <(null)>", f);
}
TEST(TestFailure, StringsEqualNoCaseFailureWithExpectedAsNull)
{
StringEqualNoCaseFailure f(test, failFileName, failLineNumber, NULLPTR, "abd", "");
FAILURE_EQUAL("expected <(null)>\n"
"\tbut was <abd>", f);
}
TEST(TestFailure, StringsEqualNoCaseFailure2)
{
StringEqualNoCaseFailure f(test, failFileName, failLineNumber, "ac", "AB", "");
FAILURE_EQUAL("expected <ac>\n"
"\tbut was <AB>\n"
"\tdifference starts at position 1 at: < AB >\n"
"\t ^", f);
}
TEST(TestFailure, DoublesEqualNormalWithText)
{
DoublesEqualFailure f(test, failFileName, failLineNumber, 1.0, 2.0, 3.0, "text");
FAILURE_EQUAL("Message: text\n"
"\texpected <1>\n"
"\tbut was <2> threshold used was <3>", f);
}
TEST(TestFailure, DoublesEqualNormal)
{
DoublesEqualFailure f(test, failFileName, failLineNumber, 1.0, 2.0, 3.0, "");
FAILURE_EQUAL("expected <1>\n"
"\tbut was <2> threshold used was <3>", f);
}
TEST(TestFailure, BinaryEqualWithText)
{
const unsigned char expectedData[] = { 0x00 };
const unsigned char actualData[] = { 0x01 };
BinaryEqualFailure f(test, failFileName, failLineNumber, expectedData, actualData, sizeof(expectedData), "text");
FAILURE_EQUAL("Message: text\n"
"\texpected <00>\n"
"\tbut was <01>\n"
"\tdifference starts at position 0 at: < 01 >\n"
"\t ^", f);
}
TEST(TestFailure, BinaryEqualOneByte)
{
const unsigned char expectedData[] = { 0x00 };
const unsigned char actualData[] = { 0x01 };
BinaryEqualFailure f(test, failFileName, failLineNumber, expectedData, actualData, sizeof(expectedData), "");
FAILURE_EQUAL("expected <00>\n"
"\tbut was <01>\n"
"\tdifference starts at position 0 at: < 01 >\n"
"\t ^", f);
}
TEST(TestFailure, BinaryEqualTwoBytes)
{
const unsigned char expectedData[] = {0x00, 0x01};
const unsigned char actualData[] = {0x00, 0x02};
BinaryEqualFailure f(test, failFileName, failLineNumber, expectedData, actualData, sizeof(expectedData), "");
FAILURE_EQUAL("expected <00 01>\n"
"\tbut was <00 02>\n"
"\tdifference starts at position 1 at: < 00 02 >\n"
"\t ^", f);
}
TEST(TestFailure, BinaryEqualThreeBytes)
{
const unsigned char expectedData[] = {0x00, 0x01, 0x00};
const unsigned char actualData[] = {0x00, 0x02, 0x00};
BinaryEqualFailure f(test, failFileName, failLineNumber, expectedData, actualData, sizeof(expectedData), "");
FAILURE_EQUAL("expected <00 01 00>\n"
"\tbut was <00 02 00>\n"
"\tdifference starts at position 1 at: < 00 02 00 >\n"
"\t ^", f);
}
TEST(TestFailure, BinaryEqualFullWidth)
{
const unsigned char expectedData[] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00};
const unsigned char actualData[] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00};
BinaryEqualFailure f(test, failFileName, failLineNumber, expectedData, actualData, sizeof(expectedData), "");
FAILURE_EQUAL("expected <00 00 00 01 00 00 00>\n"
"\tbut was <00 00 00 02 00 00 00>\n"
"\tdifference starts at position 3 at: <00 00 00 02 00 00 00>\n"
"\t ^", f);
}
TEST(TestFailure, BinaryEqualLast)
{
const unsigned char expectedData[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned char actualData[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
BinaryEqualFailure f(test, failFileName, failLineNumber, expectedData, actualData, sizeof(expectedData), "");
FAILURE_EQUAL("expected <00 00 00 00 00 00 00>\n"
"\tbut was <00 00 00 00 00 00 01>\n"
"\tdifference starts at position 6 at: <00 00 00 01 >\n"
"\t ^", f);
}
TEST(TestFailure, BinaryEqualActualNull)
{
const unsigned char expectedData[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
BinaryEqualFailure f(test, failFileName, failLineNumber, expectedData, NULLPTR, sizeof(expectedData), "");
FAILURE_EQUAL("expected <00 00 00 00 00 00 00>\n\tbut was <(null)>", f);
}
TEST(TestFailure, BinaryEqualExpectedNull)
{
const unsigned char actualData[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
BinaryEqualFailure f(test, failFileName, failLineNumber, NULLPTR, actualData, sizeof(actualData), "");
FAILURE_EQUAL("expected <(null)>\n\tbut was <00 00 00 00 00 00 01>", f);
}
TEST(TestFailure, BitsEqualWithText)
{
BitsEqualFailure f(test, failFileName, failLineNumber, 0x0001, 0x0003, 0x00FF, 2*8/CPPUTEST_CHAR_BIT, "text");
FAILURE_EQUAL("Message: text\n"
"\texpected <xxxxxxxx 00000001>\n\tbut was <xxxxxxxx 00000011>", f);
}
#if (CPPUTEST_CHAR_BIT == 16)
TEST(TestFailure, BitsEqualChar)
{
BitsEqualFailure f(test, failFileName, failLineNumber, 0x01, 0x03, 0xFF, sizeof(char), "");
FAILURE_EQUAL("expected <xxxxxxxx 00000001>\n\tbut was <xxxxxxxx 00000011>", f);
}
#else
TEST(TestFailure, BitsEqualChar)
{
BitsEqualFailure f(test, failFileName, failLineNumber, 0x01, 0x03, 0xFF, sizeof(char), "");
FAILURE_EQUAL("expected <00000001>\n\tbut was <00000011>", f);
}
#endif
TEST(TestFailure, BitsEqual16Bit)
{
BitsEqualFailure f(test, failFileName, failLineNumber, 0x0001, 0x0003, 0xFFFF, 2*8/CPPUTEST_CHAR_BIT, "");
FAILURE_EQUAL("expected <00000000 00000001>\n\tbut was <00000000 00000011>", f);
}
TEST(TestFailure, BitsEqual32Bit)
{
BitsEqualFailure f(test, failFileName, failLineNumber, 0x00000001, 0x00000003, 0xFFFFFFFF, 4*8/CPPUTEST_CHAR_BIT, "");
FAILURE_EQUAL("expected <00000000 00000000 00000000 00000001>\n\tbut was <00000000 00000000 00000000 00000011>", f);
}
TEST(TestFailure, FeatureUnsupported)
{
FeatureUnsupportedFailure f(test, failFileName, failLineNumber, "SOME_FEATURE", "");
FAILURE_EQUAL("The feature \"SOME_FEATURE\" is not supported in this environment or with the feature set selected when building the library.", f);
}

View file

@ -0,0 +1,166 @@
/*
* 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/TestFilter.h"
TEST_GROUP(TestFilter)
{
};
TEST(TestFilter, emptyFilterMatchesEverything)
{
TestFilter filter;
CHECK(filter.match("random_name"));
CHECK(filter.match(""));
CHECK(filter.match("*&%#^&%$(*&^@#(&*@#^(&*$^@#"));
}
TEST(TestFilter, defaultAbsoluteMismatches)
{
TestFilter filter("filtername");
CHECK(!filter.match("notevenclose"));
CHECK(!filter.match("filterrname"));
CHECK(!filter.match(""));
}
TEST(TestFilter, strictMatching)
{
TestFilter filter("filter");
filter.strictMatching();
CHECK(filter.match("filter"));
CHECK(!filter.match("filterr"));
CHECK(!filter.match(" filter"));
}
TEST(TestFilter, invertMatching)
{
TestFilter filter("filter");
filter.invertMatching();
CHECK(!filter.match("filter"));
CHECK(!filter.match("filterr"));
CHECK(filter.match("notevenclose"));
CHECK(filter.match(""));
}
TEST(TestFilter, invertStrictMatching)
{
TestFilter filter("filter");
filter.invertMatching();
filter.strictMatching();
CHECK(!filter.match("filter"));
CHECK(filter.match("filterr"));
CHECK(filter.match(" filter"));
}
TEST(TestFilter, equality)
{
TestFilter filter1("filter");
TestFilter filter2("filter");
TestFilter filter3("filter3");
CHECK(filter1 == filter2);
CHECK(! (filter1 == filter3));
}
TEST(TestFilter, equalityWithStrictness)
{
TestFilter filter1("filter");
TestFilter filter2("filter");
filter2.strictMatching();
CHECK(! (filter1 == filter2));
}
TEST(TestFilter, equalityWithInvertion)
{
TestFilter filter1("filter");
TestFilter filter2("filter");
filter2.invertMatching();
CHECK(! (filter1 == filter2));
}
TEST(TestFilter, notEqual)
{
TestFilter filter1("filter");
TestFilter filter2("filter");
TestFilter filter3("filter3");
CHECK(filter1 != filter3);
CHECK(! (filter1 != filter2));
}
TEST(TestFilter, stringFrom)
{
TestFilter filter("filter");
STRCMP_EQUAL("TestFilter: \"filter\"", StringFrom(filter).asCharString());
}
TEST(TestFilter, stringFromWithStrictMatching)
{
TestFilter filter("filter");
filter.strictMatching();
STRCMP_EQUAL("TestFilter: \"filter\" with strict matching", StringFrom(filter).asCharString());
}
TEST(TestFilter, stringFromWithInvertMatching)
{
TestFilter filter("filter");
filter.invertMatching();
STRCMP_EQUAL("TestFilter: \"filter\" with invert matching", StringFrom(filter).asCharString());
}
TEST(TestFilter, stringFromWithStrictInvertMatching)
{
TestFilter filter("filter");
filter.strictMatching();
filter.invertMatching();
STRCMP_EQUAL("TestFilter: \"filter\" with strict, invert matching", StringFrom(filter).asCharString());
}
TEST(TestFilter, listOfFilters)
{
TestFilter *listOfFilters = NULLPTR;
TestFilter first("foo");
TestFilter secnd("bar");
listOfFilters = first.add(listOfFilters);
listOfFilters = secnd.add(listOfFilters);
TestFilter *current = listOfFilters;
STRCMP_EQUAL("TestFilter: \"bar\"", StringFrom(*current).asCharString());
current = current->getNext();
STRCMP_EQUAL("TestFilter: \"foo\"", StringFrom(*current).asCharString());
POINTERS_EQUAL(NULLPTR, current->getNext());
}
TEST(TestFilter, constructors)
{
TestFilter filter1;
TestFilter filter2(SimpleString("a"));
TestFilter filter3("a");
CHECK(filter1.getNext() == NULLPTR);
CHECK(filter2.getNext() == NULLPTR);
CHECK(filter3.getNext() == NULLPTR);
CHECK(filter2.match("ab"));
CHECK(filter3.match("ab"));
}

View file

@ -0,0 +1,807 @@
/*
* 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_c.h"
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/PlatformSpecificFunctions.h"
extern "C" int setup_teardown_was_called_in_test_group_in_C;
extern "C" int test_was_called_in_test_group_in_C;
int setup_teardown_was_called_in_test_group_in_C = 0;
int test_was_called_in_test_group_in_C = 0;
TEST_GROUP_C_WRAPPER(TestGroupInC)
{
TEST_GROUP_C_SETUP_WRAPPER(TestGroupInC)
TEST_GROUP_C_TEARDOWN_WRAPPER(TestGroupInC)
};
TEST_C_WRAPPER(TestGroupInC, checkThatTheTestHasRun)
IGNORE_TEST_C_WRAPPER(TestGroupInC, ignoreMacroForCFile)
/*
* This test is a bit strange. They use the fact that you can do -r2 for repeating the same run.
* When you do so, the same statics will be shared and therefore we can test whether the setup/teardown is run
* correctly.
*/
TEST(TestGroupInC, setupHasBeenCalled)
{
test_was_called_in_test_group_in_C++;
/* Increased in setup, decreased in teardown. So at this point it must be 1 also on a multiple run */
LONGS_EQUAL(1, setup_teardown_was_called_in_test_group_in_C);
}
static bool hasDestructorOfTheDestructorCheckedBeenCalled;
class HasTheDestructorBeenCalledChecker
{
public:
HasTheDestructorBeenCalledChecker(){}
~HasTheDestructorBeenCalledChecker() { hasDestructorOfTheDestructorCheckedBeenCalled = true; }
};
TEST_GROUP(TestHarness_c)
{
TestTestingFixture* fixture;
TEST_SETUP()
{
hasDestructorOfTheDestructorCheckedBeenCalled = false;
fixture = new TestTestingFixture();
}
TEST_TEARDOWN()
{
delete fixture;
}
};
static void _failBoolMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_BOOL(1, 0);
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkBool)
{
CHECK_EQUAL_C_BOOL(1, 1);
CHECK_EQUAL_C_BOOL(1, 2);
fixture->setTestFunction(_failBoolMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <true>\n but was <false>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failBoolTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_BOOL_TEXT(1, 0, "BoolTestText");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkBoolText)
{
CHECK_EQUAL_C_BOOL_TEXT(1, 1, "Text");
CHECK_EQUAL_C_BOOL_TEXT(1, 2, "Text");
fixture->setTestFunction(_failBoolTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <true>\n but was <false>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: BoolTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failIntMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_INT(1, 2);
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkInt)
{
CHECK_EQUAL_C_INT(2, 2);
fixture->setTestFunction(_failIntMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failIntTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_INT_TEXT(1, 2, "IntTestText");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkIntText)
{
CHECK_EQUAL_C_INT_TEXT(2, 2, "Text");
fixture->setTestFunction(_failIntTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: IntTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failUnsignedIntMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_UINT(1, 2);
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkUnsignedInt)
{
CHECK_EQUAL_C_UINT(2, 2);
fixture->setTestFunction(_failUnsignedIntMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failUnsignedIntTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_UINT_TEXT(1, 2, "UnsignedIntTestText");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkUnsignedIntText)
{
CHECK_EQUAL_C_UINT_TEXT(2, 2, "Text");
fixture->setTestFunction(_failUnsignedIntTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: UnsignedIntTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failLongIntMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_LONG(1, 2);
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkLongInt)
{
CHECK_EQUAL_C_LONG(2, 2);
fixture->setTestFunction(_failLongIntMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failLongIntTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_LONG_TEXT(1, 2, "LongIntTestText");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkLongIntText)
{
CHECK_EQUAL_C_LONG_TEXT(2, 2, "Text");
fixture->setTestFunction(_failLongIntTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: LongIntTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failUnsignedLongIntMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_ULONG(1, 2);
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkUnsignedLongInt)
{
CHECK_EQUAL_C_ULONG(2, 2);
fixture->setTestFunction(_failUnsignedLongIntMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failUnsignedLongIntTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_ULONG_TEXT(1, 2, "UnsignedLongIntTestText");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkUnsignedLongIntText)
{
CHECK_EQUAL_C_ULONG_TEXT(2, 2, "Text");
fixture->setTestFunction(_failUnsignedLongIntTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: UnsignedLongIntTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
#ifdef CPPUTEST_USE_LONG_LONG
static void _failLongLongIntMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_LONGLONG(1, 2);
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkLongLongInt)
{
CHECK_EQUAL_C_LONGLONG(2, 2);
fixture->setTestFunction(_failLongLongIntMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failLongLongIntTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_LONGLONG_TEXT(1, 2, "LongLongTestText");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkLongLongIntText)
{
CHECK_EQUAL_C_LONGLONG_TEXT(2, 2, "Text");
fixture->setTestFunction(_failLongLongIntTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: LongLongTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failUnsignedLongLongIntMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_ULONGLONG(1, 2);
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkUnsignedLongLongInt)
{
CHECK_EQUAL_C_ULONGLONG(2, 2);
fixture->setTestFunction(_failUnsignedLongLongIntMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failUnsignedLongLongIntTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_ULONGLONG_TEXT(1, 2, "UnsignedLongLongTestText");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkUnsignedLongLongIntText)
{
CHECK_EQUAL_C_ULONGLONG_TEXT(2, 2, "Text");
fixture->setTestFunction(_failUnsignedLongLongIntTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1 (0x1)>\n but was <2 (0x2)>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: UnsignedLongLongTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
#else
static void _failLongLongIntMethod()
{
cpputest_longlong dummy_longlong;
CHECK_EQUAL_C_LONGLONG(dummy_longlong, dummy_longlong);
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkLongLongInt)
{
fixture->setTestFunction(_failLongLongIntMethod);
fixture->runAllTests();
fixture->assertPrintContains("is not supported");
fixture->assertPrintContains("arness_c");
}
static void _failLongLongIntTextMethod()
{
cpputest_longlong dummy_longlong;
CHECK_EQUAL_C_LONGLONG_TEXT(dummy_longlong, dummy_longlong, "Text");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkLongLongIntText)
{
fixture->setTestFunction(_failLongLongIntTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("is not supported");
fixture->assertPrintContains("arness_c");
}
static void _failUnsignedLongLongIntMethod()
{
cpputest_ulonglong dummy_ulonglong;
CHECK_EQUAL_C_ULONGLONG(dummy_ulonglong, dummy_ulonglong);
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkUnsignedLongLongInt)
{
fixture->setTestFunction(_failUnsignedLongLongIntMethod);
fixture->runAllTests();
fixture->assertPrintContains("is not supported");
fixture->assertPrintContains("arness_c");
}
static void _failUnsignedLongLongIntTextMethod()
{
cpputest_ulonglong dummy_ulonglong;
CHECK_EQUAL_C_ULONGLONG_TEXT(dummy_ulonglong, dummy_ulonglong, "Text");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkUnsignedLongLongIntText)
{
fixture->setTestFunction(_failUnsignedLongLongIntTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("is not supported");
fixture->assertPrintContains("arness_c");
}
#endif
static void _failRealMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_REAL(1.0, 2.0, 0.5);
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkReal)
{
CHECK_EQUAL_C_REAL(1.0, 1.1, 0.5);
fixture->setTestFunction(_failRealMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1>\n but was <2>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failRealTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_REAL_TEXT(1.0, 2.0, 0.5, "RealTestText");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkRealText)
{
CHECK_EQUAL_C_REAL_TEXT(1.0, 1.1, 0.5, "Text");
fixture->setTestFunction(_failRealTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <1>\n but was <2>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: RealTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failCharMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_CHAR('a', 'c');
}
TEST(TestHarness_c, checkChar)
{
CHECK_EQUAL_C_CHAR('a', 'a');
fixture->setTestFunction(_failCharMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <a>\n but was <c>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failCharTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_CHAR_TEXT('a', 'c', "CharTestText");
}
TEST(TestHarness_c, checkCharText)
{
CHECK_EQUAL_C_CHAR_TEXT('a', 'a', "Text");
fixture->setTestFunction(_failCharTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <a>\n but was <c>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: CharTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failUnsignedByteMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_UBYTE(254, 253);
}
TEST(TestHarness_c, checkUnsignedByte)
{
CHECK_EQUAL_C_UBYTE(254, 254);
fixture->setTestFunction(_failUnsignedByteMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <254>\n but was <253>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failUnsignedByteTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_UBYTE_TEXT(254, 253, "UnsignedByteTestText");
}
TEST(TestHarness_c, checkUnsignedByteText)
{
CHECK_EQUAL_C_UBYTE_TEXT(254, 254, "Text");
fixture->setTestFunction(_failUnsignedByteTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <254>\n but was <253>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: UnsignedByteTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failSignedByteMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_SBYTE(-3, -5);
}
TEST(TestHarness_c, checkSignedByte)
{
CHECK_EQUAL_C_SBYTE(-3, -3);
fixture->setTestFunction(_failSignedByteMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <-3>\n but was <-5>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failSignedByteTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_SBYTE_TEXT(-3, -5, "SignedByteTestText");
}
TEST(TestHarness_c, checkSignedByteText)
{
CHECK_EQUAL_C_SBYTE_TEXT(-3, -3, "Text");
fixture->setTestFunction(_failSignedByteTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <-3>\n but was <-5>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: SignedByteTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failStringMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_STRING("Hello", "Hello World");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkString)
{
CHECK_EQUAL_C_STRING("Hello", "Hello");
fixture->setTestFunction(_failStringMethod);
fixture->runAllTests();
StringEqualFailure failure(UtestShell::getCurrent(), "file", 1, "Hello", "Hello World", "");
fixture->assertPrintContains(failure.getMessage());
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failStringTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_STRING_TEXT("Hello", "Hello World", "StringTestText");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkStringText)
{
CHECK_EQUAL_C_STRING_TEXT("Hello", "Hello", "Text");
fixture->setTestFunction(_failStringTextMethod);
fixture->runAllTests();
StringEqualFailure failure(UtestShell::getCurrent(), "file", 1, "Hello", "Hello World", "");
fixture->assertPrintContains(failure.getMessage());
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: StringTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failPointerMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_POINTER(NULLPTR, (void *)0x1);
}
TEST(TestHarness_c, checkPointer)
{
CHECK_EQUAL_C_POINTER(NULLPTR, NULLPTR);
fixture->setTestFunction(_failPointerMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <0x0>\n but was <0x1>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failPointerTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_POINTER_TEXT(NULLPTR, (void *)0x1, "PointerTestText");
}
TEST(TestHarness_c, checkPointerText)
{
CHECK_EQUAL_C_POINTER_TEXT(NULLPTR, NULLPTR, "Text");
fixture->setTestFunction(_failPointerTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <0x0>\n but was <0x1>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: PointerTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failBitsMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_BITS(0x0001, (unsigned short)0x0003, 0xFFFF);
}
TEST(TestHarness_c, checkBits)
{
CHECK_EQUAL_C_BITS(0xABCD, (unsigned short)0xABCD, 0xFFFF);
fixture->setTestFunction(_failBitsMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <00000000 00000001>\n\tbut was <00000000 00000011>");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failBitsTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_EQUAL_C_BITS_TEXT(0x0001, (unsigned short)0x0003, 0xFFFF, "BitsTestText");
}
TEST(TestHarness_c, checkBitsText)
{
CHECK_EQUAL_C_BITS_TEXT(0xABCD, (unsigned short)0xABCD, 0xFFFF, "Text");
fixture->setTestFunction(_failBitsTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("expected <00000000 00000001>\n\tbut was <00000000 00000011>");
fixture->assertPrintContains("arness_c");
fixture->assertPrintContains("Message: BitsTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
FAIL_TEXT_C("Booo");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkFailText)
{
fixture->setTestFunction(_failTextMethod);
fixture->runAllTests();
fixture->assertPrintContains("Booo");
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _failMethod()
{
HasTheDestructorBeenCalledChecker checker;
FAIL_C();
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkFail)
{
fixture->setTestFunction(_failMethod);
fixture->runAllTests();
LONGS_EQUAL(1, fixture->getFailureCount());
fixture->assertPrintContains("arness_c");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _CheckMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_C(false);
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkCheck)
{
CHECK_C(true);
fixture->setTestFunction(_CheckMethod);
fixture->runAllTests();
LONGS_EQUAL(1, fixture->getFailureCount());
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
static void _CheckTextMethod()
{
HasTheDestructorBeenCalledChecker checker;
CHECK_C_TEXT(false, "CheckTestText");
} // LCOV_EXCL_LINE
TEST(TestHarness_c, checkCheckText)
{
CHECK_C_TEXT(true, "Text");
fixture->setTestFunction(_CheckTextMethod);
fixture->runAllTests();
LONGS_EQUAL(1, fixture->getFailureCount());
fixture->assertPrintContains("Message: CheckTestText");
CHECK(!hasDestructorOfTheDestructorCheckedBeenCalled);
}
#if CPPUTEST_USE_MEM_LEAK_DETECTION
TEST(TestHarness_c, cpputest_malloc_out_of_memory)
{
cpputest_malloc_set_out_of_memory();
CHECK(NULLPTR == cpputest_malloc(100));
cpputest_malloc_set_not_out_of_memory();
void * mem = cpputest_malloc(100);
CHECK(NULLPTR != mem);
cpputest_free(mem);
}
TEST(TestHarness_c, cpputest_malloc_out_of_memory_after_n_mallocs)
{
cpputest_malloc_set_out_of_memory_countdown(3);
void * m1 = cpputest_malloc(10);
void * m2 = cpputest_malloc(11);
void * m3 = cpputest_malloc(12);
CHECK(m1 != NULLPTR);
CHECK(m2 != NULLPTR);
CHECK(m3 == NULLPTR);
cpputest_malloc_set_not_out_of_memory();
cpputest_free(m1);
cpputest_free(m2);
}
TEST(TestHarness_c, cpputest_malloc_out_of_memory_after_0_mallocs)
{
cpputest_malloc_set_out_of_memory_countdown(0);
void * m1 = cpputest_malloc(10);
CHECK(m1 == NULLPTR);
cpputest_malloc_set_not_out_of_memory();
}
TEST(TestHarness_c, count_mallocs)
{
cpputest_malloc_count_reset();
void * m1 = cpputest_malloc(10);
void * m2 = cpputest_malloc(11);
void * m3 = cpputest_malloc(12);
cpputest_free(m1);
cpputest_free(m2);
cpputest_free(m3);
LONGS_EQUAL(3, cpputest_malloc_get_count());
}
#ifdef CPPUTEST_USE_STRDUP_MACROS
TEST(TestHarness_c, cpputest_strdup)
{
char * mem = cpputest_strdup("0123456789");
CHECK(NULLPTR != mem);
STRCMP_EQUAL("0123456789", mem);
cpputest_free(mem);
}
TEST(TestHarness_c, cpputest_strndup)
{
char * mem = cpputest_strndup("0123456789", 3);
CHECK(NULLPTR != mem);
STRCMP_EQUAL("012", mem);
cpputest_free(mem);
}
#endif
TEST(TestHarness_c, cpputest_calloc)
{
void * mem = cpputest_calloc(10, 10);
CHECK(NULLPTR != mem);
cpputest_free(mem);
}
TEST(TestHarness_c, cpputest_realloc_larger)
{
const char* number_string = "123456789";
char* mem1 = (char*) cpputest_malloc(10);
SimpleString::StrNCpy(mem1, number_string, 10);
CHECK(mem1 != NULLPTR);
char* mem2 = (char*) cpputest_realloc(mem1, 1000);
CHECK(mem2 != NULLPTR);
STRCMP_EQUAL(number_string, mem2);
cpputest_free(mem2);
}
#include "CppUTest/MemoryLeakDetector.h"
TEST(TestHarness_c, macros)
{
#if CPPUTEST_USE_MALLOC_MACROS
MemoryLeakDetector* memLeakDetector = MemoryLeakWarningPlugin::getGlobalDetector();
size_t memLeaks = memLeakDetector->totalMemoryLeaks(mem_leak_period_checking);
#endif
void* mem1 = malloc(10);
void* mem2 = calloc(10, 20);
void* mem3 = realloc(mem2, 100);
#if CPPUTEST_USE_MALLOC_MACROS
LONGS_EQUAL(memLeaks + 2, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
#endif
free(mem1);
free(mem3);
#if CPPUTEST_USE_MALLOC_MACROS
LONGS_EQUAL(memLeaks, memLeakDetector->totalMemoryLeaks(mem_leak_period_checking));
#endif
}
TEST(TestHarness_c, callocInitializedToZero)
{
char* mem = (char*) calloc(20, sizeof(char));
for (int i = 0; i < 20; i++)
CHECK(mem[i] == 0);
free(mem);
}
TEST(TestHarness_c, callocShouldReturnNULLWhenOutOfMemory)
{
cpputest_malloc_set_out_of_memory_countdown(0);
void * m = cpputest_calloc(1, 1);
CHECK(m == NULLPTR);
cpputest_malloc_set_not_out_of_memory();
}
#endif

View file

@ -0,0 +1,36 @@
#include "CppUTest/TestHarness_c.h"
#include "CppUTest/PlatformSpecificFunctions_c.h"
extern void functionWithUnusedParameter(void* PUNUSED(unlessParamater));
void functionWithUnusedParameter(void* PUNUSED(unlessParamater))
{
}
/* Declared in the cpp file */
extern int setup_teardown_was_called_in_test_group_in_C;
extern int test_was_called_in_test_group_in_C;
TEST_GROUP_C_SETUP(TestGroupInC)
{
setup_teardown_was_called_in_test_group_in_C++;
}
TEST_GROUP_C_TEARDOWN(TestGroupInC)
{
setup_teardown_was_called_in_test_group_in_C--;
CHECK_C(test_was_called_in_test_group_in_C == 1);
test_was_called_in_test_group_in_C--;
}
TEST_C(TestGroupInC, checkThatTheTestHasRun)
{
test_was_called_in_test_group_in_C++;
}
IGNORE_TEST_C(TestGroupInC, ignoreMacroForCFile)
{
test_was_called_in_test_group_in_C++;
}

View file

@ -0,0 +1,62 @@
/*
* 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"
class TestInstallerTestUtestShell : public UtestShell
{
};
// this is file scope because the test is installed
// with all other tests, which also happen to be
// created as static instances at file scope
TEST_GROUP(TestInstaller)
{
TestInstaller* testInstaller;
TestRegistry* myRegistry;
TestInstallerTestUtestShell shell;
void setup() _override
{
myRegistry = new TestRegistry();
myRegistry->setCurrentRegistry(myRegistry);
testInstaller = new TestInstaller(shell, "TestInstaller", "test", __FILE__, __LINE__);
}
void teardown() _override
{
myRegistry->setCurrentRegistry(NULLPTR);
testInstaller->unDo();
delete testInstaller;
delete myRegistry;
}
};
TEST(TestInstaller, Create)
{
}

View file

@ -0,0 +1,765 @@
/*
* 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/TestTestingFixture.h"
#include "CppUTest/MemoryLeakDetector.h"
TEST_GROUP(TestMemoryAllocatorTest)
{
TestMemoryAllocator* allocator;
GlobalMemoryAllocatorStash memoryAllocatorStash;
void setup() _override
{
allocator = NULLPTR;
memoryAllocatorStash.save();
}
void teardown() _override
{
memoryAllocatorStash.restore();
delete allocator;
}
};
TEST(TestMemoryAllocatorTest, SetCurrentNewAllocator)
{
allocator = new TestMemoryAllocator("new allocator for test");
setCurrentNewAllocator(allocator);
POINTERS_EQUAL(allocator, getCurrentNewAllocator());
}
TEST(TestMemoryAllocatorTest, SetCurrentNewAllocatorToDefault)
{
TestMemoryAllocator* originalAllocator = getCurrentNewAllocator();
setCurrentNewAllocatorToDefault();
POINTERS_EQUAL(defaultNewAllocator(), getCurrentNewAllocator());
setCurrentNewAllocator(originalAllocator);
}
TEST(TestMemoryAllocatorTest, SetCurrentNewArrayAllocator)
{
allocator = new TestMemoryAllocator("new array allocator for test");
setCurrentNewArrayAllocator(allocator);
POINTERS_EQUAL(allocator, getCurrentNewArrayAllocator());
setCurrentNewArrayAllocatorToDefault();
POINTERS_EQUAL(defaultNewArrayAllocator(), getCurrentNewArrayAllocator());
}
TEST(TestMemoryAllocatorTest, SetCurrentMallocAllocator)
{
allocator = new TestMemoryAllocator("malloc_allocator");
setCurrentMallocAllocator(allocator);
POINTERS_EQUAL(allocator, getCurrentMallocAllocator());
setCurrentMallocAllocatorToDefault();
POINTERS_EQUAL(defaultMallocAllocator(), getCurrentMallocAllocator());
}
TEST(TestMemoryAllocatorTest, MemoryAllocation)
{
allocator = new TestMemoryAllocator();
allocator->free_memory(allocator->alloc_memory(100, "file", 1), 100, "file", 1);
}
TEST(TestMemoryAllocatorTest, MallocNames)
{
STRCMP_EQUAL("Standard Malloc Allocator", defaultMallocAllocator()->name());
STRCMP_EQUAL("malloc", defaultMallocAllocator()->alloc_name());
STRCMP_EQUAL("free", defaultMallocAllocator()->free_name());
}
TEST(TestMemoryAllocatorTest, NewNames)
{
STRCMP_EQUAL("Standard New Allocator", defaultNewAllocator()->name());
STRCMP_EQUAL("new", defaultNewAllocator()->alloc_name());
STRCMP_EQUAL("delete", defaultNewAllocator()->free_name());
}
TEST(TestMemoryAllocatorTest, NewArrayNames)
{
STRCMP_EQUAL("Standard New [] Allocator", defaultNewArrayAllocator()->name());
STRCMP_EQUAL("new []", defaultNewArrayAllocator()->alloc_name());
STRCMP_EQUAL("delete []", defaultNewArrayAllocator()->free_name());
}
TEST(TestMemoryAllocatorTest, NullUnknownAllocation)
{
allocator = new NullUnknownAllocator;
allocator->free_memory(allocator->alloc_memory(100, "file", 1), 100, "file", 1);
}
TEST(TestMemoryAllocatorTest, NullUnknownNames)
{
allocator = new NullUnknownAllocator;
STRCMP_EQUAL("Null Allocator", allocator->name());
STRCMP_EQUAL("unknown", allocator->alloc_name());
STRCMP_EQUAL("unknown", allocator->free_name());
}
#if (! CPPUTEST_SANITIZE_ADDRESS)
#define MAX_SIZE_FOR_ALLOC ((size_t) -1 > (unsigned short)-1) ? (size_t) -97 : (size_t) -1
static void failTryingToAllocateTooMuchMemory(void)
{
TestMemoryAllocator allocator;
allocator.alloc_memory(MAX_SIZE_FOR_ALLOC, "file", 1);
} // LCOV_EXCL_LINE
TEST(TestMemoryAllocatorTest, TryingToAllocateTooMuchFailsTest)
{
TestTestingFixture fixture;
fixture.setTestFunction(&failTryingToAllocateTooMuchMemory);
fixture.runAllTests();
fixture.assertPrintContains("malloc returned null pointer");
}
#endif
TEST_GROUP(MemoryLeakAllocator)
{
MemoryLeakAllocator* allocator;
void setup() _override
{
allocator = new MemoryLeakAllocator(defaultMallocAllocator());
}
void teardown() _override
{
delete allocator;
}
};
TEST(MemoryLeakAllocator, allocMemory)
{
char* memory = allocator->alloc_memory(10, __FILE__, __LINE__);
memory[0] = 'B';
MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(allocator->actualAllocator(), memory);
/* No leaks or crashes */
}
TEST(MemoryLeakAllocator, freeMemory)
{
char* memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(allocator->actualAllocator(), 10);
allocator->free_memory(memory, 10, __FILE__, __LINE__);
/* No leaks or crashes */
}
TEST(MemoryLeakAllocator, originalAllocator)
{
POINTERS_EQUAL(defaultMallocAllocator(), allocator->actualAllocator());
STRCMP_EQUAL(defaultMallocAllocator()->alloc_name(), allocator->alloc_name());
STRCMP_EQUAL(defaultMallocAllocator()->free_name(), allocator->free_name());
}
TEST(MemoryLeakAllocator, name)
{
STRCMP_EQUAL("MemoryLeakAllocator", allocator->name());
}
#if CPPUTEST_USE_MEM_LEAK_DETECTION
#if CPPUTEST_USE_MALLOC_MACROS
class FailableMemoryAllocatorExecFunction : public ExecFunction
{
public:
FailableMemoryAllocator* allocator_;
void (*testFunction_)(FailableMemoryAllocator*);
void exec() _override
{
testFunction_(allocator_);
}
FailableMemoryAllocatorExecFunction() : allocator_(NULLPTR), testFunction_(NULLPTR) {}
virtual ~FailableMemoryAllocatorExecFunction() _destructor_override {}
};
TEST_GROUP(FailableMemoryAllocator)
{
FailableMemoryAllocator *failableMallocAllocator;
FailableMemoryAllocatorExecFunction testFunction;
TestTestingFixture fixture;
GlobalMemoryAllocatorStash stash;
void setup() _override
{
stash.save();
testFunction.allocator_ = failableMallocAllocator = new FailableMemoryAllocator("Failable Malloc Allocator", "malloc", "free");
fixture.setTestFunction(&testFunction);
setCurrentMallocAllocator(failableMallocAllocator);
}
void teardown() _override
{
failableMallocAllocator->checkAllFailedAllocsWereDone();
failableMallocAllocator->clearFailedAllocs();
delete failableMallocAllocator;
stash.restore();
}
};
TEST(FailableMemoryAllocator, MallocWorksNormallyIfNotAskedToFail)
{
int *memory = (int*)malloc(sizeof(int));
CHECK(memory != NULLPTR);
free(memory);
}
TEST(FailableMemoryAllocator, FailFirstMalloc)
{
failableMallocAllocator->failAllocNumber(1);
POINTERS_EQUAL(NULLPTR, (int*)malloc(sizeof(int)));
}
TEST(FailableMemoryAllocator, FailSecondAndFourthMalloc)
{
failableMallocAllocator->failAllocNumber(2);
failableMallocAllocator->failAllocNumber(4);
int *memory1 = (int*)malloc(sizeof(int));
int *memory2 = (int*)malloc(sizeof(int));
int *memory3 = (int*)malloc(sizeof(int));
int *memory4 = (int*)malloc(sizeof(int));
CHECK(NULLPTR != memory1);
POINTERS_EQUAL(NULLPTR, memory2);
CHECK(NULLPTR != memory3);
POINTERS_EQUAL(NULLPTR, memory4);
free(memory1);
free(memory3);
}
static void _failingAllocIsNeverDone(FailableMemoryAllocator* failableMallocAllocator)
{
failableMallocAllocator->failAllocNumber(1);
failableMallocAllocator->failAllocNumber(2);
failableMallocAllocator->failAllocNumber(3);
malloc(sizeof(int));
malloc(sizeof(int));
failableMallocAllocator->checkAllFailedAllocsWereDone();
}
TEST(FailableMemoryAllocator, CheckAllFailingAllocsWereDone)
{
testFunction.testFunction_ = _failingAllocIsNeverDone;
fixture.runAllTests();
LONGS_EQUAL(1, fixture.getFailureCount());
fixture.assertPrintContains("Expected allocation number 3 was never done");
failableMallocAllocator->clearFailedAllocs();
}
TEST(FailableMemoryAllocator, FailFirstAllocationAtGivenLine)
{
failableMallocAllocator->failNthAllocAt(1, __FILE__, __LINE__ + 2);
POINTERS_EQUAL(NULLPTR, malloc(sizeof(int)));
}
TEST(FailableMemoryAllocator, FailThirdAllocationAtGivenLine)
{
int *memory[10] = { NULLPTR };
int allocation;
failableMallocAllocator->failNthAllocAt(3, __FILE__, __LINE__ + 4);
for (allocation = 1; allocation <= 10; allocation++)
{
memory[allocation - 1] = (int *)malloc(sizeof(int));
if (memory[allocation - 1] == NULLPTR)
break;
free(memory[allocation -1]);
}
LONGS_EQUAL(3, allocation);
}
static void _failingLocationAllocIsNeverDone(FailableMemoryAllocator* failableMallocAllocator)
{
failableMallocAllocator->failNthAllocAt(1, "TestMemoryAllocatorTest.cpp", __LINE__);
failableMallocAllocator->checkAllFailedAllocsWereDone();
}
TEST(FailableMemoryAllocator, CheckAllFailingLocationAllocsWereDone)
{
testFunction.testFunction_ = _failingLocationAllocIsNeverDone;
fixture.runAllTests();
LONGS_EQUAL(1, fixture.getFailureCount());
fixture.assertPrintContains("Expected failing alloc at TestMemoryAllocatorTest.cpp:");
fixture.assertPrintContains("was never done");
failableMallocAllocator->clearFailedAllocs();
}
#endif
#endif
class MemoryAccountantExecFunction
: public ExecFunction
{
public:
virtual ~MemoryAccountantExecFunction() _destructor_override
{
}
void (*testFunction_)(MemoryAccountant*);
MemoryAccountant* parameter_;
virtual void exec() _override
{
testFunction_(parameter_);
}
};
TEST_GROUP(TestMemoryAccountant)
{
MemoryAccountant accountant;
TestTestingFixture fixture;
MemoryAccountantExecFunction testFunction;
void setup() _override
{
testFunction.parameter_ = &accountant;
fixture.setTestFunction(&testFunction);
}
void teardown() _override
{
accountant.clear();
}
};
TEST(TestMemoryAccountant, totalAllocsIsZero)
{
LONGS_EQUAL(0, accountant.totalAllocations());
LONGS_EQUAL(0, accountant.totalDeallocations());
}
TEST(TestMemoryAccountant, countAllocationsPerSize)
{
accountant.alloc(4);
LONGS_EQUAL(1, accountant.totalAllocationsOfSize(4));
LONGS_EQUAL(0, accountant.totalAllocationsOfSize(10));
LONGS_EQUAL(1, accountant.totalAllocations());
LONGS_EQUAL(0, accountant.maximumAllocationAtATimeOfSize(10));
}
TEST(TestMemoryAccountant, countAllocationsPerSizeMultipleAllocations)
{
accountant.alloc(4);
accountant.alloc(4);
accountant.alloc(8);
LONGS_EQUAL(2, accountant.totalAllocationsOfSize(4));
LONGS_EQUAL(1, accountant.totalAllocationsOfSize(8));
LONGS_EQUAL(0, accountant.totalAllocationsOfSize(10));
LONGS_EQUAL(3, accountant.totalAllocations());
}
TEST(TestMemoryAccountant, countAllocationsPerSizeMultipleAllocationsOutOfOrder)
{
accountant.alloc(4);
accountant.alloc(8);
accountant.alloc(4);
accountant.alloc(5);
accountant.alloc(2);
accountant.alloc(4);
accountant.alloc(10);
LONGS_EQUAL(3, accountant.totalAllocationsOfSize(4));
LONGS_EQUAL(1, accountant.totalAllocationsOfSize(8));
LONGS_EQUAL(1, accountant.totalAllocationsOfSize(10));
LONGS_EQUAL(7, accountant.totalAllocations());
}
TEST(TestMemoryAccountant, countDeallocationsPerSizeMultipleAllocations)
{
accountant.dealloc(8);
accountant.dealloc(4);
accountant.dealloc(8);
LONGS_EQUAL(1, accountant.totalDeallocationsOfSize(4));
LONGS_EQUAL(2, accountant.totalDeallocationsOfSize(8));
LONGS_EQUAL(0, accountant.totalDeallocationsOfSize(20));
LONGS_EQUAL(3, accountant.totalDeallocations());
}
TEST(TestMemoryAccountant, countMaximumAllocationsAtATime)
{
accountant.alloc(4);
accountant.alloc(4);
accountant.dealloc(4);
accountant.dealloc(4);
accountant.alloc(4);
LONGS_EQUAL(2, accountant.maximumAllocationAtATimeOfSize(4));
}
TEST(TestMemoryAccountant, reportNoAllocations)
{
STRCMP_EQUAL("CppUTest Memory Accountant has not noticed any allocations or deallocations. Sorry\n", accountant.report().asCharString());
}
TEST(TestMemoryAccountant, reportAllocations)
{
accountant.dealloc(8);
accountant.dealloc(8);
accountant.dealloc(8);
accountant.alloc(4);
accountant.dealloc(4);
accountant.alloc(4);
STRCMP_EQUAL("CppUTest Memory Accountant report:\n"
"Allocation size # allocations # deallocations max # allocations at one time\n"
" 4 2 1 1\n"
" 8 0 3 0\n"
" Thank you for your business\n"
, accountant.report().asCharString());
}
TEST(TestMemoryAccountant, reportAllocationsWithSizeZero)
{
accountant.dealloc(0);
accountant.dealloc(4);
accountant.dealloc(4);
accountant.alloc(4);
STRCMP_EQUAL("CppUTest Memory Accountant report:\n"
"Allocation size # allocations # deallocations max # allocations at one time\n"
"other 0 1 0\n"
" 4 1 2 1\n"
" Thank you for your business\n"
, accountant.report().asCharString());
}
static void _failUseCacheSizesAfterAllocation(MemoryAccountant* accountant)
{
size_t cacheSizes[] = {0};
accountant->alloc(4);
accountant->useCacheSizes(cacheSizes, 1);
}
TEST(TestMemoryAccountant, withCacheSizesFailsWhenAlreadyAllocatedMemory)
{
testFunction.testFunction_ = _failUseCacheSizesAfterAllocation;
fixture.runAllTests();
fixture.assertPrintContains("MemoryAccountant: Cannot set cache sizes as allocations already occured!");
}
TEST(TestMemoryAccountant, reportWithCacheSizesEmpty)
{
size_t cacheSizes[] = {0};
accountant.useCacheSizes(cacheSizes, 0);
accountant.alloc(4);
STRCMP_EQUAL("CppUTest Memory Accountant report (with cache sizes):\n"
"Cache size # allocations # deallocations max # allocations at one time\n"
"other 1 0 1\n"
" Thank you for your business\n"
, accountant.report().asCharString());
}
TEST(TestMemoryAccountant, reportWithCacheSizes)
{
size_t cacheSizes[] = {4};
accountant.useCacheSizes(cacheSizes, 1);
accountant.dealloc(8);
accountant.dealloc(12);
accountant.dealloc(20);
accountant.alloc(4);
accountant.dealloc(4);
accountant.alloc(4);
STRCMP_EQUAL("CppUTest Memory Accountant report (with cache sizes):\n"
"Cache size # allocations # deallocations max # allocations at one time\n"
" 4 2 1 1\n"
"other 0 3 0\n"
" Thank you for your business\n"
, accountant.report().asCharString());
}
TEST(TestMemoryAccountant, reportWithCacheSizesMultipleCaches)
{
size_t cacheSizes[] = {4, 10, 20};
accountant.useCacheSizes(cacheSizes, 3);
accountant.alloc(8);
accountant.alloc(12);
accountant.alloc(20);
accountant.alloc(4);
accountant.dealloc(4);
accountant.alloc(4);
STRCMP_EQUAL("CppUTest Memory Accountant report (with cache sizes):\n"
"Cache size # allocations # deallocations max # allocations at one time\n"
" 4 2 1 1\n"
" 10 1 0 1\n"
" 20 2 0 2\n"
"other 0 0 0\n"
" Thank you for your business\n"
, accountant.report().asCharString());
}
TEST_GROUP(AccountingTestMemoryAllocator)
{
MemoryAccountant accountant;
AccountingTestMemoryAllocator *allocator;
void setup() _override
{
allocator = new AccountingTestMemoryAllocator(accountant, getCurrentMallocAllocator());
}
void teardown() _override
{
accountant.clear();
delete allocator;
}
};
TEST(AccountingTestMemoryAllocator, canAllocateAndAccountMemory)
{
char* memory = allocator->alloc_memory(10, __FILE__, __LINE__);
allocator->free_memory(memory, 10, __FILE__, __LINE__);
LONGS_EQUAL(1, accountant.totalAllocationsOfSize(10));
LONGS_EQUAL(1, accountant.totalDeallocationsOfSize(10));
}
TEST(AccountingTestMemoryAllocator, canAllocateAndAccountMemoryMultipleAllocations)
{
char* memory1 = allocator->alloc_memory(10, __FILE__, __LINE__);
char* memory2 = allocator->alloc_memory(8, __FILE__, __LINE__);
char* memory3 = allocator->alloc_memory(12, __FILE__, __LINE__);
allocator->free_memory(memory1, 10, __FILE__, __LINE__);
allocator->free_memory(memory3, 12, __FILE__, __LINE__);
char* memory4 = allocator->alloc_memory(15, __FILE__, __LINE__);
char* memory5 = allocator->alloc_memory(20, __FILE__, __LINE__);
allocator->free_memory(memory2, 8, __FILE__, __LINE__);
allocator->free_memory(memory4, 15, __FILE__, __LINE__);
allocator->free_memory(memory5, 20, __FILE__, __LINE__);
char* memory6 = allocator->alloc_memory(1, __FILE__, __LINE__);
char* memory7 = allocator->alloc_memory(100, __FILE__, __LINE__);
allocator->free_memory(memory6, 1, __FILE__, __LINE__);
allocator->free_memory(memory7, 100, __FILE__, __LINE__);
LONGS_EQUAL(7, accountant.totalAllocations());
LONGS_EQUAL(7, accountant.totalDeallocations());
}
TEST(AccountingTestMemoryAllocator, useOriginalAllocatorWhenDeallocatingMemoryNotAllocatedByAllocator)
{
char* memory = getCurrentMallocAllocator()->alloc_memory(10, __FILE__, __LINE__);
allocator->free_memory(memory, 10, __FILE__, __LINE__);
LONGS_EQUAL(0, accountant.totalAllocations());
LONGS_EQUAL(1, accountant.totalDeallocations());
}
TEST(AccountingTestMemoryAllocator, allocatorForwardsAllocAndFreeName)
{
STRCMP_EQUAL("malloc", allocator->alloc_name());
STRCMP_EQUAL("free", allocator->free_name());
}
class GlobalMemoryAccountantExecFunction
: public ExecFunction
{
public:
void (*testFunction_)(GlobalMemoryAccountant*);
GlobalMemoryAccountant* parameter_;
virtual void exec() _override
{
testFunction_(parameter_);
}
};
TEST_GROUP(GlobalMemoryAccountant)
{
GlobalMemoryAccountant accountant;
TestTestingFixture fixture;
GlobalMemoryAccountantExecFunction testFunction;
GlobalMemoryAllocatorStash stash;
void setup() _override
{
testFunction.parameter_ = &accountant;
fixture.setTestFunction(&testFunction);
stash.save();
}
void teardown() _override
{
stash.restore();
}
};
TEST(GlobalMemoryAccountant, start)
{
accountant.start();
POINTERS_EQUAL(accountant.getMallocAllocator(), getCurrentMallocAllocator());
POINTERS_EQUAL(accountant.getNewAllocator(), getCurrentNewAllocator());
POINTERS_EQUAL(accountant.getNewArrayAllocator(), getCurrentNewArrayAllocator());
accountant.stop();
}
TEST(GlobalMemoryAccountant, stop)
{
TestMemoryAllocator* originalMallocAllocator = getCurrentMallocAllocator();
TestMemoryAllocator* originalNewAllocator = getCurrentNewAllocator();
TestMemoryAllocator* originalNewArrayAllocator = getCurrentNewArrayAllocator();
accountant.start();
accountant.stop();
POINTERS_EQUAL(originalMallocAllocator, getCurrentMallocAllocator());
POINTERS_EQUAL(originalNewAllocator, getCurrentNewAllocator());
POINTERS_EQUAL(originalNewArrayAllocator, getCurrentNewArrayAllocator());
}
#if CPPUTEST_USE_MEM_LEAK_DETECTION
TEST(GlobalMemoryAccountant, report)
{
accountant.start();
char* memory = new char[185];
delete [] memory;
accountant.stop();
/* Allocation includes memory leak info */
STRCMP_CONTAINS("1 1 1", accountant.report().asCharString());
}
TEST(GlobalMemoryAccountant, reportWithCacheSizes)
{
size_t cacheSizes[] = {512};
accountant.useCacheSizes(cacheSizes, 1);
accountant.start();
char* memory = new char[185];
delete [] memory;
accountant.stop();
/* Allocation includes memory leak info */
STRCMP_CONTAINS("512 1 1 1", accountant.report().asCharString());
}
#endif
static void _failStopWithoutStartingWillFail(GlobalMemoryAccountant* accountant)
{
accountant->stop();
}
TEST(GlobalMemoryAccountant, StopCantBeCalledWithoutStarting)
{
testFunction.testFunction_ = _failStopWithoutStartingWillFail;
fixture.runAllTests();
fixture.assertPrintContains("GlobalMemoryAccount: Stop called without starting");
}
static void _failStartingTwiceWillFail(GlobalMemoryAccountant* accountant)
{
accountant->start();
accountant->start();
}
TEST(GlobalMemoryAccountant, startTwiceWillFail)
{
testFunction.testFunction_ = _failStartingTwiceWillFail;
fixture.runAllTests();
accountant.stop();
fixture.assertPrintContains("Global allocator start called twice!");
}
static void _failChangeMallocMemoryAllocator(GlobalMemoryAccountant* accountant)
{
accountant->start();
setCurrentMallocAllocator(defaultMallocAllocator());
accountant->stop();
}
TEST(GlobalMemoryAccountant, checkWhetherMallocAllocatorIsNotChanged)
{
testFunction.testFunction_ = _failChangeMallocMemoryAllocator;
fixture.runAllTests();
fixture.assertPrintContains("GlobalMemoryAccountant: Malloc memory allocator has been changed while accounting for memory");
}
static void _failChangeNewMemoryAllocator(GlobalMemoryAccountant* accountant)
{
accountant->start();
setCurrentNewAllocator(defaultNewAllocator());
accountant->stop();
}
TEST(GlobalMemoryAccountant, checkWhetherNewAllocatorIsNotChanged)
{
testFunction.testFunction_ = _failChangeNewMemoryAllocator;
fixture.runAllTests();
fixture.assertPrintContains("GlobalMemoryAccountant: New memory allocator has been changed while accounting for memory");
}
static void _failChangeNewArrayMemoryAllocator(GlobalMemoryAccountant* accountant)
{
accountant->start();
setCurrentNewArrayAllocator(defaultNewArrayAllocator());
accountant->stop();
}
TEST(GlobalMemoryAccountant, checkWhetherNewArrayAllocatorIsNotChanged)
{
testFunction.testFunction_ = _failChangeNewArrayMemoryAllocator;
fixture.runAllTests();
fixture.assertPrintContains("GlobalMemoryAccountant: New Array memory allocator has been changed while accounting for memory");
}

View file

@ -0,0 +1,472 @@
/*
* 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/TestResult.h"
#include "CppUTest/PlatformSpecificFunctions.h"
static long millisTime;
extern "C" {
static long MockGetPlatformSpecificTimeInMillis()
{
return millisTime;
}
}
TEST_GROUP(TestOutput)
{
TestOutput* printer;
StringBufferTestOutput* mock;
UtestShell* tst;
TestFailure *f;
TestFailure *f2;
TestFailure *f3;
TestResult* result;
void setup() _override
{
mock = new StringBufferTestOutput();
printer = mock;
tst = new UtestShell("group", "test", "file", 10);
f = new TestFailure(tst, "failfile", 20, "message");
f2 = new TestFailure(tst, "file", 20, "message");
f3 = new TestFailure(tst, "file", 2, "message");
result = new TestResult(*mock);
result->setTotalExecutionTime(10);
millisTime = 0;
UT_PTR_SET(GetPlatformSpecificTimeInMillis, MockGetPlatformSpecificTimeInMillis);
TestOutput::setWorkingEnvironment(TestOutput::eclipse);
}
void teardown() _override
{
TestOutput::setWorkingEnvironment(TestOutput::detectEnvironment);
delete printer;
delete tst;
delete f;
delete f2;
delete f3;
delete result;
}
void runOneTest()
{
result->countTest();
result->countRun();
}
};
TEST(TestOutput, PrintConstCharStar)
{
printer->print("hello");
printer->print("hello\n");
STRCMP_EQUAL("hellohello\n", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintLong)
{
long number = 1234;
printer->print(number);
STRCMP_EQUAL("1234", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintSize)
{
size_t ten = 10;
printer->print(ten);
STRCMP_EQUAL("10", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintDouble)
{
printer->printDouble(12.34);
STRCMP_EQUAL("12.34", mock->getOutput().asCharString());
}
TEST(TestOutput, StreamOperators)
{
*printer << "n=" << 1234;
STRCMP_EQUAL("n=1234", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintTestEnded)
{
printer->printCurrentTestEnded(*result);
STRCMP_EQUAL(".", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintTestALot)
{
for (int i = 0; i < 60; ++i) {
printer->printCurrentTestEnded(*result);
}
STRCMP_EQUAL("..................................................\n..........", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintTestALotAndSimulateRepeatRun)
{
for (int i = 0; i < 60; ++i) {
runOneTest();
printer->printCurrentTestEnded(*result);
}
printer->printTestsEnded(*result);
for (int i = 0; i < 60; ++i) {
runOneTest();
printer->printCurrentTestEnded(*result);
}
STRCMP_EQUAL("..................................................\n.........." \
"\nOK (60 tests, 60 ran, 0 checks, 0 ignored, 0 filtered out, 10 ms)\n\n" \
"..................................................\n..........", mock->getOutput().asCharString());
}
TEST(TestOutput, SetProgressIndicator)
{
printer->setProgressIndicator(".");
printer->printCurrentTestEnded(*result);
printer->setProgressIndicator("!");
printer->printCurrentTestEnded(*result);
printer->setProgressIndicator(".");
printer->printCurrentTestEnded(*result);
STRCMP_EQUAL(".!.", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintTestVerboseStarted)
{
mock->verbose(TestOutput::level_verbose);
printer->printCurrentTestStarted(*tst);
STRCMP_EQUAL("TEST(group, test)", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintTestVerboseEnded)
{
mock->verbose(TestOutput::level_verbose);
result->currentTestStarted(tst);
millisTime = 5;
result->currentTestEnded(tst);
STRCMP_EQUAL("TEST(group, test) - 5 ms\n", mock->getOutput().asCharString());
}
TEST(TestOutput, printColorWithSuccess)
{
mock->color();
runOneTest();
printer->printTestsEnded(*result);
STRCMP_EQUAL("\n\033[32;1mOK (1 tests, 1 ran, 0 checks, 0 ignored, 0 filtered out, 10 ms)\033[m\n\n",
mock->getOutput().asCharString());
}
TEST(TestOutput, printColorWithFailures)
{
mock->color();
runOneTest();
result->addFailure(*f);
printer->flush();
printer->printTestsEnded(*result);
STRCMP_EQUAL("\n\033[31;1mErrors (1 failures, 1 tests, 1 ran, 0 checks, 0 ignored, 0 filtered out, 10 ms)"
"\033[m\n\n", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintTestRun)
{
printer->printTestRun(2, 3);
STRCMP_EQUAL("Test run 2 of 3\n", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintTestRunOnlyOne)
{
printer->printTestRun(1, 1);
STRCMP_EQUAL("", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintWithFailureInSameFile)
{
printer->printFailure(*f2);
STRCMP_EQUAL("\nfile:20: error: Failure in TEST(group, test)\n\tmessage\n\n", mock->getOutput().asCharString());
}
TEST(TestOutput, PrintFailureWithFailInDifferentFile)
{
printer->printFailure(*f);
const char* expected =
"\nfile:10: error: Failure in TEST(group, test)"
"\nfailfile:20: error:\n\tmessage\n\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TestOutput, PrintFailureWithFailInHelper)
{
printer->printFailure(*f3);
const char* expected =
"\nfile:10: error: Failure in TEST(group, test)"
"\nfile:2: error:\n\tmessage\n\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TestOutput, PrintInVisualStudioFormat)
{
TestOutput::setWorkingEnvironment(TestOutput::visualStudio);
printer->printFailure(*f3);
const char* expected =
"\nfile(10): error: Failure in TEST(group, test)"
"\nfile(2): error:\n\tmessage\n\n";
STRCMP_EQUAL(expected, mock->getOutput().asCharString());
}
TEST(TestOutput, PrintTestStarts)
{
printer->printTestsStarted();
STRCMP_EQUAL("", mock->getOutput().asCharString());
}
TEST(TestOutput, printTestsEnded)
{
result->countTest();
result->countCheck();
result->countIgnored();
result->countIgnored();
result->countRun();
result->countRun();
result->countRun();
printer->printTestsEnded(*result);
STRCMP_EQUAL("\nOK (1 tests, 3 ran, 1 checks, 2 ignored, 0 filtered out, 10 ms)\n\n", mock->getOutput().asCharString());
}
TEST(TestOutput, printTestsEndedWithFailures)
{
result->addFailure(*f);
printer->flush();
printer->printTestsEnded(*result);
STRCMP_EQUAL("\nErrors (1 failures, 0 tests, 0 ran, 0 checks, 0 ignored, 0 filtered out, 10 ms)\n\n", mock->getOutput().asCharString());
}
TEST(TestOutput, printTestsEndedWithNoTestsRunOrIgnored)
{
result->countTest();
printer->flush();
printer->printTestsEnded(*result);
STRCMP_EQUAL("\nErrors (ran nothing, 1 tests, 0 ran, 0 checks, 0 ignored, 0 filtered out, 10 ms)\n"
"Note: 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.\n\n",
mock->getOutput().asCharString());
}
class CompositeTestOutputTestStringBufferTestOutput : public StringBufferTestOutput
{
public:
virtual void printTestsStarted() _override
{
output += "Test Start\n";
}
virtual void printTestsEnded(const TestResult& result) _override
{
output += StringFromFormat("Test End %d\n", (int) result.getTestCount());
}
void printCurrentGroupStarted(const UtestShell& test) _override
{
output += StringFromFormat("Group %s Start\n", test.getGroup().asCharString());
}
void printCurrentGroupEnded(const TestResult& res) _override
{
output += StringFromFormat("Group End %d\n", (int) res.getTestCount());
}
virtual void printCurrentTestStarted(const UtestShell&) _override
{
output += "s";
}
void flush() _override
{
output += "flush";
}
virtual bool isVerbose()
{
return verbose_ == level_verbose || verbose_ == level_veryVerbose;
}
virtual bool isColor()
{
return color_;
}
virtual const char* getProgressIndicator()
{
return progressIndication_;
}
};
TEST_GROUP(CompositeTestOutput)
{
CompositeTestOutputTestStringBufferTestOutput* output1;
CompositeTestOutputTestStringBufferTestOutput* output2;
CompositeTestOutput compositeOutput;
TestResult* result;
UtestShell* test;
void setup() _override
{
output1 = new CompositeTestOutputTestStringBufferTestOutput;
output2 = new CompositeTestOutputTestStringBufferTestOutput;
compositeOutput.setOutputOne(output1);
compositeOutput.setOutputTwo(output2);
result = new TestResult(compositeOutput);
test = new UtestShell("Group", "Name", "file", 10);
}
void teardown() _override
{
delete test;
delete result;
}
};
TEST(CompositeTestOutput, TestStartedAndEnded)
{
compositeOutput.printTestsStarted();
compositeOutput.printTestsEnded(*result);
STRCMP_EQUAL("Test Start\nTest End 0\n", output1->getOutput().asCharString());
STRCMP_EQUAL("Test Start\nTest End 0\n", output2->getOutput().asCharString());
}
TEST(CompositeTestOutput, CurrentTestStartedAndEnded)
{
compositeOutput.printCurrentTestStarted(*test);
compositeOutput.printCurrentTestEnded(*result);
STRCMP_EQUAL("s.", output1->getOutput().asCharString());
STRCMP_EQUAL("s.", output2->getOutput().asCharString());
}
TEST(CompositeTestOutput, CurrentGroupStartedAndEnded)
{
compositeOutput.printCurrentGroupStarted(*test);
compositeOutput.printCurrentGroupEnded(*result);
STRCMP_EQUAL("Group Group Start\nGroup End 0\n", output1->getOutput().asCharString());
STRCMP_EQUAL("Group Group Start\nGroup End 0\n", output2->getOutput().asCharString());
}
TEST(CompositeTestOutput, PrintBuffer)
{
compositeOutput.printBuffer("Boo");
STRCMP_EQUAL("Boo", output1->getOutput().asCharString());
STRCMP_EQUAL("Boo", output2->getOutput().asCharString());
}
TEST(CompositeTestOutput, printChar)
{
compositeOutput.print("Boo");
STRCMP_EQUAL("Boo", output1->getOutput().asCharString());
STRCMP_EQUAL("Boo", output2->getOutput().asCharString());
}
TEST(CompositeTestOutput, printLong)
{
long ten = 10;
compositeOutput.print(ten);
STRCMP_EQUAL("10", output1->getOutput().asCharString());
STRCMP_EQUAL("10", output2->getOutput().asCharString());
}
TEST(CompositeTestOutput, PrintSize)
{
size_t ten = 10;
compositeOutput.print(ten);
STRCMP_EQUAL("10", output1->getOutput().asCharString());
STRCMP_EQUAL("10", output2->getOutput().asCharString());
}
TEST(CompositeTestOutput, printDouble)
{
compositeOutput.printDouble(1.01);
STRCMP_EQUAL("1.01", output1->getOutput().asCharString());
STRCMP_EQUAL("1.01", output2->getOutput().asCharString());
}
TEST(CompositeTestOutput, verbose)
{
compositeOutput.verbose(TestOutput::level_verbose);
CHECK(output1->isVerbose());
CHECK(output2->isVerbose());
}
TEST(CompositeTestOutput, color)
{
compositeOutput.color();
CHECK(output1->isColor());
CHECK(output2->isColor());
}
TEST(CompositeTestOutput, PrintTestFailure)
{
TestOutput::WorkingEnvironment previousEnvironment = TestOutput::getWorkingEnvironment();
TestOutput::setWorkingEnvironment(TestOutput::eclipse);
TestFailure failure(test, "file", 10, "failed");
compositeOutput.printFailure(failure);
STRCMP_EQUAL("\nfile:10: error: Failure in TEST(Group, Name)\n\tfailed\n\n", output1->getOutput().asCharString());
STRCMP_EQUAL("\nfile:10: error: Failure in TEST(Group, Name)\n\tfailed\n\n", output2->getOutput().asCharString());
TestOutput::setWorkingEnvironment(previousEnvironment);
}
TEST(CompositeTestOutput, PrintTestRun)
{
compositeOutput.printTestRun(1, 2);
STRCMP_EQUAL("Test run 1 of 2\n", output1->getOutput().asCharString());
STRCMP_EQUAL("Test run 1 of 2\n", output2->getOutput().asCharString());
}
TEST(CompositeTestOutput, setProgressIndicator)
{
compositeOutput.setProgressIndicator("?");
STRCMP_EQUAL("?", output1->getProgressIndicator());
STRCMP_EQUAL("?", output2->getProgressIndicator());
}
TEST(CompositeTestOutput, flush)
{
compositeOutput.flush();
STRCMP_EQUAL("flush", output1->getOutput().asCharString());
STRCMP_EQUAL("flush", output2->getOutput().asCharString());
}
TEST(CompositeTestOutput, deletePreviousInstanceWhenSettingNew)
{
compositeOutput.setOutputOne(new CompositeTestOutput);
compositeOutput.setOutputTwo(new CompositeTestOutput);
// CHECK NO MEMORY LEAKS
}

View file

@ -0,0 +1,427 @@
/*
* 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/TestOutput.h"
#include "CppUTest/PlatformSpecificFunctions.h"
namespace
{
const int testLineNumber = 1;
}
class MockTest: public UtestShell
{
public:
MockTest(const char* group = "Group") :
UtestShell(group, "Name", "File", testLineNumber), hasRun_(false)
{
}
virtual void runOneTest(TestPlugin*, TestResult&) _override
{
hasRun_ = true;
}
bool hasRun_;
};
class MockTestResult: public TestResult
{
public:
int countTestsStarted;
int countTestsEnded;
int countCurrentTestStarted;
int countCurrentTestEnded;
int countCurrentGroupStarted;
int countCurrentGroupEnded;
MockTestResult(TestOutput& p) :
TestResult(p)
{
resetCount();
}
virtual ~MockTestResult() _destructor_override
{
}
void resetCount()
{
countTestsStarted = 0;
countTestsEnded = 0;
countCurrentTestStarted = 0;
countCurrentTestEnded = 0;
countCurrentGroupStarted = 0;
countCurrentGroupEnded = 0;
}
virtual void testsStarted() _override
{
countTestsStarted++;
}
virtual void testsEnded() _override
{
countTestsEnded++;
}
virtual void currentTestStarted(UtestShell* /*test*/) _override
{
countCurrentTestStarted++;
}
virtual void currentTestEnded(UtestShell* /*test*/) _override
{
countCurrentTestEnded++;
}
virtual void currentGroupStarted(UtestShell* /*test*/) _override
{
countCurrentGroupStarted++;
}
virtual void currentGroupEnded(UtestShell* /*test*/) _override
{
countCurrentGroupEnded++;
}
};
TEST_GROUP(TestRegistry)
{
TestRegistry* myRegistry;
StringBufferTestOutput* output;
MockTest* test1;
MockTest* test2;
MockTest* test3;
MockTest* test4;
TestResult *result;
MockTestResult *mockResult;
void setup() _override
{
output = new StringBufferTestOutput();
mockResult = new MockTestResult(*output);
result = mockResult;
test1 = new MockTest();
test2 = new MockTest();
test3 = new MockTest("group2");
test4 = new MockTest();
myRegistry = new TestRegistry();
myRegistry->setCurrentRegistry(myRegistry);
}
void teardown() _override
{
myRegistry->setCurrentRegistry(NULLPTR);
delete myRegistry;
delete test1;
delete test2;
delete test3;
delete test4;
delete result;
delete output;
}
void addAndRunAllTests()
{
myRegistry->addTest(test1);
myRegistry->addTest(test2);
myRegistry->addTest(test3);
myRegistry->runAllTests(*result);
}
};
TEST(TestRegistry, registryMyRegistryAndReset)
{
CHECK(myRegistry->getCurrentRegistry() == myRegistry);
}
TEST(TestRegistry, emptyRegistryIsEmpty)
{
CHECK(myRegistry->countTests() == 0);
}
TEST(TestRegistry, addOneTestIsNotEmpty)
{
myRegistry->addTest(test1);
CHECK(myRegistry->countTests() == 1);
}
TEST(TestRegistry, addOneTwoTests)
{
myRegistry->addTest(test1);
myRegistry->addTest(test2);
CHECK(myRegistry->countTests() == 2);
}
TEST(TestRegistry, runTwoTests)
{
myRegistry->addTest(test1);
myRegistry->addTest(test2);
CHECK(!test1->hasRun_);
CHECK(!test2->hasRun_);
myRegistry->runAllTests(*result);
CHECK(test1->hasRun_);
CHECK(test2->hasRun_);
}
TEST(TestRegistry, runTwoTestsCheckResultFunctionsCalled)
{
myRegistry->addTest(test1);
myRegistry->addTest(test2);
myRegistry->runAllTests(*result);
LONGS_EQUAL(1, mockResult->countTestsStarted);
LONGS_EQUAL(1, mockResult->countTestsEnded);
LONGS_EQUAL(1, mockResult->countCurrentGroupStarted);
LONGS_EQUAL(1, mockResult->countCurrentGroupEnded);
LONGS_EQUAL(2, mockResult->countCurrentTestStarted);
LONGS_EQUAL(2, mockResult->countCurrentTestEnded);
}
TEST(TestRegistry, runThreeTestsandTwoGroupsCheckResultFunctionsCalled)
{
addAndRunAllTests();
LONGS_EQUAL(2, mockResult->countCurrentGroupStarted);
LONGS_EQUAL(2, mockResult->countCurrentGroupEnded);
LONGS_EQUAL(3, mockResult->countCurrentTestStarted);
LONGS_EQUAL(3, mockResult->countCurrentTestEnded);
}
TEST(TestRegistry, unDoTest)
{
myRegistry->addTest(test1);
CHECK(myRegistry->countTests() == 1);
myRegistry->unDoLastAddTest();
CHECK(myRegistry->countTests() == 0);
}
TEST(TestRegistry, unDoButNoTest)
{
CHECK(myRegistry->countTests() == 0);
myRegistry->unDoLastAddTest();
CHECK(myRegistry->countTests() == 0);
}
TEST(TestRegistry, reallyUndoLastTest)
{
myRegistry->addTest(test1);
myRegistry->addTest(test2);
CHECK(myRegistry->countTests() == 2);
myRegistry->unDoLastAddTest();
CHECK(myRegistry->countTests() == 1);
myRegistry->runAllTests(*result);
CHECK(test1->hasRun_);
CHECK(!test2->hasRun_);
}
TEST(TestRegistry, findTestWithNameDoesntExist)
{
CHECK(myRegistry->findTestWithName("ThisTestDoesntExists") == NULLPTR);
}
TEST(TestRegistry, findTestWithName)
{
test1->setTestName("NameOfATestThatDoesExist");
test2->setTestName("SomeOtherTest");
myRegistry->addTest(test1);
myRegistry->addTest(test2);
CHECK(myRegistry->findTestWithName("NameOfATestThatDoesExist") != NULLPTR);
}
TEST(TestRegistry, findTestWithGroupDoesntExist)
{
CHECK(myRegistry->findTestWithGroup("ThisTestGroupDoesntExists") == NULLPTR);
}
TEST(TestRegistry, findTestWithGroup)
{
test1->setGroupName("GroupOfATestThatDoesExist");
test2->setGroupName("SomeOtherGroup");
myRegistry->addTest(test1);
myRegistry->addTest(test2);
CHECK(myRegistry->findTestWithGroup("GroupOfATestThatDoesExist") != NULLPTR);
}
TEST(TestRegistry, nameFilterWorks)
{
test1->setTestName("testname");
test2->setTestName("noname");
TestFilter nameFilter("testname");
myRegistry->setNameFilters(&nameFilter);
addAndRunAllTests();
CHECK(test1->hasRun_);
CHECK(!test2->hasRun_);
}
TEST(TestRegistry, groupFilterWorks)
{
test1->setGroupName("groupname");
test2->setGroupName("noname");
TestFilter groupFilter("groupname");
myRegistry->setGroupFilters(&groupFilter);
addAndRunAllTests();
CHECK(test1->hasRun_);
CHECK(!test2->hasRun_);
}
TEST(TestRegistry, runTestInSeperateProcess)
{
myRegistry->setRunTestsInSeperateProcess();
myRegistry->addTest(test1);
myRegistry->runAllTests(*result);
CHECK(test1->isRunInSeperateProcess());
}
TEST(TestRegistry, CurrentRepetitionIsCorrectNone)
{
CHECK(0 == myRegistry->getCurrentRepetition());
myRegistry->runAllTests(*result);
LONGS_EQUAL(1, myRegistry->getCurrentRepetition());
}
TEST(TestRegistry, CurrentRepetitionIsCorrectTwo)
{
CHECK(0 == myRegistry->getCurrentRepetition());
myRegistry->runAllTests(*result);
myRegistry->runAllTests(*result);
LONGS_EQUAL(2, myRegistry->getCurrentRepetition());
}
class MyTestPluginDummy: public TestPlugin
{
public:
MyTestPluginDummy(const SimpleString& name) : TestPlugin(name) {}
virtual ~MyTestPluginDummy() _destructor_override {}
virtual void runAllPreTestAction(UtestShell&, TestResult&) _override {}
virtual void runAllPostTestAction(UtestShell&, TestResult&) _override {}
};
TEST(TestRegistry, ResetPluginsWorks)
{
MyTestPluginDummy plugin1("Plugin-1");
MyTestPluginDummy plugin2("Plugin-2");
myRegistry->installPlugin(&plugin1);
myRegistry->installPlugin(&plugin2);
LONGS_EQUAL(2, myRegistry->countPlugins());
myRegistry->resetPlugins();
LONGS_EQUAL(0, myRegistry->countPlugins());
}
TEST(TestRegistry, listTestGroupNames_shouldListBackwardsGroup1AfterGroup11AndGroup2OnlyOnce)
{
test1->setGroupName("GROUP_1");
myRegistry->addTest(test1);
test2->setGroupName("GROUP_2");
myRegistry->addTest(test2);
test3->setGroupName("GROUP_11");
myRegistry->addTest(test3);
test4->setGroupName("GROUP_2");
myRegistry->addTest(test4);
myRegistry->listTestGroupNames(*result);
SimpleString s = output->getOutput();
STRCMP_EQUAL("GROUP_2 GROUP_11 GROUP_1", s.asCharString());
}
TEST(TestRegistry, listTestGroupAndCaseNames_shouldListBackwardsGroupATestaAfterGroupAtestaa)
{
test1->setGroupName("GROUP_A");
test1->setTestName("test_a");
myRegistry->addTest(test1);
test2->setGroupName("GROUP_B");
test2->setTestName("test_b");
myRegistry->addTest(test2);
test3->setGroupName("GROUP_A");
test3->setTestName("test_aa");
myRegistry->addTest(test3);
myRegistry->listTestGroupAndCaseNames(*result);
SimpleString s = output->getOutput();
STRCMP_EQUAL("GROUP_A.test_aa GROUP_B.test_b GROUP_A.test_a", s.asCharString());
}
TEST(TestRegistry, shuffleEmptyListIsNoOp)
{
CHECK_TRUE(myRegistry->getFirstTest() == NULLPTR);
myRegistry->shuffleTests(0);
CHECK_TRUE(myRegistry->getFirstTest() == NULLPTR);
}
TEST(TestRegistry, shuffleSingleTestIsNoOp)
{
myRegistry->addTest(test1);
myRegistry->shuffleTests(0);
CHECK_TRUE(myRegistry->getFirstTest() == test1);
}
static int getZero()
{
return 0;
}
IGNORE_TEST(TestRegistry, shuffleTestList)
{
UT_PTR_SET(PlatformSpecificRand, getZero);
myRegistry->addTest(test3);
myRegistry->addTest(test2);
myRegistry->addTest(test1);
UtestShell* first_before = myRegistry->getFirstTest();
UtestShell* second_before = first_before->getNext();
UtestShell* third_before = second_before->getNext();
CHECK_TRUE(first_before == test1);
CHECK_TRUE(second_before == test2);
CHECK_TRUE(third_before == test3);
CHECK_TRUE(third_before->getNext() == NULLPTR);
// shuffle always with element at index 0: [1] 2 [3] --> [3] [2] 1 --> 2 3 1
myRegistry->shuffleTests(0);
UtestShell* first_after = myRegistry->getFirstTest();
UtestShell* second_after = first_after->getNext();
UtestShell* third_after = second_after->getNext();
CHECK_TRUE(first_after == test2);
CHECK_TRUE(second_after == test3);
CHECK_TRUE(third_after == test1);
CHECK_TRUE(third_after->getNext() == NULLPTR);
}
TEST(TestRegistry, reverseTests)
{
myRegistry->addTest(test1);
myRegistry->addTest(test2);
myRegistry->reverseTests();
CHECK(test1 == myRegistry->getFirstTest());
}
TEST(TestRegistry, reverseZeroTests)
{
myRegistry->reverseTests();
CHECK(NULLPTR == myRegistry->getFirstTest());
}

View file

@ -0,0 +1,99 @@
/*
* 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/PlatformSpecificFunctions.h"
#include "CppUTest/TestOutput.h"
extern "C" {
static long MockGetPlatformSpecificTimeInMillis()
{
return 10;
}
}
TEST_GROUP(TestResult)
{
TestOutput* printer;
StringBufferTestOutput* mock;
TestResult* res;
void setup() _override
{
mock = new StringBufferTestOutput();
printer = mock;
res = new TestResult(*printer);
UT_PTR_SET(GetPlatformSpecificTimeInMillis, MockGetPlatformSpecificTimeInMillis);
}
void teardown() _override
{
delete printer;
delete res;
}
};
TEST(TestResult, TestEndedWillPrintResultsAndExecutionTime)
{
res->testsEnded();
CHECK(mock->getOutput().contains("10 ms"));
}
TEST(TestResult, ResultIsOkIfTestIsRunWithNoFailures)
{
res->countTest();
res->countRun();
CHECK_FALSE(res->isFailure());
}
TEST(TestResult, ResultIsOkIfTestIsIgnored)
{
res->countTest();
res->countIgnored();
CHECK_FALSE(res->isFailure());
}
TEST(TestResult, ResultIsNotOkIfFailures)
{
res->countTest();
res->countRun();
res->addFailure(TestFailure(UtestShell::getCurrent(), StringFrom("dummy message")));
CHECK_TRUE(res->isFailure());
}
TEST(TestResult, ResultIsNotOkIfNoTestsAtAll)
{
CHECK_TRUE(res->isFailure());
}
TEST(TestResult, ResultIsNotOkIfNoTestsRunOrIgnored)
{
res->countTest();
CHECK_TRUE(res->isFailure());
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,468 @@
/*
* 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/TestTestingFixture.h"
#define CHECK_TEST_FAILS_PROPER_WITH_TEXT(text) fixture.checkTestFailsWithProperTestLocation(text, __FILE__, __LINE__)
TEST_GROUP(UnitTestStringMacros)
{
TestTestingFixture fixture;
};
static void _STRCMP_EQUALWithActualIsNULLTestMethod()
{
STRCMP_EQUAL("ok", NULLPTR);
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_EQUALAndActualIsNULL)
{
fixture.runTestWithMethod(_STRCMP_EQUALWithActualIsNULLTestMethod);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <(null)>");
}
static void _STRCMP_EQUALWithExpectedIsNULLTestMethod()
{
STRCMP_EQUAL(NULLPTR, "ok");
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_EQUALAndExpectedIsNULL)
{
fixture.runTestWithMethod(_STRCMP_EQUALWithExpectedIsNULLTestMethod);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <(null)>");
}
static void _STRCMP_CONTAINSWithActualIsNULLTestMethod()
{
STRCMP_CONTAINS("ok", NULLPTR);
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_CONTAINSAndActualIsNULL)
{
fixture.runTestWithMethod(_STRCMP_CONTAINSWithActualIsNULLTestMethod);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("did not contain <ok>");
}
static void _STRCMP_CONTAINSWithExpectedIsNULLTestMethod()
{
STRCMP_CONTAINS(NULLPTR, "ok");
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_CONTAINSAndExpectedIsNULL)
{
fixture.runTestWithMethod(_STRCMP_CONTAINSWithExpectedIsNULLTestMethod);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("did not contain <>");
}
static void _STRNCMP_EQUALWithActualIsNULLTestMethod()
{
STRNCMP_EQUAL("ok", NULLPTR, 2);
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRNCMP_EQUALAndActualIsNULL)
{
fixture.runTestWithMethod(_STRNCMP_EQUALWithActualIsNULLTestMethod);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <(null)>");
}
static void _STRNCMP_EQUALWithExpectedIsNULLTestMethod()
{
STRNCMP_EQUAL(NULLPTR, "ok", 2);
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRNCMP_EQUALAndExpectedIsNULL)
{
fixture.runTestWithMethod(_STRNCMP_EQUALWithExpectedIsNULLTestMethod);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <(null)>");
}
static void _STRCMP_NOCASE_EQUALWithActualIsNULLTestMethod()
{
STRCMP_NOCASE_EQUAL("ok", NULLPTR);
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_NOCASE_EQUALAndActualIsNULL)
{
fixture.runTestWithMethod(_STRCMP_NOCASE_EQUALWithActualIsNULLTestMethod);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <(null)>");
}
static void _STRCMP_NOCASE_EQUALWithExpectedIsNULLTestMethod()
{
STRCMP_NOCASE_EQUAL(NULLPTR, "ok");
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_NOCASE_EQUALAndExpectedIsNULL)
{
fixture.runTestWithMethod(_STRCMP_NOCASE_EQUALWithExpectedIsNULLTestMethod);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <(null)>");
}
static void _STRCMP_NOCASE_EQUALWithUnequalInputTestMethod()
{
STRCMP_NOCASE_EQUAL("no", "ok");
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_NOCASE_EQUALAndUnequalInput)
{
fixture.runTestWithMethod(_STRCMP_NOCASE_EQUALWithUnequalInputTestMethod);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <ok>");
}
static void _STRCMP_NOCASE_CONTAINSWithActualIsNULLTestMethod()
{
STRCMP_NOCASE_CONTAINS("ok", NULLPTR);
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_NOCASE_CONTAINSAndActualIsNULL)
{
fixture.runTestWithMethod(_STRCMP_NOCASE_CONTAINSWithActualIsNULLTestMethod);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("did not contain <ok>");
}
static void _STRCMP_NOCASE_CONTAINSWithExpectedIsNULLTestMethod()
{
STRCMP_NOCASE_CONTAINS(NULLPTR, "ok");
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_NOCASE_CONTAINSAndExpectedIsNULL)
{
fixture.runTestWithMethod(_STRCMP_NOCASE_CONTAINSWithExpectedIsNULLTestMethod);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("did not contain <>");
}
static void _failingTestMethodWithSTRCMP_EQUAL()
{
STRCMP_EQUAL("hello", "hell");
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_EQUAL)
{
fixture.runTestWithMethod(_failingTestMethodWithSTRCMP_EQUAL);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <hello>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <hell>");
}
TEST(UnitTestStringMacros, STRCMP_EQUALBehavesAsProperMacro)
{
if (false) STRCMP_EQUAL("1", "2");
else STRCMP_EQUAL("1", "1");
}
IGNORE_TEST(UnitTestStringMacros, STRCMP_EQUALWorksInAnIgnoredTest)
{
STRCMP_EQUAL("Hello", "World"); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
static void _failingTestMethodWithSTRCMP_EQUAL_TEXT()
{
STRCMP_EQUAL_TEXT("hello", "hell", "Failed because it failed");
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_EQUAL_TEXT)
{
fixture.runTestWithMethod(_failingTestMethodWithSTRCMP_EQUAL_TEXT);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <hello>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <hell>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("Failed because it failed");
}
TEST(UnitTestStringMacros, STRCMP_EQUAL_TEXTBehavesAsProperMacro)
{
if (false) STRCMP_EQUAL_TEXT("1", "2", "Failed because it failed");
else STRCMP_EQUAL_TEXT("1", "1", "Failed because it failed");
}
IGNORE_TEST(UnitTestStringMacros, STRCMP_EQUAL_TEXTWorksInAnIgnoredTest)
{
STRCMP_EQUAL_TEXT("Hello", "World", "Failed because it failed"); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
static void _failingTestMethodWithSTRNCMP_EQUAL()
{
STRNCMP_EQUAL("hello", "hallo", 5);
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRNCMP_EQUAL)
{
fixture.runTestWithMethod(_failingTestMethodWithSTRNCMP_EQUAL);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <hello>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <hallo>");
}
TEST(UnitTestStringMacros, STRNCMP_EQUALBehavesAsProperMacro)
{
if (false) STRNCMP_EQUAL("1", "2", 1);
else STRNCMP_EQUAL("1", "1", 1);
}
IGNORE_TEST(UnitTestStringMacros, STRNCMP_EQUALWorksInAnIgnoredTest)
{
STRNCMP_EQUAL("Hello", "World", 3); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
static void _failingTestMethodWithSTRNCMP_EQUAL_TEXT()
{
STRNCMP_EQUAL_TEXT("hello", "hallo", 5, "Failed because it failed");
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRNCMP_EQUAL_TEXT)
{
fixture.runTestWithMethod(_failingTestMethodWithSTRNCMP_EQUAL_TEXT);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <hello>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <hallo>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("Failed because it failed");
}
TEST(UnitTestStringMacros, STRNCMP_EQUAL_TEXTBehavesAsProperMacro)
{
if (false) STRNCMP_EQUAL_TEXT("1", "2", 1, "Failed because it failed");
else STRNCMP_EQUAL_TEXT("1", "1", 1, "Failed because it failed");
}
IGNORE_TEST(UnitTestStringMacros, STRNCMP_EQUAL_TEXTWorksInAnIgnoredTest)
{
STRNCMP_EQUAL_TEXT("Hello", "World", 3, "Failed because it failed"); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
static void _failingTestMethodWithSTRCMP_NOCASE_EQUAL()
{
STRCMP_NOCASE_EQUAL("hello", "Hell");
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_NOCASE_EQUAL)
{
fixture.runTestWithMethod(_failingTestMethodWithSTRCMP_NOCASE_EQUAL);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <hello>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <Hell>");
}
TEST(UnitTestStringMacros, STRCMP_NOCASE_EQUALBehavesAsProperMacro)
{
if (false) STRCMP_NOCASE_EQUAL("1", "2");
else STRCMP_NOCASE_EQUAL("1", "1");
}
IGNORE_TEST(UnitTestStringMacros, STRCMP_NOCASE_EQUALWorksInAnIgnoredTest)
{
STRCMP_NOCASE_EQUAL("Hello", "World"); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
static void _failingTestMethodWithSTRCMP_NOCASE_EQUAL_TEXT()
{
STRCMP_NOCASE_EQUAL_TEXT("hello", "hell", "Failed because it failed");
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_NOCASE_EQUAL_TEXT)
{
fixture.runTestWithMethod(_failingTestMethodWithSTRCMP_NOCASE_EQUAL_TEXT);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <hello>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <hell>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("Failed because it failed");
}
TEST(UnitTestStringMacros, STRCMP_NOCASE_EQUAL_TEXTBehavesAsProperMacro)
{
if (false) STRCMP_NOCASE_EQUAL_TEXT("1", "2", "Failed because it failed");
else STRCMP_NOCASE_EQUAL_TEXT("1", "1", "Failed because it failed");
}
IGNORE_TEST(UnitTestStringMacros, STRCMP_NOCASE_EQUAL_TEXTWorksInAnIgnoredTest)
{
STRCMP_NOCASE_EQUAL_TEXT("Hello", "World", "Failed because it failed"); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
static void _failingTestMethodWithSTRCMP_CONTAINS()
{
STRCMP_CONTAINS("hello", "world");
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_CONTAINS)
{
fixture.runTestWithMethod(_failingTestMethodWithSTRCMP_CONTAINS);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("actual <world>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("did not contain <hello>");
}
TEST(UnitTestStringMacros, STRCMP_CONTAINSBehavesAsProperMacro)
{
if (false) STRCMP_CONTAINS("1", "2");
else STRCMP_CONTAINS("1", "1");
}
IGNORE_TEST(UnitTestStringMacros, STRCMP_CONTAINSWorksInAnIgnoredTest)
{
STRCMP_CONTAINS("Hello", "World"); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
static void _failingTestMethodWithSTRCMP_CONTAINS_TEXT()
{
STRCMP_CONTAINS_TEXT("hello", "world", "Failed because it failed");
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, FailureWithSTRCMP_CONTAINS_TEXT)
{
fixture.runTestWithMethod(_failingTestMethodWithSTRCMP_CONTAINS_TEXT);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("actual <world>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("did not contain <hello>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("Failed because it failed");
}
TEST(UnitTestStringMacros, STRCMP_CONTAINS_TEXTBehavesAsProperMacro)
{
if (false) STRCMP_CONTAINS_TEXT("1", "2", "Failed because it failed");
else STRCMP_CONTAINS_TEXT("1", "1", "Failed because it failed");
}
IGNORE_TEST(UnitTestStringMacros, STRCMP_CONTAINS_TEXTWorksInAnIgnoredTest)
{
STRCMP_CONTAINS_TEXT("Hello", "World", "Failed because it failed"); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
static void _failingTestMethodWithSTRCMP_NOCASE_CONTAINS()
{
STRCMP_NOCASE_CONTAINS("hello", "WORLD");
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
}
TEST(UnitTestStringMacros, FailureWithSTRCMP_NOCASE_CONTAINS)
{
fixture.runTestWithMethod(_failingTestMethodWithSTRCMP_NOCASE_CONTAINS);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("actual <WORLD>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("did not contain <hello>");
}
TEST(UnitTestStringMacros, STRCMP_NOCASE_CONTAINSBehavesAsProperMacro)
{
if (false) STRCMP_NOCASE_CONTAINS("never", "executed");
else STRCMP_NOCASE_CONTAINS("hello", "HELLO WORLD");
}
IGNORE_TEST(UnitTestStringMacros, STRCMP_NO_CASE_CONTAINSWorksInAnIgnoredTest)
{
STRCMP_NOCASE_CONTAINS("Hello", "World"); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
static void _failingTestMethodWithSTRCMP_NOCASE_CONTAINS_TEXT()
{
STRCMP_NOCASE_CONTAINS_TEXT("hello", "WORLD", "Failed because it failed");
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
}
TEST(UnitTestStringMacros, FailureWithSTRCMP_NOCASE_CONTAINS_TEXT)
{
fixture.runTestWithMethod(_failingTestMethodWithSTRCMP_NOCASE_CONTAINS_TEXT);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("actual <WORLD>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("did not contain <hello>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("Failed because it failed");
}
TEST(UnitTestStringMacros, STRCMP_NOCASE_CONTAINS_TEXTBehavesAsProperMacro)
{
if (false) STRCMP_NOCASE_CONTAINS_TEXT("never", "executed", "Failed because it failed");
else STRCMP_NOCASE_CONTAINS_TEXT("hello", "HELLO WORLD", "Failed because it failed");
}
IGNORE_TEST(UnitTestStringMacros, STRCMP_NO_CASE_CONTAINS_TEXTWorksInAnIgnoredTest)
{
STRCMP_NOCASE_CONTAINS_TEXT("Hello", "World", "Failed because it failed"); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, NFirstCharsComparison)
{
STRNCMP_EQUAL("Hello World!", "Hello Peter!", 0);
STRNCMP_EQUAL("Hello World!", "Hello Peter!", 1);
STRNCMP_EQUAL("Hello World!", "Hello Peter!", 6);
STRNCMP_EQUAL("Hello World!", "Hello", 5);
}
static void _compareNFirstCharsWithUpperAndLowercase()
{
STRNCMP_EQUAL("hello world!", "HELLO WORLD!", 12);
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, CompareNFirstCharsWithUpperAndLowercase)
{
fixture.runTestWithMethod(_compareNFirstCharsWithUpperAndLowercase);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <hello world!>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <HELLO WORLD!>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("difference starts at position 0");
}
static void _compareNFirstCharsWithDifferenceInTheMiddle()
{
STRNCMP_EQUAL("Hello World!", "Hello Peter!", 12);
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, CompareNFirstCharsWithDifferenceInTheMiddle)
{
fixture.runTestWithMethod(_compareNFirstCharsWithDifferenceInTheMiddle);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <Hello World!>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <Hello Peter!>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("difference starts at position 6");
}
static void _compareNFirstCharsWithEmptyString()
{
STRNCMP_EQUAL("", "Not empty string", 5);
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, CompareNFirstCharsWithEmptyString)
{
fixture.runTestWithMethod(_compareNFirstCharsWithEmptyString);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <Not empty string>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("difference starts at position 0");
}
static void _compareNFirstCharsWithLastCharDifferent()
{
STRNCMP_EQUAL("Not empty string?", "Not empty string!", 17);
TestTestingFixture::lineExecutedAfterCheck(); // LCOV_EXCL_LINE
} // LCOV_EXCL_LINE
TEST(UnitTestStringMacros, CompareNFirstCharsWithLastCharDifferent)
{
fixture.runTestWithMethod(_compareNFirstCharsWithLastCharDifferent);
CHECK_TEST_FAILS_PROPER_WITH_TEXT("expected <Not empty string?>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("but was <Not empty string!>");
CHECK_TEST_FAILS_PROPER_WITH_TEXT("difference starts at position 16");
}

View file

@ -0,0 +1,211 @@
/*
* 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/CommandLineTestRunner.h"
#include "CppUTest/TestHarness.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/PlatformSpecificFunctions.h"
#include "CppUTest/StandardCLibrary.h"
#include "CppUTest/TestMemoryAllocator.h"
#if CPPUTEST_USE_STD_C_LIB
// This will cause a crash in VS2010 due to PlatformSpecificFree being uninitialized
static const SimpleString str1("abc");
static const SimpleString str2("def");
static const SimpleString str3(str1 + str2);
TEST_GROUP(UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess)
{
TestTestingFixture fixture;
};
#ifndef CPPUTEST_HAVE_FORK
TEST(UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess, DummyFailsWithMessage)
{
fixture.setRunTestsInSeperateProcess();
fixture.runAllTests();
fixture.assertPrintContains("-p doesn't work on this platform, as it is lacking fork.\b");
}
#else
static void _failFunction()
{
FAIL("This test fails");
}
static void _exitNonZeroFunction() _no_return_;
static void _exitNonZeroFunction()
{
/* destructor of static objects will be called. If StringCache was there then the allocator will report invalid deallocations of static SimpleString */
SimpleString::setStringAllocator(SimpleString::getStringAllocator()->actualAllocator());
exit(1);
}
#include <errno.h>
static int waitpid_while_debugging_stub_number_called = 0;
static int waitpid_while_debugging_stub_forced_failures = 0;
extern "C" {
static int (*original_waitpid)(int, int*, int) = NULLPTR;
static int fork_failed_stub(void) { return -1; }
static int waitpid_while_debugging_stub(int pid, int* status, int options)
{
static int saved_status;
if (waitpid_while_debugging_stub_number_called++ < waitpid_while_debugging_stub_forced_failures) {
saved_status = *status;
errno=EINTR;
return -1;
}
else {
*status = saved_status;
return original_waitpid(pid, status, options);
}
}
static int waitpid_failed_stub(int, int*, int) { return -1; }
}
#include <unistd.h>
#include <signal.h>
static void _stoppedTestFunction()
{
kill(getpid(), SIGSTOP);
}
TEST(UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess, TestInSeparateProcessWorks)
{
fixture.setRunTestsInSeperateProcess();
fixture.runAllTests();
fixture.assertPrintContains("OK (1 tests, 1 ran, 0 checks, 0 ignored, 0 filtered out");
}
TEST(UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess, FailureInSeparateProcessWorks)
{
fixture.setRunTestsInSeperateProcess();
fixture.setTestFunction(_failFunction);
fixture.runAllTests();
fixture.assertPrintContains("Failed in separate process");
fixture.assertPrintContains("Errors (1 failures, 1 tests, 1 ran, 0 checks, 0 ignored, 0 filtered out");
}
#if (! CPPUTEST_SANITIZE_ADDRESS)
static int _accessViolationTestFunction()
{
return *(volatile int*) NULLPTR;
}
TEST(UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess, AccessViolationInSeparateProcessWorks)
{
fixture.setRunTestsInSeperateProcess();
fixture.setTestFunction((void(*)())_accessViolationTestFunction);
fixture.runAllTests();
fixture.assertPrintContains("Failed in separate process - killed by signal 11");
fixture.assertPrintContains("Errors (1 failures, 1 tests, 1 ran");
}
#endif
TEST(UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess, StoppedInSeparateProcessWorks)
{
fixture.setRunTestsInSeperateProcess();
fixture.setTestFunction(_stoppedTestFunction);
fixture.runAllTests();
fixture.assertPrintContains("Stopped in separate process - continuing");
fixture.assertPrintContains("Errors (1 failures, 1 tests, 1 ran");
}
TEST(UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess, CallToForkFailedInSeparateProcessWorks)
{
UT_PTR_SET(PlatformSpecificFork, fork_failed_stub);
fixture.setRunTestsInSeperateProcess();
fixture.runAllTests();
fixture.assertPrintContains("Call to fork() failed");
fixture.assertPrintContains("Errors (1 failures, 1 tests, 1 ran");
}
TEST(UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess, CallToWaitPidWhileDebuggingInSeparateProcessWorks)
{
UT_PTR_SET(original_waitpid, PlatformSpecificWaitPid);
UT_PTR_SET(PlatformSpecificWaitPid, waitpid_while_debugging_stub);
waitpid_while_debugging_stub_number_called = 0;
waitpid_while_debugging_stub_forced_failures = 10;
fixture.setRunTestsInSeperateProcess();
fixture.runAllTests();
fixture.assertPrintContains("OK (1 tests, 1 ran, 0 checks, 0 ignored, 0 filtered out");
// extra check to confirm that waitpid() was polled until it passed (and passed call adds one)
CHECK(waitpid_while_debugging_stub_number_called > waitpid_while_debugging_stub_forced_failures);
}
TEST(UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess, CallToWaitPidStopsAndReportsAnErrorAfter20TimesRetry)
{
UT_PTR_SET(original_waitpid, PlatformSpecificWaitPid);
UT_PTR_SET(PlatformSpecificWaitPid, waitpid_while_debugging_stub);
waitpid_while_debugging_stub_number_called = 0;
waitpid_while_debugging_stub_forced_failures = 40;
fixture.setRunTestsInSeperateProcess();
fixture.runAllTests();
fixture.assertPrintContains("Call to waitpid() failed with EINTR. Tried 30 times and giving up! Sometimes happens in debugger");
// extra check to confirm that waitpid() was polled until it passed (and passed call adds one)
CHECK(waitpid_while_debugging_stub_number_called > 30);
}
TEST(UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess, CallToWaitPidFailedInSeparateProcessWorks)
{
UT_PTR_SET(PlatformSpecificWaitPid, waitpid_failed_stub);
fixture.setRunTestsInSeperateProcess();
fixture.runAllTests();
fixture.assertPrintContains("Call to waitpid() failed");
fixture.assertPrintContains("Errors (1 failures, 1 tests, 1 ran");
}
TEST(UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess, MultipleTestsInSeparateProcessAreCountedProperly)
{
fixture.setRunTestsInSeperateProcess();
fixture.runTestWithMethod(NULLPTR);
fixture.runTestWithMethod(_stoppedTestFunction);
fixture.runTestWithMethod(NULLPTR);
fixture.runTestWithMethod(_exitNonZeroFunction);
fixture.runTestWithMethod(NULLPTR);
fixture.assertPrintContains("Failed in separate process");
fixture.assertPrintContains("Stopped in separate process");
fixture.assertPrintContains("Errors (2 failures, 5 tests, 5 ran, 0 checks, 0 ignored, 0 filtered out");
}
#endif
#endif

View file

@ -0,0 +1,537 @@
/*
* 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/TestTestingFixture.h"
#include "CppUTest/PlatformSpecificFunctions.h"
TEST_GROUP(UtestShell)
{
TestTestingFixture fixture;
};
static void _failMethod()
{
FAIL("This test fails");
}
static void _passingTestMethod()
{
CHECK(true);
}
static void _passingCheckEqualTestMethod()
{
CHECK_EQUAL(1, 1);
}
static void _exitTestMethod()
{
TEST_EXIT;
FAIL("Should not get here");
}
static volatile double zero = 0.0;
TEST(UtestShell, compareDoubles)
{
double not_a_number = zero / zero;
double infinity = 1 / zero;
CHECK(doubles_equal(1.0, 1.001, 0.01));
CHECK(!doubles_equal(not_a_number, 1.001, 0.01));
CHECK(!doubles_equal(1.0, not_a_number, 0.01));
CHECK(!doubles_equal(1.0, 1.001, not_a_number));
CHECK(!doubles_equal(1.0, 1.1, 0.05));
CHECK(!doubles_equal(infinity, 1.0, 0.01));
CHECK(!doubles_equal(1.0, infinity, 0.01));
CHECK(doubles_equal(1.0, -1.0, infinity));
CHECK(doubles_equal(infinity, infinity, 0.01));
CHECK(doubles_equal(infinity, infinity, infinity));
double a = 1.2345678;
CHECK(doubles_equal(a, a, 0.000000001));
}
TEST(UtestShell, FailWillIncreaseTheAmountOfChecks)
{
fixture.setTestFunction(_failMethod);
fixture.runAllTests();
LONGS_EQUAL(1, fixture.getCheckCount());
}
TEST(UtestShell, PassedCheckEqualWillIncreaseTheAmountOfChecks)
{
fixture.setTestFunction(_passingCheckEqualTestMethod);
fixture.runAllTests();
LONGS_EQUAL(1, fixture.getCheckCount());
}
IGNORE_TEST(UtestShell, IgnoreTestAccessingFixture)
{
CHECK(&fixture != NULLPTR);
}
TEST(UtestShell, MacrosUsedInSetup)
{
IGNORE_ALL_LEAKS_IN_TEST();
fixture.setSetup(_failMethod);
fixture.setTestFunction(_passingTestMethod);
fixture.runAllTests();
LONGS_EQUAL(1, fixture.getFailureCount());
}
TEST(UtestShell, MacrosUsedInTearDown)
{
IGNORE_ALL_LEAKS_IN_TEST();
fixture.setTeardown(_failMethod);
fixture.setTestFunction(_passingTestMethod);
fixture.runAllTests();
LONGS_EQUAL(1, fixture.getFailureCount());
}
TEST(UtestShell, ExitLeavesQuietly)
{
fixture.setTestFunction(_exitTestMethod);
fixture.runAllTests();
LONGS_EQUAL(0, fixture.getFailureCount());
}
static bool cpputestHasCrashed;
static void crashMethod()
{
cpputestHasCrashed = true;
}
TEST(UtestShell, FailWillNotCrashIfNotEnabled)
{
cpputestHasCrashed = false;
UtestShell::setCrashMethod(crashMethod);
fixture.setTestFunction(_failMethod);
fixture.runAllTests();
CHECK_FALSE(cpputestHasCrashed);
LONGS_EQUAL(1, fixture.getFailureCount());
UtestShell::resetCrashMethod();
}
TEST(UtestShell, FailWillCrashIfEnabled)
{
cpputestHasCrashed = false;
UtestShell::setCrashOnFail();
UtestShell::setCrashMethod(crashMethod);
fixture.setTestFunction(_failMethod);
fixture.runAllTests();
CHECK(cpputestHasCrashed);
UtestShell::restoreDefaultTestTerminator();
UtestShell::resetCrashMethod();
}
static int teardownCalled = 0;
static void _teardownMethod()
{
teardownCalled++;
}
TEST(UtestShell, TeardownCalledAfterTestFailure)
{
teardownCalled = 0;
IGNORE_ALL_LEAKS_IN_TEST();
fixture.setTeardown(_teardownMethod);
fixture.setTestFunction(_failMethod);
fixture.runAllTests();
LONGS_EQUAL(1, fixture.getFailureCount());
LONGS_EQUAL(1, teardownCalled);
}
static int stopAfterFailure = 0;
static void _stopAfterFailureMethod()
{
FAIL("fail");
stopAfterFailure++;
}
TEST(UtestShell, TestStopsAfterTestFailure)
{
IGNORE_ALL_LEAKS_IN_TEST();
stopAfterFailure = 0;
fixture.setTestFunction(_stopAfterFailureMethod);
fixture.runAllTests();
CHECK(fixture.hasTestFailed());
LONGS_EQUAL(1, fixture.getFailureCount());
LONGS_EQUAL(0, stopAfterFailure);
}
TEST(UtestShell, TestStopsAfterSetupFailure)
{
stopAfterFailure = 0;
fixture.setSetup(_stopAfterFailureMethod);
fixture.setTeardown(_stopAfterFailureMethod);
fixture.setTestFunction(_failMethod);
fixture.runAllTests();
LONGS_EQUAL(2, fixture.getFailureCount());
LONGS_EQUAL(0, stopAfterFailure);
}
TEST(UtestShell, veryVebose)
{
UtestShell shell("Group", "name", __FILE__, __LINE__);
StringBufferTestOutput normalOutput;
normalOutput.verbose(TestOutput::level_veryVerbose);
NullTestPlugin plugin;
TestResult result(normalOutput);
shell.runOneTestInCurrentProcess(&plugin, result);
STRCMP_CONTAINS("\n------ before runTest", normalOutput.getOutput().asCharString());
}
class defaultUtestShell: public UtestShell
{
};
TEST(UtestShell, this_test_covers_the_UtestShell_createTest_and_Utest_testBody_methods)
{
defaultUtestShell shell;
fixture.addTest(&shell);
fixture.runAllTests();
LONGS_EQUAL(2, fixture.getTestCount());
}
static void StubPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin*, TestResult* result)
{
result->addFailure(TestFailure(shell, "Failed in separate process"));
}
TEST(UtestShell, RunInSeparateProcessTest)
{
UT_PTR_SET(PlatformSpecificRunTestInASeperateProcess, StubPlatformSpecificRunTestInASeperateProcess);
fixture.getRegistry()->setRunTestsInSeperateProcess();
fixture.runAllTests();
fixture.assertPrintContains("Failed in separate process");
}
#ifndef CPPUTEST_HAVE_FORK
IGNORE_TEST(UtestShell, TestDefaultCrashMethodInSeparateProcessTest) {}
#else
#if !CPPUTEST_SANITIZE_ADDRESS
TEST(UtestShell, TestDefaultCrashMethodInSeparateProcessTest)
{
fixture.setTestFunction(UtestShell::crash);
fixture.setRunTestsInSeperateProcess();
fixture.runAllTests();
fixture.assertPrintContains("Failed in separate process - killed by signal");
/* Signal 11 usually happens, but with clang3.7 on Linux, it produced signal 4 */
CHECK(fixture.getOutput().contains("signal 11") || fixture.getOutput().contains("signal 4"));
}
#endif
#endif
#if CPPUTEST_USE_STD_CPP_LIB
static bool destructorWasCalledOnFailedTest = false;
static void _destructorCalledForLocalObjects()
{
SetBooleanOnDestructorCall pleaseCallTheDestructor(destructorWasCalledOnFailedTest);
destructorWasCalledOnFailedTest = false;
FAIL("fail");
}
TEST(UtestShell, DestructorIsCalledForLocalObjectsWhenTheTestFails)
{
fixture.setTestFunction(_destructorCalledForLocalObjects);
fixture.runAllTests();
CHECK(destructorWasCalledOnFailedTest);
}
#endif
TEST_GROUP(IgnoredUtestShell)
{
TestTestingFixture fixture;
IgnoredUtestShell ignoredTest;
ExecFunctionTestShell normalUtestShell;
void setup() _override
{
fixture.addTest(&ignoredTest);
fixture.addTest(&normalUtestShell);
}
};
TEST(IgnoredUtestShell, doesIgnoreCount)
{
fixture.runAllTests();
LONGS_EQUAL(1, fixture.getIgnoreCount());
}
TEST(IgnoredUtestShell, printsIGNORE_TESTwhenVerbose)
{
fixture.setOutputVerbose();
fixture.runAllTests();
fixture.assertPrintContains("IGNORE_TEST");
}
TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedThenIncreaseRunCount)
{
ignoredTest.setRunIgnored();
fixture.runAllTests();
LONGS_EQUAL(3, fixture.getRunCount());
LONGS_EQUAL(0, fixture.getIgnoreCount());
}
TEST(IgnoredUtestShell, runIgnoredOptionNotSpecifiedThenIncreaseIgnoredCount)
{
fixture.runAllTests();
LONGS_EQUAL(2, fixture.getRunCount());
LONGS_EQUAL(1, fixture.getIgnoreCount());
}
TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedWillNotInfluenceNormalTestCount)
{
normalUtestShell.setRunIgnored();
fixture.runAllTests();
LONGS_EQUAL(2, fixture.getRunCount());
LONGS_EQUAL(1, fixture.getIgnoreCount());
}
TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedThenReturnTESTInFormattedName)
{
ignoredTest.setGroupName("TestGroup");
ignoredTest.setTestName("TestName");
ignoredTest.setRunIgnored();
fixture.runAllTests();
STRCMP_EQUAL("TEST(TestGroup, TestName)", ignoredTest.getFormattedName().asCharString());
}
TEST(IgnoredUtestShell, runIgnoredOptionNotSpecifiedThenReturnIGNORETESTInFormattedName)
{
ignoredTest.setGroupName("TestGroup");
ignoredTest.setTestName("TestName");
fixture.runAllTests();
STRCMP_EQUAL("IGNORE_TEST(TestGroup, TestName)", ignoredTest.getFormattedName().asCharString());
}
TEST(IgnoredUtestShell, runIgnoredOptionNotSpecifiedThenWillRunReturnFalse)
{
CHECK_FALSE(ignoredTest.willRun());
}
TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedThenWillRunReturnTrue)
{
ignoredTest.setRunIgnored();
CHECK_TRUE(ignoredTest.willRun());
}
TEST_BASE(MyOwnTest)
{
MyOwnTest() :
inTest(false)
{
}
bool inTest;
void setup() _override
{
CHECK(!inTest);
inTest = true;
}
void teardown() _override
{
CHECK(inTest);
inTest = false;
}
};
TEST_GROUP_BASE(UtestMyOwn, MyOwnTest)
{
};
TEST(UtestMyOwn, test)
{
CHECK(inTest);
}
class NullParameterTest: public UtestShell
{
};
TEST(UtestMyOwn, NullParameters)
{
NullParameterTest nullTest; /* Bug fix tests for creating a test without a name, fix in SimpleString */
TestFilter emptyFilter;
CHECK(nullTest.shouldRun(&emptyFilter, &emptyFilter));
}
class AllocateAndDeallocateInConstructorAndDestructor
{
char* memory_;
char* morememory_;
public:
AllocateAndDeallocateInConstructorAndDestructor()
{
memory_ = new char[100];
morememory_ = NULLPTR;
}
void allocateMoreMemory()
{
morememory_ = new char[123];
}
~AllocateAndDeallocateInConstructorAndDestructor()
{
delete [] memory_;
delete [] morememory_;
}
};
TEST_GROUP(CanHaveMemberVariablesInTestGroupThatAllocateMemoryWithoutCausingMemoryLeaks)
{
AllocateAndDeallocateInConstructorAndDestructor dummy;
};
TEST(CanHaveMemberVariablesInTestGroupThatAllocateMemoryWithoutCausingMemoryLeaks, testInTestGroupName)
{
dummy.allocateMoreMemory();
}
static int getZero()
{
return 0;
}
static int getOne()
{
return 1;
}
TEST_GROUP(UtestShellPointerArrayTest)
{
UtestShell* test0;
UtestShell* test1;
UtestShell* test2;
void setup() _override
{
test0 = new IgnoredUtestShell();
test1 = new IgnoredUtestShell();
test2 = new IgnoredUtestShell();
test0->addTest(test1);
test1->addTest(test2);
}
void teardown() _override
{
delete test0;
delete test1;
delete test2;
}
};
TEST(UtestShellPointerArrayTest, empty)
{
UtestShellPointerArray tests(NULLPTR);
tests.shuffle(0);
CHECK(NULLPTR == tests.getFirstTest());
}
TEST(UtestShellPointerArrayTest, testsAreInOrder)
{
UtestShellPointerArray tests(test0);
CHECK(tests.get(0) == test0);
CHECK(tests.get(1) == test1);
CHECK(tests.get(2) == test2);
}
TEST(UtestShellPointerArrayTest, relinkingTestsWillKeepThemTheSameWhenNothingWasDone)
{
UtestShellPointerArray tests(test0);
tests.relinkTestsInOrder();
CHECK(tests.get(0) == test0);
CHECK(tests.get(1) == test1);
CHECK(tests.get(2) == test2);
}
TEST(UtestShellPointerArrayTest, firstTestisNotTheFirstTestWithSeed1234)
{
UtestShellPointerArray tests(test0);
tests.shuffle(1234);
CHECK(tests.getFirstTest() != test0);
}
TEST(UtestShellPointerArrayTest, ShuffleListTestWithRandomAlwaysReturningZero)
{
UT_PTR_SET(PlatformSpecificRand, getZero);
UtestShellPointerArray tests(test0);
tests.shuffle(3);
CHECK(tests.get(0) == test1);
CHECK(tests.get(1) == test2);
CHECK(tests.get(2) == test0);
}
// swaps with 4 mod 3 (1) then 4 mod 2 (0): 1, [2], [0] --> [1], [0], 2 --> 0, 1, 2
TEST(UtestShellPointerArrayTest, ShuffleListTestWithRandomAlwaysReturningOne)
{
UT_PTR_SET(PlatformSpecificRand, getOne);
UtestShellPointerArray tests(test0);
tests.shuffle(3);
CHECK(tests.get(0) == test0);
CHECK(tests.get(1) == test2);
CHECK(tests.get(2) == test1);
}
TEST(UtestShellPointerArrayTest, reverse)
{
UT_PTR_SET(PlatformSpecificRand, getOne);
UtestShellPointerArray tests(test0);
tests.reverse();
CHECK(tests.get(0) == test2);
CHECK(tests.get(1) == test1);
CHECK(tests.get(2) == test0);
}