1
2 // Copyright (C) 2008-2018 Lorenzo Caminiti
3 // Distributed under the Boost Software License, Version 1.0 (see accompanying
4 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
5 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
6
7 // Test subcontracting with sparse and complex inheritance graph.
8
9 #include "../detail/oteststream.hpp"
10 #include <boost/contract/public_function.hpp>
11 #include <boost/contract/assert.hpp>
12 #include <boost/contract/check.hpp>
13 #include <boost/contract/override.hpp>
14 #include <boost/contract/base_types.hpp>
15 #include <boost/detail/lightweight_test.hpp>
16 #include <sstream>
17
18 boost::contract::test::detail::oteststream out;
19
20 struct j {
static_invariantj21 static void static_invariant() { out << "j::static_inv" << std::endl; }
invariantj22 void invariant() const { out << "j::inv" << std::endl; }
23
fj24 virtual void f(char ch, boost::contract::virtual_* v = 0) {
25 boost::contract::check c = boost::contract::public_function(v, this)
26 .precondition([&] {
27 out << "j::f::pre" << std::endl;
28 BOOST_CONTRACT_ASSERT(ch == 'j');
29 })
30 .old([] { out << "j::f::old" << std::endl; })
31 .postcondition([] { out << "j::f::post" << std::endl; })
32 ;
33 out << "j::f::body" << std::endl;
34 }
35 };
36
37 struct i {
static_invarianti38 static void static_invariant() { out << "i::static_inv" << std::endl; }
invarianti39 void invariant() const { out << "i::inv" << std::endl; }
40
fi41 virtual void f(char ch, boost::contract::virtual_* v = 0) {
42 boost::contract::check c = boost::contract::public_function(v, this)
43 .precondition([&] {
44 out << "i::f::pre" << std::endl;
45 BOOST_CONTRACT_ASSERT(ch == 'i');
46 })
47 .old([] { out << "i::f::old" << std::endl; })
48 .postcondition([] { out << "i::f::post" << std::endl; })
49 ;
50 out << "i::f::body" << std::endl;
51 }
52 };
53
54 struct k {};
55
56 struct h
57 #define BASES public j
58 : BASES
59 {
60 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
61 #undef BASES
62
static_invarianth63 static void static_invariant() { out << "h::static_inv" << std::endl; }
invarianth64 void invariant() const { out << "h::inv" << std::endl; }
65
fh66 virtual void f(char ch, boost::contract::virtual_* v = 0) /* override */ {
67 boost::contract::check c = boost::contract::public_function<
68 override_f>(v, &h::f, this, ch)
69 .precondition([&] {
70 out << "h::f::pre" << std::endl;
71 BOOST_CONTRACT_ASSERT(ch == 'h');
72 })
73 .old([] { out << "h::f::old" << std::endl; })
74 .postcondition([] { out << "h::f::post" << std::endl; })
75 ;
76 out << "h::f::body" << std::endl;
77 }
78 BOOST_CONTRACT_OVERRIDE(f)
79 };
80
81 struct e
82 #define BASES public virtual i
83 : BASES
84 {
85 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
86 #undef BASES
87
static_invariante88 static void static_invariant() { out << "e::static_inv" << std::endl; }
invariante89 void invariant() const { out << "e::inv" << std::endl; }
90
fe91 virtual void f(char ch, boost::contract::virtual_* v = 0) /* override */ {
92 boost::contract::check c = boost::contract::public_function<
93 override_f>(v, &e::f, this, ch)
94 .precondition([&] {
95 out << "e::f::pre" << std::endl;
96 BOOST_CONTRACT_ASSERT(ch == 'e');
97 })
98 .old([] { out << "e::f::old" << std::endl; })
99 .postcondition([] { out << "e::f::post" << std::endl; })
100 ;
101 out << "e::f::body" << std::endl;
102 }
103 BOOST_CONTRACT_OVERRIDE(f)
104 };
105
106 struct d
107 #define BASES public k, virtual public i
108 : BASES
109 {
110 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
111 #undef BASES
112
static_invariantd113 static void static_invariant() { out << "d::static_inv" << std::endl; }
invariantd114 void invariant() const { out << "d::inv" << std::endl; }
115 };
116
117 struct c {
static_invariantc118 static void static_invariant() { out << "c::static_inv" << std::endl; }
invariantc119 void invariant() const { out << "c::inv" << std::endl; }
120
fc121 virtual void f(char ch, boost::contract::virtual_* v = 0) {
122 boost::contract::check c = boost::contract::public_function(v, this)
123 .precondition([&] {
124 out << "c::f::pre" << std::endl;
125 BOOST_CONTRACT_ASSERT(ch == 'c');
126 })
127 .old([] { out << "c::f::old" << std::endl; })
128 .postcondition([] { out << "c::f::post" << std::endl; })
129 ;
130 out << "c::f::body" << std::endl;
131 }
132 };
133
134 struct b
135 #define BASES public c, public d
136 : BASES
137 {
138 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
139 #undef BASES
140
static_invariantb141 static void static_invariant() { out << "b::static_inv" << std::endl; }
invariantb142 void invariant() const { out << "b::inv" << std::endl; }
143 };
144
145 struct x {};
146 struct y {};
147 struct z {};
148
149 struct a
150 #define BASES public b, public x, public e, protected y, public h, \
151 private z
152 : BASES
153 {
154 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
155 #undef BASES
156
static_invarianta157 static void static_invariant() { out << "a::static_inv" << std::endl; }
invarianta158 void invariant() const { out << "a::inv" << std::endl; }
159
fa160 virtual void f(char ch, boost::contract::virtual_* v = 0) /* override */ {
161 boost::contract::check c = boost::contract::public_function<
162 override_f>(v, &a::f, this, ch)
163 .precondition([&] {
164 out << "a::f::pre" << std::endl;
165 BOOST_CONTRACT_ASSERT(ch == 'a');
166 })
167 .old([] { out << "a::f::old" << std::endl; })
168 .postcondition([] { out << "a::f::post" << std::endl; })
169 ;
170 out << "a::f::body" << std::endl;
171 }
172 BOOST_CONTRACT_OVERRIDE(f)
173 };
174
main()175 int main() {
176 std::ostringstream ok;
177
178 a aa;
179 out.str("");
180 aa.f('a');
181 ok.str(""); ok
182 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
183 << "c::static_inv" << std::endl
184 << "c::inv" << std::endl
185 << "i::static_inv" << std::endl
186 << "i::inv" << std::endl
187 << "e::static_inv" << std::endl
188 << "e::inv" << std::endl
189 << "j::static_inv" << std::endl
190 << "j::inv" << std::endl
191 << "h::static_inv" << std::endl
192 << "h::inv" << std::endl
193 << "a::static_inv" << std::endl
194 << "a::inv" << std::endl
195 #endif
196 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
197 << "c::f::pre" << std::endl
198 << "i::f::pre" << std::endl
199 << "e::f::pre" << std::endl
200 << "j::f::pre" << std::endl
201 << "h::f::pre" << std::endl
202 << "a::f::pre" << std::endl
203 #endif
204 #ifndef BOOST_CONTRACT_NO_OLDS
205 << "c::f::old" << std::endl
206 << "i::f::old" << std::endl
207 << "e::f::old" << std::endl
208 << "j::f::old" << std::endl
209 << "h::f::old" << std::endl
210 << "a::f::old" << std::endl
211 #endif
212 << "a::f::body" << std::endl
213 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
214 << "c::static_inv" << std::endl
215 << "c::inv" << std::endl
216 << "i::static_inv" << std::endl
217 << "i::inv" << std::endl
218 << "e::static_inv" << std::endl
219 << "e::inv" << std::endl
220 << "j::static_inv" << std::endl
221 << "j::inv" << std::endl
222 << "h::static_inv" << std::endl
223 << "h::inv" << std::endl
224 << "a::static_inv" << std::endl
225 << "a::inv" << std::endl
226 #endif
227 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
228 << "c::f::old" << std::endl
229 << "c::f::post" << std::endl
230 << "i::f::old" << std::endl
231 << "i::f::post" << std::endl
232 << "e::f::old" << std::endl
233 << "e::f::post" << std::endl
234 << "j::f::old" << std::endl
235 << "j::f::post" << std::endl
236 << "h::f::old" << std::endl
237 << "h::f::post" << std::endl
238 // No old call here because not a base object.
239 << "a::f::post" << std::endl
240 #endif
241 ;
242 BOOST_TEST(out.eq(ok.str()));
243
244 c cc;
245 out.str("");
246 cc.f('c');
247 ok.str(""); ok
248 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
249 << "c::static_inv" << std::endl
250 << "c::inv" << std::endl
251 #endif
252 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
253 << "c::f::pre" << std::endl
254 #endif
255 #ifndef BOOST_CONTRACT_NO_OLDS
256 << "c::f::old" << std::endl
257 #endif
258 << "c::f::body" << std::endl
259 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
260 << "c::static_inv" << std::endl
261 << "c::inv" << std::endl
262 #endif
263 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
264 // No old call here because not a base object.
265 << "c::f::post" << std::endl
266 #endif
267 ;
268 BOOST_TEST(out.eq(ok.str()));
269
270 d dd;
271 out.str("");
272 dd.f('i'); // d's f inherited from i.
273 ok.str(""); ok
274 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
275 << "i::static_inv" << std::endl
276 << "i::inv" << std::endl
277 #endif
278 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
279 << "i::f::pre" << std::endl
280 #endif
281 #ifndef BOOST_CONTRACT_NO_OLDS
282 << "i::f::old" << std::endl
283 #endif
284 << "i::f::body" << std::endl
285 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
286 << "i::static_inv" << std::endl
287 << "i::inv" << std::endl
288 #endif
289 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
290 // No old call here because not a base object.
291 << "i::f::post" << std::endl
292 #endif
293 ;
294 BOOST_TEST(out.eq(ok.str()));
295
296 e ee;
297 out.str("");
298 ee.f('e');
299 ok.str(""); ok
300 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
301 << "i::static_inv" << std::endl
302 << "i::inv" << std::endl
303 << "e::static_inv" << std::endl
304 << "e::inv" << std::endl
305 #endif
306 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
307 << "i::f::pre" << std::endl
308 << "e::f::pre" << std::endl
309 #endif
310 #ifndef BOOST_CONTRACT_NO_OLDS
311 << "i::f::old" << std::endl
312 << "e::f::old" << std::endl
313 #endif
314 << "e::f::body" << std::endl
315 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
316 << "i::static_inv" << std::endl
317 << "i::inv" << std::endl
318 << "e::static_inv" << std::endl
319 << "e::inv" << std::endl
320 #endif
321 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
322 << "i::f::old" << std::endl
323 << "i::f::post" << std::endl
324 // No old call here because not a base object.
325 << "e::f::post" << std::endl
326 #endif
327 ;
328 BOOST_TEST(out.eq(ok.str()));
329
330 i ii;
331 out.str("");
332 ii.f('i');
333 ok.str(""); ok
334 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
335 << "i::static_inv" << std::endl
336 << "i::inv" << std::endl
337 #endif
338 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
339 << "i::f::pre" << std::endl
340 #endif
341 #ifndef BOOST_CONTRACT_NO_OLDS
342 << "i::f::old" << std::endl
343 #endif
344 << "i::f::body" << std::endl
345 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
346 << "i::static_inv" << std::endl
347 << "i::inv" << std::endl
348 #endif
349 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
350 // No old call here because not a base object.
351 << "i::f::post" << std::endl
352 #endif
353 ;
354 BOOST_TEST(out.eq(ok.str()));
355
356 h hh;
357 out.str("");
358 hh.f('h');
359 ok.str(""); ok
360 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
361 << "j::static_inv" << std::endl
362 << "j::inv" << std::endl
363 << "h::static_inv" << std::endl
364 << "h::inv" << std::endl
365 #endif
366 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
367 << "j::f::pre" << std::endl
368 << "h::f::pre" << std::endl
369 #endif
370 #ifndef BOOST_CONTRACT_NO_OLDS
371 << "j::f::old" << std::endl
372 << "h::f::old" << std::endl
373 #endif
374 << "h::f::body" << std::endl
375 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
376 << "j::static_inv" << std::endl
377 << "j::inv" << std::endl
378 << "h::static_inv" << std::endl
379 << "h::inv" << std::endl
380 #endif
381 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
382 << "j::f::old" << std::endl
383 << "j::f::post" << std::endl
384 // No old call here because not a base object.
385 << "h::f::post" << std::endl
386 #endif
387 ;
388 BOOST_TEST(out.eq(ok.str()));
389
390 j jj;
391 out.str("");
392 jj.f('j');
393 ok.str(""); ok
394 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
395 << "j::static_inv" << std::endl
396 << "j::inv" << std::endl
397 #endif
398 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
399 << "j::f::pre" << std::endl
400 #endif
401 #ifndef BOOST_CONTRACT_NO_OLDS
402 << "j::f::old" << std::endl
403 #endif
404 << "j::f::body" << std::endl
405 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
406 << "j::static_inv" << std::endl
407 << "j::inv" << std::endl
408 #endif
409 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
410 // No old call here because not a base object.
411 << "j::f::post" << std::endl
412 #endif
413 ;
414 BOOST_TEST(out.eq(ok.str()));
415
416 return boost::report_errors();
417 }
418
419