From c6bdf49f0863828782e5e8c4086f3bb6036fdc4c Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sat, 10 Dec 2016 02:39:39 +0300 Subject: [PATCH] Better testing of examples, better tests coverage --- doc/stacktrace.qbk | 4 +- example/assert_handler.cpp | 56 +++++++++++ example/getting_started.cpp | 183 ---------------------------------- example/terminate_handler.cpp | 67 +++++++++++++ example/throwing_st.cpp | 4 +- example/trace_addresses.cpp | 63 ++++++++++++ test/Jamfile.v2 | 23 ++--- test/test.cpp | 2 + 8 files changed, 204 insertions(+), 198 deletions(-) create mode 100644 example/assert_handler.cpp delete mode 100644 example/getting_started.cpp create mode 100644 example/terminate_handler.cpp create mode 100644 example/trace_addresses.cpp diff --git a/doc/stacktrace.qbk b/doc/stacktrace.qbk index 6aa2e83..3aa7f0f 100644 --- a/doc/stacktrace.qbk +++ b/doc/stacktrace.qbk @@ -21,8 +21,10 @@ Boost.Stacktrace library is a simple library that provides information about cal [section Getting Started] -[import ../example/getting_started.cpp] +[import ../example/assert_handler.cpp] +[import ../example/terminate_handler.cpp] [import ../example/throwing_st.cpp] +[import ../example/trace_addresses.cpp] [section How to print current call stack] diff --git a/example/assert_handler.cpp b/example/assert_handler.cpp new file mode 100644 index 0000000..4ff928c --- /dev/null +++ b/example/assert_handler.cpp @@ -0,0 +1,56 @@ +// Copyright Antony Polukhin, 2016. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_ENABLE_ASSERT_HANDLER + +#include +BOOST_NOINLINE void foo(int i); +BOOST_NOINLINE void bar(int i); + +BOOST_NOINLINE void bar(int i) { + boost::array a = {{101, 100, 123, 23, 32}}; + if (i >= 0) { + foo(a[i]); + } else { + std::exit(1); + } +} + +BOOST_NOINLINE void foo(int i) { + bar(--i); +} + +namespace std { inline void ignore_abort(){ std::exit(0); } } +#define abort ignore_abort + +//[getting_started_assert_handlers + +// BOOST_ENABLE_ASSERT_DEBUG_HANDLER is defined for the whole project +#include // std::logic_error +#include // std::cerr +#include + +namespace boost { + inline void assertion_failed_msg(char const* expr, char const* msg, char const* function, char const* file, long line) { + std::cerr << "Expression '" << expr << "' is false in function '" << function << "': " << (msg ? msg : "<...>") << ".\n" + << "Backtrace:\n" << boost::stacktrace::stacktrace() << '\n'; + std::abort(); + } + + inline void assertion_failed(char const* expr, char const* function, char const* file, long line) { + ::boost::assertion_failed_msg(expr, 0 /*nullptr*/, function, file, line); + } +} // namespace boost +//] + + +int main() { + foo(5); + + return 2; +} + + diff --git a/example/getting_started.cpp b/example/getting_started.cpp deleted file mode 100644 index 7558944..0000000 --- a/example/getting_started.cpp +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright Antony Polukhin, 2016. -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -BOOST_NOINLINE void oops(std::size_t i); -BOOST_NOINLINE void foo(int i); -BOOST_NOINLINE void bar(int i); - -BOOST_NOINLINE void oops(std::size_t i) { - // std::terminate(); - // void (*p)() = 0; p(); - - boost::array a = {{0, 1, 2, 3, 4}}; - foo(a[i]); -} - -BOOST_NOINLINE void bar(int i) { - boost::array a = {{0, 1, 2, 3, 4}}; - if (i < 5) { - if (i >= 0) { - foo(a[i]); - } else { - oops(i); - } - } -} - -BOOST_NOINLINE void foo(int i) { - bar(--i); -} - -/* -../../../boost/array.hpp:123: T& boost::array::operator[](boost::array::size_type) [with T = int; long unsigned int N = 5ul; boost::array::reference = int&; boost::array::size_type = long unsigned int]: Assertion `(i < N)&&("out of range")' failed. -Aborted (core dumped) -*/ - -/* -Expression 'i < N' is false in function 'T& boost::array::operator[](boost::array::size_type) [with T = int; long unsigned int N = 5ul; boost::array::reference = int&; boost::array::size_type = long unsigned int]': out of range -Backtrace: - 0# boost::assertion_failed_msg(char const*, char const*, char const*, char const*, long) - 1# boost::array::operator[](unsigned long) - 2# oops(unsigned long) - 3# bar(int) - 4# foo(int) - 5# bar(int) - 6# foo(int) - 7# bar(int) - 8# foo(int) - 9# bar(int) -10# foo(int) -11# bar(int) -12# foo(int) -13# bar(int) -14# foo(int) -15# main -16# __libc_start_main -17# _start -18# ?? -*/ - -//[getting_started_assert_handlers - -// BOOST_ENABLE_ASSERT_DEBUG_HANDLER is defined for the whole project -#include // std::logic_error -#include // std::cerr -#include - -namespace boost { - void assertion_failed_msg(char const* expr, char const* msg, char const* function, char const* file, long line) { - std::cerr << "Expression '" << expr << "' is false in function '" << function << "': " << (msg ? msg : "<...>") << ".\n" - << "Backtrace:\n" << boost::stacktrace::stacktrace() << '\n'; - throw std::logic_error("assertion"); - } - - void assertion_failed(char const* expr, char const* function, char const* file, long line) { - ::boost::assertion_failed_msg(expr, 0 /*nullptr*/, function, file, line); - } -} // namespace boost -//] - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -//[getting_started_terminate_handlers - -#include // std::set_terminate, std::abort -#include // ::signal -#include -#include // std::cerr - -void my_terminate_handler() { - std::cerr << "Terminate called:\n" << boost::stacktrace::stacktrace() << '\n'; - std::abort(); -} - -void my_signal_handler(int signum) { - ::signal(signum, SIG_DFL); - boost::stacktrace::stacktrace bt; - if (bt) { - std::cerr << "Signal " << signum << ", backtrace:\n" << boost::stacktrace::stacktrace() << '\n'; // ``[footnote Strictly speaking this code is not async-signal-safe, because it uses std::cerr. [link boost_stacktrace.build_macros_and_backends Section "Build, Macros and Backends"] describes async-signal-safe backends, so if you will use the noop backend code becomes absolutely valid as that backens always returns 0 frames and `operator<<` will be never called. ]`` - } - std::abort(); -} -//] - -void setup_handlers() { -//[getting_started_setup_handlers - std::set_terminate(&my_terminate_handler); - ::signal(SIGSEGV, &my_signal_handler); -//] -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// outputs: 0x401a25,0x401a25,0x401a25,0x401a25,0x401a25,0x401a25,0x4019cb,0x401a7f,0x7f9da8a46e50,0x4013e0,0, - -#ifdef BOOST_NO_CXX11_RANGE_BASED_FOR -#include -#include // std::cout - -namespace bs = boost::stacktrace; -void dump_compact(const bs::stacktrace& st) { - for (unsigned i = 0; i < st.size(); ++i) { - bs::frame frame = st[i]; - std::cout << frame.address() << ','; - } - - std::cout << std::endl; -} -#else -//[getting_started_trace_addresses -#include -#include // std::cout - -namespace bs = boost::stacktrace; -void dump_compact(const bs::stacktrace& st) { - for (bs::frame frame: st) { - std::cout << frame.address() << ','; - } - - std::cout << std::endl; -} -//] -#endif - -BOOST_NOINLINE boost::stacktrace::stacktrace rec1(int i); -BOOST_NOINLINE boost::stacktrace::stacktrace rec2(int i); - -BOOST_NOINLINE boost::stacktrace::stacktrace rec1(int i) { - if (i < 5) { - if (!i) return boost::stacktrace::stacktrace(); - return rec2(--i); - } - - return rec2(i - 2); -} - -BOOST_NOINLINE boost::stacktrace::stacktrace rec2(int i) { - if (i < 5) { - if (!i) return boost::stacktrace::stacktrace(); - return rec2(--i); - } - - return rec2(i - 2); -} - - -#include -int main() { - dump_compact(rec1(8)); - setup_handlers(); - - BOOST_TRY { - foo(105); // testing assert handler - } BOOST_CATCH(...) { - } BOOST_CATCH_END - -} - - diff --git a/example/terminate_handler.cpp b/example/terminate_handler.cpp new file mode 100644 index 0000000..0d6d27d --- /dev/null +++ b/example/terminate_handler.cpp @@ -0,0 +1,67 @@ +// Copyright Antony Polukhin, 2016. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +BOOST_NOINLINE void foo(int i); +BOOST_NOINLINE void bar(int i); + +BOOST_NOINLINE void bar(int i) { + boost::array a = {{-1, -231, -123, -23, -32}}; + if (i >= 0) { + foo(a[i]); + } else { + std::terminate(); + } +} + +BOOST_NOINLINE void foo(int i) { + bar(--i); +} + +inline void ignore_exit(int){ std::exit(0); } +#define _Exit ignore_exit + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//[getting_started_terminate_handlers + +#include // std::set_terminate, std::abort +#include // ::signal +#include +#include // std::cerr + +void my_terminate_handler() { + std::cerr << "Terminate called:\n" << boost::stacktrace::stacktrace() << '\n'; + std::abort(); +} + +void my_signal_handler(int signum) { + ::signal(signum, SIG_DFL); + boost::stacktrace::stacktrace bt; + if (bt) { + std::cerr << "Signal " << signum << ", backtrace:\n" << boost::stacktrace::stacktrace() << '\n'; // ``[footnote Strictly speaking this code is not async-signal-safe, because it uses std::cerr. [link boost_stacktrace.build_macros_and_backends Section "Build, Macros and Backends"] describes async-signal-safe backends, so if you will use the noop backend code becomes absolutely valid as that backens always returns 0 frames and `operator<<` will be never called. ]`` + } + _Exit(-1); +} +//] + +void setup_handlers() { +//[getting_started_setup_handlers + std::set_terminate(&my_terminate_handler); + ::signal(SIGSEGV, &my_signal_handler); + ::signal(SIGABRT, &my_signal_handler); +//] +} + + +int main() { + setup_handlers(); + foo(5); + + return 2; +} + + diff --git a/example/throwing_st.cpp b/example/throwing_st.cpp index 30c982a..bdb5a1c 100644 --- a/example/throwing_st.cpp +++ b/example/throwing_st.cpp @@ -54,6 +54,7 @@ BOOST_NOINLINE void oops(int i) { throw with_trace("'i' must not be greater than zero in oops()"); //] foo(i); + std::exit(1); } #include @@ -66,6 +67,7 @@ BOOST_NOINLINE void bar(int i) { oops(i); } } + std::exit(2); } BOOST_NOINLINE void foo(int i) { @@ -84,7 +86,7 @@ int main() { std::cerr << "Backtrace:\n" << e.trace << '\n'; } } catch (const std::exception& e) { - std::cerr << e.what() << '\n'; + std::cerr << e.what() << '\n'; /*<-*/ std::exit(3); /*->*/ } //] } diff --git a/example/trace_addresses.cpp b/example/trace_addresses.cpp new file mode 100644 index 0000000..f55fb3d --- /dev/null +++ b/example/trace_addresses.cpp @@ -0,0 +1,63 @@ +// Copyright Antony Polukhin, 2016. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#ifdef BOOST_NO_CXX11_RANGE_BASED_FOR +#include +#include // std::cout + +namespace bs = boost::stacktrace; +void dump_compact(const bs::stacktrace& st) { + for (unsigned i = 0; i < st.size(); ++i) { + bs::frame frame = st[i]; + std::cout << frame.address() << ','; + } + + std::cout << std::endl; +} +#else +//[getting_started_trace_addresses +#include +#include // std::cout + +namespace bs = boost::stacktrace; +void dump_compact(const bs::stacktrace& st) { + for (bs::frame frame: st) { + std::cout << frame.address() << ','; + } + + std::cout << std::endl; +} +//] +#endif + +BOOST_NOINLINE boost::stacktrace::stacktrace rec1(int i); +BOOST_NOINLINE boost::stacktrace::stacktrace rec2(int i); + +BOOST_NOINLINE boost::stacktrace::stacktrace rec1(int i) { + if (i < 5) { + if (!i) return boost::stacktrace::stacktrace(); + return rec2(--i); + } + + return rec2(i - 2); +} + +BOOST_NOINLINE boost::stacktrace::stacktrace rec2(int i) { + if (i < 5) { + if (!i) return boost::stacktrace::stacktrace(); + return rec2(--i); + } + + return rec2(i - 2); +} + +int main() { + dump_compact(rec1(8)); +} + + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c819ede..5cf4699 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -49,19 +49,16 @@ test-suite stacktrace_tests [ run test.cpp : : : .//test_impl_lib_unwind $(LINKSHARED_UNWD) : unwind_lib ] [ run test.cpp : : : .//test_impl_lib_windbg $(LINKSHARED_WIND) : windbg_lib ] [ run test_noop.cpp : : : .//test_impl_lib_noop $(LINKSHARED_NOOP) : noop_lib ] - - # Making sure that the examples work - [ run ../example/getting_started.cpp : : : BOOST_ENABLE_ASSERT_DEBUG_HANDLER $(LINKSHARED_BT) : backtrace_getting_started ] - [ run ../example/getting_started.cpp : : : BOOST_ENABLE_ASSERT_DEBUG_HANDLER $(LINKSHARED_UNWD) : unwind_getting_started ] - [ run ../example/getting_started.cpp : : : BOOST_ENABLE_ASSERT_DEBUG_HANDLER $(LINKSHARED_WIND) : windbg_getting_started ] - [ run ../example/getting_started.cpp : : : BOOST_ENABLE_ASSERT_DEBUG_HANDLER $(LINKSHARED_NOOP) : noop_getting_started ] - [ run ../example/getting_started.cpp : : : BOOST_ENABLE_ASSERT_DEBUG_HANDLER $(AUTO_DEPS) : autodetect_getting_started ] - - [ run ../example/throwing_st.cpp : : : $(LINKSHARED_BT) : backtrace_throwing_st ] - [ run ../example/throwing_st.cpp : : : $(LINKSHARED_UNWD) : unwind_throwing_st ] - [ run ../example/throwing_st.cpp : : : $(LINKSHARED_WIND) : windbg_throwing_st ] - [ run ../example/throwing_st.cpp : : : $(LINKSHARED_NOOP) : noop_throwing_st ] - [ run ../example/throwing_st.cpp : : : $(AUTO_DEPS) : autodetect_throwing_st ] ; +# Assuring that examples compile and run. Adding sources from `examples` directory to the `type_index` test suite. +for local p in [ glob ../example/*.cpp ] +{ + stacktrace_tests += [ run $(p) : : : $(LINKSHARED_BT) : backtrace_$(p[1]:B) ] ; + stacktrace_tests += [ run $(p) : : : $(LINKSHARED_UNWD) : unwind_$(p[1]:B) ] ; + stacktrace_tests += [ run $(p) : : : $(LINKSHARED_WIND) : windbg_$(p[1]:B) ] ; + stacktrace_tests += [ run $(p) : : : $(LINKSHARED_NOOP) : noop_$(p[1]:B) ] ; + stacktrace_tests += [ run $(p) : : : $(AUTO_DEPS) : autodetect_$(p[1]:B) ] ; + +} diff --git a/test/test.cpp b/test/test.cpp index 7010cfd..1a899fc 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -229,6 +229,8 @@ void test_empty_basic_stacktrace() { BOOST_TEST(hash_value(st) == hash_value(st_t())); BOOST_TEST(st == st_t()); + BOOST_TEST(!(st < st_t())); + BOOST_TEST(!(st > st_t())); } int main() {