From 91a345bb175b115c4d3cfac552978551193d47eb Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 25 Dec 2024 17:42:06 +0000 Subject: [PATCH] Added experimental assert function handler --- .gitignore | 2 + include/etl/error_handler.h | 46 ++++- include/etl/utility.h | 2 +- .../assert_function/CMakeLists.txt | 124 +++++++++++++ .../assert_function/assert_function.cpp | 3 + .../assert_function/assert_function.h | 5 + .../assert_function/etl_profile.h | 1 + .../assert_function/test_error_handler.cpp | 167 ++++++++++++++++++ test/vs2022/etl.vcxproj | 60 +++++++ test/vs2022/etl.vcxproj.filters | 15 ++ 10 files changed, 421 insertions(+), 4 deletions(-) create mode 100644 test/etl_error_handler/assert_function/CMakeLists.txt create mode 100644 test/etl_error_handler/assert_function/assert_function.cpp create mode 100644 test/etl_error_handler/assert_function/assert_function.h create mode 100644 test/etl_error_handler/assert_function/etl_profile.h create mode 100644 test/etl_error_handler/assert_function/test_error_handler.cpp diff --git a/.gitignore b/.gitignore index 6ca19e11..a4973d42 100644 --- a/.gitignore +++ b/.gitignore @@ -391,3 +391,5 @@ test/test_file_list.txt examples/QueuedMessageRouter/vs2022/.vs/QueuedMessageRouter/CopilotIndices examples/QueuedMessageRouter/vs2022/.vs/QueuedMessageRouter/FileContentIndex examples/QueuedMessageRouter/vs2022/.vs/QueuedMessageRouter/v17 +test/etl_error_handler/assert_errors/build-make +test/etl_error_handler/assert_function/build-make diff --git a/include/etl/error_handler.h b/include/etl/error_handler.h index b08a0d4b..f0c60be6 100644 --- a/include/etl/error_handler.h +++ b/include/etl/error_handler.h @@ -255,6 +255,38 @@ namespace etl } }; } +#elif defined(ETL_USE_ASSERT_FUNCTION) +namespace etl +{ + namespace private_error_handler + { + typedef void(*assert_function_ptr_t)(const etl::exception&); + + // Stores the assert function pointer and default assert function. + template + struct assert_handler + { + static assert_function_ptr_t assert_function_ptr; + + static void default_assert(const etl::exception&) + { + assert(false); + } + }; + + template + assert_function_ptr_t assert_handler::assert_function_ptr = assert_handler::default_assert; + } + + //*************************************************************************** + /// Sets the assert function. + /// The argument function signature is void(*)(const etl::exception&) + //*************************************************************************** + void set_assert_function(etl::private_error_handler::assert_function_ptr_t afptr) + { + etl::private_error_handler::assert_handler<0>::assert_function_ptr = afptr; + } +} #endif //*************************************************************************** @@ -264,6 +296,7 @@ namespace etl /// If ETL_NO_CHECKS is defined then no runtime checks are executed at all. /// If asserts or exceptions are enabled then the error is thrown if the assert fails. The return value is always 'true'. /// If ETL_LOG_ERRORS is defined then the error is logged if the assert fails. The return value is the value of the boolean test. +/// If ETL_USE_ASSERT_FUNCTION is defined then the error is sent to the assert function. /// Otherwise 'assert' is called. The return value is always 'true'. ///\ingroup error_handler //*************************************************************************** @@ -275,6 +308,14 @@ namespace etl #define ETL_ASSERT_FAIL(e) ETL_DO_NOTHING // Does nothing. #define ETL_ASSERT_FAIL_AND_RETURN(e) ETL_DO_NOTHING // Does nothing. #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) ETL_DO_NOTHING // Does nothing. +#elif defined(ETL_USE_ASSERT_FUNCTION) + #define ETL_ASSERT(b, e) {if(!(b)) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));}} // If the condition fails, calls the assert function + #define ETL_ASSERT_OR_RETURN(b, e) {if(!(b)) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;}} // If the condition fails, calls the assert function and return + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if(!(b)) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);}} // If the condition fails, calls the assert function and return a value + + #define ETL_ASSERT_FAIL(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e));} // Calls the assert function + #define ETL_ASSERT_FAIL_AND_RETURN(e) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return;} // Calls the assert function and return + #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {etl::private_error_handler::assert_handler<0>::assert_function_ptr((e)); return (v);} // Calls the assert function and return a value #elif ETL_USING_EXCEPTIONS #if defined(ETL_LOG_ERRORS) #define ETL_ASSERT(b, e) {if (!(b)) {etl::error_handler::error((e)); throw((e));}} // If the condition fails, calls the error handler then throws an exception. @@ -292,7 +333,6 @@ namespace etl #define ETL_ASSERT_FAIL(e) {throw((e));} // Throws an exception. #define ETL_ASSERT_FAIL_AND_RETURN(e) {throw((e));} // Throws an exception. #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {throw((e));} // Throws an exception. - #endif #else #if defined(ETL_LOG_ERRORS) @@ -314,8 +354,8 @@ namespace etl #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {assert(false); return(v);} // Asserts. #else #define ETL_ASSERT(b, e) // Does nothing. - #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) return;} // Returns. - #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) return(v);} // Returns a value. + #define ETL_ASSERT_OR_RETURN(b, e) {if (!(b)) return;} // Returns. + #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if (!(b)) return(v);} // Returns a value. #define ETL_ASSERT_FAIL(e) // Does nothing. #define ETL_ASSERT_FAIL_AND_RETURN(e) {return;} // Returns. diff --git a/include/etl/utility.h b/include/etl/utility.h index 3e371b40..8ea7a475 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -640,7 +640,7 @@ namespace etl // See etl::member_function_as_static //***************************************************************************** template - class ETL_DEPRECATED member_function_wrapper; + class member_function_wrapper; template class ETL_DEPRECATED member_function_wrapper diff --git a/test/etl_error_handler/assert_function/CMakeLists.txt b/test/etl_error_handler/assert_function/CMakeLists.txt new file mode 100644 index 00000000..e996a4e3 --- /dev/null +++ b/test/etl_error_handler/assert_function/CMakeLists.txt @@ -0,0 +1,124 @@ +cmake_minimum_required(VERSION 3.5.0) +project(etl_error_handler_unit_tests) + +add_definitions(-DETL_DEBUG) +add_definitions(-DETL_USE_ASSERT_FUNCTION) +add_definitions(-DETL_VERBOSE_ERRORS) + +include_directories(${PROJECT_SOURCE_DIR}/../../../include) + +set(TEST_SOURCE_FILES + assert_function.cpp + test_error_handler.cpp + ) + +add_executable(etl_tests + ${TEST_SOURCE_FILES} + ) + +if (ETL_CXX_STANDARD MATCHES "98") + message(STATUS "Compiling for C++98") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 98) +elseif (ETL_CXX_STANDARD MATCHES "03") + message(STATUS "Compiling for C++98") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 98) +elseif (ETL_CXX_STANDARD MATCHES "11") + message(STATUS "Compiling for C++11") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 11) +elseif (ETL_CXX_STANDARD MATCHES "14") + message(STATUS "Compiling for C++14") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 14) +elseif (ETL_CXX_STANDARD MATCHES "17") + message(STATUS "Compiling for C++17") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 17) +else() + message(STATUS "Compiling for C++20") + set_property(TARGET etl_tests PROPERTY CXX_STANDARD 20) +endif() + +if (ETL_OPTIMISATION MATCHES "-O1") + message(STATUS "Compiling with -O1 optimisations") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O1") +endif() + +if (ETL_OPTIMISATION MATCHES "-O2") + message(STATUS "Compiling with -O2 optimisations") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2") +endif() + +if (ETL_OPTIMISATION MATCHES "-O3") + message(STATUS "Compiling with -O3 optimisations") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") +endif() + +target_include_directories(etl_tests + PUBLIC + ${CMAKE_CURRENT_LIST_DIR} + ) + +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") + message(STATUS "Using GCC compiler") +endif () + +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + message(STATUS "Using Clang compiler") +endif () + +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") + target_compile_options(etl_tests + PRIVATE + -fno-omit-frame-pointer + -fno-common + -Wno-deprecated-declarations + -Wall + -Wextra + -Werror + -Wfloat-equal + -Wuseless-cast + -Wshadow + -Wnull-dereference + ) +endif () + +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options(etl_tests + PRIVATE + -fno-omit-frame-pointer + -fno-common + -Wno-deprecated-declarations + -Wall + -Wextra + -Werror + -Wfloat-equal + -Wshadow + -Wnull-dereference + ) +endif () + +if ((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + if (ETL_ENABLE_SANITIZER MATCHES "ON") + message(STATUS "Compiling with Sanitizer enabled") + # MinGW doesn't presently support sanitization + if (NOT MINGW) + target_compile_options(etl_tests + PRIVATE + -fsanitize=address,undefined,bounds + ) + + target_link_options(etl_tests + PRIVATE + -fsanitize=address,undefined,bounds + ) + endif() + endif () +endif () + +# Enable the 'make test' CMake target using the executable defined above +add_test(etl_error_handler_unit_tests etl_tests) + +# Since ctest will only show you the results of the single executable +# define a target that will output all of the failing or passing tests +# as they appear from UnitTest++ +add_custom_target(test_verbose COMMAND ${CMAKE_CTEST_COMMAND} --verbose) + + diff --git a/test/etl_error_handler/assert_function/assert_function.cpp b/test/etl_error_handler/assert_function/assert_function.cpp new file mode 100644 index 00000000..a9827650 --- /dev/null +++ b/test/etl_error_handler/assert_function/assert_function.cpp @@ -0,0 +1,3 @@ + +#include "etl/exception.h" + diff --git a/test/etl_error_handler/assert_function/assert_function.h b/test/etl_error_handler/assert_function/assert_function.h new file mode 100644 index 00000000..e31f2c77 --- /dev/null +++ b/test/etl_error_handler/assert_function/assert_function.h @@ -0,0 +1,5 @@ +#include "etl/exception.h" + +extern void AssertFunction(const etl::exception& /*e*/); + +#define ETL_ASSERT_FUNCTION AssertFunction diff --git a/test/etl_error_handler/assert_function/etl_profile.h b/test/etl_error_handler/assert_function/etl_profile.h new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/etl_error_handler/assert_function/etl_profile.h @@ -0,0 +1 @@ + diff --git a/test/etl_error_handler/assert_function/test_error_handler.cpp b/test/etl_error_handler/assert_function/test_error_handler.cpp new file mode 100644 index 00000000..fa767c50 --- /dev/null +++ b/test/etl_error_handler/assert_function/test_error_handler.cpp @@ -0,0 +1,167 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/std +https://www.etlcpp.com + +Copyright(c) 2022 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "etl/error_handler.h" + +#include +#include + +#include "assert_function.h" + +int assert_return_count = 0; +int assert_count = 0; + +//***************************************************************************** +void assert_function(const etl::exception& e) +{ + std::cout << "Exception " << e.what() << " raised\n"; + + ++assert_count; +} + +//***************************************************************************** +class test_exception : public etl::exception +{ +public: + + test_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } +}; + +//***************************************************************************** +class test_exception_1 : public test_exception +{ +public: + + test_exception_1(string_type file_name_, numeric_type line_number_) + : test_exception(ETL_ERROR_TEXT("Test Exception 1", "1A"), file_name_, line_number_) + { + } +}; + +//***************************************************************************** +void Assert(bool state) +{ + ETL_ASSERT(state, ETL_ERROR(test_exception_1)); +} + +//***************************************************************************** +void AssertFail() +{ + ETL_ASSERT_FAIL(ETL_ERROR(test_exception_1)); +} + +//***************************************************************************** +void AssertAndReturn(bool state) +{ + ETL_ASSERT_OR_RETURN(state, ETL_ERROR(test_exception_1)); + + ++assert_return_count; +} + +//***************************************************************************** +void AssertFailAndReturn() +{ + ETL_ASSERT_FAIL_AND_RETURN(ETL_ERROR(test_exception_1)); + + ++assert_return_count; +} + +//***************************************************************************** +bool AssertAndReturnValue(bool state) +{ + ETL_ASSERT_OR_RETURN_VALUE(state, ETL_ERROR(test_exception_1), true); + + ++assert_return_count; + return false; +} + +//***************************************************************************** +bool AssertFailAndReturnValue() +{ + ETL_ASSERT_FAIL_AND_RETURN_VALUE(ETL_ERROR(test_exception_1), true); + + ++assert_return_count; + return false; +} + +//***************************************************************************** +int main() +{ + etl::set_assert_function(assert_function); + + Assert(false); + Assert(true); + AssertFail(); + + AssertAndReturn(false); + AssertAndReturn(true); + AssertFailAndReturn(); + + if (AssertAndReturnValue(false)) + { + ++assert_return_count; + } + + if (AssertAndReturnValue(true)) + { + ++assert_return_count; + } + + if (AssertFailAndReturnValue()) + { + ++assert_return_count; + } + + bool assert_count_passed = (assert_count == 6); + + if (assert_count_passed) + { + std::cout << "Log Count Passed\n"; + } + else + { + std::cout << "Log Count Failed\n"; + } + + bool return_count_passed = (assert_return_count == 4); + + if (return_count_passed) + { + std::cout << "Return Count Passed\n"; + } + else + { + std::cout << "Return Count Failed\n"; + } + + return (assert_count_passed && return_count_passed) ? 0 : 1; +} + diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index a12b35ae..4fcafef9 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -3349,6 +3349,21 @@ + + true + true + true + true + true + true + true + true + true + true + true + true + true + true true @@ -3545,6 +3560,36 @@ + + true + true + true + true + true + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + true + true + true + true + true + true true @@ -9085,6 +9130,21 @@ + + true + true + true + true + true + true + true + true + true + true + true + true + true + true true diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index 582ef36c..96d90d2f 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -229,6 +229,9 @@ {e2e649e4-10ee-4ed7-baa3-eb889e552ba1} + + {f51cb264-5376-47db-89d9-a515e1ac4af7} + @@ -1416,6 +1419,9 @@ ETL\Utilities + + Tests\Error Handler\Assert Function + @@ -3395,6 +3401,12 @@ Tests\Syntax Checks\Source + + Tests\Error Handler\Assert Function + + + Tests\Error Handler\Assert Function + @@ -3600,6 +3612,9 @@ Tests\Syntax Checks\Source + + Tests\Error Handler\Assert Function +