diff --git a/TODO.txt b/TODO.txt index 1dcf5e0..c1dbe02 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,23 +1,15 @@ -DOCS --------------------------------------------------------------------------- - -* Add a comment to the docs that for multi-threading, a recursive (for - virtual calls?) scoped lock can appear before contract code. - -* Look at Andrzej's discussion on preconditions: - https://akrzemi1.wordpress.com/2013/01/04/preconditions-part-i/ - IMPLEMENTATION ----------------------------------------------------------------- * Should C++11 move preserve class invariants at exit and/or on throw? * If not, how I can program C++11 move operations with the lib? (If I user boost::contract::function then I don't check inv at entry...) -* Volatile members and class invariants. +-> Volatile members and class invariants. * Disable pre, post, and/or entry/exit inv (all combinations). -* Deep-search functions to override in base_types. +-> Deep-search functions to override in base_types. * And compiler-error if public_function does not find any function to actually override. @@ -27,7 +19,7 @@ IMPLEMENTATION ----------------------------------------------------------------- * What shall I do with unions... can/shall I contract them? Check-out which members C++11 unions can have (ctors, dtor, etc.). -* Make work the case a pure virtual uses boost::optional result but an +-> Make work the case a pure virtual uses boost::optional result but an overriding function uses just T result, and the other way around too. * What happens to OLDOF and related assertions if old-of expression type T @@ -45,11 +37,28 @@ IMPLEMENTATION ----------------------------------------------------------------- then... but maybe in these cases users can just BOOST_STATIC_ASSERT(has_oldof). -TESTING ------------------------------------------------------------------------ +-> Implement .old(..) + * Also if .old(...) throws, call contract failure handlers (more correct), + but if old declaration throws (including = BOOST_CONTRACT_OLDOF(...)) + function throws (less correct). + * Add .old(...) to all existing test? + * Add .old(...) to set/ tests. -* .old(...) - * I can add this to all existing tests... - * Also include in set/ tests. +* Library data (already checking guard, failure handlers, etc.). + * Move in src/ files (also re-design impl to move as much code as possible + (i.e., min templates) to src/ for faster compile-times. + * Thread safety (of lib's data if THREAD_SAFE #defined). + +-> If an overriding functions does not specify preconditions, make sure the + overridden preconditions are checked (and not that subcontracted + preconditions always pass just because the overriding function does not + specify them). + +-> Use boost::contract::old_ptr instead of shared_ptr for old-of types (so I + can later change this type in future rev of the library if I need to). Only + export operator-> and operator* (but not other shared_ptr operations). + +TESTING ------------------------------------------------------------------------ * Use MSVC 2013 (instead of MSVC 2010) * I should be able to use lambdas also in ctor templates member inits... @@ -63,6 +72,11 @@ TESTING ------------------------------------------------------------------------ * Test what happens if bodies throw (e.g., public func should check inv, dtor too, but ctor not, etc.)... test all contract types when bodies throw. + * Test what happens if old expr thros (with and without .old(...)). + +* Test subcontracting when: + * Overridden missing pre and/or post and/or inv. + * Overridden missing from direct parent, but found in grand parent. * Contracts disabled while checking contracts. * Add a test to disable/ similar to n1962/factorial.cpp, where the @@ -82,11 +96,6 @@ TESTING ------------------------------------------------------------------------ princ does not apply here because base protected virtual cannot be called by users so it cannot be "substituted")... what will this lib do? -* If an overriding functions does not specify preconditions, make sure the - overridden preconditions are checked (and not that subcontracted - preconditions always pass just because the overriding function does not - specify them). - * Test function and array argument types like: `void f(int x[2][3], int (*g)(int))` @@ -94,3 +103,15 @@ TESTING ------------------------------------------------------------------------ (e.g., between public_function(v, func_ptr, this) and public_function(v, &a::f, this), etc.). +DOCS --------------------------------------------------------------------------- + +* Add a comment to the docs that for multi-threading, a recursive (for + virtual calls?) scoped lock can appear before contract code. + +* Look at Andrzej's discussion on preconditions: + https://akrzemi1.wordpress.com/2013/01/04/preconditions-part-i/ + +* pre > old > post all optional, but when specified must be specified in that + order (rationale, this makes contract code more readable and simplify lib + impl.) + diff --git a/example/features/introduction.cpp b/example/features/introduction.cpp index 89980a3..ac889e1 100644 --- a/example/features/introduction.cpp +++ b/example/features/introduction.cpp @@ -16,12 +16,12 @@ class pushable; template class vector - #define BASES public pushable +# define BASES public pushable : BASES { public: typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // Subcontracting. - #undef BASES +# undef BASES void invariant() const { // Checked in AND with base class invariants. BOOST_CONTRACT_ASSERT(size() <= capacity()); // Line 27. @@ -29,9 +29,10 @@ public: virtual void push_back(T const& value, boost::contract::virtual_* v = 0) /* override */ { - auto old_size = BOOST_CONTRACT_OLDOF(v, size()); // Old values. - auto c = boost::contract::public_function( - v, &vector::push_back, this, value) + boost::contract::old_ptr old_size = + BOOST_CONTRACT_OLDOF(v, size()); // Old values. + boost::contract::guard c = boost::contract::public_function< + override_push_back>(v, &vector::push_back, this, value) .precondition([&] { // Checked in OR with base preconditions. BOOST_CONTRACT_ASSERT(size() < max_size()); // Line 36. }) diff --git a/example/features/no_macros.cpp b/example/features/no_macros.cpp index ff7da84..e8fbac9 100644 --- a/example/features/no_macros.cpp +++ b/example/features/no_macros.cpp @@ -5,10 +5,11 @@ class vector { public: void push_back(T const& value, boost::contract::virtual_* v = 0) // Program old-value without macros (pass extra `v` if virtual). - boost::shared_ptr old_size = - boost::contract::copy_old() ? size() : boost::contract::old(); + boost::contract::old_ptr old_size = boost::contract::make_old( + boost::contract::copy_old() ? size() : boost::contract::make_old() + ); - auto c = boost::contract::public_function(this) + boost::contract::guard c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == *old_size + 1); }) @@ -33,11 +34,12 @@ private: class identifiers { public: virtual void push_back(int id, boost::contract::virtual_* v = 0) - // Program old-value without macros with extra `v`. - boost::shared_ptr old_size = - boost::contract::copy_old(v) ? size() : boost::contract::old(); + // Program old-value without macros but with extra `v`. + boost::contract::old_ptr old_size = boost::contract::make_old(v, + boost::contract::copy_old(v) ? size() : boost::contract::make_old() + ); - auto c = boost::contract::public_function(this) + boost::contract::guard c = boost::contract::public_function(this) .postcondition([&] { BOOST_CONTRACT_ASSERT(size() == *old_size + 1); }) @@ -64,8 +66,10 @@ private: class multi_identifiers : private boost::contract::constructor_precondition, - public identifiers, public virtual pushable, - protected sizer, private capacitor + public identifiers, + public virtual pushable, + protected sizer, + private capacitor { public: // Program `base_types` without macros (list only public bases). diff --git a/include/boost/contract/aux_/check_guard.hpp b/include/boost/contract/aux_/check_guard.hpp index 7ea9185..2fd508a 100644 --- a/include/boost/contract/aux_/check_guard.hpp +++ b/include/boost/contract/aux_/check_guard.hpp @@ -2,38 +2,6 @@ #ifndef BOOST_CONTRACT_AUX_CHECK_GUARD_HPP_ #define BOOST_CONTRACT_AUX_CHECK_GUARD_HPP_ -#include -/** @cond */ -#include -#include -#include -/** @endcond */ - -/* PUBLIC */ - -// NOTE: These macros depend on their caller's code (e.g., has `base_call()`), -// but they are defined here to avoid code duplication at the callers' side. - -#define BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN \ - if(boost::contract::aux::check_guard::checking()) return; \ - boost::contract::aux::check_guard BOOST_CONTRACT_AUX_CHECKING_GUARD_VAR_; - -#define BOOST_CONTRACT_AUX_SUBCONTRACTED_CHECK_GUARD_OR_RETURN \ - boost::shared_ptr \ - BOOST_CONTRACT_AUX_CHECKING_GUARD_VAR_; \ - if(!this->base_call()) { \ - if(boost::contract::aux::check_guard::checking()) return; \ - BOOST_CONTRACT_AUX_CHECKING_GUARD_VAR_ = \ - boost::make_shared(); \ - } - -/* PRIVATE */ - -#define BOOST_CONTRACT_AUX_CHECKING_GUARD_VAR_ \ - BOOST_CONTRACT_AUX_NAME1(BOOST_PP_CAT(checking, __LINE__)) - -/* CODE */ - namespace boost { namespace contract { namespace aux { // TODO: Consider what to do with multi-threads... multi-reads/one-write locks diff --git a/include/boost/contract/aux_/condition/check_base.hpp b/include/boost/contract/aux_/condition/check_base.hpp new file mode 100644 index 0000000..358cd71 --- /dev/null +++ b/include/boost/contract/aux_/condition/check_base.hpp @@ -0,0 +1,69 @@ + +#ifndef BOOST_CONTRACT_AUX_CHECK_BASE_HPP_ +#define BOOST_CONTRACT_AUX_CHECK_BASE_HPP_ + +#include +/** @cond */ +#include // TODO: Can I reduce boost.function overhead? +#include +/** @endcond */ + +namespace boost { namespace contract { namespace aux { + +class check_base { // Base to hold all contract objects for RAII. +public: + explicit check_base(boost::contract::from from) : + BOOST_CONTRACT_ERROR_missing_guard_declaration(false), + from_(from) + {} + + virtual ~check_base() { assert_guarded(); } // Assert in case derived don't. + + void guard() { // Must be called by contract guard ctor. + BOOST_CONTRACT_ERROR_missing_guard_declaration = true; + this->init(); // All inits (pre, old, post) done after guard decl. + } + + void assert_guarded() { // Derived dtors should call this (earlier errors). + assert(BOOST_CONTRACT_ERROR_missing_guard_declaration); + } + + template + void set_pre(F const& f) { pre_ = f; } + + template + void set_old(F const& f) { old_ = f; } + +protected: + virtual void init() {} + + void check_pre(bool throw_on_failure = false) { + try { if(pre_) pre_(); } + catch(...) { + // Subcontracted pre must throw on failure (instead of + // calling failure handler) so to be checked in logic-or. + if(throw_on_failure) throw; + boost::contract::precondition_failed(from()); + } + } + + void copy_old() { + // TODO: Document that using .old calls failure handler, = OLDOF makes + // enclosing function throw instead, when old copy throws. + try { if(old_) old_(); } + catch(...) { boost::contract::postcondition_failed(from()); } + } + + boost::contract::from from() const { return from_; } + +private: + bool BOOST_CONTRACT_ERROR_missing_guard_declaration; + boost::contract::from from_; + boost::function pre_; + boost::function old_; +}; + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/aux_/condition/check_pre_only.hpp b/include/boost/contract/aux_/condition/check_pre_only.hpp deleted file mode 100644 index 965c643..0000000 --- a/include/boost/contract/aux_/condition/check_pre_only.hpp +++ /dev/null @@ -1,47 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_CHECK_PRE_ONLY_HPP_ -#define BOOST_CONTRACT_AUX_CHECK_PRE_ONLY_HPP_ - -#include -/** @cond */ -#include // TODO: Can I reduce boost.function overhead? -/** @endcond */ - -namespace boost { namespace contract { namespace aux { - -// Also used as base to hold all contract objects for RAII. -class check_pre_only { -public: - explicit check_pre_only(boost::contract::from from) : from_(from) {} - - virtual ~check_pre_only() {} - - template - void set_pre(F const& f) { pre_ = f; pre_available(); } - -protected: - void check_pre(bool throw_on_failure = false) { - if(pre_) { - try { pre_(); } - catch(...) { - // Subcontracted pre must throw on failure (instead of - // calling failure handler) so to be checked in logic-or. - if(throw_on_failure) throw; - boost::contract::precondition_failed(from()); - } - } - } - - virtual void pre_available() {} - - boost::contract::from from() const { return from_; } - -private: - boost::contract::from from_; - boost::function pre_; -}; - -} } } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/aux_/condition/check_pre_post.hpp b/include/boost/contract/aux_/condition/check_pre_post.hpp index 99c203b..52dfbff 100644 --- a/include/boost/contract/aux_/condition/check_pre_post.hpp +++ b/include/boost/contract/aux_/condition/check_pre_post.hpp @@ -2,10 +2,10 @@ #ifndef BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_ #define BOOST_CONTRACT_AUX_CHECK_PRE_POST_HPP_ -#include -#include +#include #include #include +#include /** @cond */ #include #include // TODO: Can I reduce boost.function overhead? @@ -24,17 +24,15 @@ namespace boost { namespace contract { namespace aux { // the base uses optional but the derived does not). Fix that. template -class check_pre_post : public check_pre_only { +class check_pre_post : public check_base { public: - explicit check_pre_post(boost::contract::from from) : - check_pre_only(from) {} + explicit check_pre_post(boost::contract::from from) : check_base(from) {} virtual ~check_pre_post() {} template void set_post(F const& f) { BOOST_CONTRACT_ERROR_postcondition_result_parameter_required = f; - post_available(); } protected: @@ -46,26 +44,22 @@ protected: } catch(...) { boost::contract::postcondition_failed(from()); } } - virtual void post_available() {} - private: boost::function - BOOST_CONTRACT_ERROR_postcondition_result_parameter_required; + BOOST_CONTRACT_ERROR_postcondition_result_parameter_required; }; // TODO: Try to limit code repetition between code below and above. template<> -class check_pre_post : public check_pre_only { +class check_pre_post : public check_base { public: - explicit check_pre_post(boost::contract::from from) : - check_pre_only(from) {} + explicit check_pre_post(boost::contract::from from) : check_base(from) {} virtual ~check_pre_post() {} template void set_post(F const& f) { BOOST_CONTRACT_ERROR_postcondition_result_parameter_not_allowed = f; - post_available(); } protected: @@ -79,11 +73,9 @@ protected: void check_post(none&) { check_post(); } - virtual void post_available() {} - private: boost::function - BOOST_CONTRACT_ERROR_postcondition_result_parameter_not_allowed; + BOOST_CONTRACT_ERROR_postcondition_result_parameter_not_allowed; }; } } } 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 d662b1a..0eeb19b 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 @@ -89,15 +89,15 @@ public: virtual ~check_subcontracted_pre_post_inv() { if(!base_call_ && v_) delete v_; } - + protected: - void copy_subcontracted_oldof() { - // Old values of overloading func. on stack (so no `f` for copy_oldof). - check(boost::contract::virtual_::copy_oldof); + void init_subcontracted_old() { + // Old values of overloaded func on stack (so no functor `f` here). + execute(boost::contract::virtual_::push_old_init); } void check_subcontracted_entry_inv() { - check(boost::contract::virtual_::check_entry_inv, + execute(boost::contract::virtual_::check_entry_inv, &check_subcontracted_pre_post_inv::check_entry_inv); } @@ -119,26 +119,47 @@ protected: } } + void copy_subcontracted_old() { + execute(boost::contract::virtual_::call_old_copy, + &check_subcontracted_pre_post_inv::copy_old_v); + } + void check_subcontracted_exit_inv() { - check(boost::contract::virtual_::check_exit_inv, + execute(boost::contract::virtual_::check_exit_inv, &check_subcontracted_pre_post_inv::check_exit_inv); } void check_subcontracted_post() { - check(boost::contract::virtual_::check_post, - &check_subcontracted_pre_post_inv::check_post_result); + execute(boost::contract::virtual_::check_post, + &check_subcontracted_pre_post_inv::check_post_v); } bool base_call() const { return base_call_; } private: - void check_post_result() { + void check_post_v() { + if(base_call_) { + boost::contract::virtual_::action_enum a = v_->action_; + v_->action_ = boost::contract::virtual_::pop_old_copy; + this->copy_old(); + v_->action_ = a; + } // Ternary op here avoids extra copy of R (because constructing a &). R& r = base_call_ ? *static_cast(v_->result_) : r_; this->check_post(r); } + + void copy_old_v() { + boost::contract::virtual_::action_enum a; + if(base_call_) { + a = v_->action_; + v_->action_ = boost::contract::virtual_::push_old_copy; + } + this->copy_old(); + if(base_call_) v_->action_ = a; + } - void check(boost::contract::virtual_::action_enum a, + void execute(boost::contract::virtual_::action_enum a, void (check_subcontracted_pre_post_inv::* f)() = 0) { if(!base_call_ || v_->action_ == a) { if(v_) { diff --git a/include/boost/contract/aux_/operation/constructor.hpp b/include/boost/contract/aux_/operation/constructor.hpp index 90a36a6..729458a 100644 --- a/include/boost/contract/aux_/operation/constructor.hpp +++ b/include/boost/contract/aux_/operation/constructor.hpp @@ -16,17 +16,28 @@ namespace boost { namespace contract { namespace aux { template class constructor : public check_pre_post_inv { public: - explicit constructor(C* obj) : check_pre_post_inv( - boost::contract::from_constructor, obj) { - BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN - // No object before ctor body so check only static inv at entry. - this->check_entry_static_inv(); + explicit constructor(C* obj) : + check_pre_post_inv(boost::contract::from_constructor, + obj) + {} + +private: + void init() /* override */ { + if(check_guard::checking()) return; + { + check_guard checking; + this->check_entry_static_inv(); + // No object before ctor body so check only static inv at entry. + // Ctor pre checked by constructor_precondition. + } + this->copy_old(); } - // Ctor pre checked by constructor_precondition at start of init list. - +public: ~constructor() { - BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN + this->assert_guarded(); + if(check_guard::checking()) return; + check_guard checking; // If ctor body threw, no obj so check only static inv. Otherwise, obj // constructed so check static inv, non-static inv, and post. if(std::uncaught_exception()) { diff --git a/include/boost/contract/aux_/operation/destructor.hpp b/include/boost/contract/aux_/operation/destructor.hpp index 282c9ea..1e918a6 100644 --- a/include/boost/contract/aux_/operation/destructor.hpp +++ b/include/boost/contract/aux_/operation/destructor.hpp @@ -19,16 +19,25 @@ public: explicit destructor(C* obj) : check_pre_post_inv( boost::contract::from_destructor, obj) - { - BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN - // Obj exists (before dtor body) so check static and non-static inv. - this->check_entry_inv(); - } + {} - // Dtor cannot have pre because it has no parameters. +private: + void init() /* override */ { + if(check_guard::checking()) return; + { + check_guard checking; + // Obj exists (before dtor body) so check static and non-static inv. + this->check_entry_inv(); + // Dtor cannot have pre because it has no parameters. + } + this->copy_old(); + } +public: ~destructor() { - BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN + this->assert_guarded(); + if(check_guard::checking()) return; + check_guard checking; // If dtor body threw, obj still exists so check subcontracted static // and non-static inv (but no post because of throw). Otherwise, obj // destructed so check static inv and post (even if there is no obj diff --git a/include/boost/contract/aux_/operation/function.hpp b/include/boost/contract/aux_/operation/function.hpp index 99e4635..908947a 100644 --- a/include/boost/contract/aux_/operation/function.hpp +++ b/include/boost/contract/aux_/operation/function.hpp @@ -5,7 +5,6 @@ #include #include #include -#include /** @cond */ #include #include @@ -16,18 +15,25 @@ namespace boost { namespace contract { namespace aux { // Used for free function, private and protected member functions. class function : public check_pre_post { public: - explicit function() : check_pre_post( - boost::contract::from_function) {} + explicit function() : + check_pre_post(boost::contract::from_function) + {} private: - void pre_available() /* override */ { - BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN - this->check_pre(); + void init() /* override */ { + if(check_guard::checking()) return; + { + check_guard checking; + this->check_pre(); + } + this->copy_old(); } public: ~function() { - BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN + this->assert_guarded(); + if(check_guard::checking()) return; + check_guard checking; if(!std::uncaught_exception()) this->check_post(); } }; diff --git a/include/boost/contract/aux_/operation/public_function.hpp b/include/boost/contract/aux_/operation/public_function.hpp index 63b605b..d48b89a 100644 --- a/include/boost/contract/aux_/operation/public_function.hpp +++ b/include/boost/contract/aux_/operation/public_function.hpp @@ -16,36 +16,38 @@ template class public_function : public check_subcontracted_pre_post_inv { public: - explicit public_function( - boost::contract::virtual_* v, C* obj, R& r, A0& a0, A1& a1) : + explicit public_function(boost::contract::virtual_* v, C* obj, R& r, + A0& a0, A1& a1) : check_subcontracted_pre_post_inv( boost::contract::from_function, v, obj, r, a0, a1) - { - BOOST_CONTRACT_AUX_SUBCONTRACTED_CHECK_GUARD_OR_RETURN - this->copy_subcontracted_oldof(); - this->check_subcontracted_entry_inv(); - if(this->base_call()) { // Throw no_error so not in dtor. - this->check_subcontracted_exit_inv(); - } - } + {} private: - void pre_available() /* override */ { - BOOST_CONTRACT_AUX_SUBCONTRACTED_CHECK_GUARD_OR_RETURN - this->check_subcontracted_pre(); - } - - void post_available() /* override */ { - BOOST_CONTRACT_AUX_SUBCONTRACTED_CHECK_GUARD_OR_RETURN - if(this->base_call() && !std::uncaught_exception()) { - this->check_subcontracted_post(); // Throw no_error so not in dtor. + void init() /* override */ { + this->init_subcontracted_old(); + if(!this->base_call()) { + if(check_guard::checking()) return; + { + check_guard checking; + this->check_subcontracted_entry_inv(); + this->check_subcontracted_pre(); + } + this->copy_subcontracted_old(); + } else { + this->check_subcontracted_entry_inv(); + this->check_subcontracted_pre(); + this->copy_subcontracted_old(); + this->check_subcontracted_exit_inv(); + if(!std::uncaught_exception()) this->check_subcontracted_post(); } } - + public: ~public_function() { - BOOST_CONTRACT_AUX_SUBCONTRACTED_CHECK_GUARD_OR_RETURN + this->assert_guarded(); if(!this->base_call()) { + if(check_guard::checking()) return; + check_guard checking; this->check_subcontracted_exit_inv(); if(!std::uncaught_exception()) this->check_subcontracted_post(); } diff --git a/include/boost/contract/aux_/operation/public_static_function.hpp b/include/boost/contract/aux_/operation/public_static_function.hpp index 34ff899..68aad76 100644 --- a/include/boost/contract/aux_/operation/public_static_function.hpp +++ b/include/boost/contract/aux_/operation/public_static_function.hpp @@ -16,23 +16,29 @@ namespace boost { namespace contract { namespace aux { // No subcontracting because static so no obj and no substitution principle. template -class public_static_function : public check_pre_post_inv { +class public_static_function : public check_pre_post_inv { public: - explicit public_static_function() : check_pre_post_inv( - boost::contract::from_function, /* obj = */ 0) { - BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN - this->check_entry_static_inv(); - } + explicit public_static_function() : + check_pre_post_inv(boost::contract::from_function, + /* obj = */ 0) + {} private: - void pre_available() /* override */ { - BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN - this->check_pre(); + void init() /* override */ { + if(check_guard::checking()) return; + { + check_guard checking; + this->check_entry_static_inv(); + this->check_pre(); + } + this->copy_old(); } public: ~public_static_function() { - BOOST_CONTRACT_AUX_CHECK_GUARD_OR_RETURN + this->assert_guarded(); + if(check_guard::checking()) return; + check_guard checking; this->check_exit_static_inv(); if(!std::uncaught_exception()) this->check_post(); } diff --git a/include/boost/contract/constructor.hpp b/include/boost/contract/constructor.hpp index 6b6eb4f..84931a3 100644 --- a/include/boost/contract/constructor.hpp +++ b/include/boost/contract/constructor.hpp @@ -4,7 +4,7 @@ /** @file */ -#include +#include #include #include /** @cond */ @@ -14,8 +14,8 @@ namespace boost { namespace contract { template -set_postcondition_only<> constructor(C* obj) { - return set_postcondition_only<>(boost::make_shared< +set_old_postcondition<> constructor(C* obj) { + return set_old_postcondition<>(boost::make_shared< boost::contract::aux::constructor >(obj)); } diff --git a/include/boost/contract/core/set_nothing.hpp b/include/boost/contract/core/set_nothing.hpp index e0c8e75..2eb75a1 100644 --- a/include/boost/contract/core/set_nothing.hpp +++ b/include/boost/contract/core/set_nothing.hpp @@ -4,10 +4,23 @@ /** @file */ -#include +#include /** @cond */ #include /** @endcond */ + +namespace boost { + namespace contract { + template + class set_precondition_old_postcondition; + + template + class set_old_postcondition; + + template + class set_postcondition_only; + } +} namespace boost { namespace contract { @@ -21,15 +34,18 @@ public: // No set member functions here. private: - typedef boost::shared_ptr check_ptr; - - explicit set_nothing(check_ptr check) : check_(check) {} - + typedef boost::shared_ptr check_ptr; + explicit set_nothing(check_ptr check): check_(check) {} check_ptr check_; // Friendship used to limit library's public API. friend class guard; - friend class set_precondition_only; + + template + friend class set_precondition_old_postcondition; + + template + friend class set_old_postcondition; template friend class set_postcondition_only; diff --git a/include/boost/contract/core/set_old_postcondition.hpp b/include/boost/contract/core/set_old_postcondition.hpp new file mode 100644 index 0000000..b7cdd5e --- /dev/null +++ b/include/boost/contract/core/set_old_postcondition.hpp @@ -0,0 +1,59 @@ + +#ifndef BOOST_CONTRACT_SET_OLD_POSTCONDITION_HPP_ +#define BOOST_CONTRACT_SET_OLD_POSTCONDITION_HPP_ + +/** @file */ + +#include +#include +#include +#include +/** @cond */ +#include +/** @endcond */ + +namespace boost { + namespace contract { + template + class set_precondition_old_postcondition; + } +} + +namespace boost { namespace contract { + +template +class set_old_postcondition { // Copyable as shared * (OK also for RAII). +public: + template + set_postcondition_only old(F const& f) { + check_->set_old(f); + return set_postcondition_only(check_); + } + + template + set_nothing postcondition(F const& f) { + check_->set_post(f); + return set_nothing(check_); + } + +private: + typedef boost::shared_ptr::type> > check_ptr; + explicit set_old_postcondition(check_ptr check) : check_(check) {} + check_ptr check_; + + // Friendship used to limit library's public API. + friend class guard; + friend class set_precondition_old_postcondition; + + template + friend set_old_postcondition constructor(C*); + + template + friend set_old_postcondition destructor(C*); +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/core/set_postcondition_only.hpp b/include/boost/contract/core/set_postcondition_only.hpp index 9623348..01da1e7 100644 --- a/include/boost/contract/core/set_postcondition_only.hpp +++ b/include/boost/contract/core/set_postcondition_only.hpp @@ -1,6 +1,6 @@ -#ifndef BOOST_CONTRACT_SET_POSTCONDITION_HPP_ -#define BOOST_CONTRACT_SET_POSTCONDITION_HPP_ +#ifndef BOOST_CONTRACT_SET_POSTCONDITION_ONLY_HPP_ +#define BOOST_CONTRACT_SET_POSTCONDITION_ONLY_HPP_ /** @file */ @@ -13,8 +13,11 @@ namespace boost { namespace contract { - template - class set_precondition_postcondition; + template + class set_precondition_old_postcondition; + + template + class set_old_postcondition; } } @@ -32,20 +35,13 @@ public: private: typedef boost::shared_ptr::type> > check_ptr; - explicit set_postcondition_only(check_ptr check) : check_(check) {} - check_ptr check_; // Friendship used to limit library's public API. friend class guard; - friend class set_precondition_postcondition; - - template - friend set_postcondition_only constructor(C*); - - template - friend set_postcondition_only destructor(C*); + friend class set_precondition_old_postcondition; + friend class set_old_postcondition; }; } } // namespace diff --git a/include/boost/contract/core/set_precondition_postcondition.hpp b/include/boost/contract/core/set_precondition_old_postcondition.hpp similarity index 55% rename from include/boost/contract/core/set_precondition_postcondition.hpp rename to include/boost/contract/core/set_precondition_old_postcondition.hpp index 6c05ced..c2afc1b 100644 --- a/include/boost/contract/core/set_precondition_postcondition.hpp +++ b/include/boost/contract/core/set_precondition_old_postcondition.hpp @@ -1,11 +1,12 @@ -#ifndef BOOST_CONTRACT_SET_PRECONDITION_POSTCONDITION_HPP_ -#define BOOST_CONTRACT_SET_PRECONDITION_POSTCONDITION_HPP_ +#ifndef BOOST_CONTRACT_SET_PRECONDITION_OLD_POSTCONDITION_HPP_ +#define BOOST_CONTRACT_SET_PRECONDITION_OLD_POSTCONDITION_HPP_ /** @file */ -#include +#include #include +#include #include #include /** @cond */ @@ -23,73 +24,80 @@ namespace boost { namespace boost { namespace contract { template -class set_precondition_postcondition { // Copyable as shared * (OK for RAII). +class set_precondition_old_postcondition { // Copy as shared * (OK for RAII). public: template - set_postcondition_only precondition(F const& f) { + set_old_postcondition precondition(F const& f) { check_->set_pre(f); + return set_old_postcondition(check_); + } + + template + set_postcondition_only old(F const& f) { + check_->set_old(f); return set_postcondition_only(check_); } template - set_precondition_only postcondition(F const& f) { + set_nothing postcondition(F const& f) { check_->set_post(f); - return set_precondition_only(check_); + return set_nothing(check_); } private: typedef boost::shared_ptr::type> > check_ptr; - - explicit set_precondition_postcondition(check_ptr check) : check_(check) {} - + explicit set_precondition_old_postcondition(check_ptr check) : + check_(check) {} check_ptr check_; // Friendship used to limit library's public API. friend class guard; - friend set_precondition_postcondition<> function(); + + friend set_precondition_old_postcondition<> function(); template - friend set_precondition_postcondition<> public_function(); + friend set_precondition_old_postcondition<> public_function(); template - friend set_precondition_postcondition<> public_function(C*); + friend set_precondition_old_postcondition<> public_function(C*); template - friend set_precondition_postcondition<> public_function(virtual_*, C*); + friend set_precondition_old_postcondition<> public_function(virtual_*, C*); template - friend set_precondition_postcondition public_function( + friend set_precondition_old_postcondition public_function( virtual_*, R_&, C*); /* arity = 0 */ template - friend set_precondition_postcondition<> public_function(virtual_*, F, C*); + friend set_precondition_old_postcondition<> public_function( + virtual_*, F, C*); template - friend set_precondition_postcondition public_function( + friend set_precondition_old_postcondition public_function( virtual_*, R_&, F, C*); /* arity = 1 */ template - friend set_precondition_postcondition<> public_function( + friend set_precondition_old_postcondition<> public_function( virtual_*, F, C*, A0&); template - friend set_precondition_postcondition public_function( + friend set_precondition_old_postcondition public_function( virtual_*, R_&, F, C*, A0&); /* arity = 2 */ template - friend set_precondition_postcondition<> public_function( + friend set_precondition_old_postcondition<> public_function( virtual_*, F, C*, A0&, A1&); template - friend set_precondition_postcondition public_function( + friend set_precondition_old_postcondition public_function( virtual_*, R_&, F, C*, A0&, A1&); // TODO: Support configurable arity. diff --git a/include/boost/contract/core/set_precondition_only.hpp b/include/boost/contract/core/set_precondition_only.hpp deleted file mode 100644 index a36ec52..0000000 --- a/include/boost/contract/core/set_precondition_only.hpp +++ /dev/null @@ -1,40 +0,0 @@ - -#ifndef BOOST_CONTRACT_SET_PRECONDITION_HPP_ -#define BOOST_CONTRACT_SET_PRECONDITION_HPP_ - -/** @file */ - -#include -#include -/** @cond */ -#include -/** @endcond */ - -namespace boost { namespace contract { - -class set_precondition_only { // Copyable as shared * (OK also for RAII). -public: - template - set_nothing precondition(F const& f) { - check_->set_pre(f); - return set_nothing(check_); - } - -private: - typedef boost::shared_ptr check_ptr; - - explicit set_precondition_only(check_ptr check) : check_(check) {} - - check_ptr check_; - - // Friendship used to limit library's public API. - friend class guard; - - template - friend class set_precondition_postcondition; -}; - -} } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/core/virtual.hpp b/include/boost/contract/core/virtual.hpp index bd72ca6..00f54a7 100644 --- a/include/boost/contract/core/virtual.hpp +++ b/include/boost/contract/core/virtual.hpp @@ -6,6 +6,7 @@ #include #include #include +#include /** @endcond */ namespace boost { @@ -25,17 +26,22 @@ private: enum action_enum { // virtual_ always hold/passed by ptr so null ptr used for user call. no_action, - copy_oldof, + push_old_init, check_entry_inv, check_pre, + call_old_copy, + push_old_copy, + check_exit_inv, + pop_old_copy, check_post, - check_exit_inv + pop_old_init = check_post // These must be the same value. }; - explicit virtual_(action_enum a) : action_(a), old_values_() {} + explicit virtual_(action_enum a) : action_(a) {} action_enum action_; - std::queue > old_values_; + std::queue > old_inits_; + std::stack > old_copies_; void* result_; // Friendship used to limit library's public API. diff --git a/include/boost/contract/destructor.hpp b/include/boost/contract/destructor.hpp index b509b73..867e79b 100644 --- a/include/boost/contract/destructor.hpp +++ b/include/boost/contract/destructor.hpp @@ -4,7 +4,7 @@ /** @file */ -#include +#include #include /** @cond */ #include @@ -13,8 +13,8 @@ namespace boost { namespace contract { template -set_postcondition_only<> destructor(C* obj) { - return set_postcondition_only<>(boost::make_shared< +set_old_postcondition<> destructor(C* obj) { + return set_old_postcondition<>(boost::make_shared< boost::contract::aux::destructor >(obj)); } diff --git a/include/boost/contract/function.hpp b/include/boost/contract/function.hpp index c36f945..87c3083 100644 --- a/include/boost/contract/function.hpp +++ b/include/boost/contract/function.hpp @@ -4,7 +4,7 @@ /** @file */ -#include +#include #include /** @cond */ #include @@ -12,8 +12,8 @@ namespace boost { namespace contract { -set_precondition_postcondition<> function() { - return set_precondition_postcondition<>(boost::make_shared< +set_precondition_old_postcondition<> function() { + return set_precondition_old_postcondition<>(boost::make_shared< boost::contract::aux::function>()); } diff --git a/include/boost/contract/guard.hpp b/include/boost/contract/guard.hpp index dc6d718..071efea 100644 --- a/include/boost/contract/guard.hpp +++ b/include/boost/contract/guard.hpp @@ -4,11 +4,11 @@ /** @file */ -#include -#include +#include +#include #include #include -#include +#include /** @cond */ #include #include @@ -21,21 +21,22 @@ public: // All implicit to allow `guard c = ...`. template - /* implicit */ guard(set_precondition_postcondition const& contract) : - check_(contract.check_) {} - - /* implicit */ guard(set_precondition_only const& contract) : - check_(contract.check_) {} + /* implicit */ guard(set_precondition_old_postcondition const& contract) + : check_(contract.check_) { check_->guard(); } template - /* implicit */ guard(set_postcondition_only const& contract) : - check_(contract.check_) {} + /* implicit */ guard(set_old_postcondition const& contract) + : check_(contract.check_) { check_->guard(); } - /* implicit */ guard(set_nothing const& contract) : - check_(contract.check_) {} + template + /* implicit */ guard(set_postcondition_only const& contract) + : check_(contract.check_) { check_->guard(); } + + /* implicit */ guard(set_nothing const& contract) + : check_(contract.check_) { check_->guard(); } private: - boost::shared_ptr check_; + boost::shared_ptr check_; }; } } // namespace diff --git a/include/boost/contract/oldof.hpp b/include/boost/contract/oldof.hpp index fdc593c..2c04598 100644 --- a/include/boost/contract/oldof.hpp +++ b/include/boost/contract/oldof.hpp @@ -4,6 +4,7 @@ /** @file */ +#include #include #include #include @@ -28,7 +29,9 @@ BOOST_CONTRACT_ERROR_macro_OLDOF_requires_variadic_macros_otherwise_manually_pro /** @endcond */ // TODO: Consider providing an .old(...) setter for all contracts that will be -// called to copy old-values before body execution but after pre/inv. +// called to copy old-values before body execution but after pre/inv, and will +// call postcondition failure handler in case oldof calc throws (instead of +// making function throw). /* PUBLIC */ @@ -45,24 +48,24 @@ BOOST_CONTRACT_ERROR_macro_OLDOF_has_invalid_number_of_arguments_, \ #define BOOST_CONTRACT_ERROR_macro_OLDOF_has_invalid_number_of_arguments_1( \ value) \ - BOOST_CONTRACT_OLDOF_AUTO_(value)(boost::contract::old( \ + BOOST_CONTRACT_OLDOF_AUTO_TYPEOF_(value)(boost::contract::old( \ boost::contract::copy_old() ? (value) : boost::contract::old() \ )) #define BOOST_CONTRACT_ERROR_macro_OLDOF_has_invalid_number_of_arguments_2( \ v, value) \ - BOOST_CONTRACT_OLDOF_AUTO_(value)(boost::contract::old(v, \ + BOOST_CONTRACT_OLDOF_AUTO_TYPEOF_(value)(boost::contract::old(v, \ boost::contract::copy_old(v) ? (value) : boost::contract::old() \ )) #ifdef BOOST_NO_CXX11_AUTO_DECLARATIONS -# define BOOST_CONTRACT_OLDOF_AUTO_(value) /* nothing */ +# define BOOST_CONTRACT_OLDOF_AUTO_TYPEOF_(value) /* nothing */ #else /** @cond */ # include /** @endcond */ // Explicitly force shared_ptr conversion to allow for C++11 auto decl. -# define BOOST_CONTRACT_OLDOF_AUTO_(value) \ +# define BOOST_CONTRACT_OLDOF_AUTO_TYPEOF_(value) \ boost::shared_ptr #endif @@ -73,7 +76,7 @@ BOOST_CONTRACT_ERROR_macro_OLDOF_has_invalid_number_of_arguments_, \ namespace boost { namespace contract { bool copy_old() { -#ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS +#if BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS return false; // Post checking disabled, so never copy old values. #else return !boost::contract::aux::check_guard::checking(); @@ -81,14 +84,63 @@ bool copy_old() { } bool copy_old(virtual_* v) { -#ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS +#if BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS return false; // Post checking disabled, so never copy old values. #else - if(v) return v->action_ == boost::contract::virtual_::copy_oldof; - else return !boost::contract::aux::check_guard::checking(); + if(!v) return !boost::contract::aux::check_guard::checking(); + return v->action_ == boost::contract::virtual_::push_old_init || + v->action_ == boost::contract::virtual_::push_old_copy; #endif } +// TODO: Rename this make_old (that is is different from .old(...)) and add +// old_ptr so with and without macros: +// auto x = BOOST_CONTRACT_OLDOF(v, x); +// old_ptr x = BOOST_CONTRACT_OLDOF(v, x); +// old_ptr x = make_old(v, copy_old(v) ? x : make_old()); +// plus, make_old() return old_erasure type without operator old_ptr so +// following correctly gives compiler error: +// old_ptr = copy_old(v) ? x : make_old(); +// +// template +// class old_ptr { +// public: +// T const& operator*() const; +// T const* operator->() const; +// +// private: +// boost::shared_ptr ptr_; +// }; +// +// class old_erasure { +// public: +// // Implicitly called by using ternary operator `... ? ... : make_old()`. +// template +// /* implicit */ old_erasure(T const& old); +// +// friend old_erasure make_old() { return old_erasure(); } +// +// private: +// explicit old_erasure(); +// }; +// +// class old_unerasure { +// public: +// // Implicitly called by constructor init `old_ptr old_x = ...`. +// template +// operator old_ptr(); +// +// friend old_unerasure make_old(old_erasure const& old) { +// return old_unerasure(0, old); +// } +// +// friend old_unerasure make_old(virtual_* v, old_erasure const& old) { +// return old_unerasure(v, old); +// } +// +// private: +// explicit old_unerasure(virtual_* v, old_erasure const& old); +// }; class old { // Copyable (as *). public: explicit old() : v_(0), value_() {} @@ -113,15 +165,30 @@ public: boost::static_pointer_cast(value_); BOOST_CONTRACT_AUX_DEBUG(old_value); return old_value; - } else if(v_->action_ == boost::contract::virtual_::copy_oldof) { + } else if(v_->action_ == boost::contract::virtual_::push_old_init || + v_->action_ == boost::contract::virtual_::push_old_copy) { BOOST_CONTRACT_AUX_DEBUG(value_); - v_->old_values_.push(value_); + if(v_->action_ == boost::contract::virtual_::push_old_init) { + v_->old_inits_.push(value_); + } else { + v_->old_copies_.push(value_); + } return boost::shared_ptr(); - } else if(v_->action_ == boost::contract::virtual_::check_post) { + } else if(v_->action_ == boost::contract::virtual_::pop_old_init || + v_->action_ == boost::contract::virtual_::pop_old_copy) { BOOST_CONTRACT_AUX_DEBUG(!value_); - boost::shared_ptr value = v_->old_values_.front(); + boost::shared_ptr value; + if(v_->action_ == boost::contract::virtual_::pop_old_init) { + value = v_->old_inits_.front(); + } else { + value = v_->old_copies_.top(); + } BOOST_CONTRACT_AUX_DEBUG(value); - v_->old_values_.pop(); + if(v_->action_ == boost::contract::virtual_::pop_old_init) { + v_->old_inits_.pop(); + } else { + v_->old_copies_.pop(); + } boost::shared_ptr old_value = boost::static_pointer_cast(value); BOOST_CONTRACT_AUX_DEBUG(old_value); diff --git a/include/boost/contract/public_function.hpp b/include/boost/contract/public_function.hpp index bb3887a..7c442e6 100644 --- a/include/boost/contract/public_function.hpp +++ b/include/boost/contract/public_function.hpp @@ -4,7 +4,7 @@ /** @file */ -#include +#include #include #include #include @@ -76,15 +76,15 @@ namespace public_function_ { // For static member functions. template -set_precondition_postcondition<> public_function() { - return set_precondition_postcondition<>(boost::make_shared< +set_precondition_old_postcondition<> public_function() { + return set_precondition_old_postcondition<>(boost::make_shared< boost::contract::aux::public_static_function >()); } // For non-virtual, non-overriding member functions. template -set_precondition_postcondition<> public_function(C* obj) { - return set_precondition_postcondition<>(boost::make_shared< +set_precondition_old_postcondition<> public_function(C* obj) { + return set_precondition_old_postcondition<>(boost::make_shared< boost::contract::aux::public_function< boost::contract::aux::none, boost::contract::aux::none, @@ -115,9 +115,9 @@ set_precondition_postcondition<> public_function(C* obj) { // For virtual, non-overriding, void function. template -set_precondition_postcondition<> public_function(virtual_* v, C* obj) { +set_precondition_old_postcondition<> public_function(virtual_* v, C* obj) { // NOTE: No F so cannot enforce enclosing function is void (up to user). - return set_precondition_postcondition<>(boost::make_shared< + return set_precondition_old_postcondition<>(boost::make_shared< boost::contract::aux::public_function< boost::contract::aux::none, boost::contract::aux::none, @@ -131,9 +131,10 @@ set_precondition_postcondition<> public_function(virtual_* v, C* obj) { // For virtual, non-overriding, non-void member functions. template -set_precondition_postcondition public_function(virtual_* v, R& r, C* obj) { +set_precondition_old_postcondition public_function( + virtual_* v, R& r, C* obj) { // NOTE: No F so cannot enforce enclosing function returns R (up to user). - return set_precondition_postcondition(boost::make_shared< + return set_precondition_old_postcondition(boost::make_shared< boost::contract::aux::public_function< boost::contract::aux::none, R, @@ -149,11 +150,11 @@ set_precondition_postcondition public_function(virtual_* v, R& r, C* obj) { // For virtual, overriding, void member functions. template -set_precondition_postcondition<> public_function(virtual_* v, F, C* obj) { +set_precondition_old_postcondition<> public_function(virtual_* v, F, C* obj) { BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 0) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_VOID_RESULT_(F) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) - return set_precondition_postcondition<>(boost::make_shared< + return set_precondition_old_postcondition<>(boost::make_shared< boost::contract::aux::public_function< O, boost::contract::aux::none, @@ -167,12 +168,12 @@ set_precondition_postcondition<> public_function(virtual_* v, F, C* obj) { // For virtual, overriding, non-void member functions of class with bases. template -set_precondition_postcondition public_function( +set_precondition_old_postcondition public_function( virtual_* v, R& r, F, C* obj) { BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 0) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_RESULT_(F, R) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) - return set_precondition_postcondition(boost::make_shared< + return set_precondition_old_postcondition(boost::make_shared< boost::contract::aux::public_function< O, R, @@ -187,12 +188,12 @@ set_precondition_postcondition public_function( /* Overriding (arity = 1) */ template -set_precondition_postcondition<> public_function( +set_precondition_old_postcondition<> public_function( virtual_* v, F, C* obj, A0& a0) { BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 1) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_VOID_RESULT_(F) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) - return set_precondition_postcondition<>(boost::make_shared< + return set_precondition_old_postcondition<>(boost::make_shared< boost::contract::aux::public_function< O, boost::contract::aux::none, @@ -205,12 +206,12 @@ set_precondition_postcondition<> public_function( } template -set_precondition_postcondition public_function( +set_precondition_old_postcondition public_function( virtual_* v, R& r, F, C* obj, A0& a0) { BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 1) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_RESULT_(F, R) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) - return set_precondition_postcondition(boost::make_shared< + return set_precondition_old_postcondition(boost::make_shared< boost::contract::aux::public_function< O, R, @@ -224,12 +225,12 @@ set_precondition_postcondition public_function( /* Overriding (arity = 2) */ template -set_precondition_postcondition<> public_function( +set_precondition_old_postcondition<> public_function( virtual_* v, F, C* obj, A0& a0, A1& a1) { BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 2) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_VOID_RESULT_(F) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) - return set_precondition_postcondition<>(boost::make_shared< + return set_precondition_old_postcondition<>(boost::make_shared< boost::contract::aux::public_function< O, boost::contract::aux::none, @@ -241,12 +242,12 @@ set_precondition_postcondition<> public_function( } template -set_precondition_postcondition public_function( +set_precondition_old_postcondition public_function( virtual_* v, R& r, F, C* obj, A0& a0, A1& a1) { BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_ARITY(F, 2) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_RESULT_(F, R) BOOST_CONTRACT_PUBLIC_FUNCTION_HAS_BASE_TYPES_(C) - return set_precondition_postcondition(boost::make_shared< + return set_precondition_old_postcondition(boost::make_shared< boost::contract::aux::public_function< O, R, diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a2d9bd9..f44c18b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -31,14 +31,16 @@ test-suite disable : test-suite set : [ subdir-run set : nothing ] - [ subdir-run set : pre_only ] - [ subdir-run set : post_only ] - [ subdir-run set : pre_post ] - [ subdir-run set : post_pre ] - [ subdir-compile-fail set : pre_pre-error ] - [ subdir-compile-fail set : post_post-error ] - [ subdir-compile-fail set : pre_post_pre-error ] - [ subdir-compile-fail set : post_pre_post-error ] + [ subdir-run set : only_pre ] + [ subdir-run set : only_old ] + [ subdir-run set : only_post ] + [ subdir-run set : both_pre_old ] + [ subdir-run set : both_old_post ] + [ subdir-run set : both_pre_post ] + [ subdir-run set : all_pre_old_post ] + [ subdir-compile-fail set : old_pre-error ] + [ subdir-compile-fail set : post_old-error ] + [ subdir-compile-fail set : post_pre-error ] ; test-suite call_if : diff --git a/test/aux_/counter.hpp b/test/aux_/counter.hpp new file mode 100644 index 0000000..1ccb76f --- /dev/null +++ b/test/aux_/counter.hpp @@ -0,0 +1,41 @@ + +#ifndef BOOST_CONTRACT_AUX_TEST_COUNTER_HPP_ +#define BOOST_CONTRACT_AUX_TEST_COUNTER_HPP_ + +namespace boost { namespace contract { namespace aux { namespace test { + +// Helper to count copies and evaluations of type (e.g., for old values). +template +struct counter { + T value; + + counter() : value() { ++ctors_; } + static unsigned ctors() { return ctors_; } + + ~counter() { ++dtors_; } + static unsigned dtors() { return dtors_; } + + counter(counter const& other) : value(other.value) { ++copies_; ++ctors_; } + static unsigned copies() { return copies_; } + + static counter const& eval(counter const& me) { ++me.evals_; return me; } + static unsigned evals() { return evals_; } + +private: + counter& operator=(counter const&) /* = delete */; + + static unsigned ctors_; // Total constructions (including copies). + static unsigned dtors_; + static unsigned copies_; + static unsigned evals_; +}; + +template unsigned counter::ctors_ = 0; +template unsigned counter::dtors_ = 0; +template unsigned counter::copies_ = 0; +template unsigned counter::evals_ = 0; + +} } } } // namespace + +#endif // #include guard + diff --git a/test/aux_/cpcnt.hpp b/test/aux_/cpcnt.hpp deleted file mode 100644 index 5e2a100..0000000 --- a/test/aux_/cpcnt.hpp +++ /dev/null @@ -1,32 +0,0 @@ - -#ifndef BOOST_CONTRACT_AUX_TEST_CPCNT_HPP_ -#define BOOST_CONTRACT_AUX_TEST_CPCNT_HPP_ - -namespace boost { namespace contract { namespace aux { namespace test { - -// Helper to count copies and evaluations of type (e.g., for old values). -template -struct cpcnt { - T value; - cpcnt() : value() {} - - cpcnt(cpcnt const& other) : value(other.value) { ++copies_; } - static cpcnt const& eval(cpcnt const& me) { ++me.evals_; return me; } - - static unsigned copies() { return copies_; } - static unsigned evals() { return evals_; } - -private: - cpcnt& operator=(cpcnt const&) /* = delete */; - - static unsigned copies_; - static unsigned evals_; -}; - -template unsigned cpcnt::copies_ = 0; -template unsigned cpcnt::evals_ = 0; - -} } } } // namespace - -#endif // #include guard - diff --git a/test/constructor/bases.cpp b/test/constructor/bases.cpp index 089810d..810dd94 100644 --- a/test/constructor/bases.cpp +++ b/test/constructor/bases.cpp @@ -2,7 +2,7 @@ // Test constructor subcontracting. #include "../aux_/oteststream.hpp" -#include "../aux_/cpcnt.hpp" +#include "../aux_/counter.hpp" #include #include #include @@ -32,25 +32,27 @@ struct t BOOST_CONTRACT_ASSERT(l.value >= 0); } - struct l_tag; typedef boost::contract::aux::test::cpcnt l_type; + struct l_tag; + typedef boost::contract::aux::test::counter l_type; static l_type l; - struct z_tag; typedef boost::contract::aux::test::cpcnt z_type; + struct z_tag; + typedef boost::contract::aux::test::counter z_type; - // MSVC 2010 errors on lambdas in template member initializations... - static void constructor_precondition(z_type const& z) { - out << Id << "::ctor::pre" << std::endl; - BOOST_CONTRACT_ASSERT(z.value < 0); - } explicit t(z_type& z) : - boost::contract::constructor_precondition >( - boost::bind(&t::constructor_precondition, boost::cref(z))) + boost::contract::constructor_precondition >([&] { + out << Id << "::ctor::pre" << std::endl; + BOOST_CONTRACT_ASSERT(z.value < 0); + }) { - boost::shared_ptr old_z = - BOOST_CONTRACT_OLDOF(z_type::eval(z)); + boost::shared_ptr old_z; boost::shared_ptr old_l = BOOST_CONTRACT_OLDOF(l_type::eval(l)); boost::contract::guard c = boost::contract::constructor(this) + .old([&] { + out << Id << "::ctor::old" << std::endl; + old_z = BOOST_CONTRACT_OLDOF(z_type::eval(z)); + }) .postcondition([&] { out << Id << "::ctor::post" << std::endl; BOOST_CONTRACT_ASSERT(k_ == old_z->value); @@ -91,10 +93,12 @@ struct c BOOST_CONTRACT_ASSERT(m.value >= 0); } - struct m_tag; typedef boost::contract::aux::test::cpcnt m_type; + struct m_tag; + typedef boost::contract::aux::test::counter m_type; static m_type m; - struct y_tag; typedef boost::contract::aux::test::cpcnt y_type; + struct y_tag; + typedef boost::contract::aux::test::counter y_type; explicit c(y_type& y, t<'d'>::z_type& dz, t<'p'>::z_type& pz, t<'q'>::z_type& qz, t<'e'>::z_type& ez) : @@ -106,9 +110,12 @@ struct c { boost::shared_ptr old_y = BOOST_CONTRACT_OLDOF(y_type::eval(y)); - boost::shared_ptr old_m = - BOOST_CONTRACT_OLDOF(m_type::eval(m)); + boost::shared_ptr old_m; boost::contract::guard c = boost::contract::constructor(this) + .old([&] { + out << "c::ctor::old" << std::endl; + old_m = BOOST_CONTRACT_OLDOF(m_type::eval(m)); + }) .postcondition([&] { out << "c::ctor::post" << std::endl; BOOST_CONTRACT_ASSERT(j_ == old_y->value); @@ -161,10 +168,12 @@ struct a BOOST_CONTRACT_ASSERT(n.value >= 0); } - struct n_tag; typedef boost::contract::aux::test::cpcnt n_type; + struct n_tag; + typedef boost::contract::aux::test::counter n_type; static n_type n; - struct x_tag; typedef boost::contract::aux::test::cpcnt x_type; + struct x_tag; + typedef boost::contract::aux::test::counter x_type; explicit a(x_type& x, c::y_type& y, t<'d'>::z_type& dz, t<'p'>::z_type& pz, t<'q'>::z_type& qz, t<'e'>::z_type& ez) : @@ -174,11 +183,14 @@ struct a }), b(), c(y, dz, pz, qz, ez) { - boost::shared_ptr old_x = - BOOST_CONTRACT_OLDOF(x_type::eval(x)); + boost::shared_ptr old_x; boost::shared_ptr old_n = BOOST_CONTRACT_OLDOF(n_type::eval(n)); boost::contract::guard c = boost::contract::constructor(this) + .old([&] { + out << "a::ctor::old" << std::endl; + old_x = BOOST_CONTRACT_OLDOF(x_type::eval(x)); + }) .postcondition([&] { out << "a::ctor::post" << std::endl; BOOST_CONTRACT_ASSERT(i_ == old_x->value); @@ -201,79 +213,123 @@ a::n_type a::n; int main() { std::ostringstream ok; - t<'e'>::z_type ez; ez.value = -5; - t<'q'>::z_type qz; qz.value = -5; - t<'p'>::z_type pz; pz.value = -4; - t<'d'>::z_type dz; dz.value = -3; - c::y_type y; y.value = -2; - a::x_type x; x.value = -1; + { + t<'e'>::z_type ez; ez.value = -5; + t<'q'>::z_type qz; qz.value = -5; + t<'p'>::z_type pz; pz.value = -4; + t<'d'>::z_type dz; dz.value = -3; + c::y_type y; y.value = -2; + a::x_type x; x.value = -1; - out.str(""); - a aa(x, y, dz, pz, qz, ez); - ok.str(""); ok - // Test all constructor pre checked first. - << "a::ctor::pre" << std::endl + out.str(""); + a aa(x, y, dz, pz, qz, ez); + ok.str(""); ok + // Test all constructor pre checked first. + << "a::ctor::pre" << std::endl - << "c::ctor::pre" << std::endl + << "c::ctor::pre" << std::endl - // Test static inv, but not const inv, checked before constructor body. - << "d::ctor::pre" << std::endl - << "d::static_inv" << std::endl - << "d::ctor::body" << std::endl - << "d::static_inv" << std::endl - << "d::inv" << std::endl - << "d::ctor::post" << std::endl - - // Test check also protected bases (because part of C++ construction). - << "p::ctor::pre" << std::endl - << "p::static_inv" << std::endl - << "p::ctor::body" << std::endl - << "p::static_inv" << std::endl - << "p::inv" << std::endl - << "p::ctor::post" << std::endl - - // Test check also private bases (because part of C++ construction). - << "q::ctor::pre" << std::endl - << "q::static_inv" << std::endl - << "q::ctor::body" << std::endl - << "q::static_inv" << std::endl - << "q::inv" << std::endl - << "q::ctor::post" << std::endl + // Test static inv, but not const inv, checked before ctor body. + << "d::ctor::pre" << std::endl + << "d::static_inv" << std::endl + << "d::ctor::old" << std::endl + << "d::ctor::body" << std::endl + << "d::static_inv" << std::endl + << "d::inv" << std::endl + << "d::ctor::post" << std::endl + + // Test check also protected bases (because part of C++ constr.). + << "p::ctor::pre" << std::endl + << "p::static_inv" << std::endl + << "p::ctor::old" << std::endl + << "p::ctor::body" << std::endl + << "p::static_inv" << std::endl + << "p::inv" << std::endl + << "p::ctor::post" << std::endl + + // Test check also private bases (because part of C++ constr.). + << "q::ctor::pre" << std::endl + << "q::static_inv" << std::endl + << "q::ctor::old" << std::endl + << "q::ctor::body" << std::endl + << "q::static_inv" << std::endl + << "q::inv" << std::endl + << "q::ctor::post" << std::endl - << "e::ctor::pre" << std::endl - << "e::static_inv" << std::endl - << "e::ctor::body" << std::endl - << "e::static_inv" << std::endl - << "e::inv" << std::endl - << "e::ctor::post" << std::endl + << "e::ctor::pre" << std::endl + << "e::static_inv" << std::endl + << "e::ctor::old" << std::endl + << "e::ctor::body" << std::endl + << "e::static_inv" << std::endl + << "e::inv" << std::endl + << "e::ctor::post" << std::endl - << "c::static_inv" << std::endl - << "c::ctor::body" << std::endl - << "c::static_inv" << std::endl - << "c::inv" << std::endl - << "c::ctor::post" << 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 - << "a::static_inv" << std::endl - << "a::ctor::body" << std::endl - << "a::static_inv" << std::endl - << "a::inv" << std::endl - << "a::ctor::post" << std::endl - ; - BOOST_TEST(out.eq(ok.str())); + << "a::static_inv" << std::endl + << "a::ctor::old" << std::endl + << "a::ctor::body" << std::endl + << "a::static_inv" << std::endl + << "a::inv" << std::endl + << "a::ctor::post" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + } - BOOST_TEST_EQ(x.copies(), 1); BOOST_TEST_EQ(x.evals(), 1); - BOOST_TEST_EQ(y.copies(), 1); BOOST_TEST_EQ(y.evals(), 1); - BOOST_TEST_EQ(dz.copies(), 1); BOOST_TEST_EQ(dz.evals(), 1); - BOOST_TEST_EQ(pz.copies(), 1); BOOST_TEST_EQ(pz.evals(), 1); - BOOST_TEST_EQ(qz.copies(), 1); BOOST_TEST_EQ(qz.evals(), 1); - BOOST_TEST_EQ(ez.copies(), 1); BOOST_TEST_EQ(ez.evals(), 1); + BOOST_TEST_EQ(a::x_type::copies(), 1); + BOOST_TEST_EQ(a::x_type::evals(), 1); + BOOST_TEST_EQ(a::x_type::ctors(), a::x_type::dtors()); // No leak. + + BOOST_TEST_EQ(c::y_type::copies(), 1); + BOOST_TEST_EQ(c::y_type::evals(), 1); + BOOST_TEST_EQ(c::y_type::ctors(), c::y_type::dtors()); // No leak. + + BOOST_TEST_EQ(t<'d'>::z_type::copies(), 1); + BOOST_TEST_EQ(t<'d'>::z_type::evals(), 1); + BOOST_TEST_EQ(t<'d'>::z_type::ctors(), t<'d'>::z_type::dtors()); // No leak. + + BOOST_TEST_EQ(t<'p'>::z_type::copies(), 1); + BOOST_TEST_EQ(t<'p'>::z_type::evals(), 1); + BOOST_TEST_EQ(t<'p'>::z_type::ctors(), t<'p'>::z_type::dtors()); // No leak. + + BOOST_TEST_EQ(t<'q'>::z_type::copies(), 1); + BOOST_TEST_EQ(t<'q'>::z_type::evals(), 1); + BOOST_TEST_EQ(t<'q'>::z_type::ctors(), t<'q'>::z_type::dtors()); // No leak. - BOOST_TEST_EQ(a::n.copies(), 1); BOOST_TEST_EQ(a::n.evals(), 1); - BOOST_TEST_EQ(c::m.copies(), 1); BOOST_TEST_EQ(c::m.evals(), 1); - BOOST_TEST_EQ(t<'d'>::l.copies(), 1); BOOST_TEST_EQ(t<'d'>::l.evals(), 1); - BOOST_TEST_EQ(t<'p'>::l.copies(), 1); BOOST_TEST_EQ(t<'p'>::l.evals(), 1); - BOOST_TEST_EQ(t<'q'>::l.copies(), 1); BOOST_TEST_EQ(t<'q'>::l.evals(), 1); - BOOST_TEST_EQ(t<'e'>::l.copies(), 1); BOOST_TEST_EQ(t<'e'>::l.evals(), 1); + BOOST_TEST_EQ(t<'e'>::z_type::copies(), 1); + BOOST_TEST_EQ(t<'e'>::z_type::evals(), 1); + BOOST_TEST_EQ(t<'e'>::z_type::ctors(), t<'e'>::z_type::dtors()); // No leak. + + // Following destroy only copies (actual objects are static data members). + + BOOST_TEST_EQ(a::n_type::copies(), 1); + BOOST_TEST_EQ(a::n_type::evals(), 1); + BOOST_TEST_EQ(a::n_type::copies(), a::n_type::dtors()); // No leak. + + BOOST_TEST_EQ(c::m_type::copies(), 1); + BOOST_TEST_EQ(c::m_type::evals(), 1); + BOOST_TEST_EQ(c::m_type::copies(), c::m_type::dtors()); // No leak. + + BOOST_TEST_EQ(t<'d'>::l_type::copies(), 1); + BOOST_TEST_EQ(t<'d'>::l_type::evals(), 1); + BOOST_TEST_EQ(t<'e'>::l_type::copies(), t<'e'>::l_type::dtors()); // No leak + + BOOST_TEST_EQ(t<'p'>::l_type::copies(), 1); + BOOST_TEST_EQ(t<'p'>::l_type::evals(), 1); + BOOST_TEST_EQ(t<'e'>::l_type::copies(), t<'e'>::l_type::dtors()); // No leak + + BOOST_TEST_EQ(t<'q'>::l_type::copies(), 1); + BOOST_TEST_EQ(t<'q'>::l_type::evals(), 1); + BOOST_TEST_EQ(t<'e'>::l_type::copies(), t<'e'>::l_type::dtors()); // No leak + + BOOST_TEST_EQ(t<'e'>::l_type::copies(), 1); + BOOST_TEST_EQ(t<'e'>::l_type::evals(), 1); + BOOST_TEST_EQ(t<'e'>::l_type::copies(), t<'e'>::l_type::dtors()); // No leak return boost::report_errors(); } diff --git a/test/constructor/body_throw.cpp b/test/constructor/body_throw.cpp index 5db98d3..5ffced3 100644 --- a/test/constructor/body_throw.cpp +++ b/test/constructor/body_throw.cpp @@ -26,9 +26,8 @@ struct c }) { boost::contract::guard c = boost::contract::constructor(this) - .postcondition([&] { - out << "c::ctor::post" << std::endl; - }) + .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). @@ -48,14 +47,13 @@ struct b struct e {}; b() : - boost::contract::constructor_precondition([&] { + boost::contract::constructor_precondition([] { out << "b::ctor::pre" << std::endl; }) { boost::contract::guard c = boost::contract::constructor(this) - .postcondition([&] { - out << "b::ctor::post" << std::endl; - }) + .old([&] { out << "b::ctor::old" << std::endl; }) + .postcondition([&] { out << "b::ctor::post" << std::endl; }) ; out << "b::ctor::body" << std::endl; throw b::e(); // Test body throw (from inheritance mid branch). @@ -78,9 +76,8 @@ struct a }) { boost::contract::guard c = boost::contract::constructor(this) - .postcondition([&] { - out << "a::ctor::post" << std::endl; - }) + .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). @@ -101,12 +98,14 @@ int main() { << "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. diff --git a/test/destructor/bases.cpp b/test/destructor/bases.cpp index 180b925..cebaf8f 100644 --- a/test/destructor/bases.cpp +++ b/test/destructor/bases.cpp @@ -2,7 +2,7 @@ // Test destructor subcontracting. #include "../aux_/oteststream.hpp" -#include "../aux_/cpcnt.hpp" +#include "../aux_/counter.hpp" #include #include #include @@ -24,16 +24,20 @@ struct t { BOOST_CONTRACT_ASSERT(l.value >= 0); } - struct l_tag; typedef boost::contract::aux::test::cpcnt l_type; + struct l_tag; + typedef boost::contract::aux::test::counter l_type; static l_type l; explicit t() : k_(-1) { ++l.value; } virtual ~t() { - boost::shared_ptr old_l = - BOOST_CONTRACT_OLDOF(l_type::eval(l)); + boost::shared_ptr old_l; boost::contract::guard c = boost::contract::destructor(this) - .postcondition([old_l] { + .old([&] { + out << Id << "::dtor::old" << std::endl; + old_l = BOOST_CONTRACT_OLDOF(l_type::eval(l)); + }) + .postcondition([&old_l] { out << Id << "::dtor::post" << std::endl; BOOST_CONTRACT_ASSERT(t::l.value == old_l->value - 1); }) @@ -67,7 +71,8 @@ struct c BOOST_CONTRACT_ASSERT(m.value >= 0); } - struct m_tag; typedef boost::contract::aux::test::cpcnt m_type; + struct m_tag; + typedef boost::contract::aux::test::counter m_type; static m_type m; explicit c() : j_(-1) { ++m.value; } @@ -76,7 +81,11 @@ struct c boost::shared_ptr old_m = BOOST_CONTRACT_OLDOF(m_type::eval(m)); boost::contract::guard c = boost::contract::destructor(this) - .postcondition([old_m] { + .old([&] { + out << "c::dtor::old" << std::endl; + // Test old-of assignment above instead. + }) + .postcondition([&old_m] { out << "c::dtor::post" << std::endl; BOOST_CONTRACT_ASSERT(c::m.value == old_m->value - 1); }) @@ -116,16 +125,20 @@ struct a BOOST_CONTRACT_ASSERT(n.value >= 0); } - struct n_tag; typedef boost::contract::aux::test::cpcnt n_type; + struct n_tag; + typedef boost::contract::aux::test::counter n_type; static n_type n; explicit a() : i_(-1) { ++n.value; } virtual ~a() { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(n_type::eval(n)); + boost::shared_ptr old_n; boost::contract::guard c = boost::contract::destructor(this) - .postcondition([old_n] { + .old([&] { + out << "a::dtor::old" << std::endl; + old_n = BOOST_CONTRACT_OLDOF(n_type::eval(n)); + }) + .postcondition([&old_n] { out << "a::dtor::post" << std::endl; BOOST_CONTRACT_ASSERT(a::n.value == old_n->value - 1); }) @@ -149,6 +162,7 @@ int main() { ok.str(""); ok << "a::static_inv" << std::endl << "a::inv" << std::endl + << "a::dtor::old" << std::endl << "a::dtor::body" << std::endl // Test static inv, but not const inv, checked after destructor body. << "a::static_inv" << std::endl @@ -156,12 +170,14 @@ int main() { << "c::static_inv" << std::endl << "c::inv" << std::endl + << "c::dtor::old" << std::endl << "c::dtor::body" << std::endl << "c::static_inv" << std::endl << "c::dtor::post" << std::endl << "e::static_inv" << std::endl << "e::inv" << std::endl + << "e::dtor::old" << std::endl << "e::dtor::body" << std::endl << "e::static_inv" << std::endl << "e::dtor::post" << std::endl @@ -169,6 +185,7 @@ int main() { // Test check also private bases (because part of C++ destruction). << "q::static_inv" << std::endl << "q::inv" << std::endl + << "q::dtor::old" << std::endl << "q::dtor::body" << std::endl << "q::static_inv" << std::endl << "q::dtor::post" << std::endl @@ -176,24 +193,45 @@ int main() { // Test check also protected bases (because part of C++ destruction). << "p::static_inv" << std::endl << "p::inv" << std::endl + << "p::dtor::old" << std::endl << "p::dtor::body" << std::endl << "p::static_inv" << std::endl << "p::dtor::post" << std::endl << "d::static_inv" << std::endl << "d::inv" << std::endl + << "d::dtor::old" << std::endl << "d::dtor::body" << std::endl << "d::static_inv" << std::endl << "d::dtor::post" << std::endl ; BOOST_TEST(out.eq(ok.str())); - BOOST_TEST_EQ(a::n.copies(), 1); BOOST_TEST_EQ(a::n.evals(), 1); - BOOST_TEST_EQ(c::m.copies(), 1); BOOST_TEST_EQ(c::m.evals(), 1); - BOOST_TEST_EQ(t<'d'>::l.copies(), 1); BOOST_TEST_EQ(t<'d'>::l.evals(), 1); - BOOST_TEST_EQ(t<'p'>::l.copies(), 1); BOOST_TEST_EQ(t<'p'>::l.evals(), 1); - BOOST_TEST_EQ(t<'q'>::l.copies(), 1); BOOST_TEST_EQ(t<'q'>::l.evals(), 1); - BOOST_TEST_EQ(t<'e'>::l.copies(), 1); BOOST_TEST_EQ(t<'e'>::l.evals(), 1); + // Following destroy only copies (actual objects are static data members). + + BOOST_TEST_EQ(a::n_type::copies(), 1); + BOOST_TEST_EQ(a::n_type::evals(), 1); + BOOST_TEST_EQ(a::n_type::copies(), a::n_type::dtors()); // No leak. + + BOOST_TEST_EQ(c::m_type::copies(), 1); + BOOST_TEST_EQ(c::m_type::evals(), 1); + BOOST_TEST_EQ(c::m_type::copies(), c::m_type::dtors()); // No leak. + + BOOST_TEST_EQ(t<'d'>::l_type::copies(), 1); + BOOST_TEST_EQ(t<'d'>::l_type::evals(), 1); + BOOST_TEST_EQ(t<'d'>::l_type::copies(), t<'d'>::l_type::dtors()); // No leak + + BOOST_TEST_EQ(t<'p'>::l_type::copies(), 1); + BOOST_TEST_EQ(t<'p'>::l_type::evals(), 1); + BOOST_TEST_EQ(t<'p'>::l_type::copies(), t<'p'>::l_type::dtors()); // No leak + + BOOST_TEST_EQ(t<'q'>::l_type::copies(), 1); + BOOST_TEST_EQ(t<'q'>::l_type::evals(), 1); + BOOST_TEST_EQ(t<'q'>::l_type::copies(), t<'q'>::l_type::dtors()); // No leak + + BOOST_TEST_EQ(t<'e'>::l_type::copies(), 1); + BOOST_TEST_EQ(t<'e'>::l_type::evals(), 1); + BOOST_TEST_EQ(t<'e'>::l_type::copies(), t<'e'>::l_type::dtors()); // No leak return boost::report_errors(); } diff --git a/test/destructor/body_throw.cpp b/test/destructor/body_throw.cpp index ccb0ad3..27ecdcb 100644 --- a/test/destructor/body_throw.cpp +++ b/test/destructor/body_throw.cpp @@ -19,9 +19,8 @@ struct c { ~c() { boost::contract::guard c = boost::contract::destructor(this) - .postcondition([&] { - out << "c::dtor::post" << std::endl; - }) + .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). @@ -42,9 +41,8 @@ struct b ~b() { boost::contract::guard c = boost::contract::destructor(this) - .postcondition([&] { - out << "b::dtor::post" << std::endl; - }) + .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). @@ -63,9 +61,8 @@ struct a ~a() { boost::contract::guard c = boost::contract::destructor(this) - .postcondition([&] { - out << "a::dtor::post" << std::endl; - }) + .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). @@ -77,6 +74,7 @@ void t() { 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). @@ -84,10 +82,12 @@ void t() { << "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 throw an exception. +// 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 @@ -95,6 +95,7 @@ void t() { << "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 @@ -113,7 +114,7 @@ int main() { a aa; } // Call destructor (which calls t on throw). - BOOST_TEST(false); // Must not exit from here, but via t. + BOOST_TEST(false); // Must not exit from here, but from t. return boost::report_errors(); } diff --git a/test/disable/checking.cpp b/test/disable/checking.cpp index 088ee76..2508090 100644 --- a/test/disable/checking.cpp +++ b/test/disable/checking.cpp @@ -2,7 +2,7 @@ // Test contract checking and old value copies disabled within contracts. #include "../aux_/oteststream.hpp" -#include "../aux_/cpcnt.hpp" +#include "../aux_/counter.hpp" #include #include #include @@ -17,7 +17,8 @@ struct a { void invariant() const { out << "a::inv" << std::endl; } static void static_invariant() { out << "a::static_inv" << std::endl; } - struct x_tag; typedef boost::contract::aux::test::cpcnt x_type; + struct x_tag; + typedef boost::contract::aux::test::counter x_type; int f(x_type& x) { int result; @@ -25,6 +26,7 @@ struct a { x_type::eval(x)); boost::contract::guard c = boost::contract::public_function(this) .precondition([&] { out << "a::f::pre" << std::endl; }) + .old([&] { out << "a::f::old" << std::endl; }) .postcondition([&] { out << "a::f::post" << std::endl; BOOST_CONTRACT_ASSERT(x.value == -old_x->value); @@ -54,6 +56,7 @@ struct b { out << "b::g::pre" << std::endl; BOOST_CONTRACT_ASSERT(call_f()); }) + .old([&] { out << "b::g::old" << std::endl; }) .postcondition([&] { out << "b::g::post" << std::endl; BOOST_CONTRACT_ASSERT(call_f()); @@ -77,11 +80,14 @@ int main() { // Test only f's body (but not its contract) executed here. << "a::f::body" << std::endl + << "b::g::old" << std::endl + << "b::g::body" << std::endl << "b::static_inv" << std::endl << "b::inv" << std::endl + // No old call here because not a base object. << "b::g::post" << std::endl // Test only f's body (but not its contract) executed here. << "a::f::body" << std::endl @@ -100,9 +106,11 @@ int main() { << "a::static_inv" << std::endl << "a::inv" << std::endl << "a::f::pre" << std::endl + << "a::f::old" << std::endl << "a::f::body" << std::endl << "a::static_inv" << std::endl << "a::inv" << std::endl + // No old call here because not a base object. << "a::f::post" << std::endl ; BOOST_TEST(out.eq(ok.str())); diff --git a/test/function/body_throw.cpp b/test/function/body_throw.cpp index 6142687..a3fbdcb 100644 --- a/test/function/body_throw.cpp +++ b/test/function/body_throw.cpp @@ -14,6 +14,7 @@ struct e {}; void f() { boost::contract::guard c = boost::contract::function() .precondition([&] { out << "f::pre" << std::endl; }) + .old([&] { out << "f::old" << std::endl; }) .postcondition([&] { out << "f::post" << std::endl; }) ; out << "f::body" << std::endl; @@ -30,6 +31,7 @@ int main() { BOOST_TEST(threw); ok.str(""); ok << "f::pre" << std::endl + << "f::old" << std::endl << "f::body" << std::endl // Test no post because body threw. ; diff --git a/test/function/pre_post.cpp b/test/function/pre_post.cpp index 3cbd083..c61c471 100644 --- a/test/function/pre_post.cpp +++ b/test/function/pre_post.cpp @@ -2,7 +2,7 @@ // Test free function contracts. #include "../aux_/oteststream.hpp" -#include "../aux_/cpcnt.hpp" +#include "../aux_/counter.hpp" #include #include #include @@ -13,20 +13,23 @@ boost::contract::aux::test::oteststream out; -struct x_tag; typedef boost::contract::aux::test::cpcnt x_type; -struct y_tag; typedef boost::contract::aux::test::cpcnt y_type; +struct x_tag; typedef boost::contract::aux::test::counter x_type; +struct y_tag; typedef boost::contract::aux::test::counter y_type; bool swap(x_type& x, y_type& y) { bool result; boost::shared_ptr old_x = BOOST_CONTRACT_OLDOF(x_type::eval(x)); - boost::shared_ptr old_y = - BOOST_CONTRACT_OLDOF(y_type::eval(y)); + boost::shared_ptr old_y; boost::contract::guard c = boost::contract::function() .precondition([&] { out << "swap::pre" << std::endl; BOOST_CONTRACT_ASSERT(x.value != y.value); }) + .old([&] { + out << "swap::old" << std::endl; + old_y = BOOST_CONTRACT_OLDOF(y_type::eval(y)); + }) .postcondition([&] { out << "swap::post" << std::endl; BOOST_CONTRACT_ASSERT(x.value == old_y->value); @@ -34,6 +37,7 @@ bool swap(x_type& x, y_type& y) { BOOST_CONTRACT_ASSERT(result == (old_x->value != old_y->value)); }) ; + out << "swap::body" << std::endl; if(x.value == y.value) return result = false; int save_x = x.value; @@ -45,24 +49,32 @@ bool swap(x_type& x, y_type& y) { int main() { std::ostringstream ok; - x_type x; x.value = 123; - y_type y; y.value = 456; + { + x_type x; x.value = 123; + y_type y; y.value = 456; - out.str(""); - bool r = swap(x, y); - ok.str(""); ok - << "swap::pre" << std::endl - << "swap::body" << std::endl - << "swap::post" << std::endl - ; - BOOST_TEST(out.eq(ok.str())); + out.str(""); + bool r = swap(x, y); + ok.str(""); ok + << "swap::pre" << std::endl + << "swap::old" << std::endl + << "swap::body" << std::endl + << "swap::post" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + BOOST_TEST(r); + BOOST_TEST_EQ(x.value, 456); + BOOST_TEST_EQ(y.value, 123); + } + + BOOST_TEST_EQ(x_type::copies(), 1); + BOOST_TEST_EQ(x_type::evals(), 1); + BOOST_TEST_EQ(x_type::ctors(), x_type::dtors()); // No leak. - BOOST_TEST(r); - BOOST_TEST_EQ(x.value, 456); - BOOST_TEST_EQ(y.value, 123); - - BOOST_TEST_EQ(x.copies(), 1); BOOST_TEST_EQ(x.evals(), 1); - BOOST_TEST_EQ(y.copies(), 1); BOOST_TEST_EQ(y.evals(), 1); + BOOST_TEST_EQ(y_type::copies(), 1); + BOOST_TEST_EQ(y_type::evals(), 1); + BOOST_TEST_EQ(y_type::ctors(), y_type::dtors()); // No leak. return boost::report_errors(); } diff --git a/test/public_function/bases.cpp b/test/public_function/bases.cpp index ea2ab86..4c9ce39 100644 --- a/test/public_function/bases.cpp +++ b/test/public_function/bases.cpp @@ -25,6 +25,11 @@ int main() { << "e::f::pre" << std::endl << "c::f::pre" << std::endl << "a::f::pre" << std::endl + + << "d::f::old" << std::endl + << "e::f::old" << std::endl + << "c::f::old" << std::endl + << "a::f::old" << std::endl << "a::f::body" << std::endl @@ -37,9 +42,13 @@ int main() { << "a::static_inv" << std::endl << "a::inv" << std::endl + << "d::f::old" << std::endl << "d::f::post" << std::endl + << "e::f::old" << std::endl << "e::f::post" << std::endl + << "c::f::old" << std::endl << "c::f::post" << std::endl + // No old call here because not a base object. << "a::f::post" << std::endl ; BOOST_TEST(out.eq(ok.str())); diff --git a/test/public_function/bases.hpp b/test/public_function/bases.hpp index 41ba39a..3f17606 100644 --- a/test/public_function/bases.hpp +++ b/test/public_function/bases.hpp @@ -5,7 +5,7 @@ // Test public member function subcontracting (also with old and return values). #include "../aux_/oteststream.hpp" -#include "../aux_/cpcnt.hpp" +#include "../aux_/counter.hpp" #include #include #include @@ -18,7 +18,7 @@ boost::contract::aux::test::oteststream out; struct s_tag; -typedef boost::contract::aux::test::cpcnt s_type; +typedef boost::contract::aux::test::counter s_type; struct result_type { std::string value; @@ -40,7 +40,7 @@ struct t { static void static_invariant() { out << Id << "::static_inv" << std::endl; } struct z_tag; - typedef boost::contract::aux::test::cpcnt z_type; + typedef boost::contract::aux::test::counter z_type; z_type z; t() { z.value.push_back(Id); } @@ -54,13 +54,16 @@ result_type& t::f(s_type& s, boost::contract::virtual_* v) { static result_type result(r.str()); boost::shared_ptr old_z = BOOST_CONTRACT_OLDOF(v, z_type::eval(z)); - boost::shared_ptr old_s = - BOOST_CONTRACT_OLDOF(v, s_type::eval(s)); + boost::shared_ptr old_s; boost::contract::guard c = boost::contract::public_function(v, result, this) .precondition([&] { out << Id << "::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(s.value[0] == Id); }) + .old([&] { + out << Id << "::f::old" << std::endl; + old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s)); + }) .postcondition([&] (result_type const& result) { out << Id << "::f::post" << std::endl; BOOST_CONTRACT_ASSERT(z.value == old_z->value + old_s->value); @@ -89,7 +92,7 @@ struct c static void static_invariant() { out << "c::static_inv" << std::endl; } struct y_tag; - typedef boost::contract::aux::test::cpcnt y_type; + typedef boost::contract::aux::test::counter y_type; y_type y; c() { y.value = "c"; } @@ -99,14 +102,17 @@ struct c static result_type result("none-c"); boost::shared_ptr old_y = BOOST_CONTRACT_OLDOF(v, y_type::eval(y)); - boost::shared_ptr old_s = - BOOST_CONTRACT_OLDOF(v, s_type::eval(s)); + boost::shared_ptr old_s; boost::contract::guard c = boost::contract::public_function< override_f>(v, result, &c::f, this, s) .precondition([&] { out << "c::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(s.value == "C"); }) + .old([&] { + out << "c::f::old" << std::endl; + old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s)); + }) .postcondition([&] (result_type const& result) { out << "c::f::post" << std::endl; BOOST_CONTRACT_ASSERT(y.value == old_y->value + old_s->value); @@ -167,7 +173,7 @@ struct a static void static_invariant() { out << "a::static_inv" << std::endl; } struct x_tag; - typedef boost::contract::aux::test::cpcnt x_type; + typedef boost::contract::aux::test::counter x_type; x_type x; a() { x.value = "a"; } @@ -178,14 +184,17 @@ struct a static result_type result("none-a"); boost::shared_ptr old_x = BOOST_CONTRACT_OLDOF(v, x_type::eval(x)); - boost::shared_ptr old_s = - BOOST_CONTRACT_OLDOF(v, s_type::eval(s)); + boost::shared_ptr old_s; boost::contract::guard c = boost::contract::public_function< override_f>(v, result, &a::f, this, s) .precondition([&] { out << "a::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(s.value == "A"); }) + .old([&] { + out << "a::f::old" << std::endl; + old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s)); + }) .postcondition([&] (result_type const& result) { out << "a::f::post" << std::endl; BOOST_CONTRACT_ASSERT(x.value == old_x->value + old_s->value); diff --git a/test/public_function/bases_branch.cpp b/test/public_function/bases_branch.cpp index a123c56..4a54c9b 100644 --- a/test/public_function/bases_branch.cpp +++ b/test/public_function/bases_branch.cpp @@ -23,6 +23,10 @@ int main() { << "e::f::pre" << std::endl << "c::f::pre" << std::endl + << "d::f::old" << std::endl + << "e::f::old" << std::endl + << "c::f::old" << std::endl + << "c::f::body" << std::endl << "d::static_inv" << std::endl @@ -32,8 +36,11 @@ int main() { << "c::static_inv" << std::endl << "c::inv" << std::endl + << "d::f::old" << std::endl << "d::f::post" << std::endl + << "e::f::old" << std::endl << "e::f::post" << std::endl + // No old call here because not a base object. << "c::f::post" << std::endl ; BOOST_TEST(out.eq(ok.str())); diff --git a/test/public_function/bases_virtual.cpp b/test/public_function/bases_virtual.cpp index d904098..702b0a9 100644 --- a/test/public_function/bases_virtual.cpp +++ b/test/public_function/bases_virtual.cpp @@ -27,6 +27,11 @@ int main() { << "c::f::pre" << std::endl << "a::f::pre" << std::endl + << "d::f::old" << std::endl + << "e::f::old" << std::endl + << "c::f::old" << std::endl + << "a::f::old" << std::endl + << "a::f::body" << std::endl << "d::static_inv" << std::endl @@ -38,9 +43,13 @@ int main() { << "a::static_inv" << std::endl << "a::inv" << std::endl + << "d::f::old" << std::endl << "d::f::post" << std::endl + << "e::f::old" << std::endl << "e::f::post" << std::endl + << "c::f::old" << std::endl << "c::f::post" << std::endl + // No old call here because not a base object. << "a::f::post" << std::endl ; BOOST_TEST(out.eq(ok.str())); diff --git a/test/public_function/body_throw.cpp b/test/public_function/body_throw.cpp index 1fdd65d..2454384 100644 --- a/test/public_function/body_throw.cpp +++ b/test/public_function/body_throw.cpp @@ -24,6 +24,7 @@ struct c { out << "c::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(false); // To check derived pre. }) + .old([&] { out << "c::f::old" << std::endl; }) .postcondition([&] { out << "c::f::post" << std::endl; }) ; out << "c::f::body" << std::endl; @@ -50,6 +51,7 @@ struct b out << "b::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(false); // To check derived pre. }) + .old([&] { out << "b::f::old" << std::endl; }) .postcondition([&] { out << "b::f::post" << std::endl; }) ; out << "b::f::body" << std::endl; @@ -74,6 +76,7 @@ struct a 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; }) .postcondition([&] { out << "a::f::post" << std::endl; }) ; out << "a::f::body" << std::endl; @@ -104,6 +107,10 @@ int main() { << "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 @@ -112,6 +119,7 @@ int main() { << "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())); diff --git a/test/public_function/static.cpp b/test/public_function/static.cpp index e84207b..55e2675 100644 --- a/test/public_function/static.cpp +++ b/test/public_function/static.cpp @@ -16,12 +16,9 @@ struct b { static void f() { boost::contract::guard c = boost::contract::public_function() - .precondition([&] { - out << "b::f::pre" << std::endl; - }) - .postcondition([&] { - out << "b::f::post" << std::endl; - }) + .precondition([&] { out << "b::f::pre" << std::endl; }) + .old([&] { out << "b::f::old" << std::endl; }) + .postcondition([&] { out << "b::f::post" << std::endl; }) ; out << "b::f::body" << std::endl; } @@ -39,12 +36,9 @@ struct a static void f() { boost::contract::guard c = boost::contract::public_function() - .precondition([&] { - out << "a::f::pre" << std::endl; - }) - .postcondition([&] { - out << "a::f::post" << std::endl; - }) + .precondition([&] { out << "a::f::pre" << std::endl; }) + .old([&] { out << "a::f::old" << std::endl; }) + .postcondition([&] { out << "a::f::post" << std::endl; }) ; out << "a::f::body" << std::endl; } @@ -60,8 +54,10 @@ int main() { // principle does not apply and no subcontracting. << "a::static_inv" << std::endl << "a::f::pre" << std::endl + << "a::f::old" << std::endl << "a::f::body" << std::endl << "a::static_inv" << std::endl + // No old call here because not base object. << "a::f::post" << std::endl ; BOOST_TEST(out.eq(ok.str())); diff --git a/test/public_function/static_body_throw.cpp b/test/public_function/static_body_throw.cpp index dc479f7..e68f179 100644 --- a/test/public_function/static_body_throw.cpp +++ b/test/public_function/static_body_throw.cpp @@ -17,12 +17,9 @@ struct a { static void f() { boost::contract::guard c = boost::contract::public_function() - .precondition([&] { - out << "a::f::pre" << std::endl; - }) - .postcondition([&] { - out << "a::f::post" << std::endl; - }) + .precondition([&] { out << "a::f::pre" << std::endl; }) + .old([&] { out << "a::f::old" << std::endl; }) + .postcondition([&] { out << "a::f::post" << std::endl; }) ; out << "a::f::body" << std::endl; throw a::e(); @@ -40,6 +37,7 @@ int main() { ok.str(""); ok << "a::static_inv" << std::endl << "a::f::pre" << std::endl + << "a::f::old" << std::endl << "a::f::body" << std::endl << "a::static_inv" << std::endl // Test no post (but still static inv) because body threw. diff --git a/test/set/pre_post.cpp b/test/set/all_pre_old_post.cpp similarity index 82% rename from test/set/pre_post.cpp rename to test/set/all_pre_old_post.cpp index 5de032f..2dbbc22 100644 --- a/test/set/pre_post.cpp +++ b/test/set/all_pre_old_post.cpp @@ -1,5 +1,5 @@ -// Test pre before post (for free func, but same for all contracts). +// Test all pre, old, and post (for free func, but same for all contracts). #include "../aux_/oteststream.hpp" #include @@ -12,6 +12,7 @@ boost::contract::aux::test::oteststream out; void f() { boost::contract::guard c = boost::contract::function() .precondition([] { out << "f::pre" << std::endl; }) + .old([] { out << "f::old" << std::endl; }) .postcondition([] { out << "f::post" << std::endl; }) ; out << "f::body" << std::endl; @@ -25,6 +26,7 @@ int main() { ok.str(""); ok << "f::pre" << std::endl + << "f::old" << std::endl << "f::body" << std::endl << "f::post" << std::endl ; diff --git a/test/set/both_old_post.cpp b/test/set/both_old_post.cpp new file mode 100644 index 0000000..1e4dc60 --- /dev/null +++ b/test/set/both_old_post.cpp @@ -0,0 +1,35 @@ + +// Test both old and post (for free func, but same for all contracts). + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +void f() { + boost::contract::guard c = boost::contract::function() + .old([] { out << "f::old" << std::endl; }) + .postcondition([] { out << "f::post" << std::endl; }) + ; + out << "f::body" << std::endl; +} + +int main() { + std::ostringstream ok; + + out.str(""); + f(); + ok.str(""); + ok + << "f::old" << std::endl + << "f::body" << std::endl + << "f::post" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/set/both_pre_old.cpp b/test/set/both_pre_old.cpp new file mode 100644 index 0000000..a9be36a --- /dev/null +++ b/test/set/both_pre_old.cpp @@ -0,0 +1,35 @@ + +// Test both pre and old (for free func, but same for all contracts). + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +void f() { + boost::contract::guard c = boost::contract::function() + .precondition([] { out << "f::pre" << std::endl; }) + .old([] { out << "f::old" << std::endl; }) + ; + out << "f::body" << std::endl; +} + +int main() { + std::ostringstream ok; + + out.str(""); + f(); + ok.str(""); + ok + << "f::pre" << std::endl + << "f::old" << std::endl + << "f::body" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/set/post_pre.cpp b/test/set/both_pre_post.cpp similarity index 91% rename from test/set/post_pre.cpp rename to test/set/both_pre_post.cpp index cc4c962..ed70489 100644 --- a/test/set/post_pre.cpp +++ b/test/set/both_pre_post.cpp @@ -1,5 +1,5 @@ -// Test post before pre (for free func, but same for all contracts). +// Test both pre and post (for free func, but same for all contracts). #include "../aux_/oteststream.hpp" #include @@ -11,8 +11,8 @@ boost::contract::aux::test::oteststream out; void f() { boost::contract::guard c = boost::contract::function() - .postcondition([] { out << "f::post" << std::endl; }) .precondition([] { out << "f::pre" << std::endl; }) + .postcondition([] { out << "f::post" << std::endl; }) ; out << "f::body" << std::endl; } diff --git a/test/set/pre_pre-error.cpp b/test/set/old_pre-error.cpp similarity index 64% rename from test/set/pre_pre-error.cpp rename to test/set/old_pre-error.cpp index dfe2e79..a28f859 100644 --- a/test/set/pre_pre-error.cpp +++ b/test/set/old_pre-error.cpp @@ -1,13 +1,13 @@ -// Test multiple pre error (for free func, but same for all contracts). +// Test old before pre error (for free func, but same for all contracts). #include #include void f() { boost::contract::guard c = boost::contract::function() + .old([] {}) // Error (old before pre). .precondition([] {}) - .precondition([] {}) // Error (multiple pre). ; } diff --git a/test/set/only_old.cpp b/test/set/only_old.cpp new file mode 100644 index 0000000..25ab566 --- /dev/null +++ b/test/set/only_old.cpp @@ -0,0 +1,32 @@ + +// Test only old specified (for free func, but same for all contracts). + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +void f() { + boost::contract::guard c = boost::contract::function() + .old([] { out << "f::old" << std::endl; }) + ; + out << "f::body" << std::endl; +} + +int main() { + std::ostringstream ok; + + out.str(""); + f(); + ok.str(""); ok + << "f::old" << std::endl + << "f::body" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/set/post_only.cpp b/test/set/only_post.cpp similarity index 90% rename from test/set/post_only.cpp rename to test/set/only_post.cpp index c7f06d8..0b3cc7d 100644 --- a/test/set/post_only.cpp +++ b/test/set/only_post.cpp @@ -1,5 +1,5 @@ -// Test post only specified (for free func, but same for all contracts). +// Test only post specified (for free func, but same for all contracts). #include "../aux_/oteststream.hpp" #include diff --git a/test/set/pre_only.cpp b/test/set/only_pre.cpp similarity index 90% rename from test/set/pre_only.cpp rename to test/set/only_pre.cpp index 870c9b7..675a26d 100644 --- a/test/set/pre_only.cpp +++ b/test/set/only_pre.cpp @@ -1,5 +1,5 @@ -// Test pre only specified (for free func, but same for all contracts). +// Test only pre specified (for free func, but same for all contracts). #include "../aux_/oteststream.hpp" #include diff --git a/test/set/post_post-error.cpp b/test/set/post_old-error.cpp similarity index 55% rename from test/set/post_post-error.cpp rename to test/set/post_old-error.cpp index ea7a0f1..c7cb1fa 100644 --- a/test/set/post_post-error.cpp +++ b/test/set/post_old-error.cpp @@ -1,13 +1,13 @@ -// Test multiple post error (for free func, but same for all contracts). +// Test post before old error (for free func, but same for all contracts). #include #include void f() { boost::contract::guard c = boost::contract::function() - .postcondition([] {}) - .postcondition([] {}) // Error (multiple post). + .postcondition([] {}) // Error (post before old). + .old([] {}) ; } diff --git a/test/set/pre_post_pre-error.cpp b/test/set/post_pre-error.cpp similarity index 55% rename from test/set/pre_post_pre-error.cpp rename to test/set/post_pre-error.cpp index 7080d85..8271a83 100644 --- a/test/set/pre_post_pre-error.cpp +++ b/test/set/post_pre-error.cpp @@ -1,14 +1,13 @@ -// Test multi pre around post error (for free func, but same for all contracts). +// Test post before pre error (for free func, but same for all contracts). #include #include void f() { boost::contract::guard c = boost::contract::function() + .postcondition([] {}) // Error (post before pre). .precondition([] {}) - .postcondition([] {}) - .precondition([] {}) // Error (multiple pre around post). ; } diff --git a/test/set/post_pre_post-error.cpp b/test/set/post_pre_post-error.cpp deleted file mode 100644 index d4ba795..0000000 --- a/test/set/post_pre_post-error.cpp +++ /dev/null @@ -1,19 +0,0 @@ - -// Test multi post around pre error (for free func, but same for all contracts). - -#include -#include - -void f() { - boost::contract::guard c = boost::contract::function() - .postcondition([] {}) - .precondition([] {}) - .postcondition([] {}) // Error (multiple post around pre). - ; -} - -int main() { - f(); - return 0; -} -