From ec79700b26c95f52286de9dc5ea2d916f5838b79 Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Tue, 15 Dec 2015 11:51:44 -0800 Subject: [PATCH] added tests for throwing from .old() --- include/boost/contract.hpp | 2 - .../check_subcontracted_pre_post_inv.hpp | 2 - test/Jamfile.v2 | 14 +- test/constructor/body_throw.cpp | 55 ++++---- test/constructor/old_throw.cpp | 120 +++++++++++++++++ test/destructor/body_throw.cpp | 95 ++++++------- test/destructor/old_throw.cpp | 111 +++++++++++++++ test/function/body_throw.cpp | 30 ++--- test/function/old_throw.cpp | 46 +++++++ test/public_function/body_throw.cpp | 78 +++++------ test/public_function/old_throw.cpp | 126 ++++++++++++++++++ 11 files changed, 538 insertions(+), 141 deletions(-) create mode 100644 test/constructor/old_throw.cpp create mode 100644 test/destructor/old_throw.cpp create mode 100644 test/function/old_throw.cpp create mode 100644 test/public_function/old_throw.cpp diff --git a/include/boost/contract.hpp b/include/boost/contract.hpp index 9c40f0d..85b9643 100644 --- a/include/boost/contract.hpp +++ b/include/boost/contract.hpp @@ -24,8 +24,6 @@ // TODO: Document that there is a MSVC 2010 bug for which lambdas cannot be used in template constructor intialization list (this was fixed in MSVC 2013). Therefore, an external (static member) function must be used (possibly with bind and cref) to program constructor preconditions on MSVC 2010 instead of using lambdas. -// TODO: Test failure handlers, throw on contract failure, and throw user-defined exceptions: (1) Add a test for throwing exception handlers (somewhat similar to stroustrup97/string.cpp but more comprehensive); (2) Test what happens if bodies throw (e.g., public function should still check inv, dtor too, but ctor should not, etc.)... test all contract types when bodies throw; (3) Test what happens if old expression copies throw (with OLDOF and with .old()). - // TODO: Test contract assertion disabled while checking assertions adding a test to disable/ similar to n1962/factorial.cpp, where contract recursively calls the function itself in the assertions. // TODO: Test overloading for all contract types. Also test subcontracting of overloaded virtual functions (overload both overridden and overriding functions). diff --git a/include/boost/contract/aux_/condition/check_subcontracted_pre_post_inv.hpp b/include/boost/contract/aux_/condition/check_subcontracted_pre_post_inv.hpp index e7ee7e0..07a7181 100644 --- a/include/boost/contract/aux_/condition/check_subcontracted_pre_post_inv.hpp +++ b/include/boost/contract/aux_/condition/check_subcontracted_pre_post_inv.hpp @@ -238,8 +238,6 @@ private: check_post_r(r); } - // TODO: See if these and other enable_if can be replaced using template specializations and a base class for template where to put common code (that might be faster to compile... not sure...). - template typename boost::enable_if >::type check_post_r(Result const& r) { this->check_post(r); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 918a916..72d4149 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -28,8 +28,10 @@ test-suite constructor : [ subdir-run constructor : decl_exit_inv_none ] [ subdir-run constructor : bases ] - [ subdir-run constructor : body_throw ] [ subdir-run constructor : access ] + + [ subdir-run constructor : body_throw ] + [ subdir-run constructor : old_throw ] [ subdir-compile-fail constructor : pre_error ] ; @@ -60,9 +62,11 @@ test-suite destructor : # No decl_exit_inv_... for destructors. [ subdir-run destructor : bases ] - [ subdir-run destructor : body_throw ] [ subdir-run destructor : access ] + [ subdir-run destructor : body_throw ] + [ subdir-run destructor : old_throw ] + [ subdir-compile-fail destructor : pre_error ] ; @@ -102,8 +106,10 @@ test-suite public_function : [ subdir-run public_function : bases_branch ] [ subdir-run public_function : bases_sparse ] - [ subdir-run public_function : body_throw ] [ subdir-run public_function : access ] + + [ subdir-run public_function : body_throw ] + [ subdir-run public_function : old_throw ] [ subdir-run public_function : static ] [ subdir-run public_function : static_body_throw ] @@ -120,7 +126,9 @@ test-suite function : [ subdir-run function : decl_post_none ] [ subdir-run function : func ] + [ subdir-run function : body_throw ] + [ subdir-run function : old_throw ] ; test-suite invariant : diff --git a/test/constructor/body_throw.cpp b/test/constructor/body_throw.cpp index c86b1c4..47282cc 100644 --- a/test/constructor/body_throw.cpp +++ b/test/constructor/body_throw.cpp @@ -1,5 +1,5 @@ -// Test constructor body throwing (in middle branch of inheritance tree). +// Test throw form constructor body (in middle branch of inheritance tree). #include "../aux_/oteststream.hpp" #include @@ -44,7 +44,7 @@ struct b static void static_invariant() { out << "b::static_inv" << std::endl; } void invariant() const { out << "b::inv" << std::endl; } - struct e {}; + struct err {}; b() : boost::contract::constructor_precondition([] { @@ -56,7 +56,7 @@ struct b .postcondition([&] { out << "b::ctor::post" << std::endl; }) ; out << "b::ctor::body" << std::endl; - throw b::e(); // Test body throw (from inheritance mid branch). + throw b::err(); // Test body throws (from inheritance mid branch). } }; @@ -87,31 +87,30 @@ struct a int main() { std::ostringstream ok; - bool threw = false; - out.str(""); - try { a aa; } - catch(b::e const&) { threw = true; } - BOOST_TEST(threw); - ok.str(""); ok - << "a::ctor::pre" << std::endl - << "b::ctor::pre" << std::endl - - << "c::ctor::pre" << std::endl - << "c::static_inv" << std::endl - << "c::ctor::old" << std::endl - << "c::ctor::body" << std::endl - << "c::static_inv" << std::endl - << "c::inv" << std::endl - << "c::ctor::post" << std::endl - - << "b::static_inv" << std::endl - << "b::ctor::old" << std::endl - << "b::ctor::body" << std::endl - // Test b body threw so only static inv exit checked and then C++ - // construction mechanism quits. - << "b::static_inv" << std::endl - ; - BOOST_TEST(out.eq(ok.str())); + try { + out.str(""); + a aa; + BOOST_TEST(false); + } catch(b::err const&) { + ok.str(""); ok + << "a::ctor::pre" << std::endl + << "b::ctor::pre" << std::endl + + << "c::ctor::pre" << std::endl + << "c::static_inv" << std::endl + << "c::ctor::old" << std::endl + << "c::ctor::body" << std::endl + << "c::static_inv" << std::endl + << "c::inv" << std::endl + << "c::ctor::post" << std::endl + + << "b::static_inv" << std::endl + << "b::ctor::old" << std::endl + << "b::ctor::body" << std::endl // Test this threw... + << "b::static_inv" << std::endl // ... so check only this after. + ; + BOOST_TEST(out.eq(ok.str())); + } catch(...) { BOOST_TEST(false); } return boost::report_errors(); } diff --git a/test/constructor/old_throw.cpp b/test/constructor/old_throw.cpp new file mode 100644 index 0000000..35b9e20 --- /dev/null +++ b/test/constructor/old_throw.cpp @@ -0,0 +1,120 @@ + +// Test throw form constructor .old() (in middle branch of inheritance tree). + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct c + #define BASES private boost::contract::constructor_precondition + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + static void static_invariant() { out << "c::static_inv" << std::endl; } + void invariant() const { out << "c::inv" << std::endl; } + + c() : + boost::contract::constructor_precondition([&] { + out << "c::ctor::pre" << std::endl; + }) + { + boost::contract::guard c = boost::contract::constructor(this) + .old([&] { out << "c::ctor::old" << std::endl; }) + .postcondition([&] { out << "c::ctor::post" << std::endl; }) + ; + out << "c::ctor::body" << std::endl; + // Do not throw (from inheritance root). + } +}; + +struct b + #define BASES private boost::contract::constructor_precondition, public c + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + static void static_invariant() { out << "b::static_inv" << std::endl; } + void invariant() const { out << "b::inv" << std::endl; } + + struct err {}; + + b() : + boost::contract::constructor_precondition([] { + out << "b::ctor::pre" << std::endl; + }) + { + boost::contract::guard c = boost::contract::constructor(this) + .old([&] { + out << "b::ctor::old" << std::endl; + throw b::err(); // Test .old() throws (from mid branch). + }) + .postcondition([&] { out << "b::ctor::post" << std::endl; }) + ; + out << "b::ctor::body" << std::endl; + } +}; + +struct a + #define BASES private boost::contract::constructor_precondition, public b + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + static void static_invariant() { out << "a::static_inv" << std::endl; } + void invariant() const { out << "a::inv" << std::endl; } + + a() : + boost::contract::constructor_precondition([&] { + out << "a::ctor::pre" << std::endl; + }) + { + boost::contract::guard c = boost::contract::constructor(this) + .old([&] { out << "a::ctor::old" << std::endl; }) + .postcondition([&] { out << "a::ctor::post" << std::endl; }) + ; + out << "a::ctor::body" << std::endl; + // Do not throw (from inheritance leaf). + } +}; + +int main() { + std::ostringstream ok; + + boost::contract::set_postcondition_failed( + [] (boost::contract::from) { throw; }); + + try { + out.str(""); + a aa; + BOOST_TEST(false); + } catch(b::err const&) { + ok.str(""); ok + << "a::ctor::pre" << std::endl + << "b::ctor::pre" << std::endl + + << "c::ctor::pre" << std::endl + << "c::static_inv" << std::endl + << "c::ctor::old" << std::endl + << "c::ctor::body" << std::endl + << "c::static_inv" << std::endl + << "c::inv" << std::endl + << "c::ctor::post" << std::endl + + << "b::static_inv" << std::endl + << "b::ctor::old" << std::endl // Test this threw. + ; + BOOST_TEST(out.eq(ok.str())); + } catch(...) { BOOST_TEST(false); } + + return boost::report_errors(); +} + diff --git a/test/destructor/body_throw.cpp b/test/destructor/body_throw.cpp index c1afdba..436635c 100644 --- a/test/destructor/body_throw.cpp +++ b/test/destructor/body_throw.cpp @@ -1,5 +1,5 @@ -// Test destructor body throwing (in middle branch of inheritance tree). +// Test throw from destructor body (in middle branch of inheritance tree). #include "../aux_/oteststream.hpp" #include @@ -7,8 +7,6 @@ #include #include #include -#include -#include #include boost::contract::aux::test::oteststream out; @@ -17,7 +15,7 @@ struct c { static void static_invariant() { out << "c::static_inv" << std::endl; } void invariant() const { out << "c::inv" << std::endl; } - ~c() { + ~c() BOOST_NOEXCEPT_IF(false) { boost::contract::guard c = boost::contract::destructor(this) .old([&] { out << "c::dtor::old" << std::endl; }) .postcondition([] { out << "c::dtor::post" << std::endl; }) @@ -37,15 +35,15 @@ struct b static void static_invariant() { out << "b::static_inv" << std::endl; } void invariant() const { out << "b::inv" << std::endl; } - struct e {}; + struct err {}; - ~b() { + ~b() BOOST_NOEXCEPT_IF(false) { boost::contract::guard c = boost::contract::destructor(this) .old([&] { out << "b::dtor::old" << std::endl; }) .postcondition([] { out << "b::dtor::post" << std::endl; }) ; out << "b::dtor::body" << std::endl; - throw b::e(); // Test body throw (from inheritance mid branch). + throw b::err(); // Test body throw (from inheritance mid branch). } }; @@ -59,7 +57,7 @@ struct a static void static_invariant() { out << "a::static_inv" << std::endl; } void invariant() const { out << "a::inv" << std::endl; } - ~a() { + ~a() BOOST_NOEXCEPT_IF(false) { boost::contract::guard c = boost::contract::destructor(this) .old([&] { out << "a::dtor::old" << std::endl; }) .postcondition([] { out << "a::dtor::post" << std::endl; }) @@ -69,52 +67,45 @@ struct a } }; -void t() { - std::ostringstream ok; - ok.str(""); ok - << "a::static_inv" << std::endl - << "a::inv" << std::endl - << "a::dtor::old" << std::endl - << "a::dtor::body" << std::endl - << "a::static_inv" << std::endl - // Test a destructed (so only static_inv and post). - << "a::dtor::post" << std::endl - - << "b::static_inv" << std::endl - << "b::inv" << std::endl - << "b::dtor::old" << std::endl - << "b::dtor::body" << std::endl - -// TODO: Document this (even if dtors should never throw in C++ anyways...). -// Unfortunately, only Clang gets this right... Both MSVC and GCC seem to stop -// everything as soon as the destructor throws an exception... -#ifdef BOOST_CLANG - // Test b not destructed (so both static_inv and inv, but no post). - << "b::static_inv" << std::endl - << "b::inv" << std::endl - - << "c::static_inv" << std::endl - << "c::inv" << std::endl - << "c::dtor::old" << std::endl - << "c::dtor::body" << std::endl - // Test c not destructed (so both static_inv and inv, but no post). - << "c::static_inv" << std::endl - << "c::inv" << std::endl -#endif // BOOST_CLANG - - ; - BOOST_TEST(out.eq(ok.str())); - std::exit(boost::report_errors()); -} - int main() { - std::set_terminate(&t); // Must use terminate to handle dtor throw. - { - out.str(""); - a aa; - } // Call destructor (which calls t on throw). + std::ostringstream ok; + + try { + { + a aa; + out.str(""); + } + BOOST_TEST(false); + } catch(b::err const&) { + ok.str(""); ok + << "a::static_inv" << std::endl + << "a::inv" << std::endl + << "a::dtor::old" << std::endl + << "a::dtor::body" << std::endl + // Test a destructed (so only static_inv and post, but no inv). + << "a::static_inv" << std::endl + << "a::dtor::post" << std::endl + + << "b::static_inv" << std::endl + << "b::inv" << std::endl + << "b::dtor::old" << std::endl + << "b::dtor::body" << std::endl // Test this threw. + + // Test b not destructed (so both static_inv and inv, but no post). + << "b::static_inv" << std::endl + << "b::inv" << std::endl + + << "c::static_inv" << std::endl + << "c::inv" << std::endl + << "c::dtor::old" << std::endl + << "c::dtor::body" << std::endl + // Test c not destructed (so both static_inv and inv, but no post). + << "c::static_inv" << std::endl + << "c::inv" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + } catch(...) { BOOST_TEST(false); } - BOOST_TEST(false); // Must not exit from here, but from t. return boost::report_errors(); } diff --git a/test/destructor/old_throw.cpp b/test/destructor/old_throw.cpp new file mode 100644 index 0000000..c18cbbe --- /dev/null +++ b/test/destructor/old_throw.cpp @@ -0,0 +1,111 @@ + +// Test throw from destructor .old() (in middle branch of inheritance tree). + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct c { + static void static_invariant() { out << "c::static_inv" << std::endl; } + void invariant() const { out << "c::inv" << std::endl; } + + ~c() BOOST_NOEXCEPT_IF(false) { + boost::contract::guard c = boost::contract::destructor(this) + .old([&] { out << "c::dtor::old" << std::endl; }) + .postcondition([] { out << "c::dtor::post" << std::endl; }) + ; + out << "c::dtor::body" << std::endl; + // Do not throw (from inheritance root). + } +}; + +struct b + #define BASES public c + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + static void static_invariant() { out << "b::static_inv" << std::endl; } + void invariant() const { out << "b::inv" << std::endl; } + + struct err {}; + + ~b() BOOST_NOEXCEPT_IF(false) { + boost::contract::guard c = boost::contract::destructor(this) + .old([&] { + out << "b::dtor::old" << std::endl; + throw b::err(); // Test .old() throw (from mid branch). + }) + .postcondition([] { out << "b::dtor::post" << std::endl; }) + ; + out << "b::dtor::body" << std::endl; + } +}; + +struct a + #define BASES public b + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + static void static_invariant() { out << "a::static_inv" << std::endl; } + void invariant() const { out << "a::inv" << std::endl; } + + ~a() BOOST_NOEXCEPT_IF(false) { + boost::contract::guard c = boost::contract::destructor(this) + .old([&] { out << "a::dtor::old" << std::endl; }) + .postcondition([] { out << "a::dtor::post" << std::endl; }) + ; + out << "a::dtor::body" << std::endl; + // Do not throw (from inheritance leaf). + } +}; + +int main() { + std::ostringstream ok; + + boost::contract::set_postcondition_failed( + [] (boost::contract::from) { throw; }); + + try { + { + a aa; + out.str(""); + } + BOOST_TEST(false); + } catch(b::err const&) { + ok.str(""); ok + << "a::static_inv" << std::endl + << "a::inv" << std::endl + << "a::dtor::old" << std::endl + << "a::dtor::body" << std::endl + // Test a destructed (so only static_inv and post, but no inv). + << "a::static_inv" << std::endl + << "a::dtor::post" << std::endl + + << "b::static_inv" << std::endl + << "b::inv" << std::endl + << "b::dtor::old" << std::endl // Test this threw. + + << "c::static_inv" << std::endl + << "c::inv" << std::endl + << "c::dtor::old" << std::endl + << "c::dtor::body" << std::endl + // Test c not destructed (so both static_inv and inv, but no post). + << "c::static_inv" << std::endl + << "c::inv" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + } catch(...) { BOOST_TEST(false); } + + return boost::report_errors(); +} + diff --git a/test/function/body_throw.cpp b/test/function/body_throw.cpp index a3fbdcb..0924644 100644 --- a/test/function/body_throw.cpp +++ b/test/function/body_throw.cpp @@ -1,5 +1,5 @@ -// Test free function body throwing. +// Test throw from free function body. #include "../aux_/oteststream.hpp" #include @@ -9,7 +9,7 @@ boost::contract::aux::test::oteststream out; -struct e {}; +struct err {}; void f() { boost::contract::guard c = boost::contract::function() @@ -18,24 +18,24 @@ void f() { .postcondition([&] { out << "f::post" << std::endl; }) ; out << "f::body" << std::endl; - throw e(); // Test body throw. + throw err(); // Test body throws. } int main() { std::ostringstream ok; - bool threw = false; - out.str(""); - try { f(); } - catch(e const&) { threw = true; } - BOOST_TEST(threw); - ok.str(""); ok - << "f::pre" << std::endl - << "f::old" << std::endl - << "f::body" << std::endl - // Test no post because body threw. - ; - BOOST_TEST(out.eq(ok.str())); + try { + out.str(""); + f(); + BOOST_TEST(false); + } catch(err const&) { + ok.str(""); ok + << "f::pre" << std::endl + << "f::old" << std::endl + << "f::body" << std::endl // Test this threw. + ; + BOOST_TEST(out.eq(ok.str())); + } catch(...) { BOOST_TEST(false); } return boost::report_errors(); } diff --git a/test/function/old_throw.cpp b/test/function/old_throw.cpp new file mode 100644 index 0000000..52052dc --- /dev/null +++ b/test/function/old_throw.cpp @@ -0,0 +1,46 @@ + +// Test throw from free function .old(). + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct err {}; + +void f() { + boost::contract::guard c = boost::contract::function() + .precondition([&] { out << "f::pre" << std::endl; }) + .old([&] { + out << "f::old" << std::endl; + throw err(); // Test .old() throws. + }) + .postcondition([&] { out << "f::post" << std::endl; }) + ; + out << "f::body" << std::endl; +} + +int main() { + std::ostringstream ok; + + boost::contract::set_postcondition_failed( + [] (boost::contract::from) { throw; }); + + try { + out.str(""); + f(); + BOOST_TEST(false); + } catch(err const&) { + ok.str(""); ok + << "f::pre" << std::endl + << "f::old" << std::endl // Test this threw. + ; + BOOST_TEST(out.eq(ok.str())); + } catch(...) { BOOST_TEST(false); } + + return boost::report_errors(); +} + diff --git a/test/public_function/body_throw.cpp b/test/public_function/body_throw.cpp index 57e2888..9e625b8 100644 --- a/test/public_function/body_throw.cpp +++ b/test/public_function/body_throw.cpp @@ -1,5 +1,5 @@ -// Test constructor body throwing (in inheritance tree). +// Test from public function (derived) body. #include "../aux_/oteststream.hpp" #include @@ -16,7 +16,7 @@ struct c { static void static_invariant() { out << "c::static_inv" << std::endl; } void invariant() const { out << "c::inv" << std::endl; } - struct e {}; + struct err {}; virtual void f(boost::contract::virtual_* v = 0) { boost::contract::guard c = boost::contract::public_function(v, this) @@ -28,7 +28,7 @@ struct c { .postcondition([&] { out << "c::f::post" << std::endl; }) ; out << "c::f::body" << std::endl; - throw c::e(); + throw c::err(); // Test body throws. } }; @@ -42,7 +42,7 @@ struct b static void static_invariant() { out << "b::static_inv" << std::endl; } void invariant() const { out << "b::inv" << std::endl; } - struct e {}; + struct err {}; virtual void f(boost::contract::virtual_* v = 0) /* override */ { boost::contract::guard c = boost::contract::public_function( @@ -55,7 +55,7 @@ struct b .postcondition([&] { out << "b::f::post" << std::endl; }) ; out << "b::f::body" << std::endl; - throw b::e(); + throw b::err(); // Test body throws. } BOOST_CONTRACT_OVERRIDE(f) }; @@ -70,7 +70,7 @@ struct a static void static_invariant() { out << "a::static_inv" << std::endl; } void invariant() const { out << "a::inv" << std::endl; } - struct e {}; + struct err {}; void f(boost::contract::virtual_* v = 0) /* override */ { boost::contract::guard c = boost::contract::public_function( @@ -80,7 +80,7 @@ struct a .postcondition([&] { out << "a::f::post" << std::endl; }) ; out << "a::f::body" << std::endl; - throw a::e(); + throw a::err(); // Test body throws. } BOOST_CONTRACT_OVERRIDE(f) }; @@ -89,40 +89,40 @@ int main() { std::ostringstream ok; a aa; - c& ca = aa; // Test as virtual call via polymorphism. - bool threw = false; - out.str(""); - try { ca.f(); } - catch(a::e const&) { threw = true; } - BOOST_TEST(threw); - ok.str(""); ok - << "c::static_inv" << std::endl - << "c::inv" << std::endl - << "b::static_inv" << std::endl - << "b::inv" << std::endl - << "a::static_inv" << std::endl - << "a::inv" << std::endl + b& ba = aa; // Test as virtual call via polymorphism. + try { + out.str(""); + ba.f(); + BOOST_TEST(false); + } catch(a::err const&) { + ok.str(""); ok + << "c::static_inv" << std::endl + << "c::inv" << std::endl + << "b::static_inv" << std::endl + << "b::inv" << std::endl + << "a::static_inv" << std::endl + << "a::inv" << std::endl - << "c::f::pre" << std::endl - << "b::f::pre" << std::endl - << "a::f::pre" << std::endl - - << "c::f::old" << std::endl - << "b::f::old" << std::endl - << "a::f::old" << std::endl + << "c::f::pre" << std::endl + << "b::f::pre" << std::endl + << "a::f::pre" << std::endl + + << "c::f::old" << std::endl + << "b::f::old" << std::endl + << "a::f::old" << std::endl - << "a::f::body" << std::endl - - << "c::static_inv" << std::endl - << "c::inv" << std::endl - << "b::static_inv" << std::endl - << "b::inv" << std::endl - << "a::static_inv" << std::endl - << "a::inv" << std::endl - - // Test no post (but still subcontracted inv) because body threw. - ; - BOOST_TEST(out.eq(ok.str())); + << "a::f::body" << std::endl // Test this threw. + + // Test no post (but still subcontracted inv) because body threw. + << "c::static_inv" << std::endl + << "c::inv" << std::endl + << "b::static_inv" << std::endl + << "b::inv" << std::endl + << "a::static_inv" << std::endl + << "a::inv" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + } catch(...) { BOOST_TEST(false); } return boost::report_errors(); } diff --git a/test/public_function/old_throw.cpp b/test/public_function/old_throw.cpp new file mode 100644 index 0000000..32f2c41 --- /dev/null +++ b/test/public_function/old_throw.cpp @@ -0,0 +1,126 @@ + +// Test from public function (derived and bases) .old(). + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct c { + static void static_invariant() { out << "c::static_inv" << std::endl; } + void invariant() const { out << "c::inv" << std::endl; } + + struct err {}; + + virtual void f(boost::contract::virtual_* v = 0) { + boost::contract::guard c = boost::contract::public_function(v, this) + .precondition([&] { + out << "c::f::pre" << std::endl; + BOOST_CONTRACT_ASSERT(false); // To check derived pre. + }) + .old([&] { + out << "c::f::old" << std::endl; + throw c::err(); // Test .old() throws. + }) + .postcondition([&] { out << "c::f::post" << std::endl; }) + ; + out << "c::f::body" << std::endl; + } +}; + +struct b + #define BASES public c + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + static void static_invariant() { out << "b::static_inv" << std::endl; } + void invariant() const { out << "b::inv" << std::endl; } + + struct err {}; + + virtual void f(boost::contract::virtual_* v = 0) /* override */ { + boost::contract::guard c = boost::contract::public_function( + v, &b::f, this) + .precondition([&] { + out << "b::f::pre" << std::endl; + BOOST_CONTRACT_ASSERT(false); // To check derived pre. + }) + .old([&] { + out << "b::f::old" << std::endl; + throw b::err(); // Test .old() throws. + }) + .postcondition([&] { out << "b::f::post" << std::endl; }) + ; + out << "b::f::body" << std::endl; + } + BOOST_CONTRACT_OVERRIDE(f) +}; + +struct a + #define BASES public b + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + static void static_invariant() { out << "a::static_inv" << std::endl; } + void invariant() const { out << "a::inv" << std::endl; } + + struct err {}; + + void f(boost::contract::virtual_* v = 0) /* override */ { + boost::contract::guard c = boost::contract::public_function( + v, &a::f, this) + .precondition([&] { out << "a::f::pre" << std::endl; }) + .old([&] { + out << "a::f::old" << std::endl; + throw a::err(); // Test .old() throws. + }) + .postcondition([&] { out << "a::f::post" << std::endl; }) + ; + out << "a::f::body" << std::endl; + } + BOOST_CONTRACT_OVERRIDE(f) +}; + +int main() { + std::ostringstream ok; + + boost::contract::set_postcondition_failed( + [] (boost::contract::from) { throw; }); + + a aa; + b& ba = aa; // Test as virtual call via polymorphism. + try { + out.str(""); + ba.f(); + BOOST_TEST(false); + } catch(c::err const&) { + ok.str(""); ok + << "c::static_inv" << std::endl + << "c::inv" << std::endl + << "b::static_inv" << std::endl + << "b::inv" << std::endl + << "a::static_inv" << std::endl + << "a::inv" << std::endl + + << "c::f::pre" << std::endl + << "b::f::pre" << std::endl + << "a::f::pre" << std::endl + + << "c::f::old" << std::endl // Test this threw. + ; + BOOST_TEST(out.eq(ok.str())); + } catch(...) { BOOST_TEST(false); } + + return boost::report_errors(); +} +