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>
20 #include <boost/config.hpp>
23 boost::contract::test::detail::oteststream out;
26 typedef boost::contract::test::detail::counter<s_tag, std::string> s_type;
28 struct except_error {};
32 explicit result_type(std::string const& s) : value(s) {}
34 private: // Test non-copyable and non-default-constructible result.
36 result_type(result_type const&);
37 result_type& operator=(result_type const&);
40 // Test base without additional bases and pure virtual.
43 static void static_invariant() { out << Id << "::static_inv" << std::endl; }
45 void invariant() const {
46 out << Id << "::inv" << std::endl;
47 BOOST_CONTRACT_ASSERT(z.value != "");
51 typedef boost::contract::test::detail::counter<z_tag, std::string> z_type;
54 t() { z.value.push_back(Id); }
56 virtual result_type& f(s_type& s, boost::contract::virtual_* v = 0) = 0;
59 template<char Id> // Requires: Only pass lower case Id so it'll never be 'X'.
60 result_type& t<Id>::f(s_type& s, boost::contract::virtual_* v) {
61 std::ostringstream r; r << "none-" << Id;
62 static result_type result(r.str());
63 boost::contract::old_ptr<z_type> old_z =
64 BOOST_CONTRACT_OLDOF(v, z_type::eval(z));
65 boost::contract::old_ptr<s_type> old_s;
66 boost::contract::check c = boost::contract::public_function(v, result, this)
68 out << Id << "::f::pre" << std::endl;
69 BOOST_CONTRACT_ASSERT(s.value[0] == Id || s.value[0] == 'X');
72 out << Id << "::f::old" << std::endl;
73 old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s));
75 .postcondition([&] (result_type const& result) {
76 out << Id << "::f::post" << std::endl;
77 BOOST_CONTRACT_ASSERT(z.value == old_z->value + old_s->value);
78 BOOST_CONTRACT_ASSERT(s.value.find(old_z->value) !=
80 BOOST_CONTRACT_ASSERT(result.value == old_s->value);
83 out << Id << "::f::except" << std::endl;
84 BOOST_CONTRACT_ASSERT(z.value == old_z->value);
85 BOOST_CONTRACT_ASSERT(s.value == old_s->value);
88 out << "t<" << Id << ">::f::body" << std::endl;
89 if(s.value == "X") throw except_error();
93 // Test base with other bases, multiple inheritance, and no subcontracting from
94 // protected and private bases (even if fully contracted).
96 #define BASES public t<'d'>, protected t<'p'>, private t<'q'>, public t<'e'>
99 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
102 static void static_invariant() { out << "c::static_inv" << std::endl; }
104 void invariant() const {
105 out << "c::inv" << std::endl;
106 BOOST_CONTRACT_ASSERT(y.value != "");
110 typedef boost::contract::test::detail::counter<y_tag, std::string> y_type;
113 c() { y.value = "c"; }
115 virtual result_type& f(s_type& s, boost::contract::virtual_* v = 0)
117 static result_type result("none-c");
118 boost::contract::old_ptr<y_type> old_y =
119 BOOST_CONTRACT_OLDOF(v, y_type::eval(y));
120 boost::contract::old_ptr<s_type> old_s;
121 boost::contract::check c = boost::contract::public_function<
122 override_f>(v, result, &c::f, this, s)
124 out << "c::f::pre" << std::endl;
125 BOOST_CONTRACT_ASSERT(s.value == "C" || s.value == "X");
128 out << "c::f::old" << std::endl;
129 old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s));
131 .postcondition([&] (result_type const& result) {
132 out << "c::f::post" << std::endl;
133 BOOST_CONTRACT_ASSERT(y.value == old_y->value + old_s->value);
134 BOOST_CONTRACT_ASSERT(s.value.find(old_y->value) !=
136 BOOST_CONTRACT_ASSERT(result.value == old_s->value);
139 out << "c::f::except" << std::endl;
140 BOOST_CONTRACT_ASSERT(y.value == old_y->value);
141 BOOST_CONTRACT_ASSERT(s.value == old_s->value);
145 out << "c::f::body" << std::endl;
146 if(s.value == "X") throw except_error();
147 std::string save_s = s.value;
149 std::string save = y.value;
153 save = t<'d'>::z.value;
154 t<'d'>::z.value += save_s;
157 save = t<'e'>::z.value;
158 t<'e'>::z.value += save_s;
161 result.value = save_s;
164 BOOST_CONTRACT_OVERRIDE(f)
167 // Test no subcontracting from not (fully) contracted base.
169 static void static_invariant() { out << "b::static_inv" << std::endl; }
170 void invariant() const { out << "b::inv" << std::endl; }
174 // No contract (no virtual_ so this is not actually overridden by a::f).
175 virtual result_type& f(s_type& s) {
176 static result_type result("none-b");
177 out << "b::f::body" << std::endl;
178 result.value = s.value;
183 // Test public function with both non-contracted and contracted bases.
185 #define BASES public b, public c
188 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
191 static void static_invariant() { out << "a::static_inv" << std::endl; }
193 void invariant() const {
194 out << "a::inv" << std::endl;
195 BOOST_CONTRACT_ASSERT(x.value != "");
199 typedef boost::contract::test::detail::counter<x_tag, std::string> x_type;
202 a() { x.value = "a"; }
204 #if defined(BOOST_GCC)
205 #pragma GCC diagnostic push
206 #pragma GCC diagnostic ignored "-Woverloaded-virtual" // For a::f.
207 #elif defined(BOOST_CLANG)
208 #pragma clang diagnostic push
209 #pragma clang diagnostic ignored "-Woverloaded-virtual" // For a::f.
212 // Must use virtual_ even if no longer decl virtual for correct overloading.
213 // NOTE: This intentionally hides but does not override `b::f` (it overrides
214 // `c::f` instead). This generates warnings on some compilers (Clang, etc.).
215 result_type& f(s_type& s, boost::contract::virtual_* v = 0)
217 static result_type result("none-a");
218 boost::contract::old_ptr<x_type> old_x =
219 BOOST_CONTRACT_OLDOF(v, x_type::eval(x));
220 boost::contract::old_ptr<s_type> old_s;
221 boost::contract::check c = boost::contract::public_function<
222 override_f>(v, result, &a::f, this, s)
224 out << "a::f::pre" << std::endl;
225 BOOST_CONTRACT_ASSERT(s.value == "A" || s.value == "X");
228 out << "a::f::old" << std::endl;
229 old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s));
231 .postcondition([&] (result_type const& result) {
232 out << "a::f::post" << std::endl;
233 BOOST_CONTRACT_ASSERT(x.value == old_x->value + old_s->value);
234 BOOST_CONTRACT_ASSERT(s.value.find(old_x->value) !=
236 BOOST_CONTRACT_ASSERT(result.value == old_s->value);
239 out << "a::f::except" << std::endl;
240 BOOST_CONTRACT_ASSERT(x.value == old_x->value);
241 BOOST_CONTRACT_ASSERT(s.value == old_s->value);
245 out << "a::f::body" << std::endl;
246 if(s.value == "X") throw except_error();
247 std::string save_s = s.value;
249 std::string save = x.value;
257 save = t<'d'>::z.value;
258 t<'d'>::z.value += save_s;
261 save = t<'e'>::z.value;
262 t<'e'>::z.value += save_s;
265 result.value = save_s;
268 BOOST_CONTRACT_OVERRIDE(f)
270 #if defined(BOOST_GCC)
271 #pragma GCC diagnostic pop
272 #elif defined(BOOST_CLANG)
273 #pragma clang diagnostic pop
277 #endif // #include guard