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/.gitignore b/.gitignore index 048d48f..105789b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ CMakeUserPresets.json /.vs out/ **/cppcheck-checkers.report +/infer-out 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/README.md b/README.md index 01969c8..e041ae1 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,20 @@ 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. # 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,31 @@ 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 --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. @@ -582,8 +680,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. 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..1606e70 100644 --- a/cmake/Targets.cmake +++ b/cmake/Targets.cmake @@ -37,7 +37,13 @@ if (BUILD_TESTING) add_executable ( ${PROJECT_NAME}_Assertions_test - test/src/Assertions/AssertionsTests.cpp + test/src/Assertions/BasicAssertionsTests.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..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 @@ -92,4 +83,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..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 @@ -82,6 +73,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 83ff2e9..8cdccce 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; @@ -75,28 +77,22 @@ 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) { - 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 @@ -105,19 +101,14 @@ namespace TestCPP { */ template static void assertNotEquals ( - T1 expected, T2 actual, - string failureMessage = "Arguments are equivalent!" + 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; - - throw TestFailedException(err.str()); + const string err = checkNotEquals(shouldNotBe, actual, + failureMessage); + if (err.size()) { + throw TestFailedException(std::move(err)); } } @@ -133,18 +124,12 @@ 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; - - 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)); } } @@ -160,18 +145,12 @@ namespace TestCPP { template static void assertNotNull ( T ptr, - string failureMessage = "Object is null!" + 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)); } } @@ -187,7 +166,7 @@ namespace TestCPP { */ static void assertThrows ( function shouldThrow, - string failureMessage = + const string& failureMessage = "Should have thrown something!" ); @@ -203,7 +182,7 @@ namespace TestCPP { */ static void assertNoThrows ( function shouldNotThrow, - string failureMessage = + const string& failureMessage = "Should not have thrown anything!" ); @@ -219,7 +198,7 @@ namespace TestCPP { */ static void assertTrue ( bool condition, - string failureMessage = "Condition is false!" + const string& failureMessage = "Condition is false!" ); /** @@ -234,7 +213,7 @@ namespace TestCPP { */ static void assertFalse ( bool condition, - string failureMessage = "Condition is true!" + const string& failureMessage = "Condition is true!" ); /** @@ -254,7 +233,168 @@ 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 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 {}; + } + + template + static const string checkNotEquals( + T1 shouldNotBe, T2 actual, + const string& failureMessage + ) + { + if (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( + "", "", + nullAssertionMessage, + failureMessage, + false + ); + } + return {}; + } + + template + static const string checkNotNull( + T ptr, + const string& failureMessage + ) + { + static constexpr const char* notNullAssertionMessage = "Not Null assertion failed!"; + + bool notNull = ptr != nullptr; + if (!notNull) { + return logTestFailure( + "", "", + notNullAssertionMessage, + failureMessage, + false + ); + } + return {}; + } }; } +/** + * @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/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..1ec0ac6 100644 --- a/src/TestCPPAssertions.cpp +++ b/src/TestCPPAssertions.cpp @@ -39,9 +39,68 @@ 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, - string failureMessage + const string& failureMessage ) { try { @@ -76,7 +135,7 @@ namespace TestCPP { void Assertions::assertNoThrows ( function shouldNotThrow, - string failureMessage + const string& failureMessage ) { try { @@ -89,31 +148,43 @@ namespace TestCPP { void Assertions::assertTrue ( bool condition, - string failureMessage + const string& failureMessage ) { 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( + "", "", + atMsg, + failureMessage, + false + ); - throw TestFailedException(err.str()); + if (err.size()) { + throw TestFailedException(std::move(err)); + } } } void Assertions::assertFalse ( bool condition, - string failureMessage + const string& failureMessage ) { 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( + "", "", + atMsg, + failureMessage, + false + ); - throw TestFailedException(err.str()); + if (err.size()) { + throw TestFailedException(std::move(err)); + } } } 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: 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/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/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/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/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/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: " 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; + } +} 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" + ); + } } } }