• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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