• 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 destructor subcontracting.
8 
9 #include "../detail/oteststream.hpp"
10 #include "../detail/counter.hpp"
11 #include <boost/contract/destructor.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/preprocessor/control/iif.hpp>
17 #include <boost/detail/lightweight_test.hpp>
18 #include <sstream>
19 
20 boost::contract::test::detail::oteststream out;
21 
22 template<char Id>
23 struct t {
static_invariantt24     static void static_invariant() {
25         out << Id << "::static_inv" << std::endl;
26         BOOST_CONTRACT_ASSERT(l.value >= 0);
27     }
28 
invariantt29     void invariant() const {
30         out << Id << "::inv" << std::endl;
31         BOOST_CONTRACT_ASSERT(k_ < 0);
32     }
33 
34     struct l_tag;
35     typedef boost::contract::test::detail::counter<l_tag, int> l_type;
36     static l_type l;
37 
tt38     explicit t() : k_(-1) { ++l.value; }
39 
~tt40     virtual ~t() {
41         boost::contract::old_ptr<l_type> old_l;
42         boost::contract::check c = boost::contract::destructor(this)
43             .old([&] {
44                 out << Id << "::dtor::old" << std::endl;
45                 old_l = BOOST_CONTRACT_OLDOF(l_type::eval(l));
46             })
47             .postcondition([&old_l] {
48                 out << Id << "::dtor::post" << std::endl;
49                 BOOST_CONTRACT_ASSERT(t<Id>::l.value == old_l->value - 1);
50             })
51         ;
52         out << Id << "::dtor::body" << std::endl;
53         --l.value;
54     }
55 
56 private:
57     int k_;
58 };
59 template<char Id> typename t<Id>::l_type t<Id>::l;
60 
61 // Test deep inheritance (2 vertical levels), multiple inheritance (4
62 // horizontal levels), and that all public/protected/private part of
63 // subcontracting for destructors (not just public, because all access levels
64 // are part of C++ object destruction mechanism).
65 struct c
66     #define BASES public t<'d'>, protected t<'p'>, private t<'q'>, public t<'e'>
67     : BASES
68 {
69     typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
70     #undef BASES
71 
static_invariantc72     static void static_invariant() {
73         out << "c::static_inv" << std::endl;
74         BOOST_CONTRACT_ASSERT(m.value >= 0);
75     }
76 
invariantc77     void invariant() const {
78         out << "c::inv" << std::endl;
79         BOOST_CONTRACT_ASSERT(j_ < 0);
80     }
81 
82     struct m_tag;
83     typedef boost::contract::test::detail::counter<m_tag, int> m_type;
84     static m_type m;
85 
cc86     explicit c() : j_(-1) { ++m.value; }
87 
~cc88     virtual ~c() {
89         boost::contract::old_ptr<m_type> old_m =
90                 BOOST_CONTRACT_OLDOF(m_type::eval(m));
91         boost::contract::check c = boost::contract::destructor(this)
92             .old([] {
93                 out << "c::dtor::old" << std::endl;
94                 // Test old-of assignment above instead.
95             })
96             .postcondition([&old_m] {
97                 out << "c::dtor::post" << std::endl;
98                 BOOST_CONTRACT_ASSERT(c::m.value == old_m->value - 1);
99             })
100         ;
101         out << "c::dtor::body" << std::endl;
102         --m.value;
103     }
104 
105 private:
106     int j_;
107 };
108 c::m_type c::m;
109 
110 // Test not (fully) contracted base is not part of destructor subcontracting.
111 struct b {
static_invariantb112     static void static_invariant() { out << "b::static_inv" << std::endl; }
invariantb113     void invariant() const { out << "b::inv" << std::endl; }
114 
bb115     explicit b() {}
~bb116     virtual ~b() {} // No contract.
117 };
118 
119 struct a_n_tag; // Global decl so visible in MSVC10 lambdas.
120 typedef boost::contract::test::detail::counter<a_n_tag, int> a_n_type;
121 
122 // Test destructor with both non-contracted and contracted bases.
123 struct a
124     #define BASES public b, public c
125     : BASES
126 {
127     typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
128     #undef BASES
129 
static_invarianta130     static void static_invariant() {
131         out << "a::static_inv" << std::endl;
132         BOOST_CONTRACT_ASSERT(n.value >= 0);
133     }
134 
invarianta135     void invariant() const {
136         out << "a::inv" << std::endl;
137         BOOST_CONTRACT_ASSERT(i_ < 0);
138     }
139 
140     static a_n_type n;
141 
aa142     explicit a() : i_(-1) {
143         ++i_; --i_; // To avoid a warning when all contracts off.
144         ++n.value;
145     }
146 
~aa147     virtual ~a() {
148         boost::contract::old_ptr<a_n_type> old_n;
149         boost::contract::check c = boost::contract::destructor(this)
150             .old([&] {
151                 out << "a::dtor::old" << std::endl;
152                 old_n = BOOST_CONTRACT_OLDOF(a_n_type::eval(n));
153             })
154             .postcondition([&old_n] {
155                 out << "a::dtor::post" << std::endl;
156                 BOOST_CONTRACT_ASSERT(a::n.value == old_n->value - 1);
157             })
158         ;
159         out << "a::dtor::body" << std::endl;
160         --n.value;
161     }
162 
163 private:
164     int i_;
165 };
166 a_n_type a::n;
167 
main()168 int main() {
169     std::ostringstream ok;
170 
171     {
172         a aa;
173         out.str("");
174     } // Call aa's destructor.
175     ok.str(""); ok
176         #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
177             << "a::static_inv" << std::endl
178             << "a::inv" << std::endl
179         #endif
180         #ifndef BOOST_CONTRACT_NO_OLDS
181             << "a::dtor::old" << std::endl
182         #endif
183         << "a::dtor::body" << std::endl
184         // Test static inv, but not const inv, checked after destructor body.
185         #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
186             << "a::static_inv" << std::endl
187         #endif
188         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
189             << "a::dtor::post" << std::endl
190         #endif
191 
192         #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
193             << "c::static_inv" << std::endl
194             << "c::inv" << std::endl
195         #endif
196         #ifndef BOOST_CONTRACT_NO_OLDS
197             << "c::dtor::old" << std::endl
198         #endif
199         << "c::dtor::body" << std::endl
200         #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
201             << "c::static_inv" << std::endl
202         #endif
203         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
204             << "c::dtor::post" << std::endl
205         #endif
206 
207         #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
208             << "e::static_inv" << std::endl
209             << "e::inv" << std::endl
210         #endif
211         #ifndef BOOST_CONTRACT_NO_OLDS
212             << "e::dtor::old" << std::endl
213         #endif
214         << "e::dtor::body" << std::endl
215         #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
216             << "e::static_inv" << std::endl
217         #endif
218         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
219             << "e::dtor::post" << std::endl
220         #endif
221 
222         // Test check also private bases (because part of C++ destruction).
223         #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
224             << "q::static_inv" << std::endl
225             << "q::inv" << std::endl
226         #endif
227         #ifndef BOOST_CONTRACT_NO_OLDS
228             << "q::dtor::old" << std::endl
229         #endif
230         << "q::dtor::body" << std::endl
231         #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
232             << "q::static_inv" << std::endl
233         #endif
234         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
235             << "q::dtor::post" << std::endl
236         #endif
237 
238         // Test check also protected bases (because part of C++ destruction).
239         #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
240             << "p::static_inv" << std::endl
241             << "p::inv" << std::endl
242         #endif
243         #ifndef BOOST_CONTRACT_NO_OLDS
244             << "p::dtor::old" << std::endl
245         #endif
246         << "p::dtor::body" << std::endl
247         #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
248             << "p::static_inv" << std::endl
249         #endif
250         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
251             << "p::dtor::post" << std::endl
252         #endif
253 
254         #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
255             << "d::static_inv" << std::endl
256             << "d::inv" << std::endl
257         #endif
258         #ifndef BOOST_CONTRACT_NO_OLDS
259             << "d::dtor::old" << std::endl
260         #endif
261         << "d::dtor::body" << std::endl
262         #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
263             << "d::static_inv" << std::endl
264         #endif
265         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
266             << "d::dtor::post" << std::endl
267         #endif
268     ;
269     BOOST_TEST(out.eq(ok.str()));
270 
271     #ifndef BOOST_CONTRACT_NO_OLDS
272         #define BOOST_CONTRACT_TEST_old 1u
273     #else
274         #define BOOST_CONTRACT_TEST_old 0u
275     #endif
276 
277     // Followings destroy only copies (actual objects are static data members).
278 
279     BOOST_TEST_EQ(a_n_type::copies(), BOOST_CONTRACT_TEST_old);
280     BOOST_TEST_EQ(a_n_type::evals(), BOOST_CONTRACT_TEST_old);
281     BOOST_TEST_EQ(a_n_type::copies(), a_n_type::dtors()); // No leak.
282 
283     BOOST_TEST_EQ(c::m_type::copies(), BOOST_CONTRACT_TEST_old);
284     BOOST_TEST_EQ(c::m_type::evals(), BOOST_CONTRACT_TEST_old);
285     BOOST_TEST_EQ(c::m_type::copies(), c::m_type::dtors()); // No leak.
286 
287     BOOST_TEST_EQ(t<'d'>::l_type::copies(), BOOST_CONTRACT_TEST_old);
288     BOOST_TEST_EQ(t<'d'>::l_type::evals(), BOOST_CONTRACT_TEST_old);
289     BOOST_TEST_EQ(t<'d'>::l_type::copies(), t<'d'>::l_type::dtors()); // No leak
290 
291     BOOST_TEST_EQ(t<'p'>::l_type::copies(), BOOST_CONTRACT_TEST_old);
292     BOOST_TEST_EQ(t<'p'>::l_type::evals(), BOOST_CONTRACT_TEST_old);
293     BOOST_TEST_EQ(t<'p'>::l_type::copies(), t<'p'>::l_type::dtors()); // No leak
294 
295     BOOST_TEST_EQ(t<'q'>::l_type::copies(), BOOST_CONTRACT_TEST_old);
296     BOOST_TEST_EQ(t<'q'>::l_type::evals(), BOOST_CONTRACT_TEST_old);
297     BOOST_TEST_EQ(t<'q'>::l_type::copies(), t<'q'>::l_type::dtors()); // No leak
298 
299     BOOST_TEST_EQ(t<'e'>::l_type::copies(), BOOST_CONTRACT_TEST_old);
300     BOOST_TEST_EQ(t<'e'>::l_type::evals(), BOOST_CONTRACT_TEST_old);
301     BOOST_TEST_EQ(t<'e'>::l_type::copies(), t<'e'>::l_type::dtors()); // No leak
302 
303     #undef BOOST_CONTRACT_TEST_old
304     return boost::report_errors();
305 }
306 
307