From 4dc9cda81e8cf0b662763b1d011658bcb7c20219 Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Wed, 19 Feb 2025 16:52:07 -0800 Subject: [PATCH 01/13] List of issues to fix --- cppcheck-fix | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 cppcheck-fix diff --git a/cppcheck-fix b/cppcheck-fix new file mode 100644 index 0000000..7c9fdaf --- /dev/null +++ b/cppcheck-fix @@ -0,0 +1,33 @@ +include/internal/TestCPPAssertions.h:78:24: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] + string failureMessage = "Arguments are not equivalent!" + ^ +include/internal/TestCPPAssertions.h:109:24: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] + string failureMessage = "Arguments are equivalent!" + ^ +include/internal/TestCPPAssertions.h:136:24: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] + string failureMessage = "Object is not null!" + ^ +include/internal/TestCPPAssertions.h:163:24: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] + string failureMessage = "Object is null!" + ^ +src/TestCPPAssertions.cpp:92:20: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] + string failureMessage + ^ +src/TestCPPAssertions.cpp:107:20: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] + string failureMessage + +src/TestCPPTestCase.cpp:479:40: performance: Function parameter 'against' should be passed by const reference. [passedByValue] + bool TestCase::checkStdout (string against) { + ^ +src/TestCPPTestCase.cpp:484:37: performance: Function parameter 'against' should be passed by const reference. [passedByValue] + bool TestCase::checkLog (string against) { + ^ +src/TestCPPTestCase.cpp:489:40: performance: Function parameter 'against' should be passed by const reference. [passedByValue] + bool TestCase::checkStderr (string against) { + ^ +src/TestCPPTestCase.cpp:494:40: performance: Function parameter 'source' should be passed by const reference. [passedByValue] + bool TestCase::checkOutput (string source, string against) + ^ +src/TestCPPTestCase.cpp:494:55: performance: Function parameter 'against' should be passed by const reference. [passedByValue] + bool TestCase::checkOutput (string source, string against) + ^ From 2fb8196b353136aeaed02cfc4e14543727f5e4c9 Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Mon, 24 Feb 2025 18:42:45 -0800 Subject: [PATCH 02/13] Fix CPPCheck performance::passedByValue issues, fix using std::clog There were a number of areas affected by the performance::passedByValue issue, these also show up repeatedly in clang-tidy, so this should resolve some of those issues as well. Closes #8. All the tests pass. There was an instance of a using statement that should have been wrapped in the adjacent conditional preprocessor directive, this has been corrected. This should resolve at least one instance of the clang-tidy warning misc-unused-using-decls as reported in #45. --- include/internal/TestCPPAssertions.h | 16 ++++++++-------- include/internal/TestCPPExceptions.h | 4 ++-- include/internal/TestCPPTestCase.h | 8 ++++---- src/TestCPPAssertions.cpp | 8 ++++---- src/TestCPPExceptions.cpp | 8 ++++---- src/TestCPPTestCase.cpp | 8 ++++---- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/include/internal/TestCPPAssertions.h b/include/internal/TestCPPAssertions.h index 83ff2e9..1d86cf0 100644 --- a/include/internal/TestCPPAssertions.h +++ b/include/internal/TestCPPAssertions.h @@ -75,7 +75,7 @@ namespace TestCPP { template static void assertEquals ( T1 expected, T2 actual, - string failureMessage = "Arguments are not equivalent!" + const string& failureMessage = "Arguments are not equivalent!" ) { if (expected != actual) { @@ -106,7 +106,7 @@ namespace TestCPP { template static void assertNotEquals ( T1 expected, T2 actual, - string failureMessage = "Arguments are equivalent!" + const string& failureMessage = "Arguments are equivalent!" ) { if (expected == actual) { @@ -133,7 +133,7 @@ namespace TestCPP { template static void assertNull ( T ptr, - string failureMessage = "Object is not null!" + const string& failureMessage = "Object is not null!" ) { bool null = ptr == nullptr; @@ -160,7 +160,7 @@ namespace TestCPP { template static void assertNotNull ( T ptr, - string failureMessage = "Object is null!" + const string& failureMessage = "Object is null!" ) { bool notNull = ptr != nullptr; @@ -187,7 +187,7 @@ namespace TestCPP { */ static void assertThrows ( function shouldThrow, - string failureMessage = + const string& failureMessage = "Should have thrown something!" ); @@ -203,7 +203,7 @@ namespace TestCPP { */ static void assertNoThrows ( function shouldNotThrow, - string failureMessage = + const string& failureMessage = "Should not have thrown anything!" ); @@ -219,7 +219,7 @@ namespace TestCPP { */ static void assertTrue ( bool condition, - string failureMessage = "Condition is false!" + const string& failureMessage = "Condition is false!" ); /** @@ -234,7 +234,7 @@ namespace TestCPP { */ static void assertFalse ( bool condition, - string failureMessage = "Condition is true!" + const string& failureMessage = "Condition is true!" ); /** diff --git a/include/internal/TestCPPExceptions.h b/include/internal/TestCPPExceptions.h index 4337f25..e31b6db 100644 --- a/include/internal/TestCPPExceptions.h +++ b/include/internal/TestCPPExceptions.h @@ -66,7 +66,7 @@ namespace TestCPP { * Construct an exception of this type with a string object for * its failure message. */ - explicit TestCPPException (string&& msg); + explicit TestCPPException (const string&& msg); }; /** @@ -95,7 +95,7 @@ namespace TestCPP { * Construct an exception of this type with a string literal for * its failure message. */ - explicit TestFailedException (string&& msg); + explicit TestFailedException (const string&& msg); }; } diff --git a/include/internal/TestCPPTestCase.h b/include/internal/TestCPPTestCase.h index dc2e5f7..f092f33 100644 --- a/include/internal/TestCPPTestCase.h +++ b/include/internal/TestCPPTestCase.h @@ -221,7 +221,7 @@ namespace TestCPP { * @return True if the argument results in a successful check * using the configured comparison mode. */ - bool checkStdout (string against); + bool checkStdout (const string& against); /** * @brief Check the argument against what is captured from @@ -230,7 +230,7 @@ namespace TestCPP { * @return True if the argument results in a successful check * using the configured comparison mode. */ - bool checkLog (string against); + bool checkLog (const string& against); /** * @brief Check the argument against what is captured from @@ -240,7 +240,7 @@ namespace TestCPP { * using the configured comparison mode, false * otherwise. */ - bool checkStderr (string against); + bool checkStderr (const string& against); /** * @brief Run the test case. @@ -312,7 +312,7 @@ namespace TestCPP { * using the configured comparison mode, false * otherwise. */ - bool checkOutput (string source, string against); + bool checkOutput (const string& source, const string& against); static atomic_int stdoutCaptureCasesConstructed; static atomic_int logCaptureCasesConstructed; diff --git a/src/TestCPPAssertions.cpp b/src/TestCPPAssertions.cpp index 6680cc2..5f875ab 100644 --- a/src/TestCPPAssertions.cpp +++ b/src/TestCPPAssertions.cpp @@ -41,7 +41,7 @@ namespace TestCPP { void Assertions::assertThrows ( function shouldThrow, - string failureMessage + const string& failureMessage ) { try { @@ -76,7 +76,7 @@ namespace TestCPP { void Assertions::assertNoThrows ( function shouldNotThrow, - string failureMessage + const string& failureMessage ) { try { @@ -89,7 +89,7 @@ namespace TestCPP { void Assertions::assertTrue ( bool condition, - string failureMessage + const string& failureMessage ) { if (!condition) { @@ -104,7 +104,7 @@ namespace TestCPP { void Assertions::assertFalse ( bool condition, - string failureMessage + const string& failureMessage ) { if (condition) { diff --git a/src/TestCPPExceptions.cpp b/src/TestCPPExceptions.cpp index dc939c6..2040bef 100644 --- a/src/TestCPPExceptions.cpp +++ b/src/TestCPPExceptions.cpp @@ -31,9 +31,9 @@ For more information, please refer to #ifdef TESTCPP_STACKTRACE_ENABLED #include -#endif using std::clog; +#endif using std::string; using std::runtime_error; @@ -46,8 +46,8 @@ namespace TestCPP { clog << boost::stacktrace::stacktrace(); #endif } - TestCPPException::TestCPPException (string&& msg) : - runtime_error(std::move(msg)) + TestCPPException::TestCPPException (const string&& msg) : + runtime_error(msg) { #ifdef TESTCPP_STACKTRACE_ENABLED clog << boost::stacktrace::stacktrace(); @@ -62,7 +62,7 @@ namespace TestCPP { #endif } - TestFailedException::TestFailedException (string&& msg) : + TestFailedException::TestFailedException (const string&& msg) : TestCPPException(std::move(msg)) { #ifdef TESTCPP_STACKTRACE_ENABLED diff --git a/src/TestCPPTestCase.cpp b/src/TestCPPTestCase.cpp index 1c7dc6c..c4c3d43 100644 --- a/src/TestCPPTestCase.cpp +++ b/src/TestCPPTestCase.cpp @@ -476,22 +476,22 @@ namespace TestCPP { } } - bool TestCase::checkStdout (string against) { + bool TestCase::checkStdout (const string& against) { return checkOutput(TestCase::stdoutBuffer.get()->str(), against); } - bool TestCase::checkLog (string against) { + bool TestCase::checkLog (const string& against) { return checkOutput(TestCase::clogBuffer.get()->str(), against); } - bool TestCase::checkStderr (string against) { + bool TestCase::checkStderr (const string& against) { return checkOutput(TestCase::stderrBuffer.get()->str(), against); } - bool TestCase::checkOutput (string source, string against) + bool TestCase::checkOutput (const string& source, const string& against) { switch (this->option) { case EXACT: From be4ecf4f78402813fe2c444398097cf7d119e7f7 Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Mon, 24 Feb 2025 21:19:08 -0800 Subject: [PATCH 03/13] Add tests for verifying captured output stream functionality, formatting Added tests for the following functions: * checkStdout * checkStderr This is to increase patch coverage for #27. Formatted some lines. --- test/include/TestCase/TestCaseSuite.h | 24 ++++++++++++-- test/include/TestCase/TestCaseTests.h | 2 ++ test/src/TestCase/TestCaseTests.cpp | 46 +++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/test/include/TestCase/TestCaseSuite.h b/test/include/TestCase/TestCaseSuite.h index 68b7bc2..18b1e5a 100644 --- a/test/include/TestCase/TestCaseSuite.h +++ b/test/include/TestCase/TestCaseSuite.h @@ -19,21 +19,39 @@ namespace TestCPP { ), make_tuple( "Case runner Test - string thrown", - function(TestCaseTests::TestTestCaseGoThrowStr) + function( + TestCaseTests::TestTestCaseGoThrowStr + ) ), make_tuple( "Case runner Test - char thrown", - function(TestCaseTests::TestTestCaseGoThrowChr) + function( + TestCaseTests::TestTestCaseGoThrowChr + ) ), make_tuple( "Case runner Test - test catchall", - function(TestCaseTests::TestTestCaseGoThrowInt) + function( + TestCaseTests::TestTestCaseGoThrowInt + ) ), make_tuple( "Case setNotifyPassed Test", function( TestCaseTests::TestTestCaseSetNotifyPassed ) + ), + make_tuple( + "Case checkStdout Test", + function( + TestCaseTests::TestTestCaseCheckStdout + ) + ), + make_tuple( + "Case checkStderr Test", + function( + TestCaseTests::TestTestCaseCheckStderr + ) ) ); } diff --git a/test/include/TestCase/TestCaseTests.h b/test/include/TestCase/TestCaseTests.h index 90b526c..35ca62a 100644 --- a/test/include/TestCase/TestCaseTests.h +++ b/test/include/TestCase/TestCaseTests.h @@ -10,6 +10,8 @@ namespace TestCPP { void TestTestCaseGoThrowChr (); void TestTestCaseGoThrowInt (); void TestTestCaseSetNotifyPassed (); + void TestTestCaseCheckStdout (); + void TestTestCaseCheckStderr (); } } } diff --git a/test/src/TestCase/TestCaseTests.cpp b/test/src/TestCase/TestCaseTests.cpp index 8fef9ec..e6fe31d 100644 --- a/test/src/TestCase/TestCaseTests.cpp +++ b/test/src/TestCase/TestCaseTests.cpp @@ -3,6 +3,10 @@ using TestCPP::Util::debugLog; +using std::cerr; +using std::cout; +using std::endl; + using TCPPStr = TestCPP::TestCPPCommon::Strings; namespace TestCPP { @@ -176,6 +180,48 @@ namespace TestCPP { "TestSetNotifyPassed checkLog() 6" ); } + + void TestTestCaseCheckStdout() { + auto test = unique_ptr(new TestCase( + "TestCaseCheckStdout case Test", + function([]() { + cout << "Test output to stdout!" << endl; + }), + false, true, false, false, + TestCase::TestCaseOutCompareOptions::EXACT + )); + + Assertions::assertTrue( + test->go(), + "TestCheckStdout go() 1" + ); + + Assertions::assertTrue( + test->checkStdout("Test output to stdout!\n"), + "TestCheckStdout checkStdout() 1" + ); + } + + void TestTestCaseCheckStderr() { + auto test = unique_ptr(new TestCase( + "TestCaseCheckStderr case Test", + function([]() { + cerr << "Test output to stderr!" << endl; + }), + false, false, false, true, + TestCase::TestCaseOutCompareOptions::EXACT + )); + + Assertions::assertTrue( + test->go(), + "TestCheckStderr go() 1" + ); + + Assertions::assertTrue( + test->checkStderr("Test output to stderr!\n"), + "TestCheckStderr checkStderr() 1" + ); + } } } } From 6492242726526871c63b44817a0d975654beba6c Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Tue, 25 Feb 2025 18:00:46 -0800 Subject: [PATCH 04/13] Ignore infer output when running code analysis engine. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 048d48f..105789b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ CMakeUserPresets.json /.vs out/ **/cppcheck-checkers.report +/infer-out From 50bd0f17a6730ee5a86dd8c208416a25100aee78 Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Tue, 25 Feb 2025 18:02:02 -0800 Subject: [PATCH 05/13] Correct the SLOC number --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 01969c8..00921f9 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ The library is most useful for educational projects or small For testing more complex projects I would recommend using [GoogleTest](https://github.com/google/googletest). -The code is ~2k lines. +The code is ~1.2k lines. The Release builds are optimized for speed over size, so the build could probably be tweaked to get a smaller binary if desired. From c9e3afb8a0a40059d29abb5f02e435b7f5bc185b Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Tue, 25 Feb 2025 18:55:51 -0800 Subject: [PATCH 06/13] Added information to README about static analysis and planned features Fixed the order of GH Actions workflows. Added flawfinder and infer to the list of static analysis tools. Added that debug and release are also taken into consideration for presets. Updated the vcpkg and conan sections to more acurately reflect status. Split the Features section into Current and Planned. Added a long list of new assertions I plan on adding to the library. --- README.md | 116 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 00921f9..32f0264 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,13 @@ The Release builds are optimized for speed over size, so the # Features +See the various Milestones in GitHub to get a feel for where the + project is headed and what features are planned for the future. + +Here are the lists of current and planned features. + +## Current Features + Features of the test framework are very minimal and include: - Test case definition - Test suite definition @@ -49,6 +56,72 @@ Features of the test framework are very minimal and include: or failing in certain cases in a managed way that reduces boilerplate. +## Planned Features + +There is no plan for advanced features like mocking or death tests. +The goal is to keep the library simple and easy to use, and to delegate + more complex testing to more advanced libraries like GoogleTest, and + more advanced features like mocking/faking to external libraries; + maybe this will change in the future, since this is a project of + exploration with no real constraints other than to maintain + simplicity (complex things can be simple). + +The following features are currently planned: + - Test result output to files or stdout/stderr in a variety of formats + - JUnit XML + - xUnit XML + - CRTF JSON + - TAP (Become a TAP Producer) + - Maven Surefire XML + - Additional assertions, mostly convenient extensions of the current + assertions + - Numerical Analysis Assertions + - assertLessThan + - assertGreaterThan + - assertLessThanOrEqual + - assertGreaterThanOrEqual + - assertIsEven + - assertIsOdd + - assertIsPrime + - assertIsNotPrime + - assertIsComposite + - assertIsNotComposite + - assertIsPerfect + - assertIsNotPerfect + - assertIsPowerOf + - assertIsNotPowerOf + - assertIsDivisorOf + - assertIsNotDivisorOf + - assertIsMultipleOf + - assertIsNotMultipleOf + - assertIsFactorOf + - assertIsNotFactorOf + - assertIsDivisibleBy + - assertIsNotDivisibleBy + - Range Assertions - Dates, Times, Durations, Numbers, strings, + custom-defined ranges of varying types + - assertWithinRange + - assertNotWithinRange + - Container/string Assertions + - assertEmpty + - assertNotEmpty + - assertContains + - assertNotContains + - assertStartsWith + - assertEndsWith + - assertSizeIs + - String-only Assertions + - assertMatches + - assertNotMatches + - Miscellaneous Assertions + - assertIsOneOf + - assertIsNotOneOf + - Will apply lexicographically or numerically depending on the + type of the arguments, with parameters to control what "close" + means + - assertIsCloseTo + - assertIsNotCloseTo + # Getting Started ## Acquiring the Library @@ -74,28 +147,26 @@ Then add it to your test executable target through ### vcpkg -*In process, not working yet* +*Will be available for 1.5 release* -As of 0.1.0-beta.1, you might soon be able to also include it - in your `vcpkg` project by running the following in the root of - your project (pending vcpkg PR approval that I have in right - now https://github.com/microsoft/vcpkg/pull/37471): +You be able to include TestCPP in your `vcpkg` project by running the + following in the root of your project (pending vcpkg PR approval that + I have in right now https://github.com/microsoft/vcpkg/pull/37471): ``` - vcpkg add port testcpp + vcpkg add port eljonny-testcpp ``` ### Conan -*In process, not working yet* +*Will be available for 2.0 release* -As of 0.1.1-beta.2, you might soon be able to also include it - in your `conan` project (pending approval from the Conan - community). +You will be able to include it in your `conan` project (pending + approval from the Conan community). First add it as a dependency to your project in conanfile.txt: ``` [requires] ... -testcpp/0.1.1-beta.2 +testcpp/2.0 ``` Then installing TestCPP into your project by running the @@ -224,7 +295,7 @@ There are a number of CMake Presets defined in CMakePresets.json that align with different build configurations and analysis profiles, including all build feature variations (with/without the Demo project, with/without the tests, and subsequently with/without stacktrace - support via Boost.StackTrace). + support via Boost.StackTrace, and finally Debug and Release). To get started, open the root project folder in Visual Studio 2022 and select the desired CMake Preset from the Build Configurations dropdown @@ -403,9 +474,11 @@ Both Release and Debug configurations support building with stack trace # Static Analysis of TestCPP -You can run cppcheck and clang-tidy on the generated +You can run cppcheck, infer, and clang-tidy on the generated compile_commands.json. +Another tool that is helpful to run is flawfinder. + For clang-tidy, you can also use the CMake flag to have CMake run clang-tidy during the build. @@ -452,6 +525,19 @@ My suggested options for cppcheck are: I would recommend against using the -j parameter with cppcheck because it disables certain checks that are used in the project. +For infer, you can run the following command after configuring the + build: +``` +infer run --compilation-database path/to/compile_commands.json +``` + +For flawfinder, you can run the following command to analyze src and + then include and generate HTML reports about the results in the: +``` +flawfinder --minlevel=0 --html --columns src > out/report/flawfinder/src-flaws.html +flawfinder --minlevel=0 --html --columns include > out/report/flawfinder/i-flaws.html +``` + # Testing and Code Coverage The library is tested using itself. @@ -582,8 +668,8 @@ The workflows are as follows: - Builds and tests the library on Linux with stack traces enabled and generates code coverage reports that are then pushed to CodeCov for helpful visualizations and reporting. -- codeql.yml - - Runs the CodeQL static analysis tool on the library code. - cmake-static-analysis.yml - Runs clang-tidy and cppcheck on the library code using JacobDomagala/StaticAnalysis@master +- codeql.yml + - Runs the CodeQL static analysis tool on the library code. From ea80e259b128393b0ff1d47fe81cecf5a19c34fb Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Tue, 25 Feb 2025 20:42:51 -0800 Subject: [PATCH 07/13] Added more information on running flawfinder --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 32f0264..e041ae1 100644 --- a/README.md +++ b/README.md @@ -534,10 +534,22 @@ infer run --compilation-database path/to/compile_commands.json For flawfinder, you can run the following command to analyze src and then include and generate HTML reports about the results in the: ``` -flawfinder --minlevel=0 --html --columns src > out/report/flawfinder/src-flaws.html -flawfinder --minlevel=0 --html --columns include > out/report/flawfinder/i-flaws.html +flawfinder --minlevel=0 --html --context --columns src > out/report/flawfinder/src-flaws.html +flawfinder --minlevel=0 --html --context --columns include > out/report/flawfinder/i-flaws.html ``` +For a concise report on the command line, you can run the following + commands: +``` +flawfinder --minlevel=0 --dataonly --quiet --columns src +flawfinder --minlevel=0 --dataonly --quiet --columns include +``` + +I would also recommend using the following flawfinder arguments: +- --error-level=0 + - Sets the error level to 0, which is the lowest level of error + reporting; this is essentially all-warnings-as-errors. + # Testing and Code Coverage The library is tested using itself. From 9f447a9572d645053cf99af98e2620388b1712fa Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Tue, 25 Feb 2025 22:27:10 -0800 Subject: [PATCH 08/13] Update CMake with new test suite, fix assertEquals bug, add test suite The CMake build now includes all required sections for TestCPP_Exceptions_test, which is the addition of the Exceptions test suite to the build. Now a TestCPP_Exceptions_test executable is created and linked in. Added a test suite for TestCPPExceptions. This included adding the following files: - test/include/Exceptions/ExceptionsTests.h - Test declarations - test/include/Exceptions/ExceptionsSuite.h - Creation of test suite - test/src/Exceptions/ExceptionsTests.cpp - Implementation of tests - test/src/TestCPPExceptionsMain.cpp - Implementation of suite runner The only things that really needed to happen here were: - Test constructor variants - Make sure the constructors don't throw when given sane output Additional behavior to check: - What does it do with negative testing? If everything is good with CI after I push this I'll add some negative testing. In Assertions, assertEquals did not work correctly with C Strings. I added a template specialization that fixes this... I have a feeling this is going to need to happen in other cases as well, though I don't yet know what. --- cmake/Includes.cmake | 6 ++++ cmake/Targets.cmake | 6 ++++ cmake/Testing.cmake | 5 +++ cmake/build/DebugCompileDefs.cmake | 5 +++ cmake/build/GCCClangDebug.cmake | 6 ++++ cmake/build/GCCClangRelease.cmake | 6 ++++ cmake/build/GCCCoverage.cmake | 6 ++++ cmake/build/MSVCDebug.cmake | 6 ++++ cmake/build/MSVCRelease.cmake | 6 ++++ cmake/link/Tests.cmake | 15 +++++++++ cmake/link/TestsWithCoverage.cmake | 18 +++++++++++ include/internal/TestCPPAssertions.h | 31 ++++++++++++++++++ test/include/Exceptions/ExceptionsSuite.h | 29 +++++++++++++++++ test/include/Exceptions/ExceptionsTests.h | 13 ++++++++ test/src/Exceptions/ExceptionsTests.cpp | 38 +++++++++++++++++++++++ test/src/TestCPPExceptionsMain.cpp | 25 +++++++++++++++ 16 files changed, 221 insertions(+) create mode 100644 test/include/Exceptions/ExceptionsSuite.h create mode 100644 test/include/Exceptions/ExceptionsTests.h create mode 100644 test/src/Exceptions/ExceptionsTests.cpp create mode 100644 test/src/TestCPPExceptionsMain.cpp diff --git a/cmake/Includes.cmake b/cmake/Includes.cmake index a34ba82..90f2587 100644 --- a/cmake/Includes.cmake +++ b/cmake/Includes.cmake @@ -38,4 +38,10 @@ if (BUILD_TESTING) test/include include ) + + target_include_directories ( + ${PROJECT_NAME}_Exceptions_test PRIVATE + test/include + include + ) endif () diff --git a/cmake/Targets.cmake b/cmake/Targets.cmake index cba9f4d..89127c9 100644 --- a/cmake/Targets.cmake +++ b/cmake/Targets.cmake @@ -40,4 +40,10 @@ if (BUILD_TESTING) test/src/Assertions/AssertionsTests.cpp test/src/TestCPPAssertionsMain.cpp ) + + add_executable ( + ${PROJECT_NAME}_Exceptions_test + test/src/Exceptions/ExceptionsTests.cpp + test/src/TestCPPExceptionsMain.cpp + ) endif () diff --git a/cmake/Testing.cmake b/cmake/Testing.cmake index b7c4c1b..146527f 100644 --- a/cmake/Testing.cmake +++ b/cmake/Testing.cmake @@ -13,4 +13,9 @@ if (BUILD_TESTING) NAME ${PROJECT_NAME}AssertionsTests COMMAND ${PROJECT_NAME}_Assertions_test ) + + add_test ( + NAME ${PROJECT_NAME}ExceptionsTests + COMMAND ${PROJECT_NAME}_Exceptions_test + ) endif () diff --git a/cmake/build/DebugCompileDefs.cmake b/cmake/build/DebugCompileDefs.cmake index 024799d..8f424d3 100644 --- a/cmake/build/DebugCompileDefs.cmake +++ b/cmake/build/DebugCompileDefs.cmake @@ -28,4 +28,9 @@ if (BUILD_TESTING) PUBLIC DEBUG_LOG ) + target_compile_definitions ( + ${PROJECT_NAME}_Exceptions_test + PUBLIC + DEBUG_LOG + ) endif () diff --git a/cmake/build/GCCClangDebug.cmake b/cmake/build/GCCClangDebug.cmake index 27ce4c3..7ae11bd 100644 --- a/cmake/build/GCCClangDebug.cmake +++ b/cmake/build/GCCClangDebug.cmake @@ -103,5 +103,11 @@ else () PUBLIC ${GCC_CLANG_DEBUG_BUILD_OPTS} ) + + target_compile_options ( + ${PROJECT_NAME}_Exceptions_test + PUBLIC + ${GCC_CLANG_DEBUG_BUILD_OPTS} + ) endif () endif () diff --git a/cmake/build/GCCClangRelease.cmake b/cmake/build/GCCClangRelease.cmake index 476fce0..723a235 100644 --- a/cmake/build/GCCClangRelease.cmake +++ b/cmake/build/GCCClangRelease.cmake @@ -96,4 +96,10 @@ if (BUILD_TESTING) PUBLIC ${GCC_CLANG_RELEASE_BUILD_OPTS} ) + + target_compile_options ( + ${PROJECT_NAME}_Exceptions_test + PUBLIC + ${GCC_CLANG_RELEASE_BUILD_OPTS} + ) endif () diff --git a/cmake/build/GCCCoverage.cmake b/cmake/build/GCCCoverage.cmake index 6131b5e..d6ef9ee 100644 --- a/cmake/build/GCCCoverage.cmake +++ b/cmake/build/GCCCoverage.cmake @@ -49,3 +49,9 @@ target_compile_options ( PUBLIC ${COVERAGE_BUILD_OPTS} ) + +target_compile_options ( + ${PROJECT_NAME}_Exceptions_test + PUBLIC + ${COVERAGE_BUILD_OPTS} +) diff --git a/cmake/build/MSVCDebug.cmake b/cmake/build/MSVCDebug.cmake index be646db..136bf13 100644 --- a/cmake/build/MSVCDebug.cmake +++ b/cmake/build/MSVCDebug.cmake @@ -92,4 +92,10 @@ if (BUILD_TESTING) PUBLIC ${MSVC_DEBUG_BUILD_OPTS} ) + + target_compile_options ( + ${PROJECT_NAME}_Exceptions_test + PUBLIC + ${MSVC_DEBUG_BUILD_OPTS} + ) endif () diff --git a/cmake/build/MSVCRelease.cmake b/cmake/build/MSVCRelease.cmake index 6dc1772..c1222fe 100644 --- a/cmake/build/MSVCRelease.cmake +++ b/cmake/build/MSVCRelease.cmake @@ -82,6 +82,12 @@ if (BUILD_TESTING) PUBLIC ${MSVC_RELEASE_BUILD_OPTS} ) + + target_compile_options ( + ${PROJECT_NAME}_Exceptions_test + PUBLIC + ${MSVC_RELEASE_BUILD_OPTS} + ) endif () # This section removes the /RTC flags from the CMAKE_CXX_FLAGS_* diff --git a/cmake/link/Tests.cmake b/cmake/link/Tests.cmake index f823620..ada2836 100644 --- a/cmake/link/Tests.cmake +++ b/cmake/link/Tests.cmake @@ -17,6 +17,12 @@ if (${TESTCPP_STACKTRACE_ENABLED} AND MSVC) ole32 dbgeng ) + target_link_libraries ( + ${PROJECT_NAME}_Exceptions_test + ${PROJECT_NAME} + ole32 + dbgeng + ) elseif (${TESTCPP_STACKTRACE_ENABLED}) target_link_libraries ( @@ -34,6 +40,11 @@ elseif (${TESTCPP_STACKTRACE_ENABLED}) ${PROJECT_NAME} dl ) + target_link_libraries ( + ${PROJECT_NAME}_Exceptions_test + ${PROJECT_NAME} + dl + ) else () target_link_libraries ( @@ -48,4 +59,8 @@ else () ${PROJECT_NAME}_Assertions_test ${PROJECT_NAME} ) + target_link_libraries ( + ${PROJECT_NAME}_Exceptions_test + ${PROJECT_NAME} + ) endif () diff --git a/cmake/link/TestsWithCoverage.cmake b/cmake/link/TestsWithCoverage.cmake index ae6e6d1..244e366 100644 --- a/cmake/link/TestsWithCoverage.cmake +++ b/cmake/link/TestsWithCoverage.cmake @@ -20,6 +20,13 @@ if (${TESTCPP_STACKTRACE_ENABLED} AND MSVC) ole32 dbgeng ) + target_link_libraries ( + ${PROJECT_NAME}_Exceptions_test + ${PROJECT_NAME} + gcov + ole32 + dbgeng + ) elseif (${TESTCPP_STACKTRACE_ENABLED}) target_link_libraries ( @@ -40,6 +47,12 @@ elseif (${TESTCPP_STACKTRACE_ENABLED}) gcov dl ) + target_link_libraries ( + ${PROJECT_NAME}_Exceptions_test + ${PROJECT_NAME} + gcov + dl + ) else () target_link_libraries ( @@ -57,4 +70,9 @@ else () ${PROJECT_NAME} gcov ) + target_link_libraries ( + ${PROJECT_NAME}_Exceptions_test + ${PROJECT_NAME} + gcov + ) endif () diff --git a/include/internal/TestCPPAssertions.h b/include/internal/TestCPPAssertions.h index 1d86cf0..d65e034 100644 --- a/include/internal/TestCPPAssertions.h +++ b/include/internal/TestCPPAssertions.h @@ -28,6 +28,7 @@ For more information, please refer to #ifndef TESTCPP_ASSERTIONS_ #define TESTCPP_ASSERTIONS_ +#include #include #include #include @@ -37,6 +38,7 @@ For more information, please refer to using std::endl; using std::function; +using std::strcmp; using std::string; using std::stringstream; @@ -90,6 +92,35 @@ namespace TestCPP { } } + /** + * @brief Check that char*'s are equal using strcmp. + * @param expected The value that the actual value should be + * equivalent to. + * @param actual The actual value that will be checked against + * the expected value. + * @param failureMessage Failure message that should be logged + * if the assertion fails. This + * defaults to a generic failure + * message related to the assertion + * type. + */ + static void assertEquals( + const char* expected, const char* actual, + const string& failureMessage = "Arguments are not equivalent!" + ) + { + if (strcmp(expected, actual)) { + stringstream err; + + err << "Equivalence assertion failed!" << endl; + err << failureMessage << endl; + err << "Expected: <" << expected << ">" << endl; + err << "Actual: <" << actual << ">" << endl; + + throw TestFailedException(err.str()); + } + } + /** * @brief Check that something is not equivalent to something * else using the built-in operator== for each type. diff --git a/test/include/Exceptions/ExceptionsSuite.h b/test/include/Exceptions/ExceptionsSuite.h new file mode 100644 index 0000000..2976ee9 --- /dev/null +++ b/test/include/Exceptions/ExceptionsSuite.h @@ -0,0 +1,29 @@ +#ifndef TESTCPP_EXCEPTIONS_SUITE_ +#define TESTCPP_EXCEPTIONS_SUITE_ + +#include "ExceptionsTests.h" + +namespace TestCPP { + namespace Testing { + namespace ExceptionsSuite { + TestSuite suite( + "TestCPP Exceptions Tests", + + make_tuple( + "TestFailedException Construction Test", + function( + ExceptionsTests::TestTestFailedExceptionCtor + ) + ), + make_tuple( + "TestCPPException Construction Test", + function( + ExceptionsTests::TestTestCPPExceptionCtor + ) + ) + ); + } + } +} + +#endif diff --git a/test/include/Exceptions/ExceptionsTests.h b/test/include/Exceptions/ExceptionsTests.h new file mode 100644 index 0000000..fb2c5f5 --- /dev/null +++ b/test/include/Exceptions/ExceptionsTests.h @@ -0,0 +1,13 @@ +#ifndef TESTCPP_EXCEPTIONS_TESTS_ +#define TESTCPP_EXCEPTIONS_TESTS_ + +namespace TestCPP { + namespace Testing { + namespace ExceptionsTests { + void TestTestFailedExceptionCtor (); + void TestTestCPPExceptionCtor (); + } + } +} + +#endif diff --git a/test/src/Exceptions/ExceptionsTests.cpp b/test/src/Exceptions/ExceptionsTests.cpp new file mode 100644 index 0000000..91e4eb8 --- /dev/null +++ b/test/src/Exceptions/ExceptionsTests.cpp @@ -0,0 +1,38 @@ +#include "TestCPP.h" +#include "Exceptions/ExceptionsTests.h" + +using TestCPP::Assertions; +using TestCPP::TestCPPException; +using TestCPP::TestFailedException; + +namespace TestCPP { + namespace Testing { + namespace ExceptionsTests { + constexpr const char* msg = "Test message"; + + void TestTestCPPExceptionCtor() { + Assertions::assertNoThrows([]() { + TestCPPException e(msg); + }); + + TestCPPException e(msg); + Assertions::assertEquals(msg, e.what()); + + e = TestCPPException(string(msg)); + Assertions::assertEquals(msg, e.what()); + } + + void TestTestFailedExceptionCtor() { + Assertions::assertNoThrows([]() { + TestFailedException e(msg); + }); + + TestFailedException e(msg); + Assertions::assertEquals(msg, e.what()); + + e = TestFailedException(string(msg)); + Assertions::assertEquals(msg, e.what()); + } + } + } +} \ No newline at end of file diff --git a/test/src/TestCPPExceptionsMain.cpp b/test/src/TestCPPExceptionsMain.cpp new file mode 100644 index 0000000..7cb3822 --- /dev/null +++ b/test/src/TestCPPExceptionsMain.cpp @@ -0,0 +1,25 @@ +#include "TestCPP.h" + +using TestCPP::TestCase; +using TestCPP::TestSuite; +using std::string; +using std::make_tuple; +using std::function; + +#include "Exceptions/ExceptionsSuite.h" + +int main(void) +{ + try { + TestCPP::Testing::ExceptionsSuite::suite.run(); + return TestCPP::Util::unsignedToSigned( + TestCPP::Testing::ExceptionsSuite::suite. + getLastRunFailCount() + ); + } + catch (std::exception& e) { + std::cerr << "Test suite run failed with an exception: " + << e.what() << std::endl; + return -1; + } +} From ffffd96620ad23d77145fc997f3620bcfd63d442 Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Wed, 26 Feb 2025 00:06:58 -0800 Subject: [PATCH 09/13] Finish fixing #94, address issues with too much repeated code Most of the assertions have a common failure logging pattern, which should be consolidated into a common function call path. Devise a return value system that will work for all test failures that log details of the test failure, where they share a common output format. This is all of them except fail, assertThrows, and assertNoThrows. Basically if there is content in the error string, it will throw the failure exception causing the test to fail. Finish fixing #94 by implementing the template specialization for const char* for assertNotEquals. --- include/internal/TestCPPAssertions.h | 222 +++++++++++++++++++++------ src/TestCPPAssertions.cpp | 28 +++- 2 files changed, 194 insertions(+), 56 deletions(-) diff --git a/include/internal/TestCPPAssertions.h b/include/internal/TestCPPAssertions.h index d65e034..aa5368c 100644 --- a/include/internal/TestCPPAssertions.h +++ b/include/internal/TestCPPAssertions.h @@ -80,15 +80,9 @@ namespace TestCPP { const string& failureMessage = "Arguments are not equivalent!" ) { - if (expected != actual) { - stringstream err; - - err << "Equivalence assertion failed!" << endl; - err << failureMessage << endl; - err << "Expected: <" << expected << ">" << endl; - err << "Actual: <" << actual << ">" << endl; - - throw TestFailedException(err.str()); + const string& err = checkEquals(expected, actual, failureMessage); + if (err.size()) { + throw TestFailedException(std::move(err)); } } @@ -109,25 +103,19 @@ namespace TestCPP { const string& failureMessage = "Arguments are not equivalent!" ) { - if (strcmp(expected, actual)) { - stringstream err; - - err << "Equivalence assertion failed!" << endl; - err << failureMessage << endl; - err << "Expected: <" << expected << ">" << endl; - err << "Actual: <" << actual << ">" << endl; - - throw TestFailedException(err.str()); + const string& err = checkEquals(expected, actual, failureMessage); + if (err.size()) { + throw TestFailedException(std::move(err)); } } /** * @brief Check that something is not equivalent to something * else using the built-in operator== for each type. - * @param expected The value that the actual value should not be - * equivalent to. + * @param shouldNotBe The value that the actual value should + * not be equivalent to. * @param actual The actual value that will be checked against - * the expected value. + * the expectation value. * @param failureMessage Failure message that should be logged * if the assertion fails. This * defaults to a generic failure @@ -136,19 +124,36 @@ namespace TestCPP { */ template static void assertNotEquals ( - T1 expected, T2 actual, + T1 shouldNotBe, T2 actual, const string& failureMessage = "Arguments are equivalent!" ) { - if (expected == actual) { - stringstream err; - - err << "Non-Equivalence assertion failed!" << endl; - err << failureMessage << endl; - err << "Expected: <" << expected << ">" << endl; - err << "Actual: <" << actual << ">" << endl; + const string& err = checkNotEquals(shouldNotBe, actual, failureMessage); + if (err.size()) { + throw TestFailedException(std::move(err)); + } + } - throw TestFailedException(err.str()); + /** + * @brief Check that char*'s are not equal using strcmp. + * @param expected The value that the actual value should not + * be equivalent to. + * @param actual The actual value that will be checked against + * the expected value. + * @param failureMessage Failure message that should be logged + * if the assertion fails. This + * defaults to a generic failure + * message related to the assertion + * type. + */ + static void assertNotEquals( + const char* shouldNotBe, const char* actual, + const string& failureMessage = "Arguments are equivalent!" + ) + { + const string& err = checkNotEquals(shouldNotBe, actual, failureMessage); + if (err.size()) { + throw TestFailedException(std::move(err)); } } @@ -167,15 +172,9 @@ namespace TestCPP { const string& failureMessage = "Object is not null!" ) { - bool null = ptr == nullptr; - - if (!null) { - stringstream err; - - err << "Null assertion failed!" << endl; - err << failureMessage << endl; - - throw TestFailedException(err.str()); + const string& err = checkNull(ptr, failureMessage); + if (err.size()) { + throw TestFailedException(std::move(err)); } } @@ -194,15 +193,9 @@ namespace TestCPP { const string& failureMessage = "Object is null!" ) { - bool notNull = ptr != nullptr; - - if (!notNull) { - stringstream err; - - err << "Not Null assertion failed!" << endl; - err << failureMessage << endl; - - throw TestFailedException(err.str()); + const string& err = checkNotNull(ptr, failureMessage); + if (err.size()) { + throw TestFailedException(std::move(err)); } } @@ -285,6 +278,139 @@ namespace TestCPP { static void fail [[noreturn]] ( string failureMessage = "Forced test failure!" ); + + private: + + static constexpr const char* equivalenceAssertionMessage = "Equivalence assertion failed!"; + static constexpr const char* nonequivalenceAssertionMessage = "Non-Equivalence assertion failed!"; + + template + static const string&& logTestFailure( + T1 expectationValue, T2 actual, + const string& assertionTypeMessage, + const string& failureMessage, + const bool logValues + ) + { + stringstream err; + + err << assertionTypeMessage << endl; + err << failureMessage << endl; + + if (logValues) { + err << "Expectation value: <" << expectationValue << ">" + << endl; + err << "Actual: <" << actual << ">" << endl; + } + + return std::move(err.str()); + } + + template + static const string& checkEquals( + T1 expected, T2 actual, + const string& failureMessage + ) + { + if (expected != actual) { + return logTestFailure( + expected, actual, + equivalenceAssertionMessage, + failureMessage, + true + ); + } + return ""; + } + + static const string& checkEquals( + const char* expected, const char* actual, + const string& failureMessage + ) + { + if (strcmp(expected, actual)) { + return logTestFailure( + expected, actual, + equivalenceAssertionMessage, + failureMessage, + true + ); + } + return ""; + } + + template + static const string& checkNotEquals( + T1 shouldNotBe, T2 actual, + const string& failureMessage + ) + { + if (shouldNotBe == actual) { + return logTestFailure( + shouldNotBe, actual, + nonequivalenceAssertionMessage, + failureMessage, + true + ); + } + return ""; + } + + static const string& checkNotEquals( + const char* shouldNotBe, const char* actual, + const string& failureMessage + ) + { + if (!strcmp(shouldNotBe, actual)) { + return logTestFailure( + shouldNotBe, actual, + nonequivalenceAssertionMessage, + failureMessage, + true + ); + } + return ""; + } + + template + static const string& checkNull( + T ptr, + const string& failureMessage + ) + { + static constexpr const char* nullAssertionMessage = "Null assertion failed!"; + + bool null = ptr == nullptr; + if (!null) { + return logTestFailure( + nullptr, nullptr, + nullAssertionMessage, + failureMessage, + false + ); + } + return ""; + } + + template + static const string& assertNotNull( + T ptr, + const string& failureMessage + ) + { + static constexpr const char* notNullAssertionMessage = "Not Null assertion failed!"; + + bool notNull = ptr != nullptr; + if (!notNull) { + return logTestFailure( + nullptr, nullptr, + notNullAssertionMessage, + failureMessage, + false + ); + } + return ""; + } }; } diff --git a/src/TestCPPAssertions.cpp b/src/TestCPPAssertions.cpp index 5f875ab..61e4437 100644 --- a/src/TestCPPAssertions.cpp +++ b/src/TestCPPAssertions.cpp @@ -93,12 +93,18 @@ namespace TestCPP { ) { if (!condition) { - stringstream err; + static constexpr const char* atMsg = "Boolean Truth assertion failed!"; - err << "Boolean Truth assertion failed!" << endl; - err << failureMessage << endl; + const string& err = logTestFailure( + nullptr, nullptr, + atMsg, + failureMessage, + false + ); - throw TestFailedException(err.str()); + if (err.size()) { + throw TestFailedException(std::move(err)); + } } } @@ -108,12 +114,18 @@ namespace TestCPP { ) { if (condition) { - stringstream err; + static constexpr const char* atMsg = "Boolean False assertion failed!"; - err << "Boolean False assertion failed!" << endl; - err << failureMessage << endl; + const string& err = logTestFailure( + nullptr, nullptr, + atMsg, + failureMessage, + false + ); - throw TestFailedException(err.str()); + if (err.size()) { + throw TestFailedException(std::move(err)); + } } } From c200d7fdb3730e817bbe514aa2a404d0c31ff672 Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Wed, 26 Feb 2025 17:28:40 -0800 Subject: [PATCH 10/13] Had to stop using references after the refactor, make copies instead Use C++11 way of creating literal empty strings. --- include/internal/TestCPPAssertions.h | 32 ++++++++++++++-------------- src/TestCPPAssertions.cpp | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/internal/TestCPPAssertions.h b/include/internal/TestCPPAssertions.h index aa5368c..2768e3d 100644 --- a/include/internal/TestCPPAssertions.h +++ b/include/internal/TestCPPAssertions.h @@ -285,7 +285,7 @@ namespace TestCPP { static constexpr const char* nonequivalenceAssertionMessage = "Non-Equivalence assertion failed!"; template - static const string&& logTestFailure( + static const string logTestFailure( T1 expectationValue, T2 actual, const string& assertionTypeMessage, const string& failureMessage, @@ -303,11 +303,11 @@ namespace TestCPP { err << "Actual: <" << actual << ">" << endl; } - return std::move(err.str()); + return err.str(); } template - static const string& checkEquals( + static const string checkEquals( T1 expected, T2 actual, const string& failureMessage ) @@ -320,10 +320,10 @@ namespace TestCPP { true ); } - return ""; + return {}; } - static const string& checkEquals( + static const string checkEquals( const char* expected, const char* actual, const string& failureMessage ) @@ -336,11 +336,11 @@ namespace TestCPP { true ); } - return ""; + return {}; } template - static const string& checkNotEquals( + static const string checkNotEquals( T1 shouldNotBe, T2 actual, const string& failureMessage ) @@ -353,10 +353,10 @@ namespace TestCPP { true ); } - return ""; + return {}; } - static const string& checkNotEquals( + static const string checkNotEquals( const char* shouldNotBe, const char* actual, const string& failureMessage ) @@ -369,11 +369,11 @@ namespace TestCPP { true ); } - return ""; + return {}; } template - static const string& checkNull( + static const string checkNull( T ptr, const string& failureMessage ) @@ -383,17 +383,17 @@ namespace TestCPP { bool null = ptr == nullptr; if (!null) { return logTestFailure( - nullptr, nullptr, + "", "", nullAssertionMessage, failureMessage, false ); } - return ""; + return {}; } template - static const string& assertNotNull( + static const string checkNotNull( T ptr, const string& failureMessage ) @@ -403,13 +403,13 @@ namespace TestCPP { bool notNull = ptr != nullptr; if (!notNull) { return logTestFailure( - nullptr, nullptr, + "", "", notNullAssertionMessage, failureMessage, false ); } - return ""; + return {}; } }; } diff --git a/src/TestCPPAssertions.cpp b/src/TestCPPAssertions.cpp index 61e4437..f0d2d64 100644 --- a/src/TestCPPAssertions.cpp +++ b/src/TestCPPAssertions.cpp @@ -96,7 +96,7 @@ namespace TestCPP { static constexpr const char* atMsg = "Boolean Truth assertion failed!"; const string& err = logTestFailure( - nullptr, nullptr, + "", "", atMsg, failureMessage, false @@ -117,7 +117,7 @@ namespace TestCPP { static constexpr const char* atMsg = "Boolean False assertion failed!"; const string& err = logTestFailure( - nullptr, nullptr, + "", "", atMsg, failureMessage, false From be1af596cb7105bceb88902a0e206d7c296b8e01 Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Thu, 27 Feb 2025 01:21:57 -0800 Subject: [PATCH 11/13] Finish working #27, stop suppressing MSVC warning, fix tmpls, fixes Stop suppressing MSVC warning 4514, because those functions being removed via optimization (why they are being removed by the optimizer in Debug builds, I do not know, that should not have been happening) should not be removed. For some reason it seems like the warning-disable flag for this specific warning was not being applied anyways, even though it should have been the way the CMake build was implemented; the flag is not longer in the CMake build. Those template specializations need to be there; they may not be referenced by a library function, but it's a static function that will be accessed by library consumers, it's not intended to be used by the library itself. I had to create extern instantiations to make sure the compiler kept the template specialization defined in the cpp file. With the template specialization implementations being in the header file, they were being removed by the optimizer even with optimizations disabled in the debug build, which was super weird. This appears to only be an issue with MSVC, which is also a little weird. For #27 this should address all the issues but there's more coverage that needs to be improved to make the patch coverage acceptable. Other fixes: - checkNull, checkNotNull, checkEquals, checkNotEquals, and logTestFailure now return values (copies) instead of references, and everything has been refactored to reflect this. - Moved definitions of the template specializations of assertEquals, assertNotEquals, checkEquals, and checkNotEquals to the cpp file. - Explicit template specializations that are only declarations are supposed to be in the global scope, according to research about some warnings I saw from clang, so they are moved out of the TestCPP namespace into the global scope. It appears this is the applicable section of the C++11 standard: - 14.7.3 clause 8 seems the most applicable - 14.7.3 clause 2 is referenced on the below post and seems to be a part of why this is the way it is as well: - https://forums.oracle.com/ords/apexds/post/explicit-specialization-is-not-allowed-in-the-current-scope-8848 - C++11 standard Reference: - https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf --- cmake/build/MSVCDebug.cmake | 9 -- cmake/build/MSVCRelease.cmake | 9 -- include/internal/TestCPPAssertions.h | 147 ++++++++++++--------------- src/TestCPPAssertions.cpp | 63 +++++++++++- 4 files changed, 126 insertions(+), 102 deletions(-) diff --git a/cmake/build/MSVCDebug.cmake b/cmake/build/MSVCDebug.cmake index 136bf13..b86c7ad 100644 --- a/cmake/build/MSVCDebug.cmake +++ b/cmake/build/MSVCDebug.cmake @@ -51,15 +51,6 @@ if ("${CMAKE_CXX_FLAGS}" MATCHES "/analyze:ruleset") ) endif () -if (BUILD_TESTING) - list ( - APPEND - MSVC_DEBUG_BUILD_OPTS - /wd4514 # It's ok if the compiler removes unreferenced inline - # functions. - ) -endif () - target_compile_options ( ${PROJECT_NAME} PUBLIC diff --git a/cmake/build/MSVCRelease.cmake b/cmake/build/MSVCRelease.cmake index c1222fe..2874a78 100644 --- a/cmake/build/MSVCRelease.cmake +++ b/cmake/build/MSVCRelease.cmake @@ -41,15 +41,6 @@ if (${TESTCPP_STACKTRACE_ENABLED}) ) endif () -if (BUILD_TESTING) - list ( - APPEND - MSVC_RELEASE_BUILD_OPTS - /wd4514 # It's ok if the compiler removes unreferenced inline - # functions. - ) -endif () - target_compile_options ( ${PROJECT_NAME} PUBLIC diff --git a/include/internal/TestCPPAssertions.h b/include/internal/TestCPPAssertions.h index 2768e3d..8cdccce 100644 --- a/include/internal/TestCPPAssertions.h +++ b/include/internal/TestCPPAssertions.h @@ -80,30 +80,7 @@ namespace TestCPP { const string& failureMessage = "Arguments are not equivalent!" ) { - const string& err = checkEquals(expected, actual, failureMessage); - if (err.size()) { - throw TestFailedException(std::move(err)); - } - } - - /** - * @brief Check that char*'s are equal using strcmp. - * @param expected The value that the actual value should be - * equivalent to. - * @param actual The actual value that will be checked against - * the expected value. - * @param failureMessage Failure message that should be logged - * if the assertion fails. This - * defaults to a generic failure - * message related to the assertion - * type. - */ - static void assertEquals( - const char* expected, const char* actual, - const string& failureMessage = "Arguments are not equivalent!" - ) - { - const string& err = checkEquals(expected, actual, failureMessage); + const string err = checkEquals(expected, actual, failureMessage); if (err.size()) { throw TestFailedException(std::move(err)); } @@ -128,30 +105,8 @@ namespace TestCPP { const string& failureMessage = "Arguments are equivalent!" ) { - const string& err = checkNotEquals(shouldNotBe, actual, failureMessage); - if (err.size()) { - throw TestFailedException(std::move(err)); - } - } - - /** - * @brief Check that char*'s are not equal using strcmp. - * @param expected The value that the actual value should not - * be equivalent to. - * @param actual The actual value that will be checked against - * the expected value. - * @param failureMessage Failure message that should be logged - * if the assertion fails. This - * defaults to a generic failure - * message related to the assertion - * type. - */ - static void assertNotEquals( - const char* shouldNotBe, const char* actual, - const string& failureMessage = "Arguments are equivalent!" - ) - { - const string& err = checkNotEquals(shouldNotBe, actual, failureMessage); + const string err = checkNotEquals(shouldNotBe, actual, + failureMessage); if (err.size()) { throw TestFailedException(std::move(err)); } @@ -172,7 +127,7 @@ namespace TestCPP { const string& failureMessage = "Object is not null!" ) { - const string& err = checkNull(ptr, failureMessage); + const string err = checkNull(ptr, failureMessage); if (err.size()) { throw TestFailedException(std::move(err)); } @@ -193,7 +148,7 @@ namespace TestCPP { const string& failureMessage = "Object is null!" ) { - const string& err = checkNotNull(ptr, failureMessage); + const string err = checkNotNull(ptr, failureMessage); if (err.size()) { throw TestFailedException(std::move(err)); } @@ -323,22 +278,6 @@ namespace TestCPP { return {}; } - static const string checkEquals( - const char* expected, const char* actual, - const string& failureMessage - ) - { - if (strcmp(expected, actual)) { - return logTestFailure( - expected, actual, - equivalenceAssertionMessage, - failureMessage, - true - ); - } - return {}; - } - template static const string checkNotEquals( T1 shouldNotBe, T2 actual, @@ -356,22 +295,6 @@ namespace TestCPP { return {}; } - static const string checkNotEquals( - const char* shouldNotBe, const char* actual, - const string& failureMessage - ) - { - if (!strcmp(shouldNotBe, actual)) { - return logTestFailure( - shouldNotBe, actual, - nonequivalenceAssertionMessage, - failureMessage, - true - ); - } - return {}; - } - template static const string checkNull( T ptr, @@ -414,4 +337,64 @@ namespace TestCPP { }; } +/** + * @brief Check that char*'s are equal using strcmp. + * @param expected The value that the actual value should be + * equivalent to. + * @param actual The actual value that will be checked against + * the expected value. + * @param failureMessage Failure message that should be logged + * if the assertion fails. This + * defaults to a generic failure + * message related to the assertion + * type. + */ +template<> +void TestCPP::Assertions::assertEquals( + const char* expected, const char* actual, + const string& failureMessage +); + +extern template +void TestCPP::Assertions::assertEquals( + const char* expected, const char* actual, + const string& failureMessage +); + +/** + * @brief Check that char*'s are not equal using strcmp. + * @param expected The value that the actual value should not + * be equivalent to. + * @param actual The actual value that will be checked against + * the expected value. + * @param failureMessage Failure message that should be logged + * if the assertion fails. This + * defaults to a generic failure + * message related to the assertion + * type. + */ +template<> +void TestCPP::Assertions::assertNotEquals( + const char* shouldNotBe, const char* actual, + const string& failureMessage +); + +extern template +void TestCPP::Assertions::assertNotEquals( + const char* shouldNotBe, const char* actual, + const string& failureMessage +); + +template<> +const string TestCPP::Assertions::checkEquals( + const char* expected, const char* actual, + const string& failureMessage +); + +template<> +const string TestCPP::Assertions::checkNotEquals( + const char* shouldNotBe, const char* actual, + const string& failureMessage +); + #endif diff --git a/src/TestCPPAssertions.cpp b/src/TestCPPAssertions.cpp index f0d2d64..1ec0ac6 100644 --- a/src/TestCPPAssertions.cpp +++ b/src/TestCPPAssertions.cpp @@ -39,6 +39,65 @@ using std::stringstream; namespace TestCPP { + template<> + const string Assertions::checkEquals( + const char* expected, const char* actual, + const string& failureMessage + ) + { + if (strcmp(expected, actual)) { + return logTestFailure( + expected, actual, + equivalenceAssertionMessage, + failureMessage, + true + ); + } + return {}; + } + + template<> + const string Assertions::checkNotEquals( + const char* shouldNotBe, const char* actual, + const string& failureMessage + ) + { + if (!strcmp(shouldNotBe, actual)) { + return logTestFailure( + shouldNotBe, actual, + nonequivalenceAssertionMessage, + failureMessage, + true + ); + } + return {}; + } + + template<> + void Assertions::assertEquals( + const char* expected, const char* actual, + const string& failureMessage + ) + { + const string err = checkEquals(expected, actual, failureMessage); + if (err.size()) { + throw TestFailedException(std::move(err)); + } + } + + template<> + void Assertions::assertNotEquals( + const char* shouldNotBe, const char* actual, + const string& failureMessage + ) + { + const string err = checkNotEquals(shouldNotBe, actual, + failureMessage); + if (err.size()) { + throw TestFailedException(std::move(err)); + } + } + void Assertions::assertThrows ( function shouldThrow, const string& failureMessage @@ -95,7 +154,7 @@ namespace TestCPP { if (!condition) { static constexpr const char* atMsg = "Boolean Truth assertion failed!"; - const string& err = logTestFailure( + const string err = logTestFailure( "", "", atMsg, failureMessage, @@ -116,7 +175,7 @@ namespace TestCPP { if (condition) { static constexpr const char* atMsg = "Boolean False assertion failed!"; - const string& err = logTestFailure( + const string err = logTestFailure( "", "", atMsg, failureMessage, From 0c5ba8b35ca57db1ad057d2b7fe492bcbed761fc Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Thu, 27 Feb 2025 23:38:32 -0800 Subject: [PATCH 12/13] Restructure test files in prep for additional categories, increase cov Increase patch coverage where it was lacking for #27, #94, and #8. Added new tests so all assertions are now covered, and added negative testing for all assertions. Restructure Assertions test files so there's a paradigm for adding new assertion categories. Updated CMake build to take this into account. --- cmake/Targets.cmake | 2 +- test/include/Assertions/AssertionsSuite.h | 33 --- test/include/Assertions/AssertionsSuites.h | 101 +++++++ test/include/Assertions/AssertionsTests.h | 15 - .../include/Assertions/BasicAssertionsTests.h | 32 ++ test/src/Assertions/AssertionsTests.cpp | 48 --- test/src/Assertions/BasicAssertionsTests.cpp | 273 ++++++++++++++++++ test/src/TestCPPAssertionsMain.cpp | 13 +- 8 files changed, 416 insertions(+), 101 deletions(-) delete mode 100644 test/include/Assertions/AssertionsSuite.h create mode 100644 test/include/Assertions/AssertionsSuites.h delete mode 100644 test/include/Assertions/AssertionsTests.h create mode 100644 test/include/Assertions/BasicAssertionsTests.h delete mode 100644 test/src/Assertions/AssertionsTests.cpp create mode 100644 test/src/Assertions/BasicAssertionsTests.cpp diff --git a/cmake/Targets.cmake b/cmake/Targets.cmake index 89127c9..1606e70 100644 --- a/cmake/Targets.cmake +++ b/cmake/Targets.cmake @@ -37,7 +37,7 @@ if (BUILD_TESTING) add_executable ( ${PROJECT_NAME}_Assertions_test - test/src/Assertions/AssertionsTests.cpp + test/src/Assertions/BasicAssertionsTests.cpp test/src/TestCPPAssertionsMain.cpp ) diff --git a/test/include/Assertions/AssertionsSuite.h b/test/include/Assertions/AssertionsSuite.h deleted file mode 100644 index 68596b1..0000000 --- a/test/include/Assertions/AssertionsSuite.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef TESTCPP_ASSERTIONS_SUITE_ -#define TESTCPP_ASSERTIONS_SUITE_ - -#include "AssertionsTests.h" - -namespace TestCPP { - namespace Testing { - namespace AssertionsSuite { - TestSuite suite( - "TestCPP Assertions Tests", - - make_tuple( - "assertNull Test", - function(AssertionsTests::TestAssertNull) - ), - make_tuple( - "assertNotNull Test", - function(AssertionsTests::TestAssertNotNull) - ), - make_tuple( - "assertTrue Test", - function(AssertionsTests::TestAssertTrue) - ), - make_tuple( - "assertFalse Test", - function(AssertionsTests::TestAssertFalse) - ) - ); - } - } -} - -#endif diff --git a/test/include/Assertions/AssertionsSuites.h b/test/include/Assertions/AssertionsSuites.h new file mode 100644 index 0000000..87f2e64 --- /dev/null +++ b/test/include/Assertions/AssertionsSuites.h @@ -0,0 +1,101 @@ +#ifndef TESTCPP_ASSERTIONS_SUITE_ +#define TESTCPP_ASSERTIONS_SUITE_ + +#include "BasicAssertionsTests.h" + +namespace TestCPP { + namespace Testing { + namespace AssertionsSuites { + TestSuite basicSuite( + "TestCPP Basic Assertions Tests", + + make_tuple( + "Basic Assertion - assertEquals Test", + function(AssertionsTests::TestAssertEquals) + ), + make_tuple( + "Basic Assertion - assertEquals Not Equal Test", + function(AssertionsTests::TestAssertEqualsNotEqual) + ), + make_tuple( + "Basic Assertion - assertEquals C Strings Test", + function(AssertionsTests::TestAssertEqualsCStrings) + ), + make_tuple( + "Basic Assertion - assertEquals C Strings Not Equal Test", + function(AssertionsTests::TestAssertEqualsCStringsNotEqual) + ), + make_tuple( + "Basic Assertion - assertNotEquals Test", + function(AssertionsTests::TestAssertNotEquals) + ), + make_tuple( + "Basic Assertion - assertNotEquals Equal Test", + function(AssertionsTests::TestAssertNotEqualsEqual) + ), + make_tuple( + "Basic Assertion - assertNotEquals C Strings Test", + function(AssertionsTests::TestAssertNotEqualsCStrings) + ), + make_tuple( + "Basic Assertion - assertNotEquals C Strings Equal Test", + function(AssertionsTests::TestAssertNotEqualsCStringsEqual) + ), + make_tuple( + "Basic Assertion - assertNull Test", + function(AssertionsTests::TestAssertNull) + ), + make_tuple( + "Basic Assertion - assertNull not null Test", + function(AssertionsTests::TestAssertNullNotNull) + ), + make_tuple( + "Basic Assertion - assertNotNull Test", + function(AssertionsTests::TestAssertNotNull) + ), + make_tuple( + "Basic Assertion - assertNotNull null Test", + function(AssertionsTests::TestAssertNotNullNull) + ), + make_tuple( + "Basic Assertion - assertThrows Test", + function(AssertionsTests::TestAssertThrows) + ), + make_tuple( + "Basic Assertion - assertThrows Does Not Throw Test", + function(AssertionsTests::TestAssertThrowsDoesNotThrow) + ), + make_tuple( + "Basic Assertion - assertNoThrows Test", + function(AssertionsTests::TestAssertNoThrows) + ), + make_tuple( + "Basic Assertion - assertNoThrows Throws Test", + function(AssertionsTests::TestAssertNoThrowsThrows) + ), + make_tuple( + "Basic Assertion - assertTrue Test", + function(AssertionsTests::TestAssertTrue) + ), + make_tuple( + "Basic Assertion - assertTrue not true Test", + function(AssertionsTests::TestAssertTrueNotTrue) + ), + make_tuple( + "Basic Assertion - assertFalse Test", + function(AssertionsTests::TestAssertFalse) + ), + make_tuple( + "Basic Assertion - assertFalse not false Test", + function(AssertionsTests::TestAssertFalseNotFalse) + ), + make_tuple( + "Basic Assertion - fail Test", + function(AssertionsTests::TestFail) + ) + ); + } + } +} + +#endif diff --git a/test/include/Assertions/AssertionsTests.h b/test/include/Assertions/AssertionsTests.h deleted file mode 100644 index 9a69fb7..0000000 --- a/test/include/Assertions/AssertionsTests.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef TESTCPP_ASSERTIONS_TESTS_ -#define TESTCPP_ASSERTIONS_TESTS_ - -namespace TestCPP { - namespace Testing { - namespace AssertionsTests { - void TestAssertTrue (); - void TestAssertFalse (); - void TestAssertNull (); - void TestAssertNotNull (); - } - } -} - -#endif diff --git a/test/include/Assertions/BasicAssertionsTests.h b/test/include/Assertions/BasicAssertionsTests.h new file mode 100644 index 0000000..c2ef0a2 --- /dev/null +++ b/test/include/Assertions/BasicAssertionsTests.h @@ -0,0 +1,32 @@ +#ifndef TESTCPP_ASSERTIONS_TESTS_ +#define TESTCPP_ASSERTIONS_TESTS_ + +namespace TestCPP { + namespace Testing { + namespace AssertionsTests { + void TestAssertEquals (); + void TestAssertEqualsNotEqual (); + void TestAssertEqualsCStrings (); + void TestAssertEqualsCStringsNotEqual (); + void TestAssertNotEquals (); + void TestAssertNotEqualsEqual (); + void TestAssertNotEqualsCStrings (); + void TestAssertNotEqualsCStringsEqual (); + void TestAssertNull (); + void TestAssertNullNotNull (); + void TestAssertNotNull (); + void TestAssertNotNullNull (); + void TestAssertThrows (); + void TestAssertThrowsDoesNotThrow (); + void TestAssertNoThrows (); + void TestAssertNoThrowsThrows (); + void TestAssertTrue (); + void TestAssertTrueNotTrue (); + void TestAssertFalse (); + void TestAssertFalseNotFalse (); + void TestFail (); + } + } +} + +#endif diff --git a/test/src/Assertions/AssertionsTests.cpp b/test/src/Assertions/AssertionsTests.cpp deleted file mode 100644 index 10f4634..0000000 --- a/test/src/Assertions/AssertionsTests.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "TestCPP.h" -#include "Assertions/AssertionsTests.h" - -namespace TestCPP { - namespace Testing { - namespace AssertionsTests { - void TestAssertTrue () { - int lower = 5; - int higher = 9; - - Assertions::assertTrue(higher > lower, - "Negated condtion!"); - } - - void TestAssertFalse () { - int lower = 5; - int higher = 9; - - Assertions::assertFalse(higher < lower, - "Negated condtion!"); - } - - void TestAssertNull () { - string * nullString = nullptr; - - Assertions::assertNull(nullString, "nullptr is null!"); - } - - void TestAssertNotNull () { - string notNull("non-null"); - - Assertions::assertNotNull( - ¬Null, - "A constructed std::string is not null!" - ); - Assertions::assertNotNull( - "non-null", - "A const char * is not null!" - ); - - int testInt = 5; - - Assertions::assertNotNull(&testInt, - "An int pointer is not null!"); - } - } - } -} \ No newline at end of file diff --git a/test/src/Assertions/BasicAssertionsTests.cpp b/test/src/Assertions/BasicAssertionsTests.cpp new file mode 100644 index 0000000..99e3764 --- /dev/null +++ b/test/src/Assertions/BasicAssertionsTests.cpp @@ -0,0 +1,273 @@ +#include "TestCPP.h" +#include "Assertions/BasicAssertionsTests.h" + +namespace TestCPP { + namespace Testing { + namespace AssertionsTests { + void TestAssertEquals() { + int expected = 5; + int actual = 5; + Assertions::assertEquals(expected, actual, + "5 == 5"); + } + + void TestAssertEqualsNotEqual() { + int notEqual = 3; + int actual = 5; + + try { + Assertions::assertEquals(notEqual, actual, + "3 != 5"); + } + catch (TestFailedException& e) { + Assertions::assertEquals( + "Equivalence assertion failed!\n3 != 5\nExpectation value: <3>\nActual: <5>\n", + e.what(), + "Should be: \nActual: <5>\n>" + ); + } + } + + void TestAssertEqualsCStrings() { + const char* expected = "Hello, World!"; + const char* actual = "Hello, World!"; + Assertions::assertEquals(expected, actual, + "Hello, World! == Hello, World!"); + } + + void TestAssertEqualsCStringsNotEqual() { + const char* notEqual = "Hello World!"; + const char* actual = "Hello, World!"; + + try { + Assertions::assertEquals(notEqual, actual, + "Hello World! != Hello, World!"); + } + catch (TestFailedException& e) { + Assertions::assertEquals( + "Equivalence assertion failed!\nHello World! != Hello, World!\nExpectation value: \nActual: \n", + e.what(), + "Should be: Hello World! != Hello, World!" + ); + } + } + + void TestAssertNotEquals() { + int shouldNotBe = 5; + int actual = 9; + Assertions::assertNotEquals(shouldNotBe, actual, + "5 != 9"); + } + + void TestAssertNotEqualsEqual() { + int shouldNotBe = 9; + int actual = 9; + + try { + Assertions::assertNotEquals(shouldNotBe, actual, + "9 == 9"); + } + catch (TestFailedException& e) { + Assertions::assertEquals( + "Non-Equivalence assertion failed!\n9 == 9\nExpectation value: <9>\nActual: <9>\n", + e.what(), + "Should be: 9 == 9" + ); + } + } + + void TestAssertNotEqualsCStrings() { + const char* shouldNotBe = "Hello, World!"; + const char* actual = "Goodbye, World!"; + Assertions::assertNotEquals(shouldNotBe, actual, + "Hello, World! != Goodbye, World!"); + } + + void TestAssertNotEqualsCStringsEqual() { + const char* shouldNotBe = "Hello, World!"; + const char* actual = "Hello, World!"; + + try { + Assertions::assertNotEquals(shouldNotBe, actual, + "Hello, World! == Hello, World!"); + } + catch (TestFailedException& e) { + Assertions::assertEquals( + "Non-Equivalence assertion failed!\nHello, World! == Hello, World!\nExpectation value: \nActual: \n", + e.what(), + "Should be: Hello, World! == Hello, World!" + ); + } + } + + void TestAssertNull() { + string* nullString = nullptr; + + Assertions::assertNull(nullString, "nullptr is null!"); + } + + void TestAssertNullNotNull() { + string nonnullString = "nullptr"; + + try { + Assertions::assertNull(&nonnullString, "nullptr is not null!"); + } + catch (TestFailedException& e) { + Assertions::assertEquals( + "Null assertion failed!\nnullptr is not null!\n", + e.what(), + "Should be: nullptr is not null!" + ); + } + } + + void TestAssertNotNull() { + string notNull("non-null"); + + Assertions::assertNotNull( + ¬Null, + "A constructed std::string is not null!" + ); + Assertions::assertNotNull( + "non-null", + "A const char * is not null!" + ); + + int testInt = 5; + + Assertions::assertNotNull(&testInt, + "An int pointer is not null!"); + } + + void TestAssertNotNullNull() { + string* nullString = nullptr; + + try { + Assertions::assertNotNull(nullString, "nullptr is null!"); + } + catch (TestFailedException& e) { + Assertions::assertEquals( + "Not Null assertion failed!\nnullptr is null!\n", + e.what(), + "Should be: nullptr is null!" + ); + } + } + + void TestAssertThrows() { + auto shouldThrow = []() { + throw std::runtime_error("This should throw!"); + }; + Assertions::assertThrows(shouldThrow, + "This should throw!"); + } + + void TestAssertThrowsDoesNotThrow() { + auto shouldThrow = []() { + return; + }; + + try { + Assertions::assertThrows(shouldThrow, + "This should throw!"); + } + catch (TestFailedException& e) { + Assertions::assertEquals( + "This should throw!", + e.what(), + "Should be: This should throw!" + ); + } + } + + void TestAssertNoThrows() { + auto shouldNotThrow = []() { + return; + }; + Assertions::assertNoThrows(shouldNotThrow, + "This should not throw!"); + } + + void TestAssertNoThrowsThrows() { + auto shouldThrow = []() { + throw std::runtime_error("This should throw!"); + }; + + try { + Assertions::assertNoThrows(shouldThrow, + "This should throw!"); + } + catch (TestFailedException& e) { + Assertions::assertEquals( + "This should throw!", + e.what(), + "Should be: This should throw!" + ); + } + } + + void TestAssertTrue () { + int lower = 5; + int higher = 9; + + Assertions::assertTrue(higher > lower, + "Negated condtion!"); + } + + void TestAssertTrueNotTrue() { + int lower = 5; + int higher = 9; + + try { + Assertions::assertTrue(higher < lower, + "Negated condtion!"); + } + catch (TestFailedException& e) { + Assertions::assertEquals( + "Boolean Truth assertion failed!\nNegated condtion!\n", + e.what(), + "Should be: Negated condtion!" + ); + } + } + + void TestAssertFalse () { + int lower = 5; + int higher = 9; + + Assertions::assertFalse(higher < lower, + "Negated condtion!"); + } + + void TestAssertFalseNotFalse() { + int lower = 5; + int higher = 9; + + try { + Assertions::assertFalse(higher > lower, + "Negated condtion!"); + } + catch (TestFailedException& e) { + Assertions::assertEquals( + "Boolean False assertion failed!\nNegated condtion!\n", + e.what(), + "Should be: Negated condtion!" + ); + } + } + + void TestFail() { + try { + Assertions::fail("Forced test failure!"); + } + catch (TestFailedException& e) { + Assertions::assertEquals( + "Forced test failure!", + e.what(), + "Should be: Forced test failure!" + ); + } + } + } + } +} \ No newline at end of file diff --git a/test/src/TestCPPAssertionsMain.cpp b/test/src/TestCPPAssertionsMain.cpp index b0e5374..8016bca 100644 --- a/test/src/TestCPPAssertionsMain.cpp +++ b/test/src/TestCPPAssertionsMain.cpp @@ -6,16 +6,21 @@ using std::string; using std::make_tuple; using std::function; -#include "Assertions/AssertionsSuite.h" +#include "Assertions/AssertionsSuites.h" int main(void) { try { - TestCPP::Testing::AssertionsSuite::suite.run(); - return TestCPP::Util::unsignedToSigned( - TestCPP::Testing::AssertionsSuite::suite. + TestCPP::Testing::AssertionsSuites::basicSuite.run(); + int basicSuiteFailCount = TestCPP::Util::unsignedToSigned( + TestCPP::Testing::AssertionsSuites::basicSuite. getLastRunFailCount() ); + + int allSuitesFailCount = 0; + allSuitesFailCount += basicSuiteFailCount; + + return allSuitesFailCount; } catch (std::exception& e) { std::cerr << "Test suite run failed with an exception: " From efd470f97ae741816e081953761e19dafa058242 Mon Sep 17 00:00:00 2001 From: Jonathan Hyry Date: Fri, 28 Feb 2025 00:18:26 -0800 Subject: [PATCH 13/13] Remove list of issues that the branch fixes, add clang-diagnostics-* I have confirmed the issues on the list I'm removing here are fixed per the cppcheck run local and on the PR CI run. Added additional clang-tidy warnings: clang-diagnostics-*. --- .clang-tidy | 2 +- CMakePresets.json | 2 +- cppcheck-fix | 33 --------------------------------- 3 files changed, 2 insertions(+), 35 deletions(-) delete mode 100644 cppcheck-fix diff --git a/.clang-tidy b/.clang-tidy index 7fb79fd..0c53fac 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,5 +1,5 @@ { - "Checks": "-*,bugprone-*,cert-*,clang-analyzer-*,cppcoreguidelines-*,hicpp-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-modernize-use-nullptr,-hicpp-use-nullptr", + "Checks": "-*,bugprone-*,cert-*,clang-analyzer-*,clang-diagnostic-*,cppcoreguidelines-*,hicpp-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-modernize-use-nullptr,-hicpp-use-nullptr", "HeaderFilterRegex": ".*", "ExcludeHeaderFilterRegex": "boost/.*", "WarningsAsErrors": "*", diff --git a/CMakePresets.json b/CMakePresets.json index 4311e28..27f91d8 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -363,7 +363,7 @@ "vendor": { "microsoft.com/VisualStudioSettings/CMake/1.0": { "intelliSenseMode": "windows-clangcl-x86", - "clangTidyChecks": "-*,bugprone-*,cert-*,clang-analyzer-*,cppcoreguidelines-*,hicpp-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-modernize-use-nullptr,-hicpp-use-nullptr", + "clangTidyChecks": "-*,bugprone-*,cert-*,clang-analyzer-*,clang-diagnostic-*,cppcoreguidelines-*,hicpp-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-modernize-use-nullptr,-hicpp-use-nullptr", "enableClangTidyCodeAnalysis": true } } diff --git a/cppcheck-fix b/cppcheck-fix deleted file mode 100644 index 7c9fdaf..0000000 --- a/cppcheck-fix +++ /dev/null @@ -1,33 +0,0 @@ -include/internal/TestCPPAssertions.h:78:24: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] - string failureMessage = "Arguments are not equivalent!" - ^ -include/internal/TestCPPAssertions.h:109:24: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] - string failureMessage = "Arguments are equivalent!" - ^ -include/internal/TestCPPAssertions.h:136:24: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] - string failureMessage = "Object is not null!" - ^ -include/internal/TestCPPAssertions.h:163:24: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] - string failureMessage = "Object is null!" - ^ -src/TestCPPAssertions.cpp:92:20: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] - string failureMessage - ^ -src/TestCPPAssertions.cpp:107:20: performance: Function parameter 'failureMessage' should be passed by const reference. [passedByValue] - string failureMessage - -src/TestCPPTestCase.cpp:479:40: performance: Function parameter 'against' should be passed by const reference. [passedByValue] - bool TestCase::checkStdout (string against) { - ^ -src/TestCPPTestCase.cpp:484:37: performance: Function parameter 'against' should be passed by const reference. [passedByValue] - bool TestCase::checkLog (string against) { - ^ -src/TestCPPTestCase.cpp:489:40: performance: Function parameter 'against' should be passed by const reference. [passedByValue] - bool TestCase::checkStderr (string against) { - ^ -src/TestCPPTestCase.cpp:494:40: performance: Function parameter 'source' should be passed by const reference. [passedByValue] - bool TestCase::checkOutput (string source, string against) - ^ -src/TestCPPTestCase.cpp:494:55: performance: Function parameter 'against' should be passed by const reference. [passedByValue] - bool TestCase::checkOutput (string source, string against) - ^