2 #ifndef BOOST_CONTRACT_TEST_PUBLIC_FUNCTION_CONTRACTS_HPP_
3 #define BOOST_CONTRACT_TEST_PUBLIC_FUNCTION_CONTRACTS_HPP_
5 // Copyright (C) 2008-2018 Lorenzo Caminiti
6 // Distributed under the Boost Software License, Version 1.0 (see accompanying
7 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
8 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
10 // Test public member function subcontracting (also with old and return values).
12 #include "../detail/oteststream.hpp"
13 #include "../detail/counter.hpp"
14 #include <boost/contract/public_function.hpp>
15 #include <boost/contract/base_types.hpp>
16 #include <boost/contract/assert.hpp>
17 #include <boost/contract/old.hpp>
18 #include <boost/contract/check.hpp>
19 #include <boost/contract/override.hpp>
22 boost::contract::test::detail::oteststream out;
25 typedef boost::contract::test::detail::counter<s_tag, std::string> s_type;
27 struct except_error {};
31 explicit result_type(std::string const& s) : value(s) {}
33 private: // Test non-copyable and non-default-constructible result.
35 result_type(result_type const&);
36 result_type& operator=(result_type const&);
39 // Test base without additional bases and pure virtual.
42 static void static_invariant() { out << Id << "::static_inv" << std::endl; }
44 void invariant() const {
45 out << Id << "::inv" << std::endl;
46 BOOST_CONTRACT_ASSERT(z.value != "");
50 typedef boost::contract::test::detail::counter<z_tag, std::string> z_type;
53 t() { z.value.push_back(Id); }
55 virtual result_type& f(s_type& s, boost::contract::virtual_* v = 0) = 0;
58 template<char Id> // Requires: Only pass lower case Id so it'll never be 'X'.
59 result_type& t<Id>::f(s_type& s, boost::contract::virtual_* v) {
60 std::ostringstream r; r << "none-" << Id;
61 static result_type result(r.str());
62 boost::contract::old_ptr<z_type> old_z =
63 BOOST_CONTRACT_OLDOF(v, z_type::eval(z));
64 boost::contract::old_ptr<s_type> old_s;
65 boost::contract::check c = boost::contract::public_function(v, result, this)
67 out << Id << "::f::pre" << std::endl;
68 BOOST_CONTRACT_ASSERT(s.value[0] == Id || s.value[0] == 'X');
71 out << Id << "::f::old" << std::endl;
72 old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s));
74 .postcondition([&] (result_type const& result) {
75 out << Id << "::f::post" << std::endl;
76 BOOST_CONTRACT_ASSERT(z.value == old_z->value + old_s->value);
77 BOOST_CONTRACT_ASSERT(s.value.find(old_z->value) !=
79 BOOST_CONTRACT_ASSERT(result.value == old_s->value);
82 out << Id << "::f::except" << std::endl;
83 BOOST_CONTRACT_ASSERT(z.value == old_z->value);
84 BOOST_CONTRACT_ASSERT(s.value == old_s->value);
87 out << "t<" << Id << ">::f::body" << std::endl;
88 if(s.value == "X") throw except_error();
92 // Test base with other bases, multiple inheritance, and no subcontracting from
93 // protected and private bases (even if fully contracted).
95 #define BASES public t<'d'>, protected t<'p'>, private t<'q'>, public t<'e'>
98 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
101 static void static_invariant() { out << "c::static_inv" << std::endl; }
103 void invariant() const {
104 out << "c::inv" << std::endl;
105 BOOST_CONTRACT_ASSERT(y.value != "");
109 typedef boost::contract::test::detail::counter<y_tag, std::string> y_type;
112 c() { y.value = "c"; }
114 virtual result_type& f(s_type& s, boost::contract::virtual_* v = 0)
116 static result_type result("none-c");
117 boost::contract::old_ptr<y_type> old_y =
118 BOOST_CONTRACT_OLDOF(v, y_type::eval(y));
119 boost::contract::old_ptr<s_type> old_s;
120 boost::contract::check c = boost::contract::public_function<
121 override_f>(v, result, &c::f, this, s)
123 out << "c::f::pre" << std::endl;
124 BOOST_CONTRACT_ASSERT(s.value == "C" || s.value == "X");
127 out << "c::f::old" << std::endl;
128 old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s));
130 .postcondition([&] (result_type const& result) {
131 out << "c::f::post" << std::endl;
132 BOOST_CONTRACT_ASSERT(y.value == old_y->value + old_s->value);
133 BOOST_CONTRACT_ASSERT(s.value.find(old_y->value) !=
135 BOOST_CONTRACT_ASSERT(result.value == old_s->value);
138 out << "c::f::except" << std::endl;
139 BOOST_CONTRACT_ASSERT(y.value == old_y->value);
140 BOOST_CONTRACT_ASSERT(s.value == old_s->value);
144 out << "c::f::body" << std::endl;
145 if(s.value == "X") throw except_error();
146 std::string save_s = s.value;
148 std::string save = y.value;
152 save = t<'d'>::z.value;
153 t<'d'>::z.value += save_s;
156 save = t<'e'>::z.value;
157 t<'e'>::z.value += save_s;
160 result.value = save_s;
163 BOOST_CONTRACT_OVERRIDE(f)
166 // Test no subcontracting from not (fully) contracted base.
168 static void static_invariant() { out << "b::static_inv" << std::endl; }
169 void invariant() const { out << "b::inv" << std::endl; }
173 // No contract (no virtual_ so this is not actually overridden by a::f).
174 virtual result_type& f(s_type& s) {
175 static result_type result("none-b");
176 out << "b::f::body" << std::endl;
177 result.value = s.value;
182 // Test public function with both non-contracted and contracted bases.
184 #define BASES public b, public c
187 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
190 static void static_invariant() { out << "a::static_inv" << std::endl; }
192 void invariant() const {
193 out << "a::inv" << std::endl;
194 BOOST_CONTRACT_ASSERT(x.value != "");
198 typedef boost::contract::test::detail::counter<x_tag, std::string> x_type;
201 a() { x.value = "a"; }
203 // Must use virtual_ even if no longer decl virtual for correct overloading.
204 // NOTE: This intentionally hides but does not override `b::f` (it overrides
205 // `c::f` instead). This generates warnings on some compilers (Clang, etc.).
206 result_type& f(s_type& s, boost::contract::virtual_* v = 0)
208 static result_type result("none-a");
209 boost::contract::old_ptr<x_type> old_x =
210 BOOST_CONTRACT_OLDOF(v, x_type::eval(x));
211 boost::contract::old_ptr<s_type> old_s;
212 boost::contract::check c = boost::contract::public_function<
213 override_f>(v, result, &a::f, this, s)
215 out << "a::f::pre" << std::endl;
216 BOOST_CONTRACT_ASSERT(s.value == "A" || s.value == "X");
219 out << "a::f::old" << std::endl;
220 old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s));
222 .postcondition([&] (result_type const& result) {
223 out << "a::f::post" << std::endl;
224 BOOST_CONTRACT_ASSERT(x.value == old_x->value + old_s->value);
225 BOOST_CONTRACT_ASSERT(s.value.find(old_x->value) !=
227 BOOST_CONTRACT_ASSERT(result.value == old_s->value);
230 out << "a::f::except" << std::endl;
231 BOOST_CONTRACT_ASSERT(x.value == old_x->value);
232 BOOST_CONTRACT_ASSERT(s.value == old_s->value);
236 out << "a::f::body" << std::endl;
237 if(s.value == "X") throw except_error();
238 std::string save_s = s.value;
240 std::string save = x.value;
248 save = t<'d'>::z.value;
249 t<'d'>::z.value += save_s;
252 save = t<'e'>::z.value;
253 t<'e'>::z.value += save_s;
256 result.value = save_s;
259 BOOST_CONTRACT_OVERRIDE(f)
262 #endif // #include guard