Skip to content

Conversation

eljonny
Copy link
Owner

@eljonny eljonny commented May 2, 2024

Fixes #4

@eljonny eljonny self-assigned this May 2, 2024
Copy link

codecov bot commented May 2, 2024

Codecov Report

Attention: Patch coverage is 74.80916% with 66 lines in your changes missing coverage. Please review.

Project coverage is 77.36%. Comparing base (9b88dab) to head (b408120).
Report is 2 commits behind head on main.

Files Patch % Lines
src/TestCPPTestCase.cpp 77.19% 23 Missing and 3 partials ⚠️
src/TestCPPAssertions.cpp 44.44% 19 Missing and 1 partial ⚠️
src/TestCPPTestSuite.cpp 85.93% 9 Missing ⚠️
src/TestCPPExceptions.cpp 50.00% 6 Missing ⚠️
include/internal/TestCPPAssertions.h 55.55% 4 Missing ⚠️
include/internal/TestCPPExceptions.h 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #10      +/-   ##
==========================================
+ Coverage   69.54%   77.36%   +7.81%     
==========================================
  Files          12       19       +7     
  Lines         486      561      +75     
  Branches       55       70      +15     
==========================================
+ Hits          338      434      +96     
+ Misses        133      110      -23     
- Partials       15       17       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

github-actions bot commented May 2, 2024

⚡ Static analysis result ⚡

🔴 cppcheck found 23 issues! Click here to see details.

TestCPPException (const char * msg);
/**
* Construct an exception of this type with a string object for
* its failure message.
*/

!Line: 63 - style: Class 'TestCPPException' has a constructor with 1 argument that is not explicit. [noExplicitConstructor]

TestCPPException (string&& msg);
};
/**
* @class TestFailedException
* @author Jonathan Hyry

!Line: 69 - style: Class 'TestCPPException' has a constructor with 1 argument that is not explicit. [noExplicitConstructor]

TestFailedException (const char * msg);
/**
* Construct an exception of this type with a string literal for
* its failure message.
*/

!Line: 92 - style: Class 'TestFailedException' has a constructor with 1 argument that is not explicit. [noExplicitConstructor]

TestFailedException (string&& msg);
};
}
#endif

!Line: 98 - style: Class 'TestFailedException' has a constructor with 1 argument that is not explicit. [noExplicitConstructor]

string failureMessage = "Arguments are not equivalent!"
)
{
if (expected != actual) {
stringstream err;

!Line: 78 - performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue]

string failureMessage = "Arguments are equivalent!"
)
{
if (expected == actual) {
stringstream err;

!Line: 109 - performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue]

string failureMessage = "Object is not null!"
)
{
bool null = ptr == nullptr;
if (!null) {

!Line: 136 - performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue]

string failureMessage = "Object is null!"
)
{
bool notNull = ptr != nullptr;
if (!notNull) {

!Line: 163 - performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue]

string failureMessage
)
{
if (!condition) {
stringstream err;

!Line: 93 - performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue]

string failureMessage
)
{
if (condition) {
stringstream err;

!Line: 108 - performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue]

TestObjName (const char* name);
/**
* @brief Get the encapsulated name for the TestCPP object that
* holds this object.
* @return The name of the TestCPP object that this object

!Line: 68 - style: Class 'TestObjName' has a constructor with 1 argument that is not explicit. [noExplicitConstructor]

bool TestCase::checkStdout (string against) {
return checkOutput(TestCase::stdoutBuffer->str(),
against);
}
bool TestCase::checkLog (string against) {

!Line: 454 - performance: Function parameter 'against' should be passed by const reference. [passedByValue]

bool TestCase::checkLog (string against) {
return checkOutput(TestCase::clogBuffer->str(),
against);
}
bool TestCase::checkStderr (string against) {

!Line: 459 - performance: Function parameter 'against' should be passed by const reference. [passedByValue]

bool TestCase::checkStderr (string against) {
return checkOutput(TestCase::stderrBuffer->str(),
against);
}
bool TestCase::checkOutput (string source, string against)

!Line: 464 - performance: Function parameter 'against' should be passed by const reference. [passedByValue]

bool TestCase::checkOutput (string source, string against)
{
switch (this->option) {
case EXACT:
if (source == against) {
return true;

!Line: 469 - performance: Function parameter 'source' should be passed by const reference. [passedByValue]

bool TestCase::checkOutput (string source, string against)
{
switch (this->option) {
case EXACT:
if (source == against) {
return true;

!Line: 469 - performance: Function parameter 'against' should be passed by const reference. [passedByValue]

TestCase::TestCase (TestCase& o) {
this->outCompareOption(o.option);
this->setNotifyPassed(o.notifyTestPassed);
this->pass = o.pass;
this->lastRunTime = o.lastRunTime;

!Line: 132 - style: Parameter 'o' can be declared as reference to const [constParameterReference]

TestCase& TestCase::operator= (TestCase& rhs) {
this->outCompareOption(rhs.option);
this->setNotifyPassed(rhs.notifyTestPassed);
this->pass = rhs.pass;
this->lastRunTime = rhs.lastRunTime;

!Line: 221 - style: Parameter 'rhs' can be declared as reference to const [constParameterReference]

void TestCase::logFailure(ostream& out, string& reason) {
out << fixed;
out << setprecision(TCPPNum::TIME_PRECISION);
out << TCPPStr::TEST_ << this->testName << TCPPStr::_FAIL_
<< TCPPStr::PARENL
<< static_cast<double>(this->lastRunTime)/

!Line: 279 - style: Parameter 'reason' can be declared as reference to const [constParameterReference]

TestSuite (TestObjName&& suiteName,
typename enable_if<sizeof...(TestType) == 0>::type)
{
this->testSuitePassedMessage = true;
this->setSuiteName(move(suiteName));
this->tests = vector<TestCase>();

!Line: 81 - warning: Member variable 'TestSuite::lastRunSucceeded' is not initialized in the constructor. [uninitMemberVar]

TestSuite (TestObjName&& suiteName,
typename enable_if<sizeof...(TestType) == 0>::type)
{
this->testSuitePassedMessage = true;
this->setSuiteName(move(suiteName));
this->tests = vector<TestCase>();

!Line: 81 - warning: Member variable 'TestSuite::lastRunSuccessCount' is not initialized in the constructor. [uninitMemberVar]

TestSuite (TestObjName&& suiteName,
typename enable_if<sizeof...(TestType) == 0>::type)
{
this->testSuitePassedMessage = true;
this->setSuiteName(move(suiteName));
this->tests = vector<TestCase>();

!Line: 81 - warning: Member variable 'TestSuite::lastRunFailCount' is not initialized in the constructor. [uninitMemberVar]

TestSuite (TestObjName&& suiteName,
typename enable_if<sizeof...(TestType) == 0>::type)
{
this->testSuitePassedMessage = true;
this->setSuiteName(move(suiteName));
this->tests = vector<TestCase>();

!Line: 81 - warning: Member variable 'TestSuite::totalRuntime' is not initialized in the constructor. [uninitMemberVar]


🔴 clang-tidy found 149 issues! Click here to see details.

using std::clog;
using std::move;
using std::string;
using std::runtime_error;
namespace TestCPP {

!Line: 36 - warning: using decl 'clog' is unused [misc-unused-using-decls]

!Line: 36 - note: remove the using

using std::string;
using std::runtime_error;
namespace TestCPP {
TestCPPException::TestCPPException (const char * msg) :

!Line: 38 - warning: no header providing "std::string" is directly included [misc-include-cleaner]

using std::runtime_error;
namespace TestCPP {
TestCPPException::TestCPPException (const char * msg) :
runtime_error(msg)

!Line: 39 - warning: no header providing "std::runtime_error" is directly included [misc-include-cleaner]

runtime_error(move(msg))
{
#ifdef TESTCPP_STACKTRACE_ENABLED
clog << boost::stacktrace::stacktrace();
#endif
}

!Line: 51 - warning: passing result of std::move() as a const reference argument; no move will actually happen [hicpp-move-const-arg,performance-move-const-arg]

using std::clog;
using std::current_exception;
using std::endl;
using std::exception;
using std::exception_ptr;
using std::function;

!Line: 30 - warning: no header providing "std::clog" is directly included [misc-include-cleaner]

using std::current_exception;
using std::endl;
using std::exception;
using std::exception_ptr;
using std::function;
using std::move;

!Line: 31 - warning: no header providing "std::current_exception" is directly included [misc-include-cleaner]

using std::exception;
using std::exception_ptr;
using std::function;
using std::move;
using std::rethrow_exception;
using std::string;

!Line: 33 - warning: no header providing "std::exception" is directly included [misc-include-cleaner]

using std::exception_ptr;
using std::function;
using std::move;
using std::rethrow_exception;
using std::string;
using std::stringstream;

!Line: 34 - warning: no header providing "std::__exception_ptr::exception_ptr" is directly included [misc-include-cleaner]

using std::rethrow_exception;
using std::string;
using std::stringstream;
namespace TestCPP {

!Line: 37 - warning: no header providing "std::rethrow_exception" is directly included [misc-include-cleaner]

using std::string;
using std::stringstream;
namespace TestCPP {
void Assertions::assertThrows (

!Line: 38 - warning: no header providing "std::string" is directly included [misc-include-cleaner]

using std::stringstream;
namespace TestCPP {
void Assertions::assertThrows (
function<void()> shouldThrow,

!Line: 39 - warning: no header providing "std::stringstream" is directly included [misc-include-cleaner]

function<void()> shouldThrow,
string failureMessage
)
{
try {
shouldThrow();

!Line: 44 - warning: the parameter 'shouldThrow' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]

exception_ptr eptr = current_exception();
if (eptr) {
try {
rethrow_exception(eptr);
}

!Line: 52 - warning: variable 'eptr' of type 'exception_ptr' can be declared 'const' [misc-const-correctness]

<< endl;
}
}
else {
clog << "Something was thrown, not sure what." << endl
<< "This satisfies the assertion, so no failure is"

!Line: 61 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

clog << "Something was thrown, not sure what." << endl
<< "This satisfies the assertion, so no failure is"
<< " present. "
<< TestFailedException("Unknown thrown object").
what();
}

!Line: 65 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

function<void()> shouldNotThrow,
string failureMessage
)
{
try {
shouldNotThrow();

!Line: 79 - warning: the parameter 'shouldNotThrow' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]

string failureMessage
)
{
if (!condition) {
stringstream err;

!Line: 93 - warning: the parameter 'failureMessage' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]

err << "Boolean Truth assertion failed!" << endl;
err << failureMessage << endl;
throw TestFailedException(err.str());
}
}

!Line: 99 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

err << failureMessage << endl;
throw TestFailedException(err.str());
}
}

!Line: 100 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

string failureMessage
)
{
if (condition) {
stringstream err;

!Line: 108 - warning: the parameter 'failureMessage' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]

err << "Boolean False assertion failed!" << endl;
err << failureMessage << endl;
throw TestFailedException(err.str());
}
}

!Line: 114 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

err << failureMessage << endl;
throw TestFailedException(err.str());
}
}

!Line: 115 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

if (name) {
this->testCaseName = name;
}
else {
throw TestCPPException(TCPPStr::NVTN);
}

!Line: 51 - warning: implicit conversion 'const char *' -> 'bool' [readability-implicit-bool-conversion]

const string& TestObjName::getName () {
return this->testCaseName;
}
std::ostream& operator<< (
std::ostream& s,

!Line: 59 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

std::ostream& operator<< (
std::ostream& s,
TestObjName& tcName
)
{
s << tcName.getName();

!Line: 63 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

std::ostream& s,
TestObjName& tcName
)
{
s << tcName.getName();
return s;

!Line: 64 - warning: parameter name 's' is too short, expected at least 3 characters [readability-identifier-length]

clog << endl;
}
#endif
}
bool stringContains(const string& source,

!Line: 78 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

bool stringContains(const string& source,
const string& contains)
{
return source.find(contains) != string::npos;
}

!Line: 83 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

int unsignedToSigned(unsigned toCast) {
if (toCast <= INT_MAX) {
return static_cast<int>(toCast);
}
if (toCast >= static_cast<unsigned>(INT_MIN)) {

!Line: 89 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

using std::cerr;
using std::clog;
using std::cout;
using std::endl;
using std::exception;
using std::fixed;

!Line: 36 - warning: no header providing "std::cerr" is directly included [misc-include-cleaner]

using std::clog;
using std::cout;
using std::endl;
using std::exception;
using std::fixed;
using std::function;

!Line: 37 - warning: no header providing "std::clog" is directly included [misc-include-cleaner]

using std::cout;
using std::endl;
using std::exception;
using std::fixed;
using std::function;
using std::invalid_argument;

!Line: 38 - warning: using decl 'cout' is unused [misc-unused-using-decls]

!Line: 38 - note: remove the using

using std::exception;
using std::fixed;
using std::function;
using std::invalid_argument;
using std::move;
using std::ostream;

!Line: 40 - warning: no header providing "std::exception" is directly included [misc-include-cleaner]

using std::fixed;
using std::function;
using std::invalid_argument;
using std::move;
using std::ostream;
using std::rethrow_exception;

!Line: 41 - warning: no header providing "std::fixed" is directly included [misc-include-cleaner]

using std::invalid_argument;
using std::move;
using std::ostream;
using std::rethrow_exception;
using std::runtime_error;
using std::setprecision;

!Line: 43 - warning: using decl 'invalid_argument' is unused [misc-unused-using-decls]

!Line: 43 - note: remove the using

using std::ostream;
using std::rethrow_exception;
using std::runtime_error;
using std::setprecision;
using std::string;
using std::tuple;

!Line: 45 - warning: no header providing "std::ostream" is directly included [misc-include-cleaner]

using std::rethrow_exception;
using std::runtime_error;
using std::setprecision;
using std::string;
using std::tuple;

!Line: 46 - warning: no header providing "std::rethrow_exception" is directly included [misc-include-cleaner]

using std::rethrow_exception;
using std::runtime_error;
using std::setprecision;
using std::string;
using std::tuple;

!Line: 46 - warning: using decl 'rethrow_exception' is unused [misc-unused-using-decls]

!Line: 46 - note: remove the using

using std::runtime_error;
using std::setprecision;
using std::string;
using std::tuple;
using TCPPNum = TestCPP::TestCPPCommon::Nums;

!Line: 47 - warning: no header providing "std::runtime_error" is directly included [misc-include-cleaner]

using std::runtime_error;
using std::setprecision;
using std::string;
using std::tuple;
using TCPPNum = TestCPP::TestCPPCommon::Nums;

!Line: 47 - warning: using decl 'runtime_error' is unused [misc-unused-using-decls]

!Line: 47 - note: remove the using

using std::string;
using std::tuple;
using TCPPNum = TestCPP::TestCPPCommon::Nums;
using TCPPStr = TestCPP::TestCPPCommon::Strings;

!Line: 49 - warning: no header providing "std::string" is directly included [misc-include-cleaner]

void TestSuite::setSuiteName (TestObjName&& testSuiteName) {
this->suiteName = move(testSuiteName);
}
unsigned TestSuite::getLastRunFailCount () {
return this->lastRunFailCount;

!Line: 70 - warning: no header providing "TestCPP::TestObjName" is directly included [misc-include-cleaner]

unsigned TestSuite::getLastRunFailCount () {
return this->lastRunFailCount;
}
void TestSuite::run () {
if (this->tests.size() == 0) {

!Line: 74 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

unsigned TestSuite::getLastRunFailCount () {
return this->lastRunFailCount;
}
void TestSuite::run () {
if (this->tests.size() == 0) {

!Line: 74 - warning: method 'getLastRunFailCount' can be made const [readability-make-member-function-const]

if (this->tests.size() == 0) {
clog << TCPPStr::NTR << endl;
return;
}
this->lastRunSucceeded = true;

!Line: 79 - warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]

clog << TCPPStr::NTR << endl;
return;
}
this->lastRunSucceeded = true;
this->lastRunFailCount = 0;

!Line: 80 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

clog << endl
<< TCPPStr::START_RUN << TCPPStr::SUITE_
<< TCPPStr::APOS << this->suiteName << TCPPStr::APOS
<< endl
<< endl;

!Line: 89 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

<< endl
<< endl;
for (TestCase test : this->tests) {
bool testPassed = false;
try {

!Line: 92 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

<< endl;
for (TestCase test : this->tests) {
bool testPassed = false;
try {
testPassed = test.go();

!Line: 93 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

<< endl;
}
catch (...) {
cerr << TCPPStr::UNK_EXC
<< endl;
}

!Line: 102 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

<< endl;
}
if (!testPassed) {
this->lastRunFailCount++;

!Line: 106 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

clog << endl;
if (this->testSuitePassedMessage &&
this->lastRunFailCount == 0) {
clog << TCPPStr::ALL_ << TCPPStr::APOS << this->suiteName
<< TCPPStr::APOS << TCPPStr::_SUITE_TESTS_PASSED

!Line: 123 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

<< endl;
}
double suiteRuntimeElapsed = static_cast<double>(
this->totalRuntime)/TCPPNum::NANOS_IN_SEC;

!Line: 129 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

double suiteRuntimeElapsed = static_cast<double>(
this->totalRuntime)/TCPPNum::NANOS_IN_SEC;
clog << fixed;
clog << setprecision(0);
clog << TCPPStr::FINISHED_SUITE_ << TCPPStr::APOS

!Line: 132 - warning: variable 'suiteRuntimeElapsed' of type 'double' can be declared 'const' [misc-const-correctness]

<< endl;
}
/**
* @brief Add a test to this test suite.
*

!Line: 143 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

void TestSuite::addTest (TestCase&& test) {
this->tests.emplace_back(test);
}
/**
* @brief Add a test to this test suite.

!Line: 152 - warning: rvalue reference parameter 'test' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]

function<void()>>&& test) {
this->tests.emplace_back(
std::get<0>(test),
std::get<1>(test),
this->testSuitePassedMessage
);

!Line: 165 - warning: rvalue reference parameter 'test' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]

TestCase (
TestObjName&& testName,
function<void()> test,
bool testPassedMessage = true,
bool captureOut = false,
bool captureLog = false,

!Line: 131 - warning: function 'TestCPP::TestCase::TestCase' has a definition with different parameter names [readability-inconsistent-declaration-parameter-name]

!Line: 101 - note: the definition seen here
!Line: 131 - note: differing parameters are named here: ('testPassedMessage'), in definition: ('msg')

void logTestFailure (string failureMessage);
/**
* @brief Internal test run controller.
*/
void runTest ();
/**

!Line: 299 - warning: function 'TestCPP::TestCase::logTestFailure' has a definition with different parameter names [readability-inconsistent-declaration-parameter-name]

!Line: 291 - note: the definition seen here
!Line: 299 - note: differing parameters are named here: ('failureMessage'), in definition: ('reason')

using std::cerr;
using std::clog;
using std::cout;
using std::endl;
using std::exception;
using std::fixed;

!Line: 43 - warning: no header providing "std::cerr" is directly included [misc-include-cleaner]

using std::clog;
using std::cout;
using std::endl;
using std::exception;
using std::fixed;
using std::function;

!Line: 44 - warning: no header providing "std::clog" is directly included [misc-include-cleaner]

using std::cout;
using std::endl;
using std::exception;
using std::fixed;
using std::function;
using std::invalid_argument;

!Line: 45 - warning: no header providing "std::cout" is directly included [misc-include-cleaner]

using std::exception;
using std::fixed;
using std::function;
using std::invalid_argument;
using std::move;
using std::rethrow_exception;

!Line: 47 - warning: no header providing "std::exception" is directly included [misc-include-cleaner]

using std::fixed;
using std::function;
using std::invalid_argument;
using std::move;
using std::rethrow_exception;
using std::runtime_error;

!Line: 48 - warning: no header providing "std::fixed" is directly included [misc-include-cleaner]

using std::invalid_argument;
using std::move;
using std::rethrow_exception;
using std::runtime_error;
using std::setprecision;
using std::string;

!Line: 50 - warning: using decl 'invalid_argument' is unused [misc-unused-using-decls]

!Line: 50 - note: remove the using

using std::rethrow_exception;
using std::runtime_error;
using std::setprecision;
using std::string;
using std::tuple;

!Line: 52 - warning: no header providing "std::rethrow_exception" is directly included [misc-include-cleaner]

using std::rethrow_exception;
using std::runtime_error;
using std::setprecision;
using std::string;
using std::tuple;

!Line: 52 - warning: using decl 'rethrow_exception' is unused [misc-unused-using-decls]

!Line: 52 - note: remove the using

using std::runtime_error;
using std::setprecision;
using std::string;
using std::tuple;
using TCPPNum = TestCPP::TestCPPCommon::Nums;

!Line: 53 - warning: no header providing "std::runtime_error" is directly included [misc-include-cleaner]

using std::runtime_error;
using std::setprecision;
using std::string;
using std::tuple;
using TCPPNum = TestCPP::TestCPPCommon::Nums;

!Line: 53 - warning: using decl 'runtime_error' is unused [misc-unused-using-decls]

!Line: 53 - note: remove the using

using std::string;
using std::tuple;
using TCPPNum = TestCPP::TestCPPCommon::Nums;
using TCPPStr = TestCPP::TestCPPCommon::Strings;

!Line: 55 - warning: no header providing "std::string" is directly included [misc-include-cleaner]

using std::tuple;
using TCPPNum = TestCPP::TestCPPCommon::Nums;
using TCPPStr = TestCPP::TestCPPCommon::Strings;
namespace TestCPP {

!Line: 56 - warning: using decl 'tuple' is unused [misc-unused-using-decls]

!Line: 56 - note: remove the using

atomic_int TestCase::stdoutCaptureCasesConstructed;
atomic_int TestCase::logCaptureCasesConstructed;
atomic_int TestCase::stderrCaptureCasesConstructed;
atomic_int TestCase::stdoutCaptureCasesDestroyed;
atomic_int TestCase::logCaptureCasesDestroyed;
atomic_int TestCase::stderrCaptureCasesDestroyed;

!Line: 63 - warning: no header providing "atomic_int" is directly included [misc-include-cleaner]

TestCase::TestCase (TestObjName&& name,
function<void()> test,
bool msg,
bool captureOut, bool captureLog,
bool captureErr,
TestCase::TestCaseOutCompareOptions opt)

!Line: 101 - warning: rvalue reference parameter 'name' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved]

this->notifyTestPassed = msg;
this->test = test;
this->testName = name;
if (captureOut) {

!Line: 108 - warning: 'notifyTestPassed' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

this->test = test;
this->testName = name;
if (captureOut) {
captureStdout();

!Line: 109 - warning: 'test' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

this->test = test;
this->testName = name;
if (captureOut) {
captureStdout();

!Line: 109 - warning: parameter 'test' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

this->testName = name;
if (captureOut) {
captureStdout();
}
if (captureLog) {

!Line: 111 - warning: 'testName' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

TestCase::TestCase (TestCase& o) {
this->outCompareOption(o.option);
this->setNotifyPassed(o.notifyTestPassed);
this->pass = o.pass;
this->lastRunTime = o.lastRunTime;

!Line: 132 - warning: parameter name 'o' is too short, expected at least 3 characters [readability-identifier-length]

this->pass = o.pass;
this->lastRunTime = o.lastRunTime;
this->stdoutCaptured = o.stdoutCaptured;
this->clogCaptured = o.clogCaptured;
this->stderrCaptured = o.stderrCaptured;

!Line: 136 - warning: 'pass' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

this->lastRunTime = o.lastRunTime;
this->stdoutCaptured = o.stdoutCaptured;
this->clogCaptured = o.clogCaptured;
this->stderrCaptured = o.stderrCaptured;

!Line: 137 - warning: 'lastRunTime' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

this->stdoutCaptured = o.stdoutCaptured;
this->clogCaptured = o.clogCaptured;
this->stderrCaptured = o.stderrCaptured;
if (this->stdoutCaptured) {
captureStdout();

!Line: 139 - warning: 'stdoutCaptured' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

this->clogCaptured = o.clogCaptured;
this->stderrCaptured = o.stderrCaptured;
if (this->stdoutCaptured) {
captureStdout();
}

!Line: 140 - warning: 'clogCaptured' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

this->stderrCaptured = o.stderrCaptured;
if (this->stdoutCaptured) {
captureStdout();
}
if (this->clogCaptured) {

!Line: 141 - warning: 'stderrCaptured' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

TestCase::TestCase (TestCase&& o) {
this->outCompareOption(move(o.option));
this->setNotifyPassed(move(o.notifyTestPassed));
this->pass = move(o.pass);
this->lastRunTime = move(o.lastRunTime);

!Line: 157 - warning: an exception may be thrown in function 'TestCase' which should not throw exceptions [bugprone-exception-escape]

TestCase::TestCase (TestCase&& o) {
this->outCompareOption(move(o.option));
this->setNotifyPassed(move(o.notifyTestPassed));
this->pass = move(o.pass);
this->lastRunTime = move(o.lastRunTime);

!Line: 157 - warning: move constructors should be marked noexcept [cppcoreguidelines-noexcept-move-operations,hicpp-noexcept-move,performance-noexcept-move-constructor]

TestCase::TestCase (TestCase&& o) {
this->outCompareOption(move(o.option));
this->setNotifyPassed(move(o.notifyTestPassed));
this->pass = move(o.pass);
this->lastRunTime = move(o.lastRunTime);

!Line: 157 - warning: parameter name 'o' is too short, expected at least 3 characters [readability-identifier-length]

this->outCompareOption(move(o.option));
this->setNotifyPassed(move(o.notifyTestPassed));
this->pass = move(o.pass);
this->lastRunTime = move(o.lastRunTime);

!Line: 158 - warning: std::move of the expression of the trivially-copyable type 'TestCaseOutCompareOptions' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->setNotifyPassed(move(o.notifyTestPassed));
this->pass = move(o.pass);
this->lastRunTime = move(o.lastRunTime);
this->stdoutCaptured = move(o.stdoutCaptured);

!Line: 159 - warning: std::move of the expression of the trivially-copyable type 'bool' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->pass = move(o.pass);
this->lastRunTime = move(o.lastRunTime);
this->stdoutCaptured = move(o.stdoutCaptured);
this->clogCaptured = move(o.clogCaptured);
this->stderrCaptured = move(o.stderrCaptured);

!Line: 161 - warning: 'pass' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

this->pass = move(o.pass);
this->lastRunTime = move(o.lastRunTime);
this->stdoutCaptured = move(o.stdoutCaptured);
this->clogCaptured = move(o.clogCaptured);
this->stderrCaptured = move(o.stderrCaptured);

!Line: 161 - warning: std::move of the expression of the trivially-copyable type 'bool' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->lastRunTime = move(o.lastRunTime);
this->stdoutCaptured = move(o.stdoutCaptured);
this->clogCaptured = move(o.clogCaptured);
this->stderrCaptured = move(o.stderrCaptured);

!Line: 162 - warning: 'lastRunTime' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

this->lastRunTime = move(o.lastRunTime);
this->stdoutCaptured = move(o.stdoutCaptured);
this->clogCaptured = move(o.clogCaptured);
this->stderrCaptured = move(o.stderrCaptured);

!Line: 162 - warning: std::move of the expression of the trivially-copyable type 'long long' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->stdoutCaptured = move(o.stdoutCaptured);
this->clogCaptured = move(o.clogCaptured);
this->stderrCaptured = move(o.stderrCaptured);
if (this->stdoutCaptured) {
captureStdout();

!Line: 164 - warning: 'stdoutCaptured' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

this->stdoutCaptured = move(o.stdoutCaptured);
this->clogCaptured = move(o.clogCaptured);
this->stderrCaptured = move(o.stderrCaptured);
if (this->stdoutCaptured) {
captureStdout();

!Line: 164 - warning: std::move of the expression of the trivially-copyable type 'bool' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->clogCaptured = move(o.clogCaptured);
this->stderrCaptured = move(o.stderrCaptured);
if (this->stdoutCaptured) {
captureStdout();
}

!Line: 165 - warning: 'clogCaptured' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

this->clogCaptured = move(o.clogCaptured);
this->stderrCaptured = move(o.stderrCaptured);
if (this->stdoutCaptured) {
captureStdout();
}

!Line: 165 - warning: std::move of the expression of the trivially-copyable type 'bool' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->stderrCaptured = move(o.stderrCaptured);
if (this->stdoutCaptured) {
captureStdout();
}
if (this->clogCaptured) {

!Line: 166 - warning: 'stderrCaptured' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]

this->stderrCaptured = move(o.stderrCaptured);
if (this->stdoutCaptured) {
captureStdout();
}
if (this->clogCaptured) {

!Line: 166 - warning: std::move of the expression of the trivially-copyable type 'bool' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

delete TestCase::stdoutBuffer.get();
TestCase::stdoutBuffer = nullptr;
}
TestCase::stdoutCaptureCasesDestroyed += 1;
}

!Line: 189 - warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead [cppcoreguidelines-owning-memory]

!Line: 70 - note: variable declared here

delete TestCase::clogBuffer.get();
TestCase::clogBuffer = nullptr;
}
TestCase::logCaptureCasesDestroyed += 1;
}

!Line: 201 - warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead [cppcoreguidelines-owning-memory]

!Line: 75 - note: variable declared here

delete TestCase::stderrBuffer.get();
TestCase::stderrBuffer = nullptr;
}
TestCase::stderrCaptureCasesDestroyed += 1;
}

!Line: 213 - warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead [cppcoreguidelines-owning-memory]

!Line: 80 - note: variable declared here

TestCase& TestCase::operator= (TestCase& rhs) {
this->outCompareOption(rhs.option);
this->setNotifyPassed(rhs.notifyTestPassed);
this->pass = rhs.pass;
this->lastRunTime = rhs.lastRunTime;

!Line: 221 - warning: operator=() should take 'TestCase const&', 'TestCase&&' or 'TestCase' [cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator]

TestCase& TestCase::operator= (TestCase& rhs) {
this->outCompareOption(rhs.option);
this->setNotifyPassed(rhs.notifyTestPassed);
this->pass = rhs.pass;
this->lastRunTime = rhs.lastRunTime;

!Line: 221 - warning: operator=() does not handle self-assignment properly [cert-oop54-cpp]

TestCase& TestCase::operator= (TestCase& rhs) {
this->outCompareOption(rhs.option);
this->setNotifyPassed(rhs.notifyTestPassed);
this->pass = rhs.pass;
this->lastRunTime = rhs.lastRunTime;

!Line: 221 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

TestCase& TestCase::operator= (TestCase&& rhs) {
this->outCompareOption(move(rhs.option));
this->setNotifyPassed(move(rhs.notifyTestPassed));
this->pass = move(rhs.pass);
this->lastRunTime = move(rhs.lastRunTime);

!Line: 248 - warning: an exception may be thrown in function 'operator=' which should not throw exceptions [bugprone-exception-escape]

TestCase& TestCase::operator= (TestCase&& rhs) {
this->outCompareOption(move(rhs.option));
this->setNotifyPassed(move(rhs.notifyTestPassed));
this->pass = move(rhs.pass);
this->lastRunTime = move(rhs.lastRunTime);

!Line: 248 - warning: move assignment operators should be marked noexcept [cppcoreguidelines-noexcept-move-operations,hicpp-noexcept-move,performance-noexcept-move-constructor]

TestCase& TestCase::operator= (TestCase&& rhs) {
this->outCompareOption(move(rhs.option));
this->setNotifyPassed(move(rhs.notifyTestPassed));
this->pass = move(rhs.pass);
this->lastRunTime = move(rhs.lastRunTime);

!Line: 248 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

this->outCompareOption(move(rhs.option));
this->setNotifyPassed(move(rhs.notifyTestPassed));
this->pass = move(rhs.pass);
this->lastRunTime = move(rhs.lastRunTime);

!Line: 249 - warning: std::move of the expression of the trivially-copyable type 'TestCaseOutCompareOptions' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->setNotifyPassed(move(rhs.notifyTestPassed));
this->pass = move(rhs.pass);
this->lastRunTime = move(rhs.lastRunTime);
this->stdoutCaptured = move(rhs.stdoutCaptured);

!Line: 250 - warning: std::move of the expression of the trivially-copyable type 'bool' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->pass = move(rhs.pass);
this->lastRunTime = move(rhs.lastRunTime);
this->stdoutCaptured = move(rhs.stdoutCaptured);
this->clogCaptured = move(rhs.clogCaptured);
this->stderrCaptured = move(rhs.stderrCaptured);

!Line: 252 - warning: std::move of the expression of the trivially-copyable type 'bool' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->lastRunTime = move(rhs.lastRunTime);
this->stdoutCaptured = move(rhs.stdoutCaptured);
this->clogCaptured = move(rhs.clogCaptured);
this->stderrCaptured = move(rhs.stderrCaptured);

!Line: 253 - warning: std::move of the expression of the trivially-copyable type 'long long' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->stdoutCaptured = move(rhs.stdoutCaptured);
this->clogCaptured = move(rhs.clogCaptured);
this->stderrCaptured = move(rhs.stderrCaptured);
if (this->stdoutCaptured) {
captureStdout();

!Line: 255 - warning: std::move of the expression of the trivially-copyable type 'bool' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->clogCaptured = move(rhs.clogCaptured);
this->stderrCaptured = move(rhs.stderrCaptured);
if (this->stdoutCaptured) {
captureStdout();
}

!Line: 256 - warning: std::move of the expression of the trivially-copyable type 'bool' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

this->stderrCaptured = move(rhs.stderrCaptured);
if (this->stdoutCaptured) {
captureStdout();
}
if (this->clogCaptured) {

!Line: 257 - warning: std::move of the expression of the trivially-copyable type 'bool' has no effect; remove std::move() [hicpp-move-const-arg,performance-move-const-arg]

long long TestCase::getLastRuntime () {
return this->lastRunTime;
}
void TestCase::logFailure(ostream& out, string& reason) {
out << fixed;

!Line: 275 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

long long TestCase::getLastRuntime () {
return this->lastRunTime;
}
void TestCase::logFailure(ostream& out, string& reason) {
out << fixed;

!Line: 275 - warning: method 'getLastRuntime' can be made const [readability-make-member-function-const]

<< endl;
out << TCPPStr::REASON_ << reason << endl;
}
void TestCase::logTestFailure (string reason) {
unique_ptr<ostream> logStream = nullptr;

!Line: 287 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

out << TCPPStr::REASON_ << reason << endl;
}
void TestCase::logTestFailure (string reason) {
unique_ptr<ostream> logStream = nullptr;

!Line: 288 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

if (this->clogOriginal != nullptr) {
logStream = unique_ptr<ostream>(
new ostream(this->clogOriginal.get())
);
}
else {

!Line: 294 - warning: static member accessed through instance [readability-static-accessed-through-instance]

new ostream(this->clogOriginal.get())
);
}
else {
logStream = unique_ptr<ostream>(&clog);
}

!Line: 296 - warning: static member accessed through instance [readability-static-accessed-through-instance]

if (this->clogOriginal != nullptr) {
logStream->flush();
// If someone is looking for something in the message,
// and it's captured, make sure it's there.
logFailure(clog, reason);

!Line: 305 - warning: static member accessed through instance [readability-static-accessed-through-instance]

logStream.release();
logStream.reset();
}
void TestCase::runTest () {
clog << TCPPStr::START_RUN << this->testName << endl;

!Line: 313 - warning: the value returned by this function should not be disregarded; neglecting it may lead to errors [bugprone-unused-return-value]

clog << TCPPStr::START_RUN << this->testName << endl;
this->lastRunTime = duration(this->test).count();
if (this->notifyTestPassed) {
clog << fixed;
clog << setprecision(TCPPNum::TIME_PRECISION);
clog << TCPPStr::TEST_ << this->testName << TCPPStr::_PASS_

!Line: 318 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

<< endl;
}
this->pass = true;
}
bool TestCase::go () {

!Line: 328 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

bool TestCase::go () {
try {
runTest();
return true;
}
catch(const char * errorMessage) {

!Line: 333 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

void TestCase::captureStdout () {
if (TestCase::stdoutCaptureCasesConstructed ==
TestCase::stdoutCaptureCasesDestroyed)
{
TestCase::stdoutCaptureCasesConstructed += 1;
TestCase::stdoutBuffer =

!Line: 362 - warning: method 'captureStdout' can be made static [readability-convert-member-functions-to-static]

void TestCase::captureClog () {
if (TestCase::logCaptureCasesConstructed ==
TestCase::logCaptureCasesDestroyed)
{
TestCase::logCaptureCasesConstructed += 1;
TestCase::clogBuffer =

!Line: 382 - warning: method 'captureClog' can be made static [readability-convert-member-functions-to-static]

void TestCase::captureStdErr () {
if (TestCase::stderrCaptureCasesConstructed ==
TestCase::stderrCaptureCasesDestroyed)
{
TestCase::stderrCaptureCasesConstructed += 1;
TestCase::stderrBuffer =

!Line: 402 - warning: method 'captureStdErr' can be made static [readability-convert-member-functions-to-static]

void TestCase::clearStdoutCapture () {
if (TestCase::stdoutBuffer) {
TestCase::stdoutBuffer->str(string());
}
}

!Line: 436 - warning: method 'clearStdoutCapture' can be made static [readability-convert-member-functions-to-static]

void TestCase::clearLogCapture () {
if (TestCase::clogBuffer) {
TestCase::clogBuffer->str(string());
}
}

!Line: 442 - warning: method 'clearLogCapture' can be made static [readability-convert-member-functions-to-static]

void TestCase::clearStderrCapture () {
if (TestCase::stderrBuffer) {
TestCase::stderrBuffer->str(string());
}
}

!Line: 448 - warning: method 'clearStderrCapture' can be made static [readability-convert-member-functions-to-static]

bool TestCase::checkStdout (string against) {
return checkOutput(TestCase::stdoutBuffer->str(),
against);
}
bool TestCase::checkLog (string against) {

!Line: 454 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

against);
}
bool TestCase::checkLog (string against) {
return checkOutput(TestCase::clogBuffer->str(),
against);

!Line: 456 - warning: parameter 'against' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

bool TestCase::checkLog (string against) {
return checkOutput(TestCase::clogBuffer->str(),
against);
}
bool TestCase::checkStderr (string against) {

!Line: 459 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

against);
}
bool TestCase::checkStderr (string against) {
return checkOutput(TestCase::stderrBuffer->str(),
against);

!Line: 461 - warning: parameter 'against' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

bool TestCase::checkStderr (string against) {
return checkOutput(TestCase::stderrBuffer->str(),
against);
}
bool TestCase::checkOutput (string source, string against)

!Line: 464 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

against);
}
bool TestCase::checkOutput (string source, string against)
{
switch (this->option) {

!Line: 466 - warning: parameter 'against' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

bool TestCase::checkOutput (string source, string against)
{
switch (this->option) {
case EXACT:
if (source == against) {
return true;

!Line: 469 - warning: use a trailing return type for this function [modernize-use-trailing-return-type]

bool TestCase::checkOutput (string source, string against)
{
switch (this->option) {
case EXACT:
if (source == against) {
return true;

!Line: 469 - warning: the parameter 'source' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]

bool TestCase::checkOutput (string source, string against)
{
switch (this->option) {
case EXACT:
if (source == against) {
return true;

!Line: 469 - warning: the parameter 'against' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]

if (this->clogOriginal != nullptr) {
ostream tmp(this->clogOriginal.get());
tmp << nomatch.str() << endl;
tmp.flush();
}
else {

!Line: 482 - warning: static member accessed through instance [readability-static-accessed-through-instance]

ostream tmp(this->clogOriginal.get());
tmp << nomatch.str() << endl;
tmp.flush();
}
else {
clog << nomatch.str() << endl;

!Line: 483 - warning: static member accessed through instance [readability-static-accessed-through-instance]

tmp << nomatch.str() << endl;
tmp.flush();
}
else {
clog << nomatch.str() << endl;
}

!Line: 484 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

clog << nomatch.str() << endl;
}
return false;
}

!Line: 488 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

if (this->clogOriginal != nullptr) {
ostream tmp(this->clogOriginal.get());
tmp << nomatch.str() << endl;
tmp.flush();
}
else {

!Line: 504 - warning: static member accessed through instance [readability-static-accessed-through-instance]

ostream tmp(this->clogOriginal.get());
tmp << nomatch.str() << endl;
tmp.flush();
}
else {
clog << nomatch.str() << endl;

!Line: 505 - warning: static member accessed through instance [readability-static-accessed-through-instance]

tmp << nomatch.str() << endl;
tmp.flush();
}
else {
clog << nomatch.str() << endl;
}

!Line: 506 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

clog << nomatch.str() << endl;
}
return false;
}

!Line: 510 - warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl]

stringstream re;
re << TCPPStr::UNK_CMP_OPT_ << this->option;
throw TestCPPException(re.str());
}
}
}

!Line: 517 - warning: variable name 're' is too short, expected at least 3 characters [readability-identifier-length]


@eljonny
Copy link
Owner Author

eljonny commented May 2, 2024

Fixed the CPPCheck issue, but this line that was changed is not covered by tests.
Going to create a test for this to get the patch coverage up.

eljonny added 2 commits May 3, 2024 12:35
Use the TestCaseName class (now named TestObjName) also for TestSuite
to protect against null char * in string construction, which also
simplifies the setSuiteName logic.
Change the setSuiteName signature appropriately for the new type.
Change private suiteName member type from string to TestObjName.
Change constructor parameter for suite name from string to TestObjName,
and ensure it's moved properly when storing it.
Coincidentally, fixes GH issue #7.

Extract strings into structs per-class so strings that are used more
than once only need to be changed once, and can be referenced by tests
for log verification when appropriate.
Also if something will then be used again, just reference it.
In order to protect against null char *, we don't know how a string is
constructed before it's passed to TestObjName.
eljonny added 11 commits May 13, 2024 08:06
I broke up TestCPP.h and the corresponding .cpp file into many pieces.
It just started to get too big, and I wanted more focused TUs.
So this is the first commit for that, where I split them out into
different header files, put them in an 'internal' subdirectory, and
turned TestCPP.h into an aggregate include for including the types and
definitions needed by the library.
So the common definitions are now split out into their own header-only
definition in internal/TestCPPCommon.h.
The exception types are now in their own internal/TestCPPExceptions.h
header with corresponding .cpp.
TestCase and TestSuite now have their own headers,
internal/TestCPPTestCase.h and internal/TestCPPTestSuite.h, with
corresponding .cpps.
And finally TestCPPUtil.h is moved into internal and the TestObjName
type has been moved into the Util header and definition .cpp, but is
still in the base namespace TestCPP, not in TestCPP::Util.

The biggest functional change is splitting the assertions out of
TestSuite and into their own Assertions class, in their own TU.
So from now on, the TestCPP assertions should be referenced through the
Assertions class, not the TestSuite class, which makes a lot more
sense.
I added a couple new assertions a few weeks back, and I can see adding
more, so they really need their own type to encapsulate that
functionality.

There's some significant cleanup to do, but that will probably be in a
separate PR.
Since Assertions are now in their own TU, they now have their own
test module.
Assertion tests are removed from TestSuite tests.

Removed now-unnecessary TestCPPUtil.h #include.
Refactored assertion calls.
Formatting.
Cover the patched line to get the CodeCov patch coverage to an
acceptable level, plus a little.
Added 3 new tests for this.

Refactoring for API changes.
Use TestCPPCommon to check output is as expected.
Remove now-unnecessary TestCPPUtil.h #include.
Bump the major version because of the API change.
This is still considered a beta-project, regardless.

Work on the build takes the refactorings into account.
This includes ensuring the new header structure is properly accounted
for in packages and installation.
There are now multiple private headers, needed to encapsulate them into
a list in order to have them properly applied to packing/installing
build steps.
@eljonny
Copy link
Owner Author

eljonny commented May 13, 2024

That last commit is for the release build. I should have put it in the preprocessor def as an else though since iostream is already included in the debug build.
Fixy fix.

eljonny added 3 commits May 13, 2024 10:05
Now it is, if it doesn't need iostream for debug logging then just
include ostream for the friend operator<< overload.
I think this is not required for capture because it's constexpr.
I have to ignore the clang warning to work around the MSVC issue since
the library is for C++11 not >=C++14, where there is an available
workaround that doesn't involve ignoring a warning.
eljonny added 2 commits June 22, 2024 09:14
Initialize everything in TestCase with sane defaults.
Name the parameter in the logTestFailure function prototype.

Add boolean members that indicate whether for the given TestCase the
output should be captured.
Add implementation details for capture bools.
This ensures all are counted properly.

Rename the testPassedMessage TestSuite member to testSuitePassedMessage.
This properly differentiates it from the similar member of TestCase.

No addTest specializations in header file, only the template.
Moved the specialization from the header file that was there to the
source file.
This fixed an issue when testing where the compiler could not find the
proper specialization.

Flesh out/add/fix docs.

Fixed a huge bug in how the test passage message is enabled/disabled en-
mass through a TestSuite.
Previously the vector was iterated over with the newer style, but this
causes a copy to be made on every iteration of every TestCase, which
is completely not what we want to do here.
Fall back to index-based vector iteration so we're properly modifying
each original TestCase and not making copies thinking we're modifying
the actual TestCases.
The following is what was previously tested in TestSuite:
- Bare construction, no tests, only suite name

The following is now tested, in addition to what was previously tested:
- All possible construction parameters
  > Suite construction with TestCase objects
  > Suite construction with tuples
  > Suite construction with various mixes of TestCases and tuples
- TestSuite::enableTestPassedMessage with various mixes of numbers of
   tests.
- TestSuite::disableTestPassedMessage with various mixes of numbers of
   tests.
eljonny added 10 commits June 23, 2024 11:40
Excess whitespace in doc comments has been removed.
Docs have been expanded/fixed.

Removed unnecessary parameter from internal private API and adjust
implementation to fix unnecessary reliance on the removed parameter.
I don't know why I put this in there in the first place.
It has been unused ever since I can remember.
I think I was just messing with templates back in 2014 and this seemed
like a cool function to implement.
Make sure stream capture does not affect logging of test failures.
-----------------------------------------------------------------------
Created a subroutine for logging test failures where the output stream
is injected instead of just using std::clog.
This allows the TestCase::logTestFailure function to log to the real
clog stream and the captured (if captured) clog stream to ensure any
expected output is present for analysis.
This ensures test failures are logged even if the stream being logged to
is captured for analysis for the given test.
This was an oversight on my part, and there are more than likely other
instances where this will need to be corrected.

Fix multiple frees on streams (stringstreams and streambufs)
-----------------------------------------------------------------------
I've been working on this periodically since last month to figure out
what is happening.
It turns out, std::unique_ptr seems to add an exit handler to the
program (this is a possibility, I haven't looked at the STL
implementation code to confirm) that calls the deleter when it is a
static object.
The default deleter just calls delete on the pointed-to object without
checking that and with no context around the object.
The solution ended up being constructing each std::unique_ptr with a
custom no-op deleter to allow the TestCase destructor to properly
handle desctruction, since proper functionality of the TestCase code
depends on the semaphore behavior defined in the construction and
destruction of TestCases depending on the stream capture arguments,
so it knows when to free the buffers: only when nothing is using them.
The std::unique_ptr template arguments are adjusted accordingly, and
the buffers are now freed at the proper time and place.
The streambufs are also left alone with custom no-op deleters, as we
have no business freeing streambufs that are not ours to delete (the
underlying streams for std::cout, std::clog, and std::cerr).
There is now only one place for incrementing, and the conditions are
now logically split and actions clearer.

Tests in TestSuiteTests are no longer failing.
The output buffer was not being cleared and there was lingering buffer
content from previous tests.
The tests were checking that nothing was logged related to test passage,
so the checks for lack of output were failing.

All tests pass! :)
Try to figure out where this is happening since I have no windows box to
test this on.
Removing the debug logs.

Since the std::streambuf pointer returned by cout.rdbuf() result was
already assigned to a std::unique_ptr, it must have been what was
causing the segfault (really an Access Violation, this is Windows not
*nix/BSD).
The weird thing is that the same code was not causing the issue on any
other platform with any other compiler.
The only time the issue popped up was on Windows with the MSVC++ cl
compiler, compiling with debug options, where there were no compile
warnings or errors!
Very strange, but the good news is it pointed out 2 really severe but
subtle bugs of the same kind in 2 different places, where the wrong
std::streambuf was being stored for output capturing, which would have
caused an inability to revert the capture for tests that don't capture
output after the capturing test(s) have finished running.
All because of a copy-paste error 2 times over. Yeesh.
@eljonny
Copy link
Owner Author

eljonny commented Jun 28, 2024

Fixed a bug where capturing multiple streams in the same test resulted in an Access Violation on Windows cl in Debug.
PR now has sufficient patch coverage for merge.

@eljonny eljonny merged commit 644620a into main Jun 28, 2024
@eljonny eljonny deleted the fix-cppcheck-catchexceptionbyvalue branch June 28, 2024 01:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix CPPCheck issues - Should always catch exceptions by reference

1 participant