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 constructor subcontracting.
8
9 #include "../detail/oteststream.hpp"
10 #include "../detail/counter.hpp"
11 #include <boost/contract/constructor.hpp>
12 #include <boost/contract/base_types.hpp>
13 #include <boost/contract/assert.hpp>
14 #include <boost/contract/old.hpp>
15 #include <boost/contract/check.hpp>
16 #include <boost/bind.hpp>
17 #include <boost/ref.hpp>
18 #include <boost/detail/lightweight_test.hpp>
19 #include <sstream>
20
21 boost::contract::test::detail::oteststream out;
22
23 template<char Id>
24 struct t
25 #define BASES private boost::contract::constructor_precondition<t<Id> >
26 : BASES
27 {
28 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
29 #undef BASES
30
static_invariantt31 static void static_invariant() {
32 out << Id << "::static_inv" << std::endl;
33 BOOST_CONTRACT_ASSERT(l.value >= 0);
34 }
35
invariantt36 void invariant() const {
37 out << Id << "::inv" << std::endl;
38 BOOST_CONTRACT_ASSERT(k_ < 0);
39 }
40
41 struct l_tag;
42 typedef boost::contract::test::detail::counter<l_tag, int> l_type;
43 static l_type l;
44
45 struct z_tag;
46 typedef boost::contract::test::detail::counter<z_tag, int> z_type;
47
tt48 explicit t(z_type& z) :
49 boost::contract::constructor_precondition<t<Id> >([&] {
50 out << Id << "::ctor::pre" << std::endl;
51 BOOST_CONTRACT_ASSERT(z.value < 0);
52 })
53 {
54 boost::contract::old_ptr<z_type> old_z;
55 boost::contract::old_ptr<l_type> old_l =
56 BOOST_CONTRACT_OLDOF(l_type::eval(l));
57 boost::contract::check c = boost::contract::constructor(this)
__anond471bf540202null58 .old([&] {
59 out << Id << "::ctor::old" << std::endl;
60 old_z = BOOST_CONTRACT_OLDOF(z_type::eval(z));
61 })
__anond471bf540302null62 .postcondition([&] {
63 out << Id << "::ctor::post" << std::endl;
64 BOOST_CONTRACT_ASSERT(k_ == old_z->value);
65 BOOST_CONTRACT_ASSERT(z.value == l.value);
66 BOOST_CONTRACT_ASSERT(l.value == old_l->value + 1);
67 })
68 ;
69 out << Id << "::ctor::body" << std::endl;
70 k_ = z.value;
71 z.value = ++l.value;
72 }
73
~tt74 virtual ~t() { --l.value; }
75
76 private:
77 int k_;
78 };
79 template<char Id> typename t<Id>::l_type t<Id>::l;
80
81 // Test deep inheritance (2 vertical levels), multiple inheritance (4
82 // horizontal levels), and that all public/protected/private part of
83 // subcontracting for constructors (not just public, because all access levels
84 // are part of C++ object construction mechanism).
85 struct c
86 #define BASES private boost::contract::constructor_precondition<c>, \
87 public t<'d'>, protected t<'p'>, private t<'q'>, public t<'e'>
88 : BASES
89 {
90 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
91 #undef BASES
92
static_invariantc93 static void static_invariant() {
94 out << "c::static_inv" << std::endl;
95 BOOST_CONTRACT_ASSERT(m.value >= 0);
96 }
97
invariantc98 void invariant() const {
99 out << "c::inv" << std::endl;
100 BOOST_CONTRACT_ASSERT(j_ < 0);
101 }
102
103 struct m_tag;
104 typedef boost::contract::test::detail::counter<m_tag, int> m_type;
105 static m_type m;
106
107 struct y_tag;
108 typedef boost::contract::test::detail::counter<y_tag, int> y_type;
109
cc110 explicit c(y_type& y, t<'d'>::z_type& dz, t<'p'>::z_type& pz,
111 t<'q'>::z_type& qz, t<'e'>::z_type& ez) :
112 boost::contract::constructor_precondition<c>([&] {
113 out << "c::ctor::pre" << std::endl;
114 BOOST_CONTRACT_ASSERT(y.value < 0);
115 }),
116 t<'d'>(dz), t<'p'>(pz), t<'q'>(qz), t<'e'>(ez)
117 {
118 boost::contract::old_ptr<y_type> old_y =
119 BOOST_CONTRACT_OLDOF(y_type::eval(y));
120 boost::contract::old_ptr<m_type> old_m;
121 boost::contract::check c = boost::contract::constructor(this)
__anond471bf540502null122 .old([&] {
123 out << "c::ctor::old" << std::endl;
124 old_m = BOOST_CONTRACT_OLDOF(m_type::eval(m));
125 })
__anond471bf540602null126 .postcondition([&] {
127 out << "c::ctor::post" << std::endl;
128 BOOST_CONTRACT_ASSERT(j_ == old_y->value);
129 BOOST_CONTRACT_ASSERT(y.value == m.value);
130 BOOST_CONTRACT_ASSERT(m.value == old_m->value + 1);
131 })
132 ;
133 out << "c::ctor::body" << std::endl;
134 j_ = y.value;
135 y.value = ++m.value;
136 }
137
~cc138 virtual ~c() { --m.value; }
139
140 private:
141 int j_;
142 };
143 c::m_type c::m;
144
145 // Test not (fully) contracted base is not part of constructor subcontracting.
146 struct b
147 #define BASES private boost::contract::constructor_precondition<b>
148 : BASES
149 {
150 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
151 #undef BASES
152
static_invariantb153 static void static_invariant() { out << "b::static_inv" << std::endl; }
invariantb154 void invariant() const { out << "b::inv" << std::endl; }
155
bb156 explicit b() {} // No contract.
~bb157 virtual ~b() {}
158 };
159
160 // Test constructor with both non-contracted and contracted bases.
161 struct a
162 #define BASES private boost::contract::constructor_precondition<a>, \
163 public b, public c
164 : BASES
165 {
166 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
167 #undef BASES
168
static_invarianta169 static void static_invariant() {
170 out << "a::static_inv" << std::endl;
171 BOOST_CONTRACT_ASSERT(n.value >= 0);
172 }
173
invarianta174 void invariant() const {
175 out << "a::inv" << std::endl;
176 BOOST_CONTRACT_ASSERT(i_ < 0);
177 }
178
179 struct n_tag;
180 typedef boost::contract::test::detail::counter<n_tag, int> n_type;
181 static n_type n;
182
183 struct x_tag;
184 typedef boost::contract::test::detail::counter<x_tag, int> x_type;
185
aa186 explicit a(x_type& x, c::y_type& y, t<'d'>::z_type& dz,
187 t<'p'>::z_type& pz, t<'q'>::z_type& qz, t<'e'>::z_type& ez) :
188 boost::contract::constructor_precondition<a>([&] {
189 out << "a::ctor::pre" << std::endl;
190 BOOST_CONTRACT_ASSERT(x.value < 0);
191 }),
192 b(), c(y, dz, pz, qz, ez)
193 {
194 boost::contract::old_ptr<x_type> old_x;
195 boost::contract::old_ptr<n_type> old_n =
196 BOOST_CONTRACT_OLDOF(n_type::eval(n));
197 boost::contract::check c = boost::contract::constructor(this)
__anond471bf540802null198 .old([&] {
199 out << "a::ctor::old" << std::endl;
200 old_x = BOOST_CONTRACT_OLDOF(x_type::eval(x));
201 })
__anond471bf540902null202 .postcondition([&] {
203 out << "a::ctor::post" << std::endl;
204 BOOST_CONTRACT_ASSERT(i_ == old_x->value);
205 BOOST_CONTRACT_ASSERT(x.value == n.value);
206 BOOST_CONTRACT_ASSERT(n.value == old_n->value + 1);
207 })
208 ;
209 out << "a::ctor::body" << std::endl;
210 i_ = x.value;
211 x.value = ++n.value;
212 }
213
~aa214 virtual ~a() { --n.value; }
215
216 private:
217 int i_;
218 };
219 a::n_type a::n;
220
main()221 int main() {
222 std::ostringstream ok;
223
224 {
225 t<'e'>::z_type ez; ez.value = -5;
226 t<'q'>::z_type qz; qz.value = -5;
227 t<'p'>::z_type pz; pz.value = -4;
228 t<'d'>::z_type dz; dz.value = -3;
229 c::y_type y; y.value = -2;
230 a::x_type x; x.value = -1;
231
232 out.str("");
233 a aa(x, y, dz, pz, qz, ez);
234 ok.str(""); ok
235 // Test all constructor pre checked first.
236 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
237 << "a::ctor::pre" << std::endl
238 << "c::ctor::pre" << std::endl
239 #endif
240
241 // Test static inv, but not const inv, checked before ctor body.
242 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
243 << "d::ctor::pre" << std::endl
244 #endif
245 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
246 << "d::static_inv" << std::endl
247 #endif
248 #ifndef BOOST_CONTRACT_NO_OLDS
249 << "d::ctor::old" << std::endl
250 #endif
251 << "d::ctor::body" << std::endl
252 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
253 << "d::static_inv" << std::endl
254 << "d::inv" << std::endl
255 #endif
256 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
257 << "d::ctor::post" << std::endl
258 #endif
259
260 // Test check also protected bases (because part of C++ constr.).
261 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
262 << "p::ctor::pre" << std::endl
263 #endif
264 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
265 << "p::static_inv" << std::endl
266 #endif
267 #ifndef BOOST_CONTRACT_NO_OLDS
268 << "p::ctor::old" << std::endl
269 #endif
270 << "p::ctor::body" << std::endl
271 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
272 << "p::static_inv" << std::endl
273 << "p::inv" << std::endl
274 #endif
275 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
276 << "p::ctor::post" << std::endl
277 #endif
278
279 // Test check also private bases (because part of C++ constr.).
280 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
281 << "q::ctor::pre" << std::endl
282 #endif
283 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
284 << "q::static_inv" << std::endl
285 #endif
286 #ifndef BOOST_CONTRACT_NO_OLDS
287 << "q::ctor::old" << std::endl
288 #endif
289 << "q::ctor::body" << std::endl
290 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
291 << "q::static_inv" << std::endl
292 << "q::inv" << std::endl
293 #endif
294 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
295 << "q::ctor::post" << std::endl
296 #endif
297
298 #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
299 << "e::ctor::pre" << std::endl
300 #endif
301 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
302 << "e::static_inv" << std::endl
303 #endif
304 #ifndef BOOST_CONTRACT_NO_OLDS
305 << "e::ctor::old" << std::endl
306 #endif
307 << "e::ctor::body" << std::endl
308 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
309 << "e::static_inv" << std::endl
310 << "e::inv" << std::endl
311 #endif
312 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
313 << "e::ctor::post" << std::endl
314 #endif
315
316 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
317 << "c::static_inv" << std::endl
318 #endif
319 #ifndef BOOST_CONTRACT_NO_OLDS
320 << "c::ctor::old" << std::endl
321 #endif
322 << "c::ctor::body" << std::endl
323 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
324 << "c::static_inv" << std::endl
325 << "c::inv" << std::endl
326 #endif
327 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
328 << "c::ctor::post" << std::endl
329 #endif
330
331 #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
332 << "a::static_inv" << std::endl
333 #endif
334 #ifndef BOOST_CONTRACT_NO_OLDS
335 << "a::ctor::old" << std::endl
336 #endif
337 << "a::ctor::body" << std::endl
338 #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
339 << "a::static_inv" << std::endl
340 << "a::inv" << std::endl
341 #endif
342 #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
343 << "a::ctor::post" << std::endl
344 #endif
345 ;
346 BOOST_TEST(out.eq(ok.str()));
347 }
348
349 #ifndef BOOST_CONTRACT_NO_OLDS
350 #define BOOST_CONTRACT_TEST_old 1u
351 #else
352 #define BOOST_CONTRACT_TEST_old 0u
353 #endif
354
355 std::clog << a::x_type::copies() << std::endl;
356 std::clog << BOOST_CONTRACT_TEST_old << std::endl;
357 BOOST_TEST_EQ(a::x_type::copies(), BOOST_CONTRACT_TEST_old);
358 BOOST_TEST_EQ(a::x_type::evals(), BOOST_CONTRACT_TEST_old);
359 BOOST_TEST_EQ(a::x_type::ctors(), a::x_type::dtors()); // No leak.
360
361 BOOST_TEST_EQ(c::y_type::copies(), BOOST_CONTRACT_TEST_old);
362 BOOST_TEST_EQ(c::y_type::evals(), BOOST_CONTRACT_TEST_old);
363 BOOST_TEST_EQ(c::y_type::ctors(), c::y_type::dtors()); // No leak.
364
365 BOOST_TEST_EQ(t<'d'>::z_type::copies(), BOOST_CONTRACT_TEST_old);
366 BOOST_TEST_EQ(t<'d'>::z_type::evals(), BOOST_CONTRACT_TEST_old);
367 BOOST_TEST_EQ(t<'d'>::z_type::ctors(), t<'d'>::z_type::dtors()); // No leak.
368
369 BOOST_TEST_EQ(t<'p'>::z_type::copies(), BOOST_CONTRACT_TEST_old);
370 BOOST_TEST_EQ(t<'p'>::z_type::evals(), BOOST_CONTRACT_TEST_old);
371 BOOST_TEST_EQ(t<'p'>::z_type::ctors(), t<'p'>::z_type::dtors()); // No leak.
372
373 BOOST_TEST_EQ(t<'q'>::z_type::copies(), BOOST_CONTRACT_TEST_old);
374 BOOST_TEST_EQ(t<'q'>::z_type::evals(), BOOST_CONTRACT_TEST_old);
375 BOOST_TEST_EQ(t<'q'>::z_type::ctors(), t<'q'>::z_type::dtors()); // No leak.
376
377 BOOST_TEST_EQ(t<'e'>::z_type::copies(), BOOST_CONTRACT_TEST_old);
378 BOOST_TEST_EQ(t<'e'>::z_type::evals(), BOOST_CONTRACT_TEST_old);
379 BOOST_TEST_EQ(t<'e'>::z_type::ctors(), t<'e'>::z_type::dtors()); // No leak.
380
381 // Following destroy only copies (actual objects are static data members).
382
383 BOOST_TEST_EQ(a::n_type::copies(), BOOST_CONTRACT_TEST_old);
384 BOOST_TEST_EQ(a::n_type::evals(), BOOST_CONTRACT_TEST_old);
385 BOOST_TEST_EQ(a::n_type::copies(), a::n_type::dtors()); // No leak.
386
387 BOOST_TEST_EQ(c::m_type::copies(), BOOST_CONTRACT_TEST_old);
388 BOOST_TEST_EQ(c::m_type::evals(), BOOST_CONTRACT_TEST_old);
389 BOOST_TEST_EQ(c::m_type::copies(), c::m_type::dtors()); // No leak.
390
391 BOOST_TEST_EQ(t<'d'>::l_type::copies(), BOOST_CONTRACT_TEST_old);
392 BOOST_TEST_EQ(t<'d'>::l_type::evals(), BOOST_CONTRACT_TEST_old);
393 BOOST_TEST_EQ(t<'e'>::l_type::copies(), t<'e'>::l_type::dtors()); // No leak
394
395 BOOST_TEST_EQ(t<'p'>::l_type::copies(), BOOST_CONTRACT_TEST_old);
396 BOOST_TEST_EQ(t<'p'>::l_type::evals(), BOOST_CONTRACT_TEST_old);
397 BOOST_TEST_EQ(t<'e'>::l_type::copies(), t<'e'>::l_type::dtors()); // No leak
398
399 BOOST_TEST_EQ(t<'q'>::l_type::copies(), BOOST_CONTRACT_TEST_old);
400 BOOST_TEST_EQ(t<'q'>::l_type::evals(), BOOST_CONTRACT_TEST_old);
401 BOOST_TEST_EQ(t<'e'>::l_type::copies(), t<'e'>::l_type::dtors()); // No leak
402
403 BOOST_TEST_EQ(t<'e'>::l_type::copies(), BOOST_CONTRACT_TEST_old);
404 BOOST_TEST_EQ(t<'e'>::l_type::evals(), BOOST_CONTRACT_TEST_old);
405 BOOST_TEST_EQ(t<'e'>::l_type::copies(), t<'e'>::l_type::dtors()); // No leak
406
407 #undef BOOST_CONTRACT_TEST_old
408 return boost::report_errors();
409 }
410
411