Files
arcs/arcs-sdk/modules/cpputest/tests/CppUTestExt/MemoryReporterPluginTest.cpp
2026-08-13 16:50:52 +08:00

317 lines
13 KiB
C++

/*
* 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 "CppUTestExt/MemoryReporterPlugin.h"
#include "CppUTestExt/MemoryReportFormatter.h"
#include "CppUTestExt/MockSupport.h"
#include "CppUTestExt/MockNamedValue.h"
static TestMemoryAllocator* previousNewAllocator;
class TemporaryDefaultNewAllocator
{
TestMemoryAllocator* newAllocator;
public:
TemporaryDefaultNewAllocator(TestMemoryAllocator* oldAllocator)
{
newAllocator = getCurrentNewAllocator();
setCurrentNewAllocator(oldAllocator);
}
~TemporaryDefaultNewAllocator()
{
setCurrentNewAllocator(newAllocator);
}
};
class MockMemoryReportFormatter : public MemoryReportFormatter
{
public:
virtual void report_testgroup_start(TestResult* result, UtestShell& test) CPPUTEST_OVERRIDE
{
TemporaryDefaultNewAllocator tempAlloc(previousNewAllocator);
mock("formatter").actualCall("report_testgroup_start").withParameter("result", result).withParameter("test", &test);
}
virtual void report_testgroup_end(TestResult* result, UtestShell& test) CPPUTEST_OVERRIDE
{
TemporaryDefaultNewAllocator tempAlloc(previousNewAllocator);
mock("formatter").actualCall("report_testgroup_end").withParameter("result", result).withParameter("test", &test);
}
virtual void report_test_start(TestResult* result, UtestShell& test) CPPUTEST_OVERRIDE
{
TemporaryDefaultNewAllocator tempAlloc(previousNewAllocator);
mock("formatter").actualCall("report_test_start").withParameter("result", result).withParameter("test", &test);
}
virtual void report_test_end(TestResult* result, UtestShell& test) CPPUTEST_OVERRIDE
{
TemporaryDefaultNewAllocator tempAlloc(previousNewAllocator);
mock("formatter").actualCall("report_test_end").withParameter("result", result).withParameter("test", &test);
}
virtual void report_alloc_memory(TestResult* result, TestMemoryAllocator* allocator, size_t, char* , const char* , size_t ) CPPUTEST_OVERRIDE
{
TemporaryDefaultNewAllocator tempAlloc(previousNewAllocator);
mock("formatter").actualCall("report_alloc_memory").withParameter("result", result).withParameterOfType("TestMemoryAllocator", "allocator", allocator);
}
virtual void report_free_memory(TestResult* result, TestMemoryAllocator* allocator, char* , const char* , size_t ) CPPUTEST_OVERRIDE
{
TemporaryDefaultNewAllocator tempAlloc(previousNewAllocator);
mock("formatter").actualCall("report_free_memory").withParameter("result", result).withParameterOfType("TestMemoryAllocator", "allocator", allocator);
}
};
static MockMemoryReportFormatter formatterForPluginTest;
class MemoryReporterPluginUnderTest : public MemoryReporterPlugin
{
public:
MemoryReportFormatter* createMemoryFormatter(const SimpleString& type) CPPUTEST_OVERRIDE
{
mock("reporter").actualCall("createMemoryFormatter").onObject(this).withParameter("type", type.asCharString());
return new MockMemoryReportFormatter;
}
};
class TestMemoryAllocatorComparator : public MockNamedValueComparator
{
public:
bool isEqual(const void* object1, const void* object2) CPPUTEST_OVERRIDE
{
return ((const TestMemoryAllocator*)object1)->name() == ((const TestMemoryAllocator*)object2)->name();
}
SimpleString valueToString(const void* object) CPPUTEST_OVERRIDE
{
return ((const TestMemoryAllocator*)object)->name();
}
};
TEST_GROUP(MemoryReporterPlugin)
{
MemoryReporterPluginUnderTest* reporter;
StringBufferTestOutput output;
TestMemoryAllocatorComparator memLeakAllocatorComparator;
TestResult* result;
UtestShell* test;
void setup() CPPUTEST_OVERRIDE
{
previousNewAllocator = getCurrentNewAllocator();
result = new TestResult(output);
test = new UtestShell("groupname", "testname", "filename", 1);
reporter = new MemoryReporterPluginUnderTest;
mock("formatter").installComparator("TestMemoryAllocator", memLeakAllocatorComparator);
mock("reporter").disable();
const char *cmd_line[] = {"-pmemoryreport=normal"};
reporter->parseArguments(1, cmd_line, 0);
mock("reporter").enable();
}
void teardown() CPPUTEST_OVERRIDE
{
setCurrentNewAllocator(previousNewAllocator);
mock().clear();
delete reporter;
delete test;
delete result;
}
};
TEST(MemoryReporterPlugin, offReportsNothing)
{
MemoryReporterPluginUnderTest freshReporter;
freshReporter.preTestAction(*test, *result);
char* memory = new char;
delete memory;
freshReporter.postTestAction(*test, *result);
}
TEST(MemoryReporterPlugin, meaninglessArgumentsAreIgnored)
{
const char *cmd_line[] = {"-nothing", "-pnotmemoryreport=normal", "alsomeaningless", "-pmemoryreportnonsensebutnotus"};
CHECK(reporter->parseArguments(3, cmd_line, 1) == false);
}
TEST(MemoryReporterPlugin, commandLineParameterTurnsOnNormalLogging)
{
mock("reporter").expectOneCall("createMemoryFormatter").onObject(reporter).withParameter("type", "normal");
const char *cmd_line[] = {"-nothing", "-pmemoryreport=normal", "alsomeaningless" };
CHECK(reporter->parseArguments(3, cmd_line, 1));
}
TEST(MemoryReporterPlugin, preTestActionReportsTest)
{
mock("formatter").expectOneCall("report_testgroup_start").withParameter("result", result).withParameter("test", test);
mock("formatter").expectOneCall("report_test_start").withParameter("result", result).withParameter("test", test);
reporter->preTestAction(*test, *result);
}
TEST(MemoryReporterPlugin, postTestActionReportsTest)
{
mock("formatter").expectOneCall("report_test_end").withParameter("result", result).withParameter("test", test);
mock("formatter").expectOneCall("report_testgroup_end").withParameter("result", result).withParameter("test", test);
reporter->postTestAction(*test, *result);
}
TEST(MemoryReporterPlugin, newAllocationsAreReportedTest)
{
mock("formatter").expectOneCall("report_alloc_memory").withParameter("result", result).withParameterOfType("TestMemoryAllocator", "allocator", reporter->getNewAllocator());
mock("formatter").expectOneCall("report_free_memory").withParameter("result", result).withParameterOfType("TestMemoryAllocator", "allocator", reporter->getNewAllocator());
mock("formatter").ignoreOtherCalls();
reporter->preTestAction(*test, *result);
char *memory = getCurrentNewAllocator()->allocMemoryLeakNode(100);
getCurrentNewAllocator()->free_memory(memory, 100, "unknown", 1);
}
TEST(MemoryReporterPlugin, whenUsingOnlyMallocAllocatorNoOtherOfTheAllocatorsAreUsed)
{
mock("formatter").expectOneCall("report_test_start").withParameter("result", result).withParameter("test", test);
mock("formatter").expectOneCall("report_alloc_memory").withParameter("result", result).withParameterOfType("TestMemoryAllocator", "allocator", reporter->getMallocAllocator());
mock("formatter").expectOneCall("report_free_memory").withParameter("result", result).withParameterOfType("TestMemoryAllocator", "allocator", reporter->getMallocAllocator());
mock("formatter").ignoreOtherCalls();
reporter->preTestAction(*test, *result);
char *memory = getCurrentMallocAllocator()->allocMemoryLeakNode(100);
getCurrentMallocAllocator()->free_memory(memory, 100, "unknown", 1);
}
TEST(MemoryReporterPlugin, newArrayAllocationsAreReportedTest)
{
mock("formatter").expectOneCall("report_alloc_memory").withParameter("result", result).withParameterOfType("TestMemoryAllocator", "allocator", reporter->getNewArrayAllocator());
mock("formatter").expectOneCall("report_free_memory").withParameter("result", result).withParameterOfType("TestMemoryAllocator", "allocator", reporter->getNewArrayAllocator());
mock("formatter").ignoreOtherCalls();
reporter->preTestAction(*test, *result);
char *memory = getCurrentNewArrayAllocator()->allocMemoryLeakNode(100);
getCurrentNewArrayAllocator()->free_memory(memory, 100, "unknown", 1);
}
TEST(MemoryReporterPlugin, mallocAllocationsAreReportedTest)
{
mock("formatter").expectOneCall("report_alloc_memory").withParameter("result", result).withParameterOfType("TestMemoryAllocator", "allocator", reporter->getMallocAllocator());
mock("formatter").expectOneCall("report_free_memory").withParameter("result", result).withParameterOfType("TestMemoryAllocator", "allocator", reporter->getMallocAllocator());
mock("formatter").ignoreOtherCalls();
reporter->preTestAction(*test, *result);
char *memory = getCurrentMallocAllocator()->allocMemoryLeakNode(100);
getCurrentMallocAllocator()->free_memory(memory, 100, "unknown", 1);
}
TEST(MemoryReporterPlugin, startOfANewTestWillReportTheTestGroupStart)
{
mock("formatter").expectOneCall("report_testgroup_start").withParameter("result", result).withParameter("test", test);
mock("formatter").expectOneCall("report_test_start").withParameter("result", result).withParameter("test", test);
mock("formatter").expectOneCall("report_test_end").withParameter("result", result).withParameter("test", test);
mock("formatter").expectOneCall("report_test_start").withParameter("result", result).withParameter("test", test);
mock("formatter").expectOneCall("report_test_end").withParameter("result", result).withParameter("test", test);
mock("formatter").ignoreOtherCalls();
reporter->preTestAction(*test, *result);
reporter->postTestAction(*test, *result);
reporter->preTestAction(*test, *result);
reporter->postTestAction(*test, *result);
}
class UtestForMemoryReportingPlugingTest : public UtestShell
{
public:
UtestForMemoryReportingPlugingTest(const char* groupname, UtestShell* test) : UtestShell(groupname, "testname", "filename", 1, test)
{
}
};
TEST(MemoryReporterPlugin, endOfaTestGroupWillReportSo)
{
UtestForMemoryReportingPlugingTest fourthTest("differentGroupName", NULLPTR);
UtestForMemoryReportingPlugingTest thirdTest("differentGroupName", &fourthTest);
UtestForMemoryReportingPlugingTest secondTest("groupname", &thirdTest);
UtestForMemoryReportingPlugingTest firstTest("groupname", &secondTest);
mock("formatter").expectOneCall("report_testgroup_end").withParameter("result", result).withParameter("test", &secondTest);
mock("formatter").ignoreOtherCalls();
reporter->preTestAction(firstTest, *result);
reporter->postTestAction(firstTest, *result);
reporter->preTestAction(secondTest, *result);
reporter->postTestAction(secondTest, *result);
reporter->preTestAction(thirdTest, *result);
reporter->postTestAction(thirdTest, *result);
}
TEST(MemoryReporterPlugin, preActionReplacesAllocators)
{
mock("formatter").ignoreOtherCalls();
TestMemoryAllocator* allocator = getCurrentMallocAllocator();
reporter->preTestAction(*test, *result);
CHECK(allocator != getCurrentMallocAllocator());
}
TEST(MemoryReporterPlugin, postActionRestoresAllocators)
{
mock("formatter").ignoreOtherCalls();
TestMemoryAllocator* allocator = getCurrentMallocAllocator();
reporter->preTestAction(*test, *result);
reporter->postTestAction(*test, *result);
CHECK(allocator == getCurrentMallocAllocator());
}
TEST(MemoryReporterPlugin, shouldCreateNormalMemoryReportFormatterWithoutMock)
{
MemoryReporterPlugin realReporter;
const char *cmd_line[] = {"-pmemoryreport=normal"};
CHECK(realReporter.parseArguments(1, cmd_line, 0));
}
TEST(MemoryReporterPlugin, shouldCreateCodeMemoryReportFormatterWithoutMock)
{
MemoryReporterPlugin realReporter;
const char *cmd_line[] = {"-pmemoryreport=code"};
CHECK(realReporter.parseArguments(1, cmd_line, 0));
}
TEST(MemoryReporterPlugin, shouldntCrashCreateInvalidMemoryReportFormatterWithoutMock)
{
MemoryReporterPlugin realReporter;
const char *cmd_line[] = {"-pmemoryreport=foo"};
CHECK(realReporter.parseArguments(1, cmd_line, 0));
realReporter.preTestAction(*test, *result);
realReporter.postTestAction(*test, *result);
}