// no #include guard // Copyright (C) 2008-2018 Lorenzo Caminiti // Distributed under the Boost Software License, Version 1.0 (see accompanying // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt). // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html // Test base and derived classes mixing boost::optional and non- result types. #include "../detail/oteststream.hpp" #include "../detail/counter.hpp" #include #include #include #include #include #include #include #include #include #include boost::contract::test::detail::oteststream out; struct ch_tag; typedef boost::contract::test::detail::counter ch_type; #ifdef BOOST_CONTRACT_TEST_REF // Test with result types by reference. #define BOOST_CONTRACT_TEST_CH_TYPE ch_type& #define BOOST_CONTRACT_TEST_CH_INIT = ch_init ch_type ch_init; unsigned const ch_extras = 2; // 1 local and 1 global var. #else // Test with result types by value. #define BOOST_CONTRACT_TEST_CH_TYPE ch_type #define BOOST_CONTRACT_TEST_CH_INIT /* nothing */ unsigned const ch_extras = 1; // 1 for local var (no global var). #endif bool tested_d_copies = false; struct d { static void static_invariant() { out << "d::static_inv" << std::endl; } void invariant() const { out << "d::inv" << std::endl; } virtual BOOST_CONTRACT_TEST_CH_TYPE f( ch_type& ch, boost::contract::virtual_* v = 0) { unsigned const old_ch_copies = ch_type::copies(); boost::optional result; boost::contract::check c = boost::contract::public_function( v, result, this) .precondition([&] { out << "d::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(ch.value == 'd'); }) .old([] { out << "d::f::old" << std::endl; }) .postcondition([&] (boost::optional const& result) { out << "d::f::post" << std::endl; BOOST_CONTRACT_ASSERT(result->value == ch.value); }) ; BOOST_TEST_EQ(ch_type::copies(), old_ch_copies); tested_d_copies = true; out << "d::f::body" << std::endl; return *(result = ch); } }; bool tested_c_copies = false; struct c #define BASES public d : BASES { typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES static void static_invariant() { out << "c::static_inv" << std::endl; } void invariant() const { out << "c::inv" << std::endl; } virtual BOOST_CONTRACT_TEST_CH_TYPE f( ch_type& ch, boost::contract::virtual_* v = 0) /* override */ { unsigned const old_ch_copies = ch_type::copies(); boost::optional result; boost::contract::check c = boost::contract::public_function( v, result, &c::f, this, ch) .precondition([&] { out << "c::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(ch.value == 'c'); }) .old([] { out << "c::f::old" << std::endl; }) .postcondition([&] (boost::optional const& result) { out << "c::f::post" << std::endl; BOOST_CONTRACT_ASSERT(result->value == ch.value); }) ; BOOST_TEST_EQ(ch_type::copies(), old_ch_copies); tested_c_copies = true; out << "c::f::body" << std::endl; return *(result = ch); } BOOST_CONTRACT_OVERRIDE(f) }; bool tested_b_copies = false; struct b #define BASES public c : BASES { typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES static void static_invariant() { out << "b::static_inv" << std::endl; } void invariant() const { out << "b::inv" << std::endl; } virtual BOOST_CONTRACT_TEST_CH_TYPE f( ch_type& ch, boost::contract::virtual_* v = 0) /* override */ { unsigned const old_ch_copies = ch_type::copies(); BOOST_CONTRACT_TEST_CH_TYPE result BOOST_CONTRACT_TEST_CH_INIT; boost::contract::check c = boost::contract::public_function( v, result, &b::f, this, ch) .precondition([&] { out << "b::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(ch.value == 'b'); }) .old([] { out << "b::f::old" << std::endl; }) .postcondition([&] (ch_type const& result) { out << "b::f::post" << std::endl; BOOST_CONTRACT_ASSERT(result.value == ch.value); }) ; BOOST_TEST_EQ(ch_type::copies(), old_ch_copies); tested_b_copies = true; out << "b::f::body" << std::endl; return result = ch; } BOOST_CONTRACT_OVERRIDE(f) }; bool tested_a_copies = false; struct a #define BASES public b : BASES { typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES static void static_invariant() { out << "a::static_inv" << std::endl; } void invariant() const { out << "a::inv" << std::endl; } virtual BOOST_CONTRACT_TEST_CH_TYPE f( ch_type& ch, boost::contract::virtual_* v = 0) /* override */ { unsigned const old_ch_copies = ch_type::copies(); boost::optional result; boost::contract::check c = boost::contract::public_function( v, result, &a::f, this, ch) .precondition([&] { out << "a::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(ch.value == 'a'); }) .old([] { out << "a::f::old" << std::endl; }) .postcondition([&] (boost::optional const& result) { out << "a::f::post" << std::endl; BOOST_CONTRACT_ASSERT(result->value == ch.value); }) ; BOOST_TEST_EQ(ch_type::copies(), old_ch_copies); tested_a_copies = true; out << "a::f::body" << std::endl; return *(result = ch); } BOOST_CONTRACT_OVERRIDE(f) }; bool tested_e_copies = false; struct e #define BASES public b : BASES { typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; #undef BASES static void static_invariant() { out << "e::static_inv" << std::endl; } void invariant() const { out << "e::inv" << std::endl; } virtual BOOST_CONTRACT_TEST_CH_TYPE f( ch_type& ch, boost::contract::virtual_* v = 0) /* override */ { unsigned const old_ch_copies = ch_type::copies(); BOOST_CONTRACT_TEST_CH_TYPE result BOOST_CONTRACT_TEST_CH_INIT; boost::contract::check c = boost::contract::public_function( v, result, &e::f, this, ch) .precondition([&] { out << "e::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(ch.value == 'e'); }) .old([] { out << "e::f::old" << std::endl; }) .postcondition([&] (ch_type const& result) { out << "e::f::post" << std::endl; BOOST_CONTRACT_ASSERT(result.value == ch.value); }) ; BOOST_TEST_EQ(ch_type::copies(), old_ch_copies); tested_e_copies = true; out << "e::f::body" << std::endl; return result = ch; } BOOST_CONTRACT_OVERRIDE(f) }; int main() { std::ostringstream ok; ch_type ch; #ifdef BOOST_CONTRACT_TEST_REF ch_init.value = '\0'; #endif // Test optional in overriding a::f and non-optional in overridden b::f. a aa; ch.value = 'a'; out.str(""); aa.f(ch); ok.str(""); ok #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS << "d::static_inv" << std::endl << "d::inv" << 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 #endif #ifndef BOOST_CONTRACT_NO_PRECONDITIONS << "d::f::pre" << std::endl << "c::f::pre" << std::endl << "b::f::pre" << std::endl << "a::f::pre" << std::endl #endif #ifndef BOOST_CONTRACT_NO_OLDS << "d::f::old" << std::endl << "c::f::old" << std::endl << "b::f::old" << std::endl << "a::f::old" << std::endl #endif << "a::f::body" << std::endl #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS << "d::static_inv" << std::endl << "d::inv" << 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 #endif #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS << "d::f::old" << std::endl << "d::f::post" << std::endl << "c::f::old" << std::endl << "c::f::post" << std::endl << "b::f::old" << std::endl << "b::f::post" << std::endl << "a::f::post" << std::endl #endif ; BOOST_TEST(out.eq(ok.str())); BOOST_TEST(tested_a_copies); BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras); // Test non-optional in overriding b::f and optional in overridden c::f. b bb; ch.value = 'b'; out.str(""); bb.f(ch); ok.str(""); ok #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS << "d::static_inv" << std::endl << "d::inv" << std::endl << "c::static_inv" << std::endl << "c::inv" << std::endl << "b::static_inv" << std::endl << "b::inv" << std::endl #endif #ifndef BOOST_CONTRACT_NO_PRECONDITIONS << "d::f::pre" << std::endl << "c::f::pre" << std::endl << "b::f::pre" << std::endl #endif #ifndef BOOST_CONTRACT_NO_OLDS << "d::f::old" << std::endl << "c::f::old" << std::endl << "b::f::old" << std::endl #endif << "b::f::body" << std::endl #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS << "d::static_inv" << std::endl << "d::inv" << std::endl << "c::static_inv" << std::endl << "c::inv" << std::endl << "b::static_inv" << std::endl << "b::inv" << std::endl #endif #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS << "d::f::old" << std::endl << "d::f::post" << std::endl << "c::f::old" << std::endl << "c::f::post" << std::endl << "b::f::post" << std::endl #endif ; BOOST_TEST(out.eq(ok.str())); BOOST_TEST(tested_b_copies); BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras); // Test optional in both overriding c::f and overridden d::f. c cc; ch.value = 'c'; out.str(""); cc.f(ch); ok.str(""); ok #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS << "d::static_inv" << std::endl << "d::inv" << std::endl << "c::static_inv" << std::endl << "c::inv" << std::endl #endif #ifndef BOOST_CONTRACT_NO_PRECONDITIONS << "d::f::pre" << std::endl << "c::f::pre" << std::endl #endif #ifndef BOOST_CONTRACT_NO_OLDS << "d::f::old" << std::endl << "c::f::old" << std::endl #endif << "c::f::body" << std::endl #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS << "d::static_inv" << std::endl << "d::inv" << std::endl << "c::static_inv" << std::endl << "c::inv" << std::endl #endif #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS << "d::f::old" << std::endl << "d::f::post" << std::endl << "c::f::post" << std::endl #endif ; BOOST_TEST(out.eq(ok.str())); BOOST_TEST(tested_c_copies); BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras); // Test non-optional in both overriding c::f and overridden d::f. e ee; ch.value = 'e'; out.str(""); ee.f(ch); ok.str(""); ok #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS << "d::static_inv" << std::endl << "d::inv" << std::endl << "c::static_inv" << std::endl << "c::inv" << std::endl << "b::static_inv" << std::endl << "b::inv" << std::endl << "e::static_inv" << std::endl << "e::inv" << std::endl #endif #ifndef BOOST_CONTRACT_NO_PRECONDITIONS << "d::f::pre" << std::endl << "c::f::pre" << std::endl << "b::f::pre" << std::endl << "e::f::pre" << std::endl #endif #ifndef BOOST_CONTRACT_NO_OLDS << "d::f::old" << std::endl << "c::f::old" << std::endl << "b::f::old" << std::endl << "e::f::old" << std::endl #endif << "e::f::body" << std::endl #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS << "d::static_inv" << std::endl << "d::inv" << std::endl << "c::static_inv" << std::endl << "c::inv" << std::endl << "b::static_inv" << std::endl << "b::inv" << std::endl << "e::static_inv" << std::endl << "e::inv" << std::endl #endif #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS << "d::f::old" << std::endl << "d::f::post" << std::endl << "c::f::old" << std::endl << "c::f::post" << std::endl << "b::f::old" << std::endl << "b::f::post" << std::endl << "e::f::post" << std::endl #endif ; BOOST_TEST(out.eq(ok.str())); BOOST_TEST(tested_e_copies); BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras); return boost::report_errors(); }