1
2 // no #include guard
3
4 // Copyright (C) 2008-2018 Lorenzo Caminiti
5 // Distributed under the Boost Software License, Version 1.0 (see accompanying
6 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
7 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
8
9 // Test base and derived classes mixing boost::optional and non- result types.
10
11 #include "../detail/oteststream.hpp"
12 #include "../detail/counter.hpp"
13 #include <boost/contract/base_types.hpp>
14 #include <boost/contract/public_function.hpp>
15 #include <boost/contract/override.hpp>
16 #include <boost/contract/check.hpp>
17 #include <boost/contract/assert.hpp>
18 #include <boost/optional.hpp>
19 #include <boost/detail/lightweight_test.hpp>
20 #include <boost/config.hpp>
21 #include <sstream>
22 #include <cassert>
23
24 boost::contract::test::detail::oteststream out;
25
26 struct ch_tag;
27 typedef boost::contract::test::detail::counter<ch_tag, char> ch_type;
28
29 #ifdef BOOST_CONTRACT_TEST_REF // Test with result types by reference.
30 #define BOOST_CONTRACT_TEST_CH_TYPE ch_type&
31 #define BOOST_CONTRACT_TEST_CH_INIT = ch_init
32 ch_type ch_init;
33 unsigned const ch_extras = 2; // 1 local and 1 global var.
34 #else // Test with result types by value.
35 #define BOOST_CONTRACT_TEST_CH_TYPE ch_type
36 #define BOOST_CONTRACT_TEST_CH_INIT /* nothing */
37 unsigned const ch_extras = 1; // 1 for local var (no global var).
38 #endif
39
40 bool tested_d_copies = false;
41 struct d {
static_invariantd42 static void static_invariant() { out << "d::static_inv" << std::endl; }
invariantd43 void invariant() const { out << "d::inv" << std::endl; }
44
fd45 virtual BOOST_CONTRACT_TEST_CH_TYPE f(
46 ch_type& ch, boost::contract::virtual_* v = 0) {
47 unsigned const old_ch_copies = ch_type::copies();
48 boost::optional<BOOST_CONTRACT_TEST_CH_TYPE> result;
49 boost::contract::check c = boost::contract::public_function(
50 v, result, this)
51 .precondition([&] {
52 out << "d::f::pre" << std::endl;
53 BOOST_CONTRACT_ASSERT(ch.value == 'd');
54 })
55 .old([] { out << "d::f::old" << std::endl; })
56 .postcondition([&] (boost::optional<ch_type const&> const& result) {
57 out << "d::f::post" << std::endl;
58 BOOST_CONTRACT_ASSERT(result->value == ch.value);
59 })
60 ;
61 BOOST_TEST_EQ(ch_type::copies(), old_ch_copies);
62 tested_d_copies = true;
63
64 out << "d::f::body" << std::endl;
65 return *(result = ch);
66 }
67 };
68
69 bool tested_c_copies = false;
70 struct c
71 #define BASES public d
72 : BASES
73 {
74 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
75 #undef BASES
76
static_invariantc77 static void static_invariant() { out << "c::static_inv" << std::endl; }
invariantc78 void invariant() const { out << "c::inv" << std::endl; }
79
fc80 virtual BOOST_CONTRACT_TEST_CH_TYPE f(
81 ch_type& ch, boost::contract::virtual_* v = 0) /* override */ {
82 unsigned const old_ch_copies = ch_type::copies();
83 boost::optional<BOOST_CONTRACT_TEST_CH_TYPE> result;
84 boost::contract::check c = boost::contract::public_function<override_f>(
85 v, result, &c::f, this, ch)
86 .precondition([&] {
87 out << "c::f::pre" << std::endl;
88 BOOST_CONTRACT_ASSERT(ch.value == 'c');
89 })
90 .old([] { out << "c::f::old" << std::endl; })
91 .postcondition([&] (boost::optional<ch_type const&> const& result) {
92 out << "c::f::post" << std::endl;
93 BOOST_CONTRACT_ASSERT(result->value == ch.value);
94 })
95 ;
96 BOOST_TEST_EQ(ch_type::copies(), old_ch_copies);
97 tested_c_copies = true;
98
99 out << "c::f::body" << std::endl;
100 return *(result = ch);
101 }
102 BOOST_CONTRACT_OVERRIDE(f)
103 };
104
105 bool tested_b_copies = false;
106 struct b
107 #define BASES public c
108 : BASES
109 {
110 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
111 #undef BASES
112
static_invariantb113 static void static_invariant() { out << "b::static_inv" << std::endl; }
invariantb114 void invariant() const { out << "b::inv" << std::endl; }
115
fb116 virtual BOOST_CONTRACT_TEST_CH_TYPE f(
117 ch_type& ch, boost::contract::virtual_* v = 0) /* override */ {
118 unsigned const old_ch_copies = ch_type::copies();
119 BOOST_CONTRACT_TEST_CH_TYPE result BOOST_CONTRACT_TEST_CH_INIT;
120 boost::contract::check c = boost::contract::public_function<override_f>(
121 v, result, &b::f, this, ch)
122 .precondition([&] {
123 out << "b::f::pre" << std::endl;
124 BOOST_CONTRACT_ASSERT(ch.value == 'b');
125 })
126 .old([] { out << "b::f::old" << std::endl; })
127 .postcondition([&] (ch_type const& result) {
128 out << "b::f::post" << std::endl;
129 BOOST_CONTRACT_ASSERT(result.value == ch.value);
130 })
131 ;
132 BOOST_TEST_EQ(ch_type::copies(), old_ch_copies);
133 tested_b_copies = true;
134
135 out << "b::f::body" << std::endl;
136 return result = ch;
137 }
138 BOOST_CONTRACT_OVERRIDE(f)
139 };
140
141 bool tested_a_copies = false;
142 struct a
143 #define BASES public b
144 : BASES
145 {
146 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
147 #undef BASES
148
static_invarianta149 static void static_invariant() { out << "a::static_inv" << std::endl; }
invarianta150 void invariant() const { out << "a::inv" << std::endl; }
151
fa152 virtual BOOST_CONTRACT_TEST_CH_TYPE f(
153 ch_type& ch, boost::contract::virtual_* v = 0) /* override */ {
154 unsigned const old_ch_copies = ch_type::copies();
155 boost::optional<BOOST_CONTRACT_TEST_CH_TYPE> result;
156 boost::contract::check c = boost::contract::public_function<override_f>(
157 v, result, &a::f, this, ch)
158 .precondition([&] {
159 out << "a::f::pre" << std::endl;
160 BOOST_CONTRACT_ASSERT(ch.value == 'a');
161 })
162 .old([] { out << "a::f::old" << std::endl; })
163 .postcondition([&] (boost::optional<ch_type const&> const& result) {
164 out << "a::f::post" << std::endl;
165 BOOST_CONTRACT_ASSERT(result->value == ch.value);
166 })
167 ;
168 BOOST_TEST_EQ(ch_type::copies(), old_ch_copies);
169 tested_a_copies = true;
170
171 out << "a::f::body" << std::endl;
172 return *(result = ch);
173 }
174 BOOST_CONTRACT_OVERRIDE(f)
175 };
176
177 bool tested_e_copies = false;
178 struct e
179 #define BASES public b
180 : BASES
181 {
182 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
183 #undef BASES
184
static_invariante185 static void static_invariant() { out << "e::static_inv" << std::endl; }
invariante186 void invariant() const { out << "e::inv" << std::endl; }
187
fe188 virtual BOOST_CONTRACT_TEST_CH_TYPE f(
189 ch_type& ch, boost::contract::virtual_* v = 0) /* override */ {
190 unsigned const old_ch_copies = ch_type::copies();
191 BOOST_CONTRACT_TEST_CH_TYPE result BOOST_CONTRACT_TEST_CH_INIT;
192 boost::contract::check c = boost::contract::public_function<override_f>(
193 v, result, &e::f, this, ch)
194 .precondition([&] {
195 out << "e::f::pre" << std::endl;
196 BOOST_CONTRACT_ASSERT(ch.value == 'e');
197 })
198 .old([] { out << "e::f::old" << std::endl; })
199 .postcondition([&] (ch_type const& result) {
200 out << "e::f::post" << std::endl;
201 BOOST_CONTRACT_ASSERT(result.value == ch.value);
202 })
203 ;
204 BOOST_TEST_EQ(ch_type::copies(), old_ch_copies);
205 tested_e_copies = true;
206
207 out << "e::f::body" << std::endl;
208 return result = ch;
209 }
210 BOOST_CONTRACT_OVERRIDE(f)
211 };
212
main()213 int main() {
214 std::ostringstream ok;
215 ch_type ch;
216 #ifdef BOOST_CONTRACT_TEST_REF
217 ch_init.value = '\0';
218 #endif
219
220 // Test optional in overriding a::f and non-optional in overridden b::f.
221 a aa;
222 ch.value = 'a';
223 out.str("");
224 aa.f(ch);
225 ok.str(""); ok
226 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
227 << "d::static_inv" << std::endl
228 << "d::inv" << std::endl
229 << "c::static_inv" << std::endl
230 << "c::inv" << std::endl
231 << "b::static_inv" << std::endl
232 << "b::inv" << std::endl
233 << "a::static_inv" << std::endl
234 << "a::inv" << std::endl
235 #endif
236 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
237 << "d::f::pre" << std::endl
238 << "c::f::pre" << std::endl
239 << "b::f::pre" << std::endl
240 << "a::f::pre" << std::endl
241 #endif
242 #ifndef BOOST_CONTRACT_NO_OLDS
243 << "d::f::old" << std::endl
244 << "c::f::old" << std::endl
245 << "b::f::old" << std::endl
246 << "a::f::old" << std::endl
247 #endif
248 << "a::f::body" << std::endl
249 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
250 << "d::static_inv" << std::endl
251 << "d::inv" << std::endl
252 << "c::static_inv" << std::endl
253 << "c::inv" << std::endl
254 << "b::static_inv" << std::endl
255 << "b::inv" << std::endl
256 << "a::static_inv" << std::endl
257 << "a::inv" << std::endl
258 #endif
259 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
260 << "d::f::old" << std::endl
261 << "d::f::post" << std::endl
262 << "c::f::old" << std::endl
263 << "c::f::post" << std::endl
264 << "b::f::old" << std::endl
265 << "b::f::post" << std::endl
266 << "a::f::post" << std::endl
267 #endif
268 ;
269 BOOST_TEST(out.eq(ok.str()));
270 BOOST_TEST(tested_a_copies);
271 BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras);
272
273 // Test non-optional in overriding b::f and optional in overridden c::f.
274 b bb;
275 ch.value = 'b';
276 out.str("");
277 bb.f(ch);
278 ok.str(""); ok
279 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
280 << "d::static_inv" << std::endl
281 << "d::inv" << std::endl
282 << "c::static_inv" << std::endl
283 << "c::inv" << std::endl
284 << "b::static_inv" << std::endl
285 << "b::inv" << std::endl
286 #endif
287 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
288 << "d::f::pre" << std::endl
289 << "c::f::pre" << std::endl
290 << "b::f::pre" << std::endl
291 #endif
292 #ifndef BOOST_CONTRACT_NO_OLDS
293 << "d::f::old" << std::endl
294 << "c::f::old" << std::endl
295 << "b::f::old" << std::endl
296 #endif
297 << "b::f::body" << std::endl
298 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
299 << "d::static_inv" << std::endl
300 << "d::inv" << std::endl
301 << "c::static_inv" << std::endl
302 << "c::inv" << std::endl
303 << "b::static_inv" << std::endl
304 << "b::inv" << std::endl
305 #endif
306 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
307 << "d::f::old" << std::endl
308 << "d::f::post" << std::endl
309 << "c::f::old" << std::endl
310 << "c::f::post" << std::endl
311 << "b::f::post" << std::endl
312 #endif
313 ;
314 BOOST_TEST(out.eq(ok.str()));
315 BOOST_TEST(tested_b_copies);
316 BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras);
317
318 // Test optional in both overriding c::f and overridden d::f.
319 c cc;
320 ch.value = 'c';
321 out.str("");
322 cc.f(ch);
323 ok.str(""); ok
324 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
325 << "d::static_inv" << std::endl
326 << "d::inv" << std::endl
327 << "c::static_inv" << std::endl
328 << "c::inv" << std::endl
329 #endif
330 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
331 << "d::f::pre" << std::endl
332 << "c::f::pre" << std::endl
333 #endif
334 #ifndef BOOST_CONTRACT_NO_OLDS
335 << "d::f::old" << std::endl
336 << "c::f::old" << std::endl
337 #endif
338 << "c::f::body" << std::endl
339 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
340 << "d::static_inv" << std::endl
341 << "d::inv" << std::endl
342 << "c::static_inv" << std::endl
343 << "c::inv" << std::endl
344 #endif
345 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
346 << "d::f::old" << std::endl
347 << "d::f::post" << std::endl
348 << "c::f::post" << std::endl
349 #endif
350 ;
351 BOOST_TEST(out.eq(ok.str()));
352 BOOST_TEST(tested_c_copies);
353 BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras);
354
355 // Test non-optional in both overriding c::f and overridden d::f.
356 e ee;
357 ch.value = 'e';
358 out.str("");
359 ee.f(ch);
360 ok.str(""); ok
361 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
362 << "d::static_inv" << std::endl
363 << "d::inv" << std::endl
364 << "c::static_inv" << std::endl
365 << "c::inv" << std::endl
366 << "b::static_inv" << std::endl
367 << "b::inv" << std::endl
368 << "e::static_inv" << std::endl
369 << "e::inv" << std::endl
370 #endif
371 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
372 << "d::f::pre" << std::endl
373 << "c::f::pre" << std::endl
374 << "b::f::pre" << std::endl
375 << "e::f::pre" << std::endl
376 #endif
377 #ifndef BOOST_CONTRACT_NO_OLDS
378 << "d::f::old" << std::endl
379 << "c::f::old" << std::endl
380 << "b::f::old" << std::endl
381 << "e::f::old" << std::endl
382 #endif
383 << "e::f::body" << std::endl
384 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
385 << "d::static_inv" << std::endl
386 << "d::inv" << std::endl
387 << "c::static_inv" << std::endl
388 << "c::inv" << std::endl
389 << "b::static_inv" << std::endl
390 << "b::inv" << std::endl
391 << "e::static_inv" << std::endl
392 << "e::inv" << std::endl
393 #endif
394 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
395 << "d::f::old" << std::endl
396 << "d::f::post" << std::endl
397 << "c::f::old" << std::endl
398 << "c::f::post" << std::endl
399 << "b::f::old" << std::endl
400 << "b::f::post" << std::endl
401 << "e::f::post" << std::endl
402 #endif
403 ;
404 BOOST_TEST(out.eq(ok.str()));
405 BOOST_TEST(tested_e_copies);
406 BOOST_TEST_EQ(ch_type::ctors(), ch_type::dtors() + ch_extras);
407
408 return boost::report_errors();
409 }
410
411