• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 #ifndef BOOST_CONTRACT_TEST_PUBLIC_FUNCTION_CONTRACTS_HPP_
3 #define BOOST_CONTRACT_TEST_PUBLIC_FUNCTION_CONTRACTS_HPP_
4 
5 // Copyright (C) 2008-2018 Lorenzo Caminiti
6 // Distributed under the Boost Software License, Version 1.0 (see accompanying
7 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
8 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
9 
10 // Test public member function subcontracting (also with old and return values).
11 
12 #include "../detail/oteststream.hpp"
13 #include "../detail/counter.hpp"
14 #include <boost/contract/public_function.hpp>
15 #include <boost/contract/base_types.hpp>
16 #include <boost/contract/assert.hpp>
17 #include <boost/contract/old.hpp>
18 #include <boost/contract/check.hpp>
19 #include <boost/contract/override.hpp>
20 #include <boost/config.hpp>
21 #include <string>
22 
23 boost::contract::test::detail::oteststream out;
24 
25 struct s_tag;
26 typedef boost::contract::test::detail::counter<s_tag, std::string> s_type;
27 
28 struct except_error {};
29 
30 struct result_type {
31     std::string value;
result_typeresult_type32     explicit result_type(std::string const& s) : value(s) {}
33 
34 private: // Test non-copyable and non-default-constructible result.
35     result_type();
36     result_type(result_type const&);
37     result_type& operator=(result_type const&);
38 };
39 
40 // Test base without additional bases and pure virtual.
41 template<char Id>
42 struct t {
static_invariantt43     static void static_invariant() { out << Id << "::static_inv" << std::endl; }
44 
invariantt45     void invariant() const {
46         out << Id << "::inv" << std::endl;
47         BOOST_CONTRACT_ASSERT(z.value != "");
48     }
49 
50     struct z_tag;
51     typedef boost::contract::test::detail::counter<z_tag, std::string> z_type;
52     z_type z;
53 
tt54     t() { z.value.push_back(Id); }
55 
56     virtual result_type& f(s_type& s, boost::contract::virtual_* v = 0) = 0;
57 };
58 
59 template<char Id> // Requires: Only pass lower case Id so it'll never be 'X'.
f(s_type & s,boost::contract::virtual_ * v)60 result_type& t<Id>::f(s_type& s, boost::contract::virtual_* v) {
61     std::ostringstream r; r << "none-" << Id;
62     static result_type result(r.str());
63     boost::contract::old_ptr<z_type> old_z =
64             BOOST_CONTRACT_OLDOF(v, z_type::eval(z));
65     boost::contract::old_ptr<s_type> old_s;
66     boost::contract::check c = boost::contract::public_function(v, result, this)
67         .precondition([&] {
68             out << Id << "::f::pre" << std::endl;
69             BOOST_CONTRACT_ASSERT(s.value[0] == Id || s.value[0] == 'X');
70         })
71         .old([&] {
72             out << Id << "::f::old" << std::endl;
73             old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s));
74         })
75         .postcondition([&] (result_type const& result) {
76             out << Id << "::f::post" << std::endl;
77             BOOST_CONTRACT_ASSERT(z.value == old_z->value + old_s->value);
78             BOOST_CONTRACT_ASSERT(s.value.find(old_z->value) !=
79                     std::string::npos);
80             BOOST_CONTRACT_ASSERT(result.value == old_s->value);
81         })
82         .except([&] {
83             out << Id << "::f::except" << std::endl;
84             BOOST_CONTRACT_ASSERT(z.value == old_z->value);
85             BOOST_CONTRACT_ASSERT(s.value == old_s->value);
86         })
87     ;
88     out << "t<" << Id << ">::f::body" << std::endl;
89     if(s.value == "X") throw except_error();
90     return result;
91 }
92 
93 // Test base with other bases, multiple inheritance, and no subcontracting from
94 // protected and private bases (even if fully contracted).
95 struct c
96     #define BASES public t<'d'>, protected t<'p'>, private t<'q'>, public t<'e'>
97     : BASES
98 {
99     typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
100     #undef BASES
101 
static_invariantc102     static void static_invariant() { out << "c::static_inv" << std::endl; }
103 
invariantc104     void invariant() const {
105         out << "c::inv" << std::endl;
106         BOOST_CONTRACT_ASSERT(y.value != "");
107     }
108 
109     struct y_tag;
110     typedef boost::contract::test::detail::counter<y_tag, std::string> y_type;
111     y_type y;
112 
cc113     c() { y.value = "c"; }
114 
fc115     virtual result_type& f(s_type& s, boost::contract::virtual_* v = 0)
116             /* override */ {
117         static result_type result("none-c");
118         boost::contract::old_ptr<y_type> old_y =
119                 BOOST_CONTRACT_OLDOF(v, y_type::eval(y));
120         boost::contract::old_ptr<s_type> old_s;
121         boost::contract::check c = boost::contract::public_function<
122                 override_f>(v, result, &c::f, this, s)
123             .precondition([&] {
124                 out << "c::f::pre" << std::endl;
125                 BOOST_CONTRACT_ASSERT(s.value == "C" || s.value == "X");
126             })
127             .old([&] {
128                 out << "c::f::old" << std::endl;
129                 old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s));
130             })
131             .postcondition([&] (result_type const& result) {
132                 out << "c::f::post" << std::endl;
133                 BOOST_CONTRACT_ASSERT(y.value == old_y->value + old_s->value);
134                 BOOST_CONTRACT_ASSERT(s.value.find(old_y->value) !=
135                         std::string::npos);
136                 BOOST_CONTRACT_ASSERT(result.value == old_s->value);
137             })
138             .except([&] {
139                 out << "c::f::except" << std::endl;
140                 BOOST_CONTRACT_ASSERT(y.value == old_y->value);
141                 BOOST_CONTRACT_ASSERT(s.value == old_s->value);
142             })
143         ;
144 
145         out << "c::f::body" << std::endl;
146         if(s.value == "X") throw except_error();
147         std::string save_s = s.value;
148 
149         std::string save = y.value;
150         y.value += save_s;
151         s.value = save;
152 
153         save = t<'d'>::z.value;
154         t<'d'>::z.value += save_s;
155         s.value += save;
156 
157         save = t<'e'>::z.value;
158         t<'e'>::z.value += save_s;
159         s.value += save;
160 
161         result.value = save_s;
162         return result;
163     }
164     BOOST_CONTRACT_OVERRIDE(f)
165 };
166 
167 // Test no subcontracting from not (fully) contracted base.
168 struct b {
static_invariantb169     static void static_invariant() { out << "b::static_inv" << std::endl; }
invariantb170     void invariant() const { out << "b::inv" << std::endl; }
171 
~bb172     virtual ~b() {}
173 
174     // No contract (no virtual_ so this is not actually overridden by a::f).
fb175     virtual result_type& f(s_type& s) {
176         static result_type result("none-b");
177         out << "b::f::body" << std::endl;
178         result.value = s.value;
179         return result;
180     }
181 };
182 
183 // Test public function with both non-contracted and contracted bases.
184 struct a
185     #define BASES public b, public c
186     : BASES
187 {
188     typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
189     #undef BASES
190 
static_invarianta191     static void static_invariant() { out << "a::static_inv" << std::endl; }
192 
invarianta193     void invariant() const {
194         out << "a::inv" << std::endl;
195         BOOST_CONTRACT_ASSERT(x.value != "");
196     }
197 
198     struct x_tag;
199     typedef boost::contract::test::detail::counter<x_tag, std::string> x_type;
200     x_type x;
201 
aa202     a() { x.value = "a"; }
203 
204     #if defined(BOOST_GCC)
205         #pragma GCC diagnostic push
206         #pragma GCC diagnostic ignored "-Woverloaded-virtual" // For a::f.
207     #elif defined(BOOST_CLANG)
208         #pragma clang diagnostic push
209         #pragma clang diagnostic ignored "-Woverloaded-virtual" // For a::f.
210     #endif
211 
212     // Must use virtual_ even if no longer decl virtual for correct overloading.
213     // NOTE: This intentionally hides but does not override `b::f` (it overrides
214     // `c::f` instead). This generates warnings on some compilers (Clang, etc.).
fa215     result_type& f(s_type& s, boost::contract::virtual_* v = 0)
216             /* override */ {
217         static result_type result("none-a");
218         boost::contract::old_ptr<x_type> old_x =
219                 BOOST_CONTRACT_OLDOF(v, x_type::eval(x));
220         boost::contract::old_ptr<s_type> old_s;
221         boost::contract::check c = boost::contract::public_function<
222                 override_f>(v, result, &a::f, this, s)
223             .precondition([&] {
224                 out << "a::f::pre" << std::endl;
225                 BOOST_CONTRACT_ASSERT(s.value == "A" || s.value == "X");
226             })
227             .old([&] {
228                 out << "a::f::old" << std::endl;
229                 old_s = BOOST_CONTRACT_OLDOF(v, s_type::eval(s));
230             })
231             .postcondition([&] (result_type const& result) {
232                 out << "a::f::post" << std::endl;
233                 BOOST_CONTRACT_ASSERT(x.value == old_x->value + old_s->value);
234                 BOOST_CONTRACT_ASSERT(s.value.find(old_x->value) !=
235                         std::string::npos);
236                 BOOST_CONTRACT_ASSERT(result.value == old_s->value);
237             })
238             .except([&] {
239                 out << "a::f::except" << std::endl;
240                 BOOST_CONTRACT_ASSERT(x.value == old_x->value);
241                 BOOST_CONTRACT_ASSERT(s.value == old_s->value);
242             })
243         ;
244 
245         out << "a::f::body" << std::endl;
246         if(s.value == "X") throw except_error();
247         std::string save_s = s.value;
248 
249         std::string save = x.value;
250         x.value += save_s;
251         s.value = save;
252 
253         save = y.value;
254         y.value += save_s;
255         s.value += save;
256 
257         save = t<'d'>::z.value;
258         t<'d'>::z.value += save_s;
259         s.value += save;
260 
261         save = t<'e'>::z.value;
262         t<'e'>::z.value += save_s;
263         s.value += save;
264 
265         result.value = save_s;
266         return result;
267     }
268     BOOST_CONTRACT_OVERRIDE(f)
269 
270     #if defined(BOOST_GCC)
271         #pragma GCC diagnostic pop
272     #elif defined(BOOST_CLANG)
273         #pragma clang diagnostic pop
274     #endif
275 };
276 
277 #endif // #include guard
278 
279