Files
xtensa_dsp/test/test_utility/include/CppUTestExt/GTestConvertor.h
2022-09-13 10:33:44 +08:00

388 lines
12 KiB
C++

/*
* Copyright (c) 2011, 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.
*/
#ifndef GTESTCONVERTOR_H_
#define GTESTCONVERTOR_H_
#include "CppUTest/Utest.h"
#ifdef GTEST__H_
#error "Please include this file before you include any other GTest files"
#endif
/*
* Usage:
*
* This file must only be included in the main. The whole implementation is inline so that this can
* be compiled on usage and not on CppUTest compile-time. This avoids a hard dependency with CppUTest
* and with GTest
*
* Add the following lines to your main:
*
* GTestConvertor convertor;
* convertor.addAllGTestToTestRegistry();
*
*
*/
class GTestResultReporter;
class GTestFlagsThatAllocateMemory;
namespace testing {
class TestInfo;
class TestCase;
class Test;
}
class GTestShell : public UtestShell
{
::testing::TestInfo* testinfo_;
GTestShell* next_;
GTestFlagsThatAllocateMemory* flags_;
public:
GTestShell(::testing::TestInfo* testinfo, GTestShell* next, GTestFlagsThatAllocateMemory* flags);
virtual Utest* createTest() _override;
GTestShell* nextGTest()
{
return next_;
}
};
/* Enormous hack!
*
* This sucks enormously. We need to do two things in GTest that seem to not be possible without
* this hack. Hopefully there is *another way*.
*
* We need to access the factory in the TestInfo in order to be able to create tests. The factory
* is private and there seems to be no way to access it...
*
* We need to be able to call the Test SetUp and TearDown methods, but they are protected for
* some reason. We can't subclass either as the tests are created with the TEST macro.
*
* If anyone knows how to get the above things done *without* these ugly #defines, let me know!
*
*/
#define private public
#define protected public
#include "CppUTestExt/GTest.h"
#include "CppUTestExt/GMock.h"
#include "gtest/gtest-spi.h"
#include "gtest/gtest-death-test.h"
/*
* We really need some of its internals as they don't have a public interface.
*
*/
#define GTEST_IMPLEMENTATION_ 1
#include "src/gtest-internal-inl.h"
#include "CppUTest/TestRegistry.h"
#include "CppUTest/TestFailure.h"
#include "CppUTest/TestResult.h"
#ifdef GTEST_VERSION_GTEST_1_7
#define GTEST_STRING std::string
#define GTEST_NO_STRING_VALUE ""
#else
#define GTEST_STRING ::testing::internal::String
#define GTEST_NO_STRING_VALUE NULL
#endif
/* Store some of the flags as we'll need to reset them each test to avoid leaking memory */
class GTestFlagsThatAllocateMemory
{
public:
void storeValuesOfGTestFLags()
{
GTestFlagcolor = ::testing::GTEST_FLAG(color);
GTestFlagfilter = ::testing::GTEST_FLAG(filter);
GTestFlagoutput = ::testing::GTEST_FLAG(output);
GTestFlagdeath_test_style = ::testing::GTEST_FLAG(death_test_style);
GTestFlaginternal_run_death_test = ::testing::internal::GTEST_FLAG(internal_run_death_test);
#ifndef GTEST_VERSION_GTEST_1_5
GTestFlagstream_result_to = ::testing::GTEST_FLAG(stream_result_to);
#endif
}
void resetValuesOfGTestFlags()
{
::testing::GTEST_FLAG(color) = GTestFlagcolor;
::testing::GTEST_FLAG(filter) = GTestFlagfilter;
::testing::GTEST_FLAG(output) = GTestFlagoutput;
::testing::GTEST_FLAG(death_test_style) = GTestFlagdeath_test_style;
::testing::internal::GTEST_FLAG(internal_run_death_test) = GTestFlaginternal_run_death_test;
#ifndef GTEST_VERSION_GTEST_1_5
::testing::GTEST_FLAG(stream_result_to) = GTestFlagstream_result_to;
#endif
}
void setGTestFLagValuesToNULLToAvoidMemoryLeaks()
{
#ifndef GTEST_VERSION_GTEST_1_7
::testing::GTEST_FLAG(color) = GTEST_NO_STRING_VALUE;
::testing::GTEST_FLAG(filter) = GTEST_NO_STRING_VALUE;
::testing::GTEST_FLAG(output) = GTEST_NO_STRING_VALUE;
::testing::GTEST_FLAG(death_test_style) = GTEST_NO_STRING_VALUE;
::testing::internal::GTEST_FLAG(internal_run_death_test) = GTEST_NO_STRING_VALUE;
#ifndef GTEST_VERSION_GTEST_1_5
::testing::GTEST_FLAG(stream_result_to) = GTEST_NO_STRING_VALUE;
#endif
#endif
}
private:
GTEST_STRING GTestFlagcolor;
GTEST_STRING GTestFlagfilter;
GTEST_STRING GTestFlagoutput;
GTEST_STRING GTestFlagdeath_test_style;
GTEST_STRING GTestFlaginternal_run_death_test;
#ifndef GTEST_VERSION_GTEST_1_5
GTEST_STRING GTestFlagstream_result_to;
#endif
};
class GTestConvertor
{
public:
GTestConvertor(bool shouldSimulateFailureAtCreationToAllocateThreadLocalData = true);
virtual ~GTestConvertor();
virtual void addAllGTestToTestRegistry();
protected:
virtual void simulateGTestFailureToPreAllocateAllTheThreadLocalData();
virtual void addNewTestCaseForTestInfo(::testing::TestInfo* testinfo);
virtual void addAllTestsFromTestCaseToTestRegistry(::testing::TestCase* testcase);
virtual void createDummyInSequenceToAndFailureReporterAvoidMemoryLeakInGMock();
private:
GTestResultReporter* reporter_;
GTestShell* first_;
GTestFlagsThatAllocateMemory flags_;
};
class GTestDummyResultReporter : public ::testing::ScopedFakeTestPartResultReporter
{
public:
GTestDummyResultReporter () : ::testing::ScopedFakeTestPartResultReporter(INTERCEPT_ALL_THREADS, NULL) {}
virtual void ReportTestPartResult(const ::testing::TestPartResult& /*result*/) {}
};
class GMockTestTerminator : public TestTerminator
{
public:
GMockTestTerminator(const ::testing::TestPartResult& result) : result_(result)
{
}
virtual void exitCurrentTest() const
{
/*
* When using GMock, it throws an exception from the destructor leaving
* the system in an unstable state.
* Therefore, when the test fails because of failed gmock expectation
* then don't throw the exception, but let it return. Usually this should
* already be at the end of the test, so it doesn't matter much
*/
/*
* TODO: We probably want this check here, however the tests fail when putting it there. Also, we'll need to
* check how to get all the gTest tests to run within CppUTest. At the moment, the 'death tests' seem to fail
* still.
*
* if (result_.type() == ::testing::TestPartResult::kFatalFailure) {
*/
if (!SimpleString(result_.message()).contains("Actual: never called") &&
!SimpleString(result_.message()).contains("Actual function call count doesn't match"))
throw CppUTestFailedException();
}
virtual ~GMockTestTerminator()
{
}
private:
const ::testing::TestPartResult& result_;
};
class GTestResultReporter : public ::testing::ScopedFakeTestPartResultReporter
{
public:
GTestResultReporter () : ::testing::ScopedFakeTestPartResultReporter(INTERCEPT_ALL_THREADS, NULL) {}
virtual void ReportTestPartResult(const ::testing::TestPartResult& result)
{
FailFailure failure(UtestShell::getCurrent(), result.file_name(), result.line_number(), result.message());
UtestShell::getCurrent()->failWith(failure, GMockTestTerminator(result));
}
};
inline GTestShell::GTestShell(::testing::TestInfo* testinfo, GTestShell* next, GTestFlagsThatAllocateMemory* flags) : testinfo_(testinfo), next_(next), flags_(flags)
{
setGroupName(testinfo->test_case_name());
setTestName(testinfo->name());
}
class GTestUTest: public Utest {
public:
GTestUTest(::testing::TestInfo* testinfo, GTestFlagsThatAllocateMemory* flags) : testinfo_(testinfo), test_(NULL), flags_(flags)
{
}
void testBody()
{
try {
test_->TestBody();
}
catch (CppUTestFailedException& ex)
{
}
}
void setup()
{
flags_->resetValuesOfGTestFlags();
#ifdef GTEST_VERSION_GTEST_1_5
test_ = testinfo_->impl()->factory_->CreateTest();
#else
test_ = testinfo_->factory_->CreateTest();
#endif
::testing::UnitTest::GetInstance()->impl()->set_current_test_info(testinfo_);
try {
test_->SetUp();
}
catch (CppUTestFailedException& ex)
{
}
}
void teardown()
{
try {
test_->TearDown();
}
catch (CppUTestFailedException& ex)
{
}
::testing::UnitTest::GetInstance()->impl()->set_current_test_info(NULL);
delete test_;
flags_->setGTestFLagValuesToNULLToAvoidMemoryLeaks();
::testing::internal::DeathTest::set_last_death_test_message(GTEST_NO_STRING_VALUE);
}
private:
::testing::Test* test_;
::testing::TestInfo* testinfo_;
GTestFlagsThatAllocateMemory* flags_;
};
inline Utest* GTestShell::createTest()
{
return new GTestUTest(testinfo_, flags_);
};
inline void GTestConvertor::simulateGTestFailureToPreAllocateAllTheThreadLocalData()
{
GTestDummyResultReporter *dummyReporter = new GTestDummyResultReporter();
ASSERT_TRUE(false);
delete dummyReporter;
}
inline GTestConvertor::GTestConvertor(bool shouldSimulateFailureAtCreationToAllocateThreadLocalData) : first_(NULL)
{
if (shouldSimulateFailureAtCreationToAllocateThreadLocalData)
simulateGTestFailureToPreAllocateAllTheThreadLocalData();
reporter_ = new GTestResultReporter();
}
inline GTestConvertor::~GTestConvertor()
{
delete reporter_;
while (first_) {
GTestShell* next = first_->nextGTest();
delete first_;
first_ = next;
}
}
inline void GTestConvertor::addNewTestCaseForTestInfo(::testing::TestInfo* testinfo)
{
first_ = new GTestShell(testinfo, first_, &flags_);
TestRegistry::getCurrentRegistry()->addTest(first_);
}
inline void GTestConvertor::addAllTestsFromTestCaseToTestRegistry(::testing::TestCase* testcase)
{
int currentTestCount = 0;
::testing::TestInfo* currentTest = (::testing::TestInfo*) testcase->GetTestInfo(currentTestCount);
while (currentTest) {
addNewTestCaseForTestInfo(currentTest);
currentTestCount++;
currentTest = (::testing::TestInfo*) testcase->GetTestInfo(currentTestCount);
}
}
inline void GTestConvertor::createDummyInSequenceToAndFailureReporterAvoidMemoryLeakInGMock()
{
::testing::InSequence seq;
::testing::internal::GetFailureReporter();
}
inline void GTestConvertor::addAllGTestToTestRegistry()
{
createDummyInSequenceToAndFailureReporterAvoidMemoryLeakInGMock();
flags_.storeValuesOfGTestFLags();
int argc = 2;
const char * argv[] = {"NameOfTheProgram", "--gmock_catch_leaked_mocks=0"};
::testing::InitGoogleMock(&argc, (char**) argv);
::testing::UnitTest* unitTests = ::testing::UnitTest::GetInstance();
int currentUnitTestCount = 0;
::testing::TestCase* currentTestCase = (::testing::TestCase*) unitTests->GetTestCase(currentUnitTestCount);
while (currentTestCase) {
addAllTestsFromTestCaseToTestRegistry(currentTestCase);
currentUnitTestCount++;
currentTestCase = (::testing::TestCase*) unitTests->GetTestCase(currentUnitTestCount);
}
}
#endif