Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of cpputest by
src/CppUTest/Utest.cpp
- Committer:
- Kojto
- Date:
- 2015-05-13
- Revision:
- 3:9e8c8907d9ee
- Parent:
- 1:4769360130ed
File content as of revision 3:9e8c8907d9ee:
/* * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the <organization> nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "CppUTest/TestHarness.h" #include "CppUTest/TestRegistry.h" #include "CppUTest/PlatformSpecificFunctions.h" #include "CppUTest/TestOutput.h" bool doubles_equal(double d1, double d2, double threshold) { if (PlatformSpecificIsNan(d1) || PlatformSpecificIsNan(d2) || PlatformSpecificIsNan(threshold)) return false; return PlatformSpecificFabs(d1 - d2) <= threshold; } /* Sometimes stubs use the CppUTest assertions. * Its not correct to do so, but this small helper class will prevent a segmentation fault and instead * will give an error message and also the file/line of the check that was executed outside the tests. */ class OutsideTestRunnerUTest: public UtestShell { public: static OutsideTestRunnerUTest& instance(); virtual TestResult& getTestResult() { return defaultTestResult; } virtual void exitCurrentTest() { } virtual ~OutsideTestRunnerUTest() { } private: OutsideTestRunnerUTest() : UtestShell("\n\t NOTE: Assertion happened without being in a test run (perhaps in main?)", "\n\t Something is very wrong. Check this assertion and fix", "unknown file", 0), defaultTestResult(defaultOutput) { } ConsoleTestOutput defaultOutput; TestResult defaultTestResult; }; OutsideTestRunnerUTest& OutsideTestRunnerUTest::instance() { static OutsideTestRunnerUTest instance_; return instance_; } /* * Below helpers are used for the PlatformSpecificSetJmp and LongJmp. They pass a method for what needs to happen after * the jump, so that the stack stays right. * */ extern "C" { static void helperDoTestSetup(void* data) { ((Utest*)data)->setup(); } static void helperDoTestBody(void* data) { ((Utest*)data)->testBody(); } static void helperDoTestTeardown(void* data) { ((Utest*)data)->teardown(); } struct HelperTestRunInfo { HelperTestRunInfo(UtestShell* shell, TestPlugin* plugin, TestResult* result) : shell_(shell), plugin_(plugin), result_(result){} UtestShell* shell_; TestPlugin* plugin_; TestResult* result_; }; static void helperDoRunOneTestInCurrentProcess(void* data) { HelperTestRunInfo* runInfo = (HelperTestRunInfo*) data; UtestShell* shell = runInfo->shell_; TestPlugin* plugin = runInfo->plugin_; TestResult* result = runInfo->result_; shell->runOneTestInCurrentProcess(plugin, *result); } static void helperDoRunOneTestSeperateProcess(void* data) { HelperTestRunInfo* runInfo = (HelperTestRunInfo*) data; UtestShell* shell = runInfo->shell_; TestPlugin* plugin = runInfo->plugin_; TestResult* result = runInfo->result_; PlatformSpecificRunTestInASeperateProcess(shell, plugin, result); } } /******************************** */ UtestShell::UtestShell() : group_("UndefinedTestGroup"), name_("UndefinedTest"), file_("UndefinedFile"), lineNumber_(0), next_(&NullTestShell::instance()), isRunAsSeperateProcess_(false), hasFailed_(false) { } UtestShell::UtestShell(const char* groupName, const char* testName, const char* fileName, int lineNumber) : group_(groupName), name_(testName), file_(fileName), lineNumber_(lineNumber), next_(&NullTestShell::instance()), isRunAsSeperateProcess_(false), hasFailed_(false) { } UtestShell::UtestShell(const char* groupName, const char* testName, const char* fileName, int lineNumber, UtestShell* nextTest) : group_(groupName), name_(testName), file_(fileName), lineNumber_(lineNumber), next_(nextTest), isRunAsSeperateProcess_(false), hasFailed_(false) { } UtestShell::~UtestShell() { } static void defaultCrashMethod() { UtestShell* ptr = (UtestShell*) 0x0; ptr->countTests(); } static void (*pleaseCrashMeRightNow) () = defaultCrashMethod; void UtestShell::setCrashMethod(void (*crashme)()) { pleaseCrashMeRightNow = crashme; } void UtestShell::resetCrashMethod() { pleaseCrashMeRightNow = defaultCrashMethod; } void UtestShell::crash() { pleaseCrashMeRightNow(); } void UtestShell::runOneTest(TestPlugin* plugin, TestResult& result) { HelperTestRunInfo runInfo(this, plugin, &result); if (isRunInSeperateProcess()) PlatformSpecificSetJmp(helperDoRunOneTestSeperateProcess, &runInfo); else PlatformSpecificSetJmp(helperDoRunOneTestInCurrentProcess, &runInfo); } Utest* UtestShell::createTest() { return new Utest(); } void UtestShell::destroyTest(Utest* test) { delete test; } void UtestShell::runOneTestInCurrentProcess(TestPlugin* plugin, TestResult& result) { plugin->runAllPreTestAction(*this, result); //save test context, so that test class can be tested UtestShell* savedTest = UtestShell::getCurrent(); TestResult* savedResult = UtestShell::getTestResult(); result.countRun(); UtestShell::setTestResult(&result); UtestShell::setCurrentTest(this); Utest* testToRun = createTest(); testToRun->run(); destroyTest(testToRun); UtestShell::setCurrentTest(savedTest); UtestShell::setTestResult(savedResult); plugin->runAllPostTestAction(*this, result); } UtestShell *UtestShell::getNext() const { return next_; } UtestShell* UtestShell::addTest(UtestShell *test) { next_ = test; return this; } int UtestShell::countTests() { return next_->countTests() + 1; } bool UtestShell::isNull() const { return false; } SimpleString UtestShell::getMacroName() const { return "TEST"; } const SimpleString UtestShell::getName() const { return SimpleString(name_); } const SimpleString UtestShell::getGroup() const { return SimpleString(group_); } SimpleString UtestShell::getFormattedName() const { SimpleString formattedName(getMacroName()); formattedName += "("; formattedName += group_; formattedName += ", "; formattedName += name_; formattedName += ")"; return formattedName; } bool UtestShell::hasFailed() const { return hasFailed_; } const char* UtestShell::getProgressIndicator() const { return "."; } bool UtestShell::isRunInSeperateProcess() const { return isRunAsSeperateProcess_; } void UtestShell::setRunInSeperateProcess() { isRunAsSeperateProcess_ = true; } void UtestShell::setFileName(const char* fileName) { file_ = fileName; } void UtestShell::setLineNumber(int lineNumber) { lineNumber_ = lineNumber; } void UtestShell::setGroupName(const char* groupName) { group_ = groupName; } void UtestShell::setTestName(const char* testName) { name_ = testName; } const SimpleString UtestShell::getFile() const { return SimpleString(file_); } int UtestShell::getLineNumber() const { return lineNumber_; } bool UtestShell::shouldRun(const TestFilter& groupFilter, const TestFilter& nameFilter) const { if (groupFilter.match(group_) && nameFilter.match(name_)) return true; return false; } void UtestShell::failWith(const TestFailure& failure) { failWith(failure, NormalTestTerminator()); } void UtestShell::failWith(const TestFailure& failure, const TestTerminator& terminator) { hasFailed_ = true; getTestResult()->addFailure(failure); terminator.exitCurrentTest(); } void UtestShell::assertTrue(bool condition, const char * checkString, const char* conditionString, const char* fileName, int lineNumber, const TestTerminator& testTerminator) { assertTrueText(condition, checkString, conditionString, "", fileName, lineNumber, testTerminator); } void UtestShell::assertTrueText(bool condition, const char *checkString, const char *conditionString, const char* text, const char *fileName, int lineNumber, const TestTerminator& testTerminator) { getTestResult()->countCheck(); if (!condition) failWith(CheckFailure(this, fileName, lineNumber, checkString, conditionString, text), testTerminator); } void UtestShell::fail(const char *text, const char* fileName, int lineNumber, const TestTerminator& testTerminator) { getTestResult()->countCheck(); failWith(FailFailure(this, fileName, lineNumber, text), testTerminator); } void UtestShell::assertCstrEqual(const char* expected, const char* actual, const char* fileName, int lineNumber, const TestTerminator& testTerminator) { getTestResult()->countCheck(); if (actual == 0 && expected == 0) return; if (actual == 0 || expected == 0) failWith(StringEqualFailure(this, fileName, lineNumber, expected, actual), testTerminator); if (PlatformSpecificStrCmp(expected, actual) != 0) failWith(StringEqualFailure(this, fileName, lineNumber, expected, actual), testTerminator); } void UtestShell::assertCstrNoCaseEqual(const char* expected, const char* actual, const char* fileName, int lineNumber) { getTestResult()->countCheck(); if (actual == 0 && expected == 0) return; if (actual == 0 || expected == 0) failWith(StringEqualNoCaseFailure(this, fileName, lineNumber, expected, actual)); if (!SimpleString(expected).equalsNoCase(actual)) failWith(StringEqualNoCaseFailure(this, fileName, lineNumber, expected, actual)); } void UtestShell::assertCstrContains(const char* expected, const char* actual, const char* fileName, int lineNumber) { getTestResult()->countCheck(); if (actual == 0 && expected == 0) return; if(actual == 0 || expected == 0) failWith(ContainsFailure(this, fileName, lineNumber, expected, actual)); if (!SimpleString(actual).contains(expected)) failWith(ContainsFailure(this, fileName, lineNumber, expected, actual)); } void UtestShell::assertCstrNoCaseContains(const char* expected, const char* actual, const char* fileName, int lineNumber) { getTestResult()->countCheck(); if (actual == 0 && expected == 0) return; if(actual == 0 || expected == 0) failWith(ContainsFailure(this, fileName, lineNumber, expected, actual)); if (!SimpleString(actual).containsNoCase(expected)) failWith(ContainsFailure(this, fileName, lineNumber, expected, actual)); } void UtestShell::assertLongsEqual(long expected, long actual, const char* fileName, int lineNumber, const TestTerminator& testTerminator) { getTestResult()->countCheck(); if (expected != actual) failWith(LongsEqualFailure (this, fileName, lineNumber, expected, actual), testTerminator); } void UtestShell::assertUnsignedLongsEqual(unsigned long expected, unsigned long actual, const char* fileName, int lineNumber, const TestTerminator& testTerminator) { getTestResult()->countCheck(); if (expected != actual) failWith(UnsignedLongsEqualFailure (this, fileName, lineNumber, expected, actual), testTerminator); } void UtestShell::assertPointersEqual(const void* expected, const void* actual, const char* fileName, int lineNumber) { getTestResult()->countCheck(); if (expected != actual) failWith(EqualsFailure(this, fileName, lineNumber, StringFrom(expected), StringFrom(actual))); } void UtestShell::assertDoublesEqual(double expected, double actual, double threshold, const char* fileName, int lineNumber, const TestTerminator& testTerminator) { getTestResult()->countCheck(); if (!doubles_equal(expected, actual, threshold)) failWith(DoublesEqualFailure(this, fileName, lineNumber, expected, actual, threshold), testTerminator); } void UtestShell::assertEquals(bool failed, const char* expected, const char* actual, const char* file, int line, const TestTerminator& testTerminator) { getTestResult()->countCheck(); if (failed) failWith(CheckEqualFailure(this, file, line, expected, actual), testTerminator); } void UtestShell::print(const char *text, const char* fileName, int lineNumber) { SimpleString stringToPrint = "\n"; stringToPrint += fileName; stringToPrint += ":"; stringToPrint += StringFrom(lineNumber); stringToPrint += " "; stringToPrint += text; getTestResult()->print(stringToPrint.asCharString()); } void UtestShell::print(const SimpleString& text, const char* fileName, int lineNumber) { print(text.asCharString(), fileName, lineNumber); } TestResult* UtestShell::testResult_ = NULL; UtestShell* UtestShell::currentTest_ = NULL; void UtestShell::setTestResult(TestResult* result) { testResult_ = result; } void UtestShell::setCurrentTest(UtestShell* test) { currentTest_ = test; } TestResult* UtestShell::getTestResult() { if (testResult_ == NULL) return &OutsideTestRunnerUTest::instance().getTestResult(); return testResult_; } UtestShell* UtestShell::getCurrent() { if (currentTest_ == NULL) return &OutsideTestRunnerUTest::instance(); return currentTest_; } ExecFunctionTestShell::~ExecFunctionTestShell() { } ////////////// Utest //////////// Utest::Utest() { } Utest::~Utest() { } #if CPPUTEST_USE_STD_CPP_LIB void Utest::run() { try { if (PlatformSpecificSetJmp(helperDoTestSetup, this)) { PlatformSpecificSetJmp(helperDoTestBody, this); } } catch (CppUTestFailedException&) { PlatformSpecificRestoreJumpBuffer(); } try { PlatformSpecificSetJmp(helperDoTestTeardown, this); } catch (CppUTestFailedException&) { PlatformSpecificRestoreJumpBuffer(); } } #else void Utest::run() { if (PlatformSpecificSetJmp(helperDoTestSetup, this)) { PlatformSpecificSetJmp(helperDoTestBody, this); } PlatformSpecificSetJmp(helperDoTestTeardown, this); } #endif void Utest::setup() { } void Utest::testBody() { } void Utest::teardown() { } ////////////// NullTestShell //////////// NullTestShell::NullTestShell() : UtestShell("NullGroup", "NullName", "NullFile", -1, 0) { } NullTestShell::NullTestShell(const char* fileName, int lineNumber) : UtestShell("NullGroup", "NullName", fileName, lineNumber, 0) { } NullTestShell::~NullTestShell() { } NullTestShell& NullTestShell::instance() { static NullTestShell _instance; return _instance; } int NullTestShell::countTests() { return 0; } UtestShell* NullTestShell::getNext() const { return &instance(); } bool NullTestShell::isNull() const { return true; } void NullTestShell::testBody() { } /////////////////// Terminators TestTerminator::~TestTerminator() { } void NormalTestTerminator::exitCurrentTest() const { #if CPPUTEST_USE_STD_CPP_LIB throw CppUTestFailedException(); #else TestTerminatorWithoutExceptions().exitCurrentTest(); #endif } NormalTestTerminator::~NormalTestTerminator() { } void TestTerminatorWithoutExceptions::exitCurrentTest() const { PlatformSpecificLongJmp(); } TestTerminatorWithoutExceptions::~TestTerminatorWithoutExceptions() { } //////////////////// ExecFunctionTest ExecFunctionTest::ExecFunctionTest(ExecFunctionTestShell* shell) : shell_(shell) { } void ExecFunctionTest::testBody() { if (shell_->testFunction_) shell_->testFunction_(); } void ExecFunctionTest::setup() { if (shell_->setup_) shell_->setup_(); } void ExecFunctionTest::teardown() { if (shell_->teardown_) shell_->teardown_(); } /////////////// IgnoredUtestShell ///////////// IgnoredUtestShell::IgnoredUtestShell() { } IgnoredUtestShell::~IgnoredUtestShell() { } const char* IgnoredUtestShell::getProgressIndicator() const { return "!"; } SimpleString IgnoredUtestShell::getMacroName() const { return "IGNORE_TEST"; } void IgnoredUtestShell::runOneTest(TestPlugin* /* plugin */, TestResult& result) { result.countIgnored(); } ////////////// TestInstaller //////////// TestInstaller::TestInstaller(UtestShell& shell, const char* groupName, const char* testName, const char* fileName, int lineNumber) { shell.setGroupName(groupName); shell.setTestName(testName); shell.setFileName(fileName); shell.setLineNumber(lineNumber); TestRegistry::getCurrentRegistry()->addTest(&shell); } TestInstaller::~TestInstaller() { } void TestInstaller::unDo() { TestRegistry::getCurrentRegistry()->unDoLastAddTest(); }