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