diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 new file mode 100644 index 0000000..35942da --- /dev/null +++ b/example/Jamfile.v2 @@ -0,0 +1,3 @@ + +subdir-run meyer97 : stack4_run ; + diff --git a/example/meyer97/stack4.hpp b/example/meyer97/stack4.hpp new file mode 100644 index 0000000..722e45f --- /dev/null +++ b/example/meyer97/stack4.hpp @@ -0,0 +1,171 @@ + +#ifndef STACK4_HPP_ +#define STACK4_HPP_ + +#include + +template +class stack4 + #define BASES private boost::contract::constructor_precondition > + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { + BOOST_CONTRACT_ASSERT(count() >= 0); // Count non-negative. + BOOST_CONTRACT_ASSERT(count() <= capacity()); // Count bounded. + BOOST_CONTRACT_ASSERT(empty() == (count() == 0)); // Empty if no item. + } + +public: + /* Initialization */ + + // Allocate static from a maximum of n items. + explicit stack4(int n) : + boost::contract::constructor_precondition([&] { + BOOST_CONTRACT_ASSERT(n >= 0); // Non-negative capacity. + }) + { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() == n); // Capacity set. + }) + ; + + capacity_ = n; + count_ = 0; + array_ = new T[n]; + } + + // Deep copy via constructor. + /* implicit */ stack4(stack4 const& other) { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() == other.capacity()); + BOOST_CONTRACT_ASSERT(count() == other.count()); + // All items equal to other's items one by one. + }) + ; + + capacity_ = other.capacity_; + count_ = other.count_; + array_ = new T[other.capacity_]; + for(int i = 0; i < other.count_; ++i) array_[i] = other.array_[i]; + } + + // Deep copy via assignment. + stack4& operator=(stack4 const& other) { + auto c = boost::contract::public_member(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() == other.capacity()); + BOOST_CONTRACT_ASSERT(count() == other.count()); + // All items euqal to other's items one by one. + }) + ; + + delete[] array_; + capacity_ = other.capacity_; + count_ = other.capacity_; + array_ = new T[other.capacity_]; + for(int i = 0; i < other.count_; ++i) array_[i] = other.array_[i]; + return *this; + } + + // Destroy this stack. + virtual ~stack4() { + auto c = boost::contract::destructor(this); // Check invariants. + delete[] array_; + } + + /* Access */ + + // Max number of stack items. + int capacity() const { + auto c = boost::contract::public_member(this); // Check invariants. + return capacity_; + } + + // Number of stack items. + int count() const { + auto c = boost::contract::public_member(this); // Check invariants. + return count_; + } + + // Top item. + T const& item() const { + auto c = boost::contract::public_member(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); // Not empty (count > 0). + }) + ; + return array_[count_ - 1]; + } + + /* Status Report */ + + // Is stack empty? + bool empty() const { + bool result; + auto c = boost::contract::public_member(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result == + (count() == 0)); // Empty definition. + }) + ; + return result = (count_ == 0); + } + + // Is stack full? + bool full() const { + bool result; + auto c = boost::contract::public_member(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result == + (count() == capacity())); // Full definition. + }) + ; + return result = (count_ == capacity_); + } + + /* Element Change */ + + // Add x on top. + void put(T const& x) { + auto old_count = BOOST_CONTRACT_OLDOF(count()); + auto c = boost::contract::public_member(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!full()); // Not full. + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); // Not empty. + BOOST_CONTRACT_ASSERT(item() == x); // Added to top. + BOOST_CONTRACT_ASSERT(count() == *old_count + 1); // One more. + }) + ; + array_[count_++] = x; + } + + // Remove top item. + void remove() { + auto old_count = BOOST_CONTRACT_OLDOF(count()); + auto c = boost::contract::public_member(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); // Not empty (count > 0). + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!full()); // Not full. + BOOST_CONTRACT_ASSERT(count() == *old_count - 1); // One less. + }) + ; + --count_; + } + +private: + int capacity_; + int count_; + T* array_; // Internally using C-style array. +}; + +#endif // #include guard + diff --git a/example/meyer97/stack4_run.cpp b/example/meyer97/stack4_run.cpp new file mode 100644 index 0000000..e6c8d8f --- /dev/null +++ b/example/meyer97/stack4_run.cpp @@ -0,0 +1,20 @@ + +#include "stack4.hpp" +#include + +int main() { + stack4 s(3); + BOOST_TEST_EQ(s.capacity(), 3); + BOOST_TEST_EQ(s.count(), 0); + + s.put(123); + BOOST_TEST(!s.empty()); + BOOST_TEST(!s.full()); + BOOST_TEST_EQ(s.item(), 123); + + s.remove(); + BOOST_TEST(s.empty()); + + return boost::report_errors(); +} + diff --git a/features.txt b/features.txt index 5e10b5b..c9852d3 100644 --- a/features.txt +++ b/features.txt @@ -1,20 +1,16 @@ Features to test: -o Constructors w/ subcontracting +x Constructors w/ subcontracting --> pre > bases' pre > for x in [bases, class] ( static_inv (but not inv) > body > static_inv > inv > post ) --> protected and private bases ALSO contract (because always part of C++ obj construction mechanism) -o Constructor preconditions checked before member initialization list -o Constructors have no `.precondition` (must use `constructor_precondition` instead) -o Overloaded Constructors, also with no preconditions -o Constructors above w/ bind +x Constructor preconditions checked before member initialization list +x Constructors have no `.precondition` (must use `constructor_precondition` instead) -o Destructors subcontracting (w/ postconditions) +x Destructors subcontracting (w/ postconditions) --> for x in [class, reverse(bases)] ( static_inv > inv > body > static_inv (but not inv) > post ) --> protected and private bases ALSO contract (because always part of C++ obj destructor mechanism) -o Destructors have no `.precondition` (because destructors have no argument) -o Destructors above w/ bind -(No overload because destructors have no argument) +x Destructors have no `.precondition` (because destructors have no argument) * Private members check pre and post, but no cv/static invariants and no subcontracting * Private members above w/ bind @@ -29,28 +25,21 @@ o Destructors above w/ bind --> pre in logic-or --> post and inv in logic-and --> protected and private bases do not subcontract -* Require, but always allow, bind for public virtual members -* Require, but always allow, introspect for overriding public members -* Public members above w/ bind -o Free functions pre and post (but obviously no cv/static invariants and no subcontracting) -o Free functions above w/ bind -o Check (just for free functions, other contract use same set_... classes anyways) that: +x Free functions pre and post (but obviously no cv/static invariants and no subcontracting) +x Check (just for free functions, other contract use same set_... classes anyways) that: OK: nothing | pre (only) | post (only) | pre > post | post > pre Error: pre > pre | post > post | pre > post > pre | post > pre > post -For all contract types (constructors, etc.): -* Member function passed to bind must be const -* Function passed to bind must take all args as T const&, but last arg that must be boost::contract::call -* Arguments passed to bind should not be every copied (cpcnt == 0) - -* Old values with/without bind, with/without subcontracting +x Old values with/without subcontracting --> copied and evaluated only once by OLDOF -* Test bind wit a member function taking no argument and a free function taking a single argument as pointer (to make sure these overloads can be resolved) -* Result... maybe test with/without boost::optional... +* Result... by ref so never copied +* Result as boost::optional... by ref so never copied * On body throw... for all contract types +* Throw from contract (non-contract exception) * Failure handlers and throw on contract failure * Disable pre, post, and/or entry/exit inv (all combinations) +* Contracts disabled while checking contracts... * Overloading for all contracts * Volatile inv * No static inv / const inv / volatile inv when static_inv / inv const / inv const volatile func not defined (for ctor, dtor, and pub member) diff --git a/include/boost/contract.hpp b/include/boost/contract.hpp index aae4e85..1d2b94d 100644 --- a/include/boost/contract.hpp +++ b/include/boost/contract.hpp @@ -6,12 +6,11 @@ #include #include -#include #include #include #include -#include #include +#include #include #include #include diff --git a/include/boost/contract/aux_/condition/check_pre_post.hpp b/include/boost/contract/aux_/condition/check_pre_post.hpp index 53f9472..7b6fddb 100644 --- a/include/boost/contract/aux_/condition/check_pre_post.hpp +++ b/include/boost/contract/aux_/condition/check_pre_post.hpp @@ -4,8 +4,8 @@ #include #include -#include #include +#include /** @cond */ #include // TODO: Can I reduce boost.function overhead? /** @endcond */ @@ -41,7 +41,7 @@ private: // TODO: I should avoid repeating code between this and above... template<> -class check_pre_post : public check_pre_only { +class check_pre_post : public check_pre_only { public: explicit check_pre_post(boost::contract::from from) : check_pre_only(from) {} @@ -52,11 +52,13 @@ public: void set_post(F const& f) { post_ = f; post_available(); } protected: - void check_post(boost::contract::aux::none&) { + void check_post() { try { if(post_) post_(); } catch(...) { boost::contract::postcondition_failed(from()); } } + void check_post(none&) { check_post(); } + virtual void post_available() {} private: diff --git a/include/boost/contract/aux_/condition/check_pre_post_inv.hpp b/include/boost/contract/aux_/condition/check_pre_post_inv.hpp index d5cdef7..9fd2b5f 100644 --- a/include/boost/contract/aux_/condition/check_pre_post_inv.hpp +++ b/include/boost/contract/aux_/condition/check_pre_post_inv.hpp @@ -6,6 +6,7 @@ #include #include #include +#include /** @cond */ #include #include @@ -16,19 +17,18 @@ namespace boost { namespace contract { namespace aux { template class check_pre_post_inv : public check_pre_post { // Copyable (as *). public: + // obj can be 0 for static member functions. explicit check_pre_post_inv(boost::contract::from from, C* obj) : check_pre_post(from), obj_(obj) {} virtual ~check_pre_post_inv() {} protected: - void check_entry_inv() { - check_inv(/* on_enty = */ true, /* static_inv_only = */ false); - } - - void check_exit_inv() { - check_inv(/* on_enty = */ false, /* static_inv_only = */ false); - } + void check_exit_inv() { check_inv(false, false); } + void check_entry_inv() { check_inv(true, false); } + + void check_entry_static_inv() { check_inv(true, true); } + void check_exit_static_inv() { check_inv(false, true); } C* object() { return obj_; } @@ -56,6 +56,7 @@ private: void check_const_inv(bool, boost::mpl::false_ const&) {} void check_const_inv(bool on_entry, boost::mpl::true_ const&) { + BOOST_CONTRACT_AUX_DEBUG(obj_); try { obj_->BOOST_CONTRACT_CONFIG_INVARIANT(); } catch(...) { if(on_entry) { 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 6a6be18..8441b15 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 @@ -171,7 +171,7 @@ private: BOOST_CONTRACT_AUX_DEBUG(nest_->v_->action_ != boost::contract::virtual_::no_action); try { - O::template BOOST_CONTRACT_AUX_NAME1(base_call)( + O::template BOOST_CONTRACT_AUX_NAME1(base_call)( nest_->object(), nest_->a0_, nest_->v_); } catch(check_subcontracted_pre_post_inv_::no_error const&) { if(nest_->v_->action_ == boost::contract::virtual_::check_pre) { diff --git a/include/boost/contract/aux_/function/constructor.hpp b/include/boost/contract/aux_/function/constructor.hpp index cb9d2b2..951cb99 100644 --- a/include/boost/contract/aux_/function/constructor.hpp +++ b/include/boost/contract/aux_/function/constructor.hpp @@ -4,55 +4,35 @@ #include #include +#include /** @cond */ #include /** @endcond */ namespace boost { namespace contract { namespace aux { +// Ctor subcontracting impl via C++ obj construction mechanism. template -class constructor : - // Ctor subcontracting impl via C++ obj construction mechanism. - public boost::contract::aux::check_pre_post_inv { +class constructor : public check_pre_post_inv { public: - explicit constructor(boost::shared_ptr call, - C const* obj) : - boost::contract::aux::check_pre_post_inv(boost::contract:: - from_constructor, call, obj) - { init(); } - - explicit constructor(C const* obj) : boost::contract::aux:: - check_pre_post_inv(boost::contract::from_constructor, obj) - { init(); } - -private: - void init() { - // No object before ctor body so only static inv at entry. - this->check_entry_inv(/* static_inv_only = */ true); - if(this->decl_call()) { // Throw no error (so not in dtor). - this->check_exit_inv(/* static_inv_only = */ - std::uncaught_exception()); - } + explicit constructor(C* obj) : + check_pre_post_inv( + boost::contract::from_constructor, obj) + { + // No object before ctor body so check only static inv at entry. + this->check_entry_static_inv(); } // Ctor pre checked by constructor_precondition at start of init list. - void post_available() /* override */ { - if(this->decl_call() && !std::uncaught_exception()) { - this->check_post(); // Throw no_error (so not in dtor). - } - } - -public: - // If ctor body threw, only check static inv, otherwise obj constructed so - // check also non-static inv and post (subcontracting implemented - // automatically via C++ object constructor mechanism, so no calls to - // check_subcontracted_... in this case). ~constructor() { - if(!this->decl_call()) { - this->check_exit_inv(/* static_inv_only = */ - std::uncaught_exception()); - if(!std::uncaught_exception()) this->check_post(); + // 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()) { + this->check_exit_static_inv(); + } else { + this->check_exit_inv(); + this->check_post(); } } }; diff --git a/include/boost/contract/aux_/function/destructor.hpp b/include/boost/contract/aux_/function/destructor.hpp index 8ec67c1..0c2c801 100644 --- a/include/boost/contract/aux_/function/destructor.hpp +++ b/include/boost/contract/aux_/function/destructor.hpp @@ -4,63 +4,40 @@ #include #include -#include +#include /** @cond */ #include /** @endcond */ namespace boost { namespace contract { namespace aux { +// Dtor subcontracting impl via C++ obj destruction mechanism. template -class destructor : public boost::contract::aux::check_pre_post_inv { +class destructor : public check_pre_post_inv { public: - explicit destructor(C const* obj) : - boost::contract::aux::check_pre_post_inv( + explicit destructor(C* obj) : + check_pre_post_inv( boost::contract::from_destructor, obj) - { init(); } - - explicit destructor(boost::shared_ptr call, - C const* obj) : - boost::contract::aux::check_pre_post_inv( - boost::contract::from_destructor, call, obj) - { init(); } - -private: - // Obj still exists (before dtor body) so check static and non-static inv - // (subcontracting implemented automatically via C++ object destruction - // mechanism, so no calls to check_subcontracted_... in this case). - void init() { + { + // Obj exists (before dtor body) so check static and non-static inv. this->check_entry_inv(); - if(this->decl_call()) { - this->check_exit_inv(/* static_inv_only = */ - !std::uncaught_exception()); - } } // Dtor cannot have pre because it has no parameters. - // Ctor post always checked after body, at exit (see below). - // NOTE: Even if there is no obj after dtor body, this library allows for - // dtor post (e.g., to check static members for an instance counter class). - void post_available() /* override */ { - if(this->decl_call() && !std::uncaught_exception()) { - this->check_post(); - } - } - -public: - // 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 static inv and post (subcontracting implemented - // automatically via C++ object destruction mechanism, so no calls to - // check_subcontracted_... in this case). - // NOTE: In theory C++ destructors should not throw, but the language allows - // for that so this library must handle such a case. ~destructor() { - if(!this->decl_call()) { - this->check_exit_inv(/* static_inv_only = */ - !std::uncaught_exception()); - if(!std::uncaught_exception()) this->check_post(); + // 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 + // after dtor body, this library allows dtor post, for example to check + // static members for an instance counter class). + // NOTE: In theory C++ destructors should not throw, but the language + // allows for that so this library must handle such a case. + if(std::uncaught_exception()) { + this->check_exit_inv(); + } else { + this->check_exit_static_inv(); + this->check_post(); } } }; diff --git a/include/boost/contract/aux_/function/free_function.hpp b/include/boost/contract/aux_/function/free_function.hpp index a02d478..a91ffa5 100644 --- a/include/boost/contract/aux_/function/free_function.hpp +++ b/include/boost/contract/aux_/function/free_function.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include /** @cond */ #include #include @@ -14,24 +14,16 @@ namespace boost { namespace contract { namespace aux { // Also used for private and protected members. template -class basic_free_function : public check_pre_post { +class basic_free_function : public check_pre_post { public: - explicit basic_free_function() : check_pre_post(From) {} - - explicit basic_free_function(boost::shared_ptr decl_call) : - check_pre_post(From, decl_call) {} + explicit basic_free_function() : check_pre_post(From) {} private: - void pre_available() /* override */ { check_pre(); } + void pre_available() /* override */ { this->check_pre(); } - void post_available() /* override */ { - // Throw no_error (so not in dtor). - if(this->decl_call() && !std::uncaught_exception()) check_post(); - } - public: ~basic_free_function() { - if(!this->decl_call() && !std::uncaught_exception()) check_post(); + if(!std::uncaught_exception()) this->check_post(); } }; diff --git a/include/boost/contract/aux_/function/public_member.hpp b/include/boost/contract/aux_/function/public_member.hpp index 2b28084..198f5cb 100644 --- a/include/boost/contract/aux_/function/public_member.hpp +++ b/include/boost/contract/aux_/function/public_member.hpp @@ -4,6 +4,7 @@ #include #include +#include /** @cond */ #include #include @@ -37,10 +38,9 @@ private: public: ~public_member() { - // Body didn't throw. - if(!this->base_call() && !std::uncaught_exception()) { + if(!this->base_call()) { this->check_subcontracted_exit_inv(); - this->check_subcontracted_post(); + if(!std::uncaught_exception()) this->check_subcontracted_post(); } } }; diff --git a/include/boost/contract/aux_/function/public_static_member.hpp b/include/boost/contract/aux_/function/public_static_member.hpp new file mode 100644 index 0000000..c0182d0 --- /dev/null +++ b/include/boost/contract/aux_/function/public_static_member.hpp @@ -0,0 +1,38 @@ + +#ifndef BOOST_CONTRACT_AUX_PUBLIC_STATIC_MEMBER_HPP_ +#define BOOST_CONTRACT_AUX_PUBLIC_STATIC_MEMBER_HPP_ + +#include +#include +#include +#include +/** @cond */ +#include +#include +/** @endcond */ + +namespace boost { namespace contract { namespace aux { + +// No subcontracting because static so no obj and no subst. principle. +template +class public_static_member : public check_pre_post_inv { +public: + explicit public_static_member() : check_pre_post_inv( + boost::contract::from_public_member, 0) { + this->check_entry_static_inv(); + } + +private: + void pre_available() /* override */ { this->check_pre(); } + +public: + ~public_static_member() { + this->check_exit_static_inv(); + if(!std::uncaught_exception()) this->check_post(); + } +}; + +} } } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/aux_/none.hpp b/include/boost/contract/aux_/none.hpp index 701cfd6..a6e2eba 100644 --- a/include/boost/contract/aux_/none.hpp +++ b/include/boost/contract/aux_/none.hpp @@ -6,7 +6,7 @@ namespace boost { namespace contract { namespace aux { class none { // Tag for "no type". public: - static none value; // Tag for "no value". + static none value; // Tag for "no value" (can take ref, ptr, etc.). // Allow default constructor and copy operations. @@ -15,6 +15,10 @@ public: none none::value; +// Transform `void` to `none` type. +template struct none_if_void { typedef T type; }; +template<> struct none_if_void { typedef none type; }; + // TODO: Remove, for testing only... #include std::ostream& operator<<(std::ostream& out, none const&) { diff --git a/include/boost/contract/constructor.hpp b/include/boost/contract/constructor.hpp index 03b742e..ecba5a9 100644 --- a/include/boost/contract/constructor.hpp +++ b/include/boost/contract/constructor.hpp @@ -5,7 +5,6 @@ /** @file */ #include -#include #include #include /** @cond */ @@ -15,14 +14,8 @@ namespace boost { namespace contract { template -set_postcondition_only constructor(decl const& c, C const* obj) { - return set_postcondition_only(boost::make_shared< - boost::contract::aux::constructor >(c.call_, obj)); -} - -template -set_postcondition_only constructor(C const* obj) { - return set_postcondition_only(boost::make_shared< +set_postcondition_only<> constructor(C* obj) { + return set_postcondition_only<>(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 0b93fb4..9275df3 100644 --- a/include/boost/contract/core/set_nothing.hpp +++ b/include/boost/contract/core/set_nothing.hpp @@ -21,15 +21,16 @@ public: // No set function members here. private: - explicit set_nothing(boost::shared_ptr< - boost::contract::aux::check_pre_only> check) : check_(check) {} - - boost::shared_ptr 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 scoped; friend class set_precondition_only; - template friend class set_postcondition_only; + + template + friend class set_postcondition_only; }; } } // namespace diff --git a/include/boost/contract/core/set_postcondition_only.hpp b/include/boost/contract/core/set_postcondition_only.hpp index 8226e06..088ef33 100644 --- a/include/boost/contract/core/set_postcondition_only.hpp +++ b/include/boost/contract/core/set_postcondition_only.hpp @@ -6,13 +6,14 @@ #include #include +#include /** @cond */ #include /** @endcond */ namespace boost { namespace contract { -template +template class set_postcondition_only { public: template @@ -22,14 +23,22 @@ public: } private: - explicit set_postcondition_only(boost::shared_ptr< - boost::contract::aux::check_pre_post > check) : check_(check) {} - - boost::shared_ptr > check_; + 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 scoped; - template friend class set_precondition_postcondition; + + template + friend class set_precondition_postcondition; + + template + friend set_postcondition_only constructor(C*); + + template + friend set_postcondition_only destructor(C*); }; } } // namespace diff --git a/include/boost/contract/core/set_precondition_only.hpp b/include/boost/contract/core/set_precondition_only.hpp index 2cdb825..ff67e87 100644 --- a/include/boost/contract/core/set_precondition_only.hpp +++ b/include/boost/contract/core/set_precondition_only.hpp @@ -21,15 +21,15 @@ public: } private: - explicit set_precondition_only(boost::shared_ptr< - boost::contract::aux::check_pre_only> check) : check_(check) {} - - boost::shared_ptr check_; + 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 scoped; - template friend class set_precondition_postcondition; - + + template + friend class set_precondition_postcondition; }; } } // namespace diff --git a/include/boost/contract/core/set_precondition_postcondition.hpp b/include/boost/contract/core/set_precondition_postcondition.hpp index a15fc83..5457635 100644 --- a/include/boost/contract/core/set_precondition_postcondition.hpp +++ b/include/boost/contract/core/set_precondition_postcondition.hpp @@ -7,6 +7,7 @@ #include #include #include +#include /** @cond */ #include /** @endcond */ @@ -21,7 +22,7 @@ namespace boost { namespace boost { namespace contract { -template +template class set_precondition_postcondition { public: template @@ -37,16 +38,29 @@ public: } private: - explicit set_precondition_postcondition(boost::shared_ptr< - boost::contract::aux::check_pre_post > check) : check_(check) {} - - boost::shared_ptr > check_; + typedef boost::shared_ptr::type> > check_ptr; + explicit set_precondition_postcondition(check_ptr check) : check_(check) {} + check_ptr check_; // Friendship used to limit library's public API. friend class scoped; + friend set_precondition_postcondition<> free_function(); + friend set_precondition_postcondition<> protected_member(); + friend set_precondition_postcondition<> private_member(); + + template + friend set_precondition_postcondition<> public_member(); + + template + friend set_precondition_postcondition<> public_member(virtual_*, C*); template friend set_precondition_postcondition public_member(virtual_*, R_&, C*); + + template + friend set_precondition_postcondition<> public_member(virtual_*, F, C*); + template friend set_precondition_postcondition public_member( virtual_*, R_&, F, C*, A0&); diff --git a/include/boost/contract/destructor.hpp b/include/boost/contract/destructor.hpp index 8d161a0..5c1d014 100644 --- a/include/boost/contract/destructor.hpp +++ b/include/boost/contract/destructor.hpp @@ -5,7 +5,6 @@ /** @file */ #include -#include #include /** @cond */ #include @@ -14,17 +13,11 @@ namespace boost { namespace contract { template -set_postcondition_only destructor(C const* obj) { - return set_postcondition_only(boost::make_shared< +set_postcondition_only<> destructor(C* obj) { + return set_postcondition_only<>(boost::make_shared< boost::contract::aux::destructor >(obj)); } -template -set_postcondition_only destructor(decl const& c, C const* obj) { - return set_postcondition_only(boost::make_shared< - boost::contract::aux::destructor >(c.call_, obj)); -} - } } // namespace #endif // #include guard diff --git a/include/boost/contract/free_function.hpp b/include/boost/contract/free_function.hpp index d439319..bba5a03 100644 --- a/include/boost/contract/free_function.hpp +++ b/include/boost/contract/free_function.hpp @@ -5,7 +5,6 @@ /** @file */ #include -#include #include /** @cond */ #include @@ -13,17 +12,11 @@ namespace boost { namespace contract { -boost::contract::set_precondition_postcondition free_function() { - return boost::contract::set_precondition_postcondition(boost::make_shared< +set_precondition_postcondition<> free_function() { + return set_precondition_postcondition<>(boost::make_shared< boost::contract::aux::free_function>()); } -boost::contract::set_precondition_postcondition free_function( - boost::contract::decl const& c) { - return boost::contract::set_precondition_postcondition(boost::make_shared< - boost::contract::aux::free_function>(c.call_)); -} - } } // namespace #endif // #include guard diff --git a/include/boost/contract/oldof.hpp b/include/boost/contract/oldof.hpp index e797fcd..6485c8c 100644 --- a/include/boost/contract/oldof.hpp +++ b/include/boost/contract/oldof.hpp @@ -26,6 +26,9 @@ BOOST_CONTRACT_ERROR_macro_OLDOF_requires_variadic_macros_otherwise_manually_pro #include /** @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. + /* PUBLIC */ #define BOOST_CONTRACT_OLDOF(...) \ @@ -91,9 +94,8 @@ public: explicit old(virtual_* v, old const& other) : v_(v), value_(other.value_) {} template - /* implicit */ old(T const& old_value) : - value_(boost::make_shared(old_value)) { // T's one single copy. - } + /* implicit */ old(T const& old_value) : v_(0), + value_(boost::make_shared(old_value)) {} // T's one single copy. // TODO: I might be able to use unique_ptr here instead of shared_ptr. That // might be the true for the pointer that holds contract and call as well... diff --git a/include/boost/contract/override.hpp b/include/boost/contract/override.hpp index 490146e..a0d1ae4 100644 --- a/include/boost/contract/override.hpp +++ b/include/boost/contract/override.hpp @@ -6,6 +6,7 @@ #include #include +#include #include /** @cond */ #include @@ -20,6 +21,20 @@ struct trait { \ BOOST_CONTRACT_AUX_INTROSPECTION_HAS_MEMBER_FUNCTION( \ BOOST_CONTRACT_AUX_NAME1(has_member_function), f) \ + \ + template< \ + class BOOST_CONTRACT_AUX_NAME1(B), \ + class BOOST_CONTRACT_AUX_NAME1(C) \ + > \ + static void BOOST_CONTRACT_AUX_NAME1(base_call)( \ + BOOST_CONTRACT_AUX_NAME1(C)* BOOST_CONTRACT_AUX_NAME1(obj), \ + boost::contract::aux::none&, \ + boost::contract::virtual_* BOOST_CONTRACT_AUX_NAME1(v) \ + ) { \ + BOOST_CONTRACT_AUX_NAME1(obj)->BOOST_CONTRACT_AUX_NAME1(B)::f( \ + BOOST_CONTRACT_AUX_NAME1(v) \ + ); \ + } \ \ template< \ class BOOST_CONTRACT_AUX_NAME1(B), \ diff --git a/include/boost/contract/private_member.hpp b/include/boost/contract/private_member.hpp index 85f9440..f732b97 100644 --- a/include/boost/contract/private_member.hpp +++ b/include/boost/contract/private_member.hpp @@ -5,7 +5,6 @@ /** @file */ #include -#include #include /** @cond */ #include @@ -13,17 +12,11 @@ namespace boost { namespace contract { -boost::contract::set_precondition_postcondition private_member() { - return boost::contract::set_precondition_postcondition(boost::make_shared< +set_precondition_postcondition<> private_member() { + return set_precondition_postcondition<>(boost::make_shared< boost::contract::aux::private_member>()); } -boost::contract::set_precondition_postcondition private_member( - boost::contract::call const& c) { - return boost::contract::set_precondition_postcondition(boost::make_shared< - boost::contract::aux::private_member>(c.call_)); -} - } } // namespace #endif // diff --git a/include/boost/contract/protected_member.hpp b/include/boost/contract/protected_member.hpp index 94716e0..24067b2 100644 --- a/include/boost/contract/protected_member.hpp +++ b/include/boost/contract/protected_member.hpp @@ -5,7 +5,6 @@ /** @file */ #include -#include #include /** @cond */ #include @@ -13,17 +12,11 @@ namespace boost { namespace contract { -boost::contract::set_precondition_postcondition protected_member() { - return boost::contract::set_precondition_postcondition(boost::make_shared< +set_precondition_postcondition<> protected_member() { + return set_precondition_postcondition<>(boost::make_shared< boost::contract::aux::protected_member>()); } -boost::contract::set_precondition_postcondition protected_member( - boost::contract::call const& c) { - return boost::contract::set_precondition_postcondition(boost::make_shared< - boost::contract::aux::protected_member>(c.call_)); -} - } } // namespace #endif // diff --git a/include/boost/contract/public_member.hpp b/include/boost/contract/public_member.hpp index a1ab498..3204f0c 100644 --- a/include/boost/contract/public_member.hpp +++ b/include/boost/contract/public_member.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include /** @cond */ #include @@ -14,10 +15,17 @@ namespace boost { namespace contract { +// For public static member functions. +template +set_precondition_postcondition<> public_member() { + return set_precondition_postcondition<>(boost::make_shared< + boost::contract::aux::public_static_member >()); +} + // For non-virtual of class with no bases. template -set_precondition_postcondition public_member(C* obj) { - return set_precondition_postcondition(boost::make_shared< +set_precondition_postcondition<> public_member(C* obj) { + return set_precondition_postcondition<>(boost::make_shared< boost::contract::aux::public_member< boost::contract::aux::none, boost::contract::aux::none, @@ -25,13 +33,14 @@ set_precondition_postcondition public_member(C* obj) { C, boost::contract::aux::none > - >(0, obj, boost::contract::aux::none::value)); + >(0, obj, boost::contract::aux::none::value, + boost::contract::aux::none::value)); } // For virtual members of class with no bases. template -set_precondition_postcondition public_member(virtual_* v, C* obj) { - return set_precondition_postcondition(boost::make_shared< +set_precondition_postcondition<> public_member(virtual_* v, C* obj) { + return set_precondition_postcondition<>(boost::make_shared< boost::contract::aux::public_member< boost::contract::aux::none, boost::contract::aux::none, @@ -39,7 +48,8 @@ set_precondition_postcondition public_member(virtual_* v, C* obj) { C, boost::contract::aux::none > - >(v, obj, boost::contract::aux::none::value)); + >(v, obj, boost::contract::aux::none::value, + boost::contract::aux::none::value)); } // TODO: R should be specified *only* when v is present. If F present but not @@ -71,8 +81,8 @@ set_precondition_postcondition public_member(virtual_* v, R& r, C* obj) { // For non-virtual members of class with bases. template -set_precondition_postcondition public_member(F, C* obj) { - return set_precondition_postcondition(boost::make_shared< +set_precondition_postcondition<> public_member(F, C* obj) { + return set_precondition_postcondition<>(boost::make_shared< boost::contract::aux::public_member< O, boost::contract::aux::none, @@ -85,8 +95,8 @@ set_precondition_postcondition public_member(F, C* obj) { // For virtual members of class with bases. template -set_precondition_postcondition public_member(virtual_* v, F, C* obj) { - return set_precondition_postcondition(boost::make_shared< +set_precondition_postcondition<> public_member(virtual_* v, F, C* obj) { + return set_precondition_postcondition<>(boost::make_shared< boost::contract::aux::public_member< O, boost::contract::aux::none, @@ -94,14 +104,15 @@ set_precondition_postcondition public_member(virtual_* v, F, C* obj) { C, boost::contract::aux::none > - >(v, obj, boost::contract::aux::none::value)); + >(v, obj, boost::contract::aux::none::value, + boost::contract::aux::none::value)); } // arity = 1 template -set_precondition_postcondition public_member(F, C* obj, A0& a0) { - return set_precondition_postcondition(boost::make_shared< +set_precondition_postcondition<> public_member(F, C* obj, A0& a0) { + return set_precondition_postcondition<>(boost::make_shared< boost::contract::aux::public_member< O, boost::contract::aux::none, diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 6374432..41bc928 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,5 +1,35 @@ -subdir-run public_member : bases_leaf_call ; -subdir-run public_member : bases_virtual_call ; -subdir-run public_member : bases_branch_call ; +subdir-run constructor : bases ; +subdir-run constructor : body_throw ; +subdir-compile-fail constructor : no_pre-error ; + +subdir-run destructor : bases ; +subdir-run destructor : body_throw ; +subdir-compile-fail destructor : no_pre-error ; + +subdir-run public_member : bases ; +subdir-run public_member : bases_virtual ; +subdir-run public_member : bases_branch ; +subdir-run public_member : body_throw ; +subdir-run public_member : static ; +subdir-run public_member : static_body_throw ; + +subdir-run protected_member : bases ; +subdir-run protected_member : body_throw ; + +subdir-run private_member : bases ; +subdir-run private_member : body_throw ; + +subdir-run free_function : nominal ; +subdir-run free_function : body_throw ; + +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 ; diff --git a/test/constructor/bases.cpp b/test/constructor/bases.cpp index 80ead12..9821d6f 100644 --- a/test/constructor/bases.cpp +++ b/test/constructor/bases.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -25,51 +25,50 @@ struct t void invariant() const { out << Id << "::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ < 0); + BOOST_CONTRACT_ASSERT(k_ < 0); } static void static_invariant() { out << Id << "::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); + BOOST_CONTRACT_ASSERT(l.value >= 0); } - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; + struct l_tag; typedef boost::contract::aux::test::cpcnt l_type; + static l_type l; - struct arg_tag; - typedef boost::contract::aux::test::cpcnt arg_cnt; + struct z_tag; typedef boost::contract::aux::test::cpcnt z_type; // MSVC 2010 errors on lambdas in template member initializations... - static void constructor_precondition(arg_cnt const& arg) { + static void constructor_precondition(z_type const& z) { out << Id << "::ctor::pre" << std::endl; - BOOST_CONTRACT_ASSERT(arg.value < 0); + BOOST_CONTRACT_ASSERT(z.value < 0); } - explicit t(arg_cnt& arg) : + explicit t(z_type& z) : boost::contract::constructor_precondition >( - boost::bind(&t::constructor_precondition, boost::cref(arg))) + boost::bind(&t::constructor_precondition, boost::cref(z))) { - boost::shared_ptr old_arg = - BOOST_CONTRACT_OLDOF(arg_cnt::eval(arg)); - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(n_cnt::eval(n)); - boost::contract::var contract = boost::contract::constructor(this) + boost::shared_ptr old_z = + BOOST_CONTRACT_OLDOF(z_type::eval(z)); + boost::shared_ptr old_l = + BOOST_CONTRACT_OLDOF(l_type::eval(l)); + boost::contract::scoped c = boost::contract::constructor(this) .postcondition([&] { out << Id << "::ctor::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == old_arg->value); - BOOST_CONTRACT_ASSERT(arg.value == n.value); - BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); + BOOST_CONTRACT_ASSERT(k_ == old_z->value); + BOOST_CONTRACT_ASSERT(z.value == l.value); + BOOST_CONTRACT_ASSERT(l.value == old_l->value + 1); }) ; out << Id << "::ctor::body" << std::endl; - i_ = arg.value; - arg.value = ++n.value; + k_ = z.value; + z.value = ++l.value; } - virtual ~t() { --n.value; } + virtual ~t() { --l.value; } private: - int i_; + int k_; }; -template typename t::n_cnt t::n; +template typename t::l_type t::l; // Test deep inheritance (2 vertical levels), multiple inheritance (4 // horizontal levels), and that all public/protected/private part of @@ -77,7 +76,7 @@ template typename t::n_cnt t::n; // are part of C++ object construction mechanism). struct c #define BASES private boost::contract::constructor_precondition, \ - public t<'d'>, protected t<'e'>, private t<'f'> + public t<'d'>, protected t<'p'>, private t<'q'>, public t<'e'> : BASES { typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; @@ -85,50 +84,49 @@ struct c void invariant() const { out << "c::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ < 0); + BOOST_CONTRACT_ASSERT(j_ < 0); } static void static_invariant() { out << "c::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); + BOOST_CONTRACT_ASSERT(m.value >= 0); } - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; + struct m_tag; typedef boost::contract::aux::test::cpcnt m_type; + static m_type m; - struct arg_tag; - typedef boost::contract::aux::test::cpcnt arg_cnt; + struct y_tag; typedef boost::contract::aux::test::cpcnt y_type; - explicit c(arg_cnt& arg, t<'d'>::arg_cnt& d_arg, t<'e'>::arg_cnt& e_arg, - t<'f'>::arg_cnt& f_arg) : + 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) : boost::contract::constructor_precondition([&] { out << "c::ctor::pre" << std::endl; - BOOST_CONTRACT_ASSERT(arg.value < 0); + BOOST_CONTRACT_ASSERT(y.value < 0); }), - t<'d'>(d_arg), t<'e'>(e_arg), t<'f'>(f_arg) + t<'d'>(dz), t<'p'>(pz), t<'q'>(qz), t<'e'>(ez) { - boost::shared_ptr old_arg = - BOOST_CONTRACT_OLDOF(arg_cnt::eval(arg)); - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(n_cnt::eval(n)); - boost::contract::var contract = boost::contract::constructor(this) + 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::contract::scoped c = boost::contract::constructor(this) .postcondition([&] { out << "c::ctor::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == old_arg->value); - BOOST_CONTRACT_ASSERT(arg.value == n.value); - BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); + BOOST_CONTRACT_ASSERT(j_ == old_y->value); + BOOST_CONTRACT_ASSERT(y.value == m.value); + BOOST_CONTRACT_ASSERT(m.value == old_m->value + 1); }) ; out << "c::ctor::body" << std::endl; - i_ = arg.value; - arg.value = ++n.value; + j_ = y.value; + y.value = ++m.value; } - virtual ~c() { --n.value; } + virtual ~c() { --m.value; } private: - int i_; + int j_; }; -c::n_cnt c::n; +c::m_type c::m; // Test not (fully) contracted base is not part of constructor subcontracting. struct b @@ -163,36 +161,34 @@ struct a BOOST_CONTRACT_ASSERT(n.value >= 0); } - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; + struct n_tag; typedef boost::contract::aux::test::cpcnt n_type; + static n_type n; - struct arg_tag; - typedef boost::contract::aux::test::cpcnt arg_cnt; + struct x_tag; typedef boost::contract::aux::test::cpcnt x_type; - explicit a(arg_cnt& arg, c::arg_cnt& c_arg, t<'d'>::arg_cnt& d_arg, - t<'e'>::arg_cnt& e_arg, t<'f'>::arg_cnt& f_arg) : + 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) : boost::contract::constructor_precondition([&] { out << "a::ctor::pre" << std::endl; - BOOST_CONTRACT_ASSERT(arg.value < 0); + BOOST_CONTRACT_ASSERT(x.value < 0); }), - b(), - c(c_arg, d_arg, e_arg, f_arg) + b(), c(y, dz, pz, qz, ez) { - boost::shared_ptr old_arg = - BOOST_CONTRACT_OLDOF(arg_cnt::eval(arg)); - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(n_cnt::eval(n)); - boost::contract::var contract = boost::contract::constructor(this) + boost::shared_ptr old_x = + BOOST_CONTRACT_OLDOF(x_type::eval(x)); + boost::shared_ptr old_n = + BOOST_CONTRACT_OLDOF(n_type::eval(n)); + boost::contract::scoped c = boost::contract::constructor(this) .postcondition([&] { out << "a::ctor::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == old_arg->value); - BOOST_CONTRACT_ASSERT(arg.value == n.value); + BOOST_CONTRACT_ASSERT(i_ == old_x->value); + BOOST_CONTRACT_ASSERT(x.value == n.value); BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); }) ; out << "a::ctor::body" << std::endl; - i_ = arg.value; - arg.value = ++n.value; + i_ = x.value; + x.value = ++n.value; } virtual ~a() { --n.value; } @@ -200,32 +196,49 @@ struct a private: int i_; }; -a::n_cnt a::n; +a::n_type a::n; int main() { std::ostringstream ok; - t<'f'>::arg_cnt f_arg; f_arg.value = -5; - t<'e'>::arg_cnt e_arg; e_arg.value = -4; - t<'d'>::arg_cnt d_arg; d_arg.value = -3; - c::arg_cnt c_arg; c_arg.value = -2; - a::arg_cnt a_arg; a_arg.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(a_arg, c_arg, d_arg, e_arg, f_arg); - ok.str(""); - ok + 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 - << "d::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 << "e::ctor::pre" << std::endl << "e::static_inv" << std::endl @@ -234,13 +247,6 @@ int main() { << "e::inv" << std::endl << "e::ctor::post" << std::endl - << "f::ctor::pre" << std::endl - << "f::static_inv" << std::endl - << "f::ctor::body" << std::endl - << "f::static_inv" << std::endl - << "f::inv" << std::endl - << "f::ctor::post" << std::endl - << "c::static_inv" << std::endl << "c::ctor::body" << std::endl << "c::static_inv" << std::endl @@ -255,17 +261,19 @@ int main() { ; BOOST_TEST(out.eq(ok.str())); - BOOST_TEST_EQ(a_arg.copies(), 1); BOOST_TEST_EQ(a_arg.evals(), 1); - BOOST_TEST_EQ(c_arg.copies(), 1); BOOST_TEST_EQ(c_arg.evals(), 1); - BOOST_TEST_EQ(d_arg.copies(), 1); BOOST_TEST_EQ(d_arg.evals(), 1); - BOOST_TEST_EQ(e_arg.copies(), 1); BOOST_TEST_EQ(e_arg.evals(), 1); - BOOST_TEST_EQ(f_arg.copies(), 1); BOOST_TEST_EQ(f_arg.evals(), 1); + 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::n.copies(), 1); BOOST_TEST_EQ(a::n.evals(), 1); - BOOST_TEST_EQ(c::n.copies(), 1); BOOST_TEST_EQ(c::n.evals(), 1); - BOOST_TEST_EQ(t<'d'>::n.copies(), 1); BOOST_TEST_EQ(t<'d'>::n.evals(), 1); - BOOST_TEST_EQ(t<'e'>::n.copies(), 1); BOOST_TEST_EQ(t<'e'>::n.evals(), 1); - BOOST_TEST_EQ(t<'f'>::n.copies(), 1); BOOST_TEST_EQ(t<'f'>::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); return boost::report_errors(); } diff --git a/test/constructor/bases_decl.cpp b/test/constructor/bases_decl.cpp deleted file mode 100644 index fb358c8..0000000 --- a/test/constructor/bases_decl.cpp +++ /dev/null @@ -1,300 +0,0 @@ - -// Test constructor subcontracting and contract declaration functions. - -#include "../aux_/oteststream.hpp" -#include "../aux_/cpcnt.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -boost::contract::aux::test::oteststream out; - -template -struct t - #define BASES private boost::contract::constructor_precondition > - : BASES -{ - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void invariant() const { - out << Id << "::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ < 0); - } - static void static_invariant() { - out << Id << "::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); - } - - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; - - struct arg_tag; - typedef boost::contract::aux::test::cpcnt arg_cnt; - - // MSVC 2010 errors on lambdas in template member initializations... - static void constructor_precondition(arg_cnt const& arg) { - out << Id << "::ctor::pre" << std::endl; - BOOST_CONTRACT_ASSERT(arg.value < 0); - } - void constructor(arg_cnt const& arg, boost::contract::decl c) const { - boost::shared_ptr old_arg = - BOOST_CONTRACT_OLDOF(c, arg_cnt::eval(arg)); - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(c, n_cnt::eval(n)); - boost::contract::var contract = boost::contract::constructor(c, this) - .postcondition([&] { - out << Id << "::ctor::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == old_arg->value); - BOOST_CONTRACT_ASSERT(arg.value == n.value); - BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); - }) - ; - } - explicit t(arg_cnt& arg) : - boost::contract::constructor_precondition >(boost::bind( - &t::constructor_precondition, boost::cref(arg))) - { - unsigned save_arg_copies = arg.copies(); - boost::contract::var contract = boost::contract::decl_function( - this, arg, &t::constructor); - // Test decl_function did not copy (only 1 copy from contract old-of). - BOOST_TEST_EQ(arg.copies(), save_arg_copies + 1); - - out << Id << "::ctor::body" << std::endl; - i_ = arg.value; - arg.value = ++n.value; - } - - virtual ~t() { --n.value; } - -private: - int i_; -}; -template typename t::n_cnt t::n; - -// Test deep inheritance (2 vertical levels), multiple inheritance (4 -// horizontal levels), and that all public/protected/private part of -// subcontracting for constructors (not just public, because all access levels -// are part of C++ object construction mechanism). -struct c - #define BASES private boost::contract::constructor_precondition, \ - public t<'d'>, protected t<'e'>, private t<'f'> - : BASES -{ - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void invariant() const { - out << "c::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ < 0); - } - static void static_invariant() { - out << "c::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); - } - - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; - - struct arg_tag; - typedef boost::contract::aux::test::cpcnt arg_cnt; - - static void constructor_precondition(arg_cnt const& arg) { - out << "c::ctor::pre" << std::endl; - BOOST_CONTRACT_ASSERT(arg.value < 0); - } - void constructor(arg_cnt const& arg, boost::contract::decl c) const { - boost::shared_ptr old_arg = - BOOST_CONTRACT_OLDOF(c, arg_cnt::eval(arg)); - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(c, n_cnt::eval(n)); - boost::contract::var contract = boost::contract::constructor(c, this) - .postcondition([&] { - out << "c::ctor::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == old_arg->value); - BOOST_CONTRACT_ASSERT(arg.value == n.value); - BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); - }) - ; - } - explicit c(arg_cnt& arg, t<'d'>::arg_cnt& d_arg, t<'e'>::arg_cnt& e_arg, - t<'f'>::arg_cnt& f_arg) : - boost::contract::constructor_precondition(boost::bind( - &constructor_precondition, boost::cref(arg))), - t<'d'>(d_arg), t<'e'>(e_arg), t<'f'>(f_arg) - { - unsigned save_arg_copies = arg.copies(); - boost::contract::var contract = boost::contract::decl_function( - this, arg, &c::constructor); - // Test decl_function did not copy (only 1 copy from contract old-of). - BOOST_TEST_EQ(arg.copies(), save_arg_copies + 1); - - out << "c::ctor::body" << std::endl; - i_ = arg.value; - arg.value = ++n.value; - } - - virtual ~c() { --n.value; } - -private: - int i_; -}; -c::n_cnt c::n; - -// Test not (fully) contracted base is not part of constructor subcontracting. -struct b - #define BASES private boost::contract::constructor_precondition - : BASES -{ - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void invariant() const { out << "b::inv" << std::endl; } - static void static_invariant() { out << "b::static_inv" << std::endl; } - - explicit b() {} // No contract. - virtual ~b() {} -}; - -// Test both non-contracted and contracted bases. -struct a - #define BASES private boost::contract::constructor_precondition, \ - public b, public c - : BASES -{ - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void invariant() const { - out << "a::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ < 0); - } - static void static_invariant() { - out << "a::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); - } - - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; - - struct arg_tag; - typedef boost::contract::aux::test::cpcnt arg_cnt; - - static void constructor_precondition(arg_cnt const& arg) { - out << "a::ctor::pre" << std::endl; - BOOST_CONTRACT_ASSERT(arg.value < 0); - } - void constructor(arg_cnt const& arg, boost::contract::decl c) const { - boost::shared_ptr old_arg = - BOOST_CONTRACT_OLDOF(c, arg_cnt::eval(arg)); - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(c, n_cnt::eval(n)); - boost::contract::var contract = boost::contract::constructor(c, this) - .postcondition([&] { - out << "a::ctor::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == old_arg->value); - BOOST_CONTRACT_ASSERT(arg.value == n.value); - BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); - }) - ; - } - explicit a(arg_cnt& arg, c::arg_cnt& c_arg, t<'d'>::arg_cnt& d_arg, - t<'e'>::arg_cnt& e_arg, t<'f'>::arg_cnt& f_arg) : - boost::contract::constructor_precondition(boost::bind( - &a::constructor_precondition, boost::cref(arg))), - b(), c(c_arg, d_arg, e_arg, f_arg) - { - unsigned save_arg_copies = arg.copies(); - boost::contract::var contract = boost::contract::decl_function( - this, arg, &a::constructor); - // Test decl_function did not copy (only 1 copy from contract old-of). - BOOST_TEST_EQ(arg.copies(), save_arg_copies + 1); - - out << "a::ctor::body" << std::endl; - i_ = arg.value; - arg.value = ++n.value; - } - - virtual ~a() { --n.value; } - -private: - int i_; -}; -a::n_cnt a::n; - -int main() { - std::ostringstream ok; - - t<'f'>::arg_cnt f_arg; f_arg.value = -5; - t<'e'>::arg_cnt e_arg; e_arg.value = -4; - t<'d'>::arg_cnt d_arg; d_arg.value = -3; - c::arg_cnt c_arg; c_arg.value = -2; - a::arg_cnt a_arg; a_arg.value = -1; - - out.str(""); - a aa(a_arg, c_arg, d_arg, e_arg, f_arg); - ok.str(""); - ok - // Test all constructor pre checked first. - << "a::ctor::pre" << std::endl - << "c::ctor::pre" << std::endl - << "d::ctor::pre" << std::endl - - // Test static inv, but not const inv, checked before constructor body. - << "d::static_inv" << std::endl - << "d::ctor::body" << std::endl - << "d::static_inv" << std::endl - << "d::inv" << std::endl - << "d::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 - - << "f::ctor::pre" << std::endl - << "f::static_inv" << std::endl - << "f::ctor::body" << std::endl - << "f::static_inv" << std::endl - << "f::inv" << std::endl - << "f::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 - - << "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())); - - BOOST_TEST_EQ(a_arg.copies(), 1); BOOST_TEST_EQ(a_arg.evals(), 1); - BOOST_TEST_EQ(c_arg.copies(), 1); BOOST_TEST_EQ(c_arg.evals(), 1); - BOOST_TEST_EQ(d_arg.copies(), 1); BOOST_TEST_EQ(d_arg.evals(), 1); - BOOST_TEST_EQ(e_arg.copies(), 1); BOOST_TEST_EQ(e_arg.evals(), 1); - BOOST_TEST_EQ(f_arg.copies(), 1); BOOST_TEST_EQ(f_arg.evals(), 1); - - BOOST_TEST_EQ(a::n.copies(), 1); BOOST_TEST_EQ(a::n.evals(), 1); - BOOST_TEST_EQ(c::n.copies(), 1); BOOST_TEST_EQ(c::n.evals(), 1); - BOOST_TEST_EQ(t<'d'>::n.copies(), 1); BOOST_TEST_EQ(t<'d'>::n.evals(), 1); - BOOST_TEST_EQ(t<'e'>::n.copies(), 1); BOOST_TEST_EQ(t<'e'>::n.evals(), 1); - BOOST_TEST_EQ(t<'f'>::n.copies(), 1); BOOST_TEST_EQ(t<'f'>::n.evals(), 1); - - return boost::report_errors(); -} - diff --git a/test/constructor/body_throw.cpp b/test/constructor/body_throw.cpp new file mode 100644 index 0000000..23882c3 --- /dev/null +++ b/test/constructor/body_throw.cpp @@ -0,0 +1,119 @@ + +// Test constructor body throwing (in middle branch of inheritance tree). + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct c + #define BASES private boost::contract::constructor_precondition + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { out << "c::inv" << std::endl; } + static void static_invariant() { out << "c::static_inv" << std::endl; } + + c() : + boost::contract::constructor_precondition([&] { + out << "c::ctor::pre" << std::endl; + }) + { + boost::contract::scoped c = boost::contract::constructor(this) + .postcondition([&] { + out << "c::ctor::post" << std::endl; + }) + ; + out << "c::ctor::body" << std::endl; + // Do not throw (from inheritance root). + } +}; + +struct b + #define BASES private boost::contract::constructor_precondition, public c + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { out << "b::inv" << std::endl; } + static void static_invariant() { out << "b::static_inv" << std::endl; } + + struct e {}; + + b() : + boost::contract::constructor_precondition([&] { + out << "b::ctor::pre" << std::endl; + }) + { + boost::contract::scoped c = boost::contract::constructor(this) + .postcondition([&] { + out << "b::ctor::post" << std::endl; + }) + ; + out << "b::ctor::body" << std::endl; + throw b::e(); // Test body throw (from inheritance mid branch). + } +}; + +struct a + #define BASES private boost::contract::constructor_precondition, public b + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { out << "a::inv" << std::endl; } + static void static_invariant() { out << "a::static_inv" << std::endl; } + + a() : + boost::contract::constructor_precondition([&] { + out << "a::ctor::pre" << std::endl; + }) + { + boost::contract::scoped c = boost::contract::constructor(this) + .postcondition([&] { + out << "a::ctor::post" << std::endl; + }) + ; + out << "a::ctor::body" << std::endl; + // Do not throw (from inheritance leaf). + } +}; + +int main() { + std::ostringstream ok; + + bool threw = false; + out.str(""); + try { a aa; } + catch(b::e const&) { threw = true; } + BOOST_TEST(threw); + ok.str(""); ok + << "a::ctor::pre" << std::endl + << "b::ctor::pre" << std::endl + + << "c::ctor::pre" << std::endl + << "c::static_inv" << std::endl + << "c::ctor::body" << std::endl + << "c::static_inv" << std::endl + << "c::inv" << std::endl + << "c::ctor::post" << std::endl + + << "b::static_inv" << std::endl + << "b::ctor::body" << std::endl + // Test b body threw so only static inv exit checked and then C++ + // construction mechanism quits. + << "b::static_inv" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/constructor/no_pre-error.cpp b/test/constructor/no_pre-error.cpp index 690e3df..a5c16d6 100644 --- a/test/constructor/no_pre-error.cpp +++ b/test/constructor/no_pre-error.cpp @@ -1,12 +1,12 @@ // Test constructor cannot use `.precondition(...)`. -#include #include +#include struct a { a() { - boost::contract::scoped contract = boost::contract::constructor(this) + boost::contract::scoped c = boost::contract::constructor(this) .precondition([] {}) // Error (must use constructor_precondition). ; } diff --git a/test/constructor/overload.cpp b/test/constructor/overload.cpp deleted file mode 100644 index b0b728e..0000000 --- a/test/constructor/overload.cpp +++ /dev/null @@ -1,146 +0,0 @@ - -// Test constructor overloads. - -#include "../aux_/oteststream.hpp" -#include "../aux_/cpcnt.hpp" -#include -#include -#include -#include -#include -#include -#include - -boost::contract::aux::test::oteststream out; - -struct a - #define BASES private boost::contract::constructor_precondition - : BASES -{ - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void invariant() const { - out << "a::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == -1 || i_ > 0); - } - static void static_invariant() { - out << "a::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); - } - - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; - - explicit a() : // Test overload with no argument. - // Test overload with no preconditions. - i_(-1) - { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(n_cnt::eval(n)); - boost::contract::var contract = boost::contract::constructor(this) - .postcondition([&] { - out << "a::ctor()::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == -1); - BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); - }) - ; - ++n.value; - } - - explicit a(int i) : // Test overload with int. - boost::contract::constructor_precondition([&] { - out << "a::ctor(int)::pre" << std::endl; - BOOST_CONTRACT_ASSERT(i > 0); - }), - i_(i) - { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(n_cnt::eval(n)); - boost::contract::var contract = boost::contract::constructor(this) - .postcondition([&] { - out << "a::ctor(int)::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == i); - BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); - }) - ; - ++n.value; - } - - explicit a(char h) : // Test overload with char. - boost::contract::constructor_precondition([&] { - out << "a::ctor(char)::pre" << std::endl; - BOOST_CONTRACT_ASSERT(h != '\0'); - }), - i_(h) - { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(n_cnt::eval(n)); - boost::contract::var contract = boost::contract::constructor(this) - .postcondition([&] { - out << "a::ctor(char)::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == h); - BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); - }) - ; - ++n.value; - } - - ~a() { --n.value; } - -private: - int i_; -}; -a::n_cnt a::n; - -int main() { - std::ostringstream ok; - - out.str(""); - a aa; - ok.str(""); - ok - // No preconditions. - << "a::static_inv" << 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(a::n.copies(), 1); - BOOST_TEST_EQ(a::n.evals(), 1); - out << std::endl; - - out.str(""); - a ai(123); - ok.str(""); - ok - << "a::ctor(int)::pre" << std::endl - << "a::static_inv" << std::endl - << "a::static_inv" << std::endl - << "a::inv" << std::endl - << "a::ctor(int)::post" << std::endl - ; - BOOST_TEST(out.eq(ok.str())); - BOOST_TEST_EQ(a::n.copies(), 2); - BOOST_TEST_EQ(a::n.evals(), 2); - out << std::endl; - - out.str(""); - a ac('x'); - ok.str(""); - ok - << "a::ctor(char)::pre" << std::endl - << "a::static_inv" << std::endl - << "a::static_inv" << std::endl - << "a::inv" << std::endl - << "a::ctor(char)::post" << std::endl - ; - BOOST_TEST(out.eq(ok.str())); - BOOST_TEST_EQ(a::n.copies(), 3); - BOOST_TEST_EQ(a::n.evals(), 3); - out << std::endl; - - return boost::report_errors(); -} - diff --git a/test/constructor/overload_decl.cpp b/test/constructor/overload_decl.cpp deleted file mode 100644 index 7c86708..0000000 --- a/test/constructor/overload_decl.cpp +++ /dev/null @@ -1,172 +0,0 @@ - -// Test constructor overloads using bind. - -#include "../aux_/oteststream.hpp" -#include "../aux_/cpcnt.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -boost::contract::aux::test::oteststream out; - -struct a - #define BASES private boost::contract::constructor_precondition - : BASES -{ - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void invariant() const { - out << "a::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == -1 || i_ > 0); - } - static void static_invariant() { - out << "a::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); - } - - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; - - void constructor(boost::contract::decl c) const { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(c, n_cnt::eval(n)); - boost::contract::constructor(c, this) - .postcondition([&] { - out << "a::ctor()::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == -1); - BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); - }) - ; - } - explicit a() : // Test overload with no argument. - // Test overload with no preconditions. - i_(-1) - { - boost::contract::var contract = boost::contract::decl_function( - this, &a::constructor); - ++n.value; - } - - struct i_tag; typedef boost::contract::aux::test::cpcnt i_cnt; - - static void constructor_precondition(int const i) { - out << "a::ctor(int)::pre" << std::endl; - BOOST_CONTRACT_ASSERT(i > 0); - } - void constructor(i_cnt const& i, boost::contract::decl c) const { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(c, n_cnt::eval(n)); - boost::contract::constructor(c, this) - .postcondition([&] { - out << "a::ctor(int)::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == i.value); - BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); - }) - ; - } - explicit a(int i) : // Test overload with int. - boost::contract::constructor_precondition(boost::bind(static_cast< - void (*)(int const)>(&a::constructor_precondition), i)), - i_(i) - { - i_cnt i_arg; i_arg.value = i; - boost::contract::var contract = boost::contract::decl_function( - this, i_arg, &a::constructor); - BOOST_TEST_EQ(i_arg.copies(), 0); // Test bind args never copied. - ++n.value; - } - - struct h_tag; typedef boost::contract::aux::test::cpcnt h_cnt; - - static void constructor_precondition(char const h) { - out << "a::ctor(char)::pre" << std::endl; - BOOST_CONTRACT_ASSERT(h != '\0'); - } - void constructor(h_cnt const& h, boost::contract::decl c) const { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(c, n_cnt::eval(n)); - boost::contract::constructor(c, this) - .postcondition([&] { - out << "a::ctor(char)::post" << std::endl; - BOOST_CONTRACT_ASSERT(i_ == h.value); - BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1); - }) - ; - } - explicit a(char h) : // Test overload with char. - boost::contract::constructor_precondition(boost::bind(static_cast< - void (*)(char const)>(&a::constructor_precondition), h)), - i_(h) - { - h_cnt h_arg; h_arg.value = h; - boost::contract::var contract = boost::contract::decl_function( - this, h_arg, &a::constructor); - BOOST_TEST_EQ(h_arg.copies(), 0); // Test bind args never copied. - ++n.value; - } - - ~a() { --n.value; } - -private: - int i_; -}; -a::n_cnt a::n; - -int main() { - std::ostringstream ok; - - out.str(""); - a aa; - ok.str(""); - ok - // No preconditions. - << "a::static_inv" << 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(a::n.copies(), 1); - BOOST_TEST_EQ(a::n.evals(), 1); - out << std::endl; - - out.str(""); - a ai(123); - ok.str(""); - ok - << "a::ctor(int)::pre" << std::endl - << "a::static_inv" << std::endl - << "a::static_inv" << std::endl - << "a::inv" << std::endl - << "a::ctor(int)::post" << std::endl - ; - BOOST_TEST(out.eq(ok.str())); - BOOST_TEST_EQ(a::n.copies(), 2); - BOOST_TEST_EQ(a::n.evals(), 2); - out << std::endl; - - out.str(""); - a ac('x'); - ok.str(""); - ok - << "a::ctor(char)::pre" << std::endl - << "a::static_inv" << std::endl - << "a::static_inv" << std::endl - << "a::inv" << std::endl - << "a::ctor(char)::post" << std::endl - ; - BOOST_TEST(out.eq(ok.str())); - BOOST_TEST_EQ(a::n.copies(), 3); - BOOST_TEST_EQ(a::n.evals(), 3); - out << std::endl; - - return boost::report_errors(); -} - diff --git a/test/destructor/bases.cpp b/test/destructor/bases.cpp index dcbe6e3..21af829 100644 --- a/test/destructor/bases.cpp +++ b/test/destructor/bases.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -17,42 +17,42 @@ template struct t { void invariant() const { out << Id << "::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ < 0); + BOOST_CONTRACT_ASSERT(k_ < 0); } static void static_invariant() { out << Id << "::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); + BOOST_CONTRACT_ASSERT(l.value >= 0); } - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; + struct l_tag; typedef boost::contract::aux::test::cpcnt l_type; + static l_type l; - explicit t() : i_(-1) { ++n.value; } + explicit t() : k_(-1) { ++l.value; } virtual ~t() { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(n_cnt::eval(n)); - boost::contract::var contract = boost::contract::destructor(this) - .postcondition([old_n] { + boost::shared_ptr old_l = + BOOST_CONTRACT_OLDOF(l_type::eval(l)); + boost::contract::scoped c = boost::contract::destructor(this) + .postcondition([old_l] { out << Id << "::dtor::post" << std::endl; - BOOST_CONTRACT_ASSERT(t::n.value == old_n->value - 1); + BOOST_CONTRACT_ASSERT(t::l.value == old_l->value - 1); }) ; out << Id << "::dtor::body" << std::endl; - --n.value; + --l.value; } private: - int i_; + int k_; }; -template typename t::n_cnt t::n; +template typename t::l_type t::l; // Test deep inheritance (2 vertical levels), multiple inheritance (4 // horizontal levels), and that all public/protected/private part of // subcontracting for destructors (not just public, because all access levels // are part of C++ object destruction mechanism). struct c - #define BASES public t<'d'>, protected t<'e'>, private t<'f'> + #define BASES public t<'d'>, protected t<'p'>, private t<'q'>, public t<'e'> : BASES { typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; @@ -60,35 +60,35 @@ struct c void invariant() const { out << "c::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ < 0); + BOOST_CONTRACT_ASSERT(j_ < 0); } static void static_invariant() { out << "c::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); + BOOST_CONTRACT_ASSERT(m.value >= 0); } - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; + struct m_tag; typedef boost::contract::aux::test::cpcnt m_type; + static m_type m; - explicit c() : i_(-1) { ++n.value; } + explicit c() : j_(-1) { ++m.value; } virtual ~c() { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(n_cnt::eval(n)); - boost::contract::var contract = boost::contract::destructor(this) - .postcondition([old_n] { + boost::shared_ptr old_m = + BOOST_CONTRACT_OLDOF(m_type::eval(m)); + boost::contract::scoped c = boost::contract::destructor(this) + .postcondition([old_m] { out << "c::dtor::post" << std::endl; - BOOST_CONTRACT_ASSERT(c::n.value == old_n->value - 1); + BOOST_CONTRACT_ASSERT(c::m.value == old_m->value - 1); }) ; out << "c::dtor::body" << std::endl; - --n.value; + --m.value; } private: - int i_; + int j_; }; -c::n_cnt c::n; +c::m_type c::m; // Test not (fully) contracted base is not part of destructor subcontracting. struct b { @@ -116,15 +116,15 @@ struct a BOOST_CONTRACT_ASSERT(n.value >= 0); } - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; + struct n_tag; typedef boost::contract::aux::test::cpcnt n_type; + static n_type n; explicit a() : i_(-1) { ++n.value; } virtual ~a() { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(n_cnt::eval(n)); - boost::contract::var contract = boost::contract::destructor(this) + boost::shared_ptr old_n = + BOOST_CONTRACT_OLDOF(n_type::eval(n)); + boost::contract::scoped c = boost::contract::destructor(this) .postcondition([old_n] { out << "a::dtor::post" << std::endl; BOOST_CONTRACT_ASSERT(a::n.value == old_n->value - 1); @@ -137,7 +137,7 @@ struct a private: int i_; }; -a::n_cnt a::n; +a::n_type a::n; int main() { std::ostringstream ok; @@ -146,8 +146,7 @@ int main() { a aa; out.str(""); } // Call aa's destructor. - ok.str(""); - ok + ok.str(""); ok << "a::static_inv" << std::endl << "a::inv" << std::endl << "a::dtor::body" << std::endl @@ -161,17 +160,25 @@ int main() { << "c::static_inv" << std::endl << "c::dtor::post" << std::endl - << "f::static_inv" << std::endl - << "f::inv" << std::endl - << "f::dtor::body" << std::endl - << "f::static_inv" << std::endl - << "f::dtor::post" << std::endl - << "e::static_inv" << std::endl << "e::inv" << std::endl << "e::dtor::body" << std::endl << "e::static_inv" << std::endl << "e::dtor::post" << std::endl + + // Test check also private bases (because part of C++ destruction). + << "q::static_inv" << std::endl + << "q::inv" << std::endl + << "q::dtor::body" << std::endl + << "q::static_inv" << std::endl + << "q::dtor::post" << std::endl + + // Test check also protected bases (because part of C++ destruction). + << "p::static_inv" << std::endl + << "p::inv" << 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 @@ -182,10 +189,11 @@ int main() { BOOST_TEST(out.eq(ok.str())); BOOST_TEST_EQ(a::n.copies(), 1); BOOST_TEST_EQ(a::n.evals(), 1); - BOOST_TEST_EQ(c::n.copies(), 1); BOOST_TEST_EQ(c::n.evals(), 1); - BOOST_TEST_EQ(t<'d'>::n.copies(), 1); BOOST_TEST_EQ(t<'d'>::n.evals(), 1); - BOOST_TEST_EQ(t<'e'>::n.copies(), 1); BOOST_TEST_EQ(t<'e'>::n.evals(), 1); - BOOST_TEST_EQ(t<'f'>::n.copies(), 1); BOOST_TEST_EQ(t<'f'>::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); return boost::report_errors(); } diff --git a/test/destructor/bases_decl.cpp b/test/destructor/bases_decl.cpp deleted file mode 100644 index d2fa174..0000000 --- a/test/destructor/bases_decl.cpp +++ /dev/null @@ -1,205 +0,0 @@ - -// Test destructor subcontracting with contract declaration functions. - -#include "../aux_/oteststream.hpp" -#include "../aux_/cpcnt.hpp" -#include -#include -#include -#include -#include -#include -#include -#include - -boost::contract::aux::test::oteststream out; - -template -struct t { - void invariant() const { - out << Id << "::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ < 0); - } - static void static_invariant() { - out << Id << "::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); - } - - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; - - explicit t() : i_(-1) { ++n.value; } - - void destructor(boost::contract::decl c) const { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(c, n_cnt::eval(n)); - boost::contract::var contract = boost::contract::destructor(c, this) - .postcondition([old_n] { // Still.. shall not capture this. - out << Id << "::dtor::post" << std::endl; - BOOST_CONTRACT_ASSERT(t::n.value == old_n->value - 1); - }) - ; - } - virtual ~t() { - boost::contract::var contract = boost::contract::decl_function( - this, &t::destructor); - out << Id << "::dtor::body" << std::endl; - --n.value; - } - -private: - int i_; -}; -template typename t::n_cnt t::n; - -// Test deep inheritance (2 vertical levels), multiple inheritance (4 -// horizontal levels), and that all public/protected/private part of -// subcontracting for destructors (not just public, because all access levels -// are part of C++ object destruction mechanism). -struct c - #define BASES public t<'d'>, protected t<'e'>, private t<'f'> - : BASES -{ - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void invariant() const { - out << "c::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ < 0); - } - static void static_invariant() { - out << "c::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); - } - - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; - - explicit c() : i_(-1) { ++n.value; } - - void destructor(boost::contract::decl c) const { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(c, n_cnt::eval(n)); - boost::contract::var contract = boost::contract::destructor(c, this) - .postcondition([old_n] { - out << "c::dtor::post" << std::endl; - BOOST_CONTRACT_ASSERT(c::n.value == old_n->value - 1); - }) - ; - } - virtual ~c() { - boost::contract::var contract = boost::contract::decl_function( - this, &c::destructor); - out << "c::dtor::body" << std::endl; - --n.value; - } - -private: - int i_; -}; -c::n_cnt c::n; - -// Test not (fully) contracted base is not part of destructor subcontracting. -struct b { - void invariant() const { out << "b::inv" << std::endl; } - static void static_invariant() { out << "b::static_inv" << std::endl; } - - explicit b() {} - virtual ~b() {} // No contract. -}; - -// Test destructor with both non-contracted and contracted bases. -struct a - #define BASES public b, public c - : BASES -{ - typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; - #undef BASES - - void invariant() const { - out << "a::inv" << std::endl; - BOOST_CONTRACT_ASSERT(i_ < 0); - } - static void static_invariant() { - out << "a::static_inv" << std::endl; - BOOST_CONTRACT_ASSERT(n.value >= 0); - } - - struct n_tag; typedef boost::contract::aux::test::cpcnt n_cnt; - static n_cnt n; - - explicit a() : i_(-1) { ++n.value; } - - void destructor(boost::contract::decl c) const { - boost::shared_ptr old_n = - BOOST_CONTRACT_OLDOF(c, n_cnt::eval(n)); - boost::contract::var contract = boost::contract::destructor(c, this) - .postcondition([old_n] { - out << "a::dtor::post" << std::endl; - BOOST_CONTRACT_ASSERT(a::n.value == old_n->value - 1); - }) - ; - } - virtual ~a() { - boost::contract::var contract = boost::contract::decl_function( - this, &a::destructor); - out << "a::dtor::body" << std::endl; - --n.value; - } - -private: - int i_; -}; -a::n_cnt a::n; - -int main() { - std::ostringstream ok; - - { - a aa; - out.str(""); - } // Call aa's destructor. - ok.str(""); - ok - << "a::static_inv" << std::endl - << "a::inv" << std::endl - << "a::dtor::body" << std::endl - // Test static inv, but not const inv, checked after destructor body. - << "a::static_inv" << std::endl - << "a::dtor::post" << std::endl - - << "c::static_inv" << std::endl - << "c::inv" << std::endl - << "c::dtor::body" << std::endl - << "c::static_inv" << std::endl - << "c::dtor::post" << std::endl - - << "f::static_inv" << std::endl - << "f::inv" << std::endl - << "f::dtor::body" << std::endl - << "f::static_inv" << std::endl - << "f::dtor::post" << std::endl - - << "e::static_inv" << std::endl - << "e::inv" << std::endl - << "e::dtor::body" << std::endl - << "e::static_inv" << std::endl - << "e::dtor::post" << std::endl - - << "d::static_inv" << std::endl - << "d::inv" << 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::n.copies(), 1); BOOST_TEST_EQ(c::n.evals(), 1); - BOOST_TEST_EQ(t<'d'>::n.copies(), 1); BOOST_TEST_EQ(t<'d'>::n.evals(), 1); - BOOST_TEST_EQ(t<'e'>::n.copies(), 1); BOOST_TEST_EQ(t<'e'>::n.evals(), 1); - BOOST_TEST_EQ(t<'f'>::n.copies(), 1); BOOST_TEST_EQ(t<'f'>::n.evals(), 1); - - return boost::report_errors(); -} - diff --git a/test/destructor/body_throw.cpp b/test/destructor/body_throw.cpp new file mode 100644 index 0000000..4f2d5f3 --- /dev/null +++ b/test/destructor/body_throw.cpp @@ -0,0 +1,119 @@ + +// Test destructor body throwing (in middle branch of inheritance tree). + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct c { + void invariant() const { out << "c::inv" << std::endl; } + static void static_invariant() { out << "c::static_inv" << std::endl; } + + ~c() { + boost::contract::scoped c = boost::contract::destructor(this) + .postcondition([&] { + out << "c::dtor::post" << std::endl; + }) + ; + out << "c::dtor::body" << std::endl; + // Do not throw (from inheritance root). + } +}; + +struct b + #define BASES public c + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { out << "b::inv" << std::endl; } + static void static_invariant() { out << "b::static_inv" << std::endl; } + + struct e {}; + + ~b() { + boost::contract::scoped c = boost::contract::destructor(this) + .postcondition([&] { + out << "b::dtor::post" << std::endl; + }) + ; + out << "b::dtor::body" << std::endl; + throw b::e(); // Test body throw (from inheritance mid branch). + } +}; + +struct a + #define BASES public b + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { out << "a::inv" << std::endl; } + static void static_invariant() { out << "a::static_inv" << std::endl; } + + ~a() { + boost::contract::scoped c = boost::contract::destructor(this) + .postcondition([&] { + out << "a::dtor::post" << std::endl; + }) + ; + out << "a::dtor::body" << std::endl; + // Do not throw (from inheritance leaf). + } +}; + +void t() { + std::ostringstream ok; + ok.str(""); ok + << "a::static_inv" << std::endl + << "a::inv" << std::endl + << "a::dtor::body" << std::endl + << "a::static_inv" << std::endl + // Test a destructed (so only static_inv and post). + << "a::dtor::post" << std::endl + + << "b::static_inv" << std::endl + << "b::inv" << std::endl + << "b::dtor::body" << std::endl + +// Unfortunately, only Clang gets this right... Both MSVC and GCC seem to stop +// everything as soon as the destructor throw an exception. +#ifdef BOOST_CLANG + // Test b not destructed (so both static_inv and inv, but no post). + << "b::static_inv" << std::endl + << "b::inv" << std::endl + + << "c::static_inv" << std::endl + << "c::inv" << std::endl + << "c::dtor::body" << std::endl + // Test c not destructed (so both static_inv and inv, but no post). + << "c::static_inv" << std::endl + << "c::inv" << std::endl +#endif // BOOST_CLANG + + ; + BOOST_TEST(out.eq(ok.str())); + std::exit(boost::report_errors()); +} + +int main() { + std::set_terminate(&t); // Must use terminate to handle dtor throw. + { + out.str(""); + a aa; + } // Call destructor (which calls t on throw). + + BOOST_TEST(false); // Must not exit from here, but via t. + return boost::report_errors(); +} + diff --git a/test/destructor/no_pre-error.cpp b/test/destructor/no_pre-error.cpp index 5c81da9..e6ee623 100644 --- a/test/destructor/no_pre-error.cpp +++ b/test/destructor/no_pre-error.cpp @@ -2,12 +2,12 @@ // Test destructor cannot use `.precondition(...)`. #include -#include +#include struct a { ~a() { - boost::contract::var contract = boost::contract::destructor(this) - .precondition([] {}) // Error (no func arg so never pre). + boost::contract::scoped c = boost::contract::destructor(this) + .precondition([] {}) // Error (no dtor func arg so never pre). ; } }; diff --git a/test/free_function/body_throw.cpp b/test/free_function/body_throw.cpp new file mode 100644 index 0000000..b5e86d3 --- /dev/null +++ b/test/free_function/body_throw.cpp @@ -0,0 +1,40 @@ + +// Test free function body throwing. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct e {}; + +void f() { + boost::contract::scoped c = boost::contract::free_function() + .precondition([&] { out << "f::pre" << std::endl; }) + .postcondition([&] { out << "f::post" << std::endl; }) + ; + out << "f::body" << std::endl; + throw e(); // Test body throw. +} + +int main() { + std::ostringstream ok; + + bool threw = false; + out.str(""); + try { f(); } + catch(e const&) { threw = true; } + BOOST_TEST(threw); + ok.str(""); ok + << "f::pre" << std::endl + << "f::body" << std::endl + // Test no post because body threw. + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/free_function/pre_post.cpp b/test/free_function/nominal.cpp similarity index 81% rename from test/free_function/pre_post.cpp rename to test/free_function/nominal.cpp index 11d44a4..e973cd4 100644 --- a/test/free_function/pre_post.cpp +++ b/test/free_function/nominal.cpp @@ -5,8 +5,8 @@ #include "../aux_/cpcnt.hpp" #include #include -#include #include +#include #include #include #include @@ -16,12 +16,13 @@ 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; -void swap(x_type& x, y_type& y) { +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::contract::var contract = boost::contract::free_function() + boost::contract::scoped c = boost::contract::free_function() .precondition([&] { out << "swap::pre" << std::endl; BOOST_CONTRACT_ASSERT(x.value != y.value); @@ -30,12 +31,15 @@ void swap(x_type& x, y_type& y) { out << "swap::post" << std::endl; BOOST_CONTRACT_ASSERT(x.value == old_y->value); BOOST_CONTRACT_ASSERT(y.value == old_x->value); + 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; x.value = y.value; y.value = save_x; + return result = true; } int main() { @@ -45,16 +49,17 @@ int main() { y_type y; y.value = 456; out.str(""); - swap(x, y); - BOOST_TEST_EQ(x.value, 456); - BOOST_TEST_EQ(y.value, 123); - ok.str(""); - ok + 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())); + + 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); diff --git a/test/free_function/post_post-error.cpp b/test/free_function/post_post-error.cpp deleted file mode 100644 index 2f0e58e..0000000 --- a/test/free_function/post_post-error.cpp +++ /dev/null @@ -1,18 +0,0 @@ - -// Test double post error (for free func, but same for all contracts). - -#include -#include - -void f() { - boost::contract::var contract = boost::contract::free_function() - .postcondition([] {}) - .postcondition([] {}) // Error (double post). - ; -} - -int main() { - f(); - return 0; -} - diff --git a/test/free_function/post_pre_post-error.cpp b/test/free_function/post_pre_post-error.cpp deleted file mode 100644 index 54687ac..0000000 --- a/test/free_function/post_pre_post-error.cpp +++ /dev/null @@ -1,19 +0,0 @@ - -// Test double post error (for free func, but same for all contracts). - -#include -#include - -void f() { - boost::contract::var contract = boost::contract::free_function() - .postcondition([] {}) - .precondition([] {}) - .postcondition([] {}) // Error (double post, after a pre). - ; -} - -int main() { - f(); - return 0; -} - diff --git a/test/free_function/pre_post_decl.cpp b/test/free_function/pre_post_decl.cpp deleted file mode 100644 index 882d8b9..0000000 --- a/test/free_function/pre_post_decl.cpp +++ /dev/null @@ -1,68 +0,0 @@ - -// Test free function contracts using contract declaration functions. - -#include "../aux_/oteststream.hpp" -#include "../aux_/cpcnt.hpp" -#include -#include -#include -#include -#include -#include -#include -#include - -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; - -void swap(x_type const& x, y_type const& y, boost::contract::decl c) { - boost::shared_ptr old_x = - BOOST_CONTRACT_OLDOF(c, x_type::eval(x)); - boost::shared_ptr old_y = - BOOST_CONTRACT_OLDOF(c, y_type::eval(y)); - boost::contract::var contract = boost::contract::free_function(c) - .precondition([&] { - out << "swap::pre" << std::endl; - BOOST_CONTRACT_ASSERT(x.value != y.value); - }) - .postcondition([&] { - out << "swap::post" << std::endl; - BOOST_CONTRACT_ASSERT(x.value == old_y->value); - BOOST_CONTRACT_ASSERT(y.value == old_x->value); - }) - ; -} -void swap(x_type& x, y_type& y) { - boost::contract::var contract = boost::contract::decl_function(x, y, &swap); - out << "swap::body" << std::endl; - int save_x = x.value; - x.value = y.value; - y.value = save_x; -} - -int main() { - std::ostringstream ok; - - x_type x; x.value = 123; - y_type y; y.value = 456; - - out.str(""); - swap(x, y); - BOOST_TEST_EQ(x.value, 456); - BOOST_TEST_EQ(y.value, 123); - ok.str(""); - ok - << "swap::pre" << std::endl - << "swap::body" << std::endl - << "swap::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); - - return boost::report_errors(); -} - diff --git a/test/free_function/pre_post_pre-error.cpp b/test/free_function/pre_post_pre-error.cpp deleted file mode 100644 index ae5a6e3..0000000 --- a/test/free_function/pre_post_pre-error.cpp +++ /dev/null @@ -1,19 +0,0 @@ - -// Test double pre error (for free func, but same for all contracts). - -#include -#include - -void f() { - boost::contract::var contract = boost::contract::free_function() - .precondition([] {}) - .postcondition([] {}) - .precondition([] {}) // Error (double pre, after a post). - ; -} - -int main() { - f(); - return 0; -} - diff --git a/test/free_function/pre_pre-error.cpp b/test/free_function/pre_pre-error.cpp deleted file mode 100644 index fd03062..0000000 --- a/test/free_function/pre_pre-error.cpp +++ /dev/null @@ -1,18 +0,0 @@ - -// Test double error (for free func, but same for all contracts). - -#include -#include - -void f() { - boost::contract::var contract = boost::contract::free_function() - .precondition([] {}) - .precondition([] {}) // Error (double pre). - ; -} - -int main() { - f(); - return 0; -} - diff --git a/test/private_member/bases.cpp b/test/private_member/bases.cpp new file mode 100644 index 0000000..7f4a75d --- /dev/null +++ b/test/private_member/bases.cpp @@ -0,0 +1,74 @@ + +// Test private member function contracts. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct b { + void invariant() const { out << "b::inv" << std::endl; } + static void static_invariant() { out << "b::static_inv" << std::endl; } + +private: + virtual void f() { + boost::contract::scoped c = boost::contract::private_member() + .precondition([&] { + out << "b::f::pre" << std::endl; + }) + .postcondition([&] { + out << "b::f::post" << std::endl; + }) + ; + out << "b::f::body" << std::endl; + } +}; + +struct a + #define BASES public b + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { out << "a::inv" << std::endl; } + static void static_invariant() { out << "a::static_inv" << std::endl; } + + void call_f() { f(); } + +private: + virtual void f() { + boost::contract::scoped c = boost::contract::private_member() + .precondition([&] { + out << "a::f::pre" << std::endl; + }) + .postcondition([&] { + out << "a::f::post" << std::endl; + }) + ; + out << "a::f::body" << std::endl; + } +}; + +int main() { + std::ostringstream ok; + + a aa; + out.str(""); + aa.call_f(); + ok.str(""); ok + // Test not part of public API so no inv, plus cannot be called directly + // so substitution principle does not applu and no subcontracting. + << "a::f::pre" << std::endl + << "a::f::body" << std::endl + << "a::f::post" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/private_member/body_throw.cpp b/test/private_member/body_throw.cpp new file mode 100644 index 0000000..99b7dac --- /dev/null +++ b/test/private_member/body_throw.cpp @@ -0,0 +1,49 @@ + +// Test private member function throwing. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct a { + void invariant() const { out << "a::inv" << std::endl; } + static void static_invariant() { out << "a::static_inv" << std::endl; } + + struct e {}; + + void call_f() { f(); } + +private: + virtual void f() { + boost::contract::scoped c = boost::contract::private_member() + .precondition([&] { out << "a::f::pre" << std::endl; }) + .postcondition([&] { out << "a::f::post" << std::endl; }) + ; + out << "a::f::body" << std::endl; + throw a::e(); + } +}; + +int main() { + std::ostringstream ok; + + a aa; + bool threw = false; + out.str(""); + try { aa.call_f(); } + catch(a::e const&) { threw = true; } + BOOST_TEST(threw); + ok.str(""); ok + << "a::f::pre" << std::endl + << "a::f::body" << std::endl + // Test no post because body threw (never inv because not public). + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/protected_member/bases.cpp b/test/protected_member/bases.cpp new file mode 100644 index 0000000..38c7006 --- /dev/null +++ b/test/protected_member/bases.cpp @@ -0,0 +1,74 @@ + +// Test protected member function contracts. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct b { + void invariant() const { out << "b::inv" << std::endl; } + static void static_invariant() { out << "b::static_inv" << std::endl; } + +protected: + virtual void f() { + boost::contract::scoped c = boost::contract::protected_member() + .precondition([&] { + out << "b::f::pre" << std::endl; + }) + .postcondition([&] { + out << "b::f::post" << std::endl; + }) + ; + out << "b::f::body" << std::endl; + } +}; + +struct a + #define BASES public b + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { out << "a::inv" << std::endl; } + static void static_invariant() { out << "a::static_inv" << std::endl; } + + void call_f() { f(); } + +protected: + virtual void f() { + boost::contract::scoped c = boost::contract::protected_member() + .precondition([&] { + out << "a::f::pre" << std::endl; + }) + .postcondition([&] { + out << "a::f::post" << std::endl; + }) + ; + out << "a::f::body" << std::endl; + } +}; + +int main() { + std::ostringstream ok; + + a aa; + out.str(""); + aa.call_f(); + ok.str(""); ok + // Test not part of public API so no inv, plus cannot be called directly + // so no substitution principle and no subcontracting. + << "a::f::pre" << std::endl + << "a::f::body" << std::endl + << "a::f::post" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/protected_member/body_throw.cpp b/test/protected_member/body_throw.cpp new file mode 100644 index 0000000..38f5d60 --- /dev/null +++ b/test/protected_member/body_throw.cpp @@ -0,0 +1,49 @@ + +// Test protected member function throwing. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct a { + void invariant() const { out << "a::inv" << std::endl; } + static void static_invariant() { out << "a::static_inv" << std::endl; } + + struct e {}; + + void call_f() { f(); } + +protected: + virtual void f() { + boost::contract::scoped c = boost::contract::protected_member() + .precondition([&] { out << "a::f::pre" << std::endl; }) + .postcondition([&] { out << "a::f::post" << std::endl; }) + ; + out << "a::f::body" << std::endl; + throw a::e(); + } +}; + +int main() { + std::ostringstream ok; + + a aa; + bool threw = false; + out.str(""); + try { aa.call_f(); } + catch(a::e const&) { threw = true; } + BOOST_TEST(threw); + ok.str(""); ok + << "a::f::pre" << std::endl + << "a::f::body" << std::endl + // Test no post because body threw (never inv because not public). + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/public_member/bases_leaf_call.cpp b/test/public_member/bases.cpp similarity index 100% rename from test/public_member/bases_leaf_call.cpp rename to test/public_member/bases.cpp diff --git a/test/public_member/bases.hpp b/test/public_member/bases.hpp index c145836..53e208a 100644 --- a/test/public_member/bases.hpp +++ b/test/public_member/bases.hpp @@ -139,6 +139,11 @@ struct c // Test no subcontracting from not (fully) contracted base. struct b { + void invariant() const { out << "b::inv" << std::endl; } + static void static_invariant() { out << "b::static_inv" << std::endl; } + + virtual ~b() {} + virtual result_type& f(s_type& s) { // No contract. static result_type result("none-b"); out << "b::f::body" << std::endl; diff --git a/test/public_member/bases_branch_call.cpp b/test/public_member/bases_branch.cpp similarity index 100% rename from test/public_member/bases_branch_call.cpp rename to test/public_member/bases_branch.cpp diff --git a/test/public_member/bases_virtual_call.cpp b/test/public_member/bases_virtual.cpp similarity index 100% rename from test/public_member/bases_virtual_call.cpp rename to test/public_member/bases_virtual.cpp diff --git a/test/public_member/body_throw.cpp b/test/public_member/body_throw.cpp new file mode 100644 index 0000000..4854f26 --- /dev/null +++ b/test/public_member/body_throw.cpp @@ -0,0 +1,121 @@ + +// Test constructor body throwing (in inheritance tree). + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct c { + void invariant() const { out << "c::inv" << std::endl; } + static void static_invariant() { out << "c::static_inv" << std::endl; } + + struct e {}; + + virtual void f(boost::contract::virtual_* v = 0) { + boost::contract::scoped c = boost::contract::public_member(v, this) + .precondition([&] { + out << "c::f::pre" << std::endl; + BOOST_CONTRACT_ASSERT(false); // To check derived pre. + }) + .postcondition([&] { out << "c::f::post" << std::endl; }) + ; + out << "c::f::body" << std::endl; + throw c::e(); + } +}; + +struct b + #define BASES public c + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { out << "b::inv" << std::endl; } + static void static_invariant() { out << "b::static_inv" << std::endl; } + + struct e {}; + + virtual void f(boost::contract::virtual_* v = 0) /* override */ { + boost::contract::scoped c = boost::contract::public_member( + v, &b::f, this) + .precondition([&] { + out << "b::f::pre" << std::endl; + BOOST_CONTRACT_ASSERT(false); // To check derived pre. + }) + .postcondition([&] { out << "b::f::post" << std::endl; }) + ; + out << "b::f::body" << std::endl; + throw b::e(); + } + BOOST_CONTRACT_OVERRIDE(f) +}; + +struct a + #define BASES public b + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { out << "a::inv" << std::endl; } + static void static_invariant() { out << "a::static_inv" << std::endl; } + + struct e {}; + + void f(boost::contract::virtual_* v = 0) /* override */ { + boost::contract::scoped c = boost::contract::public_member( + v, &a::f, this) + .precondition([&] { out << "a::f::pre" << std::endl; }) + .postcondition([&] { out << "a::f::post" << std::endl; }) + ; + out << "a::f::body" << std::endl; + throw a::e(); + } + BOOST_CONTRACT_OVERRIDE(f) +}; + +int main() { + std::ostringstream ok; + + a aa; + c& ca = aa; // Test as virtual call via polymorphism. + bool threw = false; + out.str(""); + try { ca.f(); } + catch(a::e const&) { threw = true; } + BOOST_TEST(threw); + ok.str(""); ok + << "c::static_inv" << std::endl + << "c::inv" << std::endl + << "b::static_inv" << std::endl + << "b::inv" << std::endl + << "a::static_inv" << std::endl + << "a::inv" << std::endl + + << "c::f::pre" << std::endl + << "b::f::pre" << std::endl + << "a::f::pre" << std::endl + + << "a::f::body" << std::endl + + << "c::static_inv" << std::endl + << "c::inv" << std::endl + << "b::static_inv" << std::endl + << "b::inv" << std::endl + << "a::static_inv" << std::endl + << "a::inv" << std::endl + // Test no post (but still subcontracted inv) because body threw. + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/public_member/static.cpp b/test/public_member/static.cpp new file mode 100644 index 0000000..2739d1a --- /dev/null +++ b/test/public_member/static.cpp @@ -0,0 +1,71 @@ + +// Test public static member function contracts. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct b { + void invariant() const { out << "b::inv" << std::endl; } + static void static_invariant() { out << "b::static_inv" << std::endl; } + + static void f() { + boost::contract::scoped c = boost::contract::public_member() + .precondition([&] { + out << "b::f::pre" << std::endl; + }) + .postcondition([&] { + out << "b::f::post" << std::endl; + }) + ; + out << "b::f::body" << std::endl; + } +}; + +struct a + #define BASES public b + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const { out << "a::inv" << std::endl; } + static void static_invariant() { out << "a::static_inv" << std::endl; } + + static void f() { + boost::contract::scoped c = boost::contract::public_member() + .precondition([&] { + out << "a::f::pre" << std::endl; + }) + .postcondition([&] { + out << "a::f::post" << std::endl; + }) + ; + out << "a::f::body" << std::endl; + } +}; + +int main() { + std::ostringstream ok; + + out.str(""); + a::f(); + ok.str(""); ok + // Static so no object thus only static inv, plus never virtual so subst + // principle does not apply and no subcontracting. + << "a::static_inv" << std::endl + << "a::f::pre" << std::endl + << "a::f::body" << std::endl + << "a::static_inv" << std::endl + << "a::f::post" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/public_member/static_body_throw.cpp b/test/public_member/static_body_throw.cpp new file mode 100644 index 0000000..7dbdce6 --- /dev/null +++ b/test/public_member/static_body_throw.cpp @@ -0,0 +1,51 @@ + +// Test public static member throwing. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct a { + void invariant() const { out << "a::inv" << std::endl; } + static void static_invariant() { out << "a::static_inv" << std::endl; } + + struct e {}; + + static void f() { + boost::contract::scoped c = boost::contract::public_member() + .precondition([&] { + out << "a::f::pre" << std::endl; + }) + .postcondition([&] { + out << "a::f::post" << std::endl; + }) + ; + out << "a::f::body" << std::endl; + throw a::e(); + } +}; + +int main() { + std::ostringstream ok; + + bool threw = false; + out.str(""); + try { a::f(); } + catch(a::e const&) { threw = true; } + BOOST_TEST(threw); + ok.str(""); ok + << "a::static_inv" << std::endl + << "a::f::pre" << std::endl + << "a::f::body" << std::endl + << "a::static_inv" << std::endl + // Test no post (but still static inv) because body threw. + ; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/free_function/nothing.cpp b/test/set/nothing.cpp similarity index 74% rename from test/free_function/nothing.cpp rename to test/set/nothing.cpp index 5e64653..06c551a 100644 --- a/test/free_function/nothing.cpp +++ b/test/set/nothing.cpp @@ -3,14 +3,14 @@ #include "../aux_/oteststream.hpp" #include -#include +#include #include #include boost::contract::aux::test::oteststream out; void f() { - boost::contract::var contract = boost::contract::free_function(); + boost::contract::scoped c = boost::contract::free_function(); out << "f::body" << std::endl; } @@ -19,8 +19,7 @@ int main() { out.str(""); f(); - ok.str(""); - ok << "f::body" << std::endl; + ok.str(""); ok << "f::body" << std::endl; BOOST_TEST(out.eq(ok.str())); return boost::report_errors(); diff --git a/test/free_function/post_only.cpp b/test/set/post_only.cpp similarity index 82% rename from test/free_function/post_only.cpp rename to test/set/post_only.cpp index b20c105..e2bf5df 100644 --- a/test/free_function/post_only.cpp +++ b/test/set/post_only.cpp @@ -3,14 +3,14 @@ #include "../aux_/oteststream.hpp" #include -#include +#include #include #include boost::contract::aux::test::oteststream out; void f() { - boost::contract::var contract = boost::contract::free_function() + boost::contract::scoped c = boost::contract::free_function() .postcondition([] { out << "f::post" << std::endl; }) ; out << "f::body" << std::endl; @@ -21,8 +21,7 @@ int main() { out.str(""); f(); - ok.str(""); - ok + ok.str(""); ok << "f::body" << std::endl << "f::post" << std::endl ; diff --git a/test/set/post_post-error.cpp b/test/set/post_post-error.cpp new file mode 100644 index 0000000..d7b98c8 --- /dev/null +++ b/test/set/post_post-error.cpp @@ -0,0 +1,18 @@ + +// Test multiple post error (for free func, but same for all contracts). + +#include +#include + +void f() { + boost::contract::scoped c = boost::contract::free_function() + .postcondition([] {}) + .postcondition([] {}) // Error (multiple post). + ; +} + +int main() { + f(); + return 0; +} + diff --git a/test/free_function/post_pre.cpp b/test/set/post_pre.cpp similarity index 77% rename from test/free_function/post_pre.cpp rename to test/set/post_pre.cpp index e227583..9bc20b7 100644 --- a/test/free_function/post_pre.cpp +++ b/test/set/post_pre.cpp @@ -1,16 +1,16 @@ -// Test post specified before pre (for free func, but same for all contracts). +// Test post before pre (for free func, but same for all contracts). #include "../aux_/oteststream.hpp" #include -#include +#include #include #include boost::contract::aux::test::oteststream out; void f() { - boost::contract::var contract = boost::contract::free_function() + boost::contract::scoped c = boost::contract::free_function() .postcondition([] { out << "f::post" << std::endl; }) .precondition([] { out << "f::pre" << std::endl; }) ; diff --git a/test/set/post_pre_post-error.cpp b/test/set/post_pre_post-error.cpp new file mode 100644 index 0000000..d363b0e --- /dev/null +++ b/test/set/post_pre_post-error.cpp @@ -0,0 +1,19 @@ + +// Test multi post around pre error (for free func, but same for all contracts). + +#include +#include + +void f() { + boost::contract::scoped c = boost::contract::free_function() + .postcondition([] {}) + .precondition([] {}) + .postcondition([] {}) // Error (multiple post around pre). + ; +} + +int main() { + f(); + return 0; +} + diff --git a/test/free_function/pre_only.cpp b/test/set/pre_only.cpp similarity index 82% rename from test/free_function/pre_only.cpp rename to test/set/pre_only.cpp index 8ad026b..945773f 100644 --- a/test/free_function/pre_only.cpp +++ b/test/set/pre_only.cpp @@ -3,14 +3,14 @@ #include "../aux_/oteststream.hpp" #include -#include +#include #include #include boost::contract::aux::test::oteststream out; void f() { - boost::contract::var contract = boost::contract::free_function() + boost::contract::scoped c = boost::contract::free_function() .precondition([] { out << "f::pre" << std::endl; }) ; out << "f::body" << std::endl; @@ -21,8 +21,7 @@ int main() { out.str(""); f(); - ok.str(""); - ok + ok.str(""); ok << "f::pre" << std::endl << "f::body" << std::endl ; diff --git a/test/set/pre_post.cpp b/test/set/pre_post.cpp new file mode 100644 index 0000000..604e3d1 --- /dev/null +++ b/test/set/pre_post.cpp @@ -0,0 +1,35 @@ + +// Test pre before 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::scoped c = boost::contract::free_function() + .precondition([] { out << "f::pre" << 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::pre" << 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/pre_post_pre-error.cpp b/test/set/pre_post_pre-error.cpp new file mode 100644 index 0000000..685512c --- /dev/null +++ b/test/set/pre_post_pre-error.cpp @@ -0,0 +1,19 @@ + +// Test multi pre around post error (for free func, but same for all contracts). + +#include +#include + +void f() { + boost::contract::scoped c = boost::contract::free_function() + .precondition([] {}) + .postcondition([] {}) + .precondition([] {}) // Error (multiple pre around post). + ; +} + +int main() { + f(); + return 0; +} + diff --git a/test/set/pre_pre-error.cpp b/test/set/pre_pre-error.cpp new file mode 100644 index 0000000..66f788d --- /dev/null +++ b/test/set/pre_pre-error.cpp @@ -0,0 +1,18 @@ + +// Test multiple pre error (for free func, but same for all contracts). + +#include +#include + +void f() { + boost::contract::scoped c = boost::contract::free_function() + .precondition([] {}) + .precondition([] {}) // Error (multiple pre). + ; +} + +int main() { + f(); + return 0; +} +