]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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 public function overloads. | |
8 | ||
9 | #include "../detail/oteststream.hpp" | |
10 | #include <boost/contract/public_function.hpp> | |
11 | #include <boost/contract/base_types.hpp> | |
12 | #include <boost/contract/override.hpp> | |
13 | #include <boost/contract/check.hpp> | |
14 | #include <boost/detail/lightweight_test.hpp> | |
15 | #include <sstream> | |
16 | #include <string> | |
17 | ||
18 | boost::contract::test::detail::oteststream out; | |
19 | ||
20 | struct b { | |
21 | static void static_invariant() { out << "b::static_inv" << std::endl; } | |
22 | void invariant() const { out << "b::inv" << std::endl; } | |
23 | ||
92f5a8d4 | 24 | virtual void f(int /* x */, boost::contract::virtual_* v = 0) { |
11fdf7f2 TL |
25 | boost::contract::check c = boost::contract::public_function(v, this) |
26 | .precondition([] { out << "b::f(int)::pre" << std::endl; }) | |
27 | .old([] { out << "b::f(int)::old" << std::endl; }) | |
28 | .postcondition([] { out << "b::f(int)::post" << std::endl; }) | |
29 | ; | |
30 | out << "b::f(int)::body" << std::endl; | |
31 | } | |
32 | ||
92f5a8d4 | 33 | virtual void f(char const* /* x */, boost::contract::virtual_* v = 0) { |
11fdf7f2 TL |
34 | boost::contract::check c = boost::contract::public_function(v, this) |
35 | .precondition([] { out << "b::f(char const*)::pre" << std::endl; }) | |
36 | .old([] { out << "b::f(char const*)::old" << std::endl; }) | |
37 | .postcondition( | |
38 | [] { out << "b::f(char const*)::post" << std::endl; }) | |
39 | ; | |
40 | out << "b::f(char const*)::body" << std::endl; | |
41 | } | |
42 | ||
92f5a8d4 | 43 | virtual void f(int /* x */, int /* y */, boost::contract::virtual_* v = 0) { |
11fdf7f2 TL |
44 | boost::contract::check c = boost::contract::public_function(v, this) |
45 | .precondition([] { out << "b::f(int, int)::pre" << std::endl; }) | |
46 | .old([] { out << "b::f(int, int)::old" << std::endl; }) | |
47 | .postcondition([] { out << "b::f(int, int)::post" << std::endl; }) | |
48 | ; | |
49 | out << "b::f(int, int)::body" << std::endl; | |
50 | } | |
51 | ||
52 | virtual void f(boost::contract::virtual_* v = 0) { | |
53 | boost::contract::check c = boost::contract::public_function(v, this) | |
54 | .precondition([] { out << "b::f()::pre" << std::endl; }) | |
55 | .old([] { out << "b::f()::old" << std::endl; }) | |
56 | .postcondition([] { out << "b::f()::post" << std::endl; }) | |
57 | ; | |
58 | out << "b::f()::body" << std::endl; | |
59 | } | |
60 | ||
92f5a8d4 | 61 | void f(int /* x */[2][3], boost::contract::virtual_* v = 0) { |
11fdf7f2 TL |
62 | boost::contract::check c = boost::contract::public_function(v, this) |
63 | .precondition([] { out << "b::f(int[2][3])::pre" << std::endl; }) | |
64 | .old([] { out << "b::f(int[2][3])::old" << std::endl; }) | |
65 | .postcondition([] { out << "b::f(int[2][3])::post" << std::endl; }) | |
66 | ; | |
67 | out << "b::f(int[2][3])::body" << std::endl; | |
68 | } | |
69 | ||
92f5a8d4 | 70 | void f(void (* /* x */)(int), boost::contract::virtual_* v = 0) { |
11fdf7f2 TL |
71 | boost::contract::check c = boost::contract::public_function(v, this) |
72 | .precondition( | |
73 | [] { out << "b::f(void (*)(int))::pre" << std::endl; }) | |
74 | .old( | |
75 | [] { out << "b::f(void (*)(int))::old" << std::endl; }) | |
76 | .postcondition( | |
77 | [] { out << "b::f(void (*)(int))::post" << std::endl; }) | |
78 | ; | |
79 | out << "b::f(void (*)(int))::body" << std::endl; | |
80 | } | |
81 | }; | |
82 | ||
83 | struct a | |
84 | #define BASES public b | |
85 | : BASES | |
86 | { | |
87 | typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; | |
88 | #undef BASES | |
89 | ||
90 | static void static_invariant() { out << "a::static_inv" << std::endl; } | |
91 | void invariant() const { out << "a::inv" << std::endl; } | |
92 | ||
93 | void f(int x, boost::contract::virtual_* v = 0) /* override */ { | |
94 | boost::contract::check c = boost::contract::public_function<override_f>( | |
95 | v, | |
96 | static_cast<void (a::*)(int, boost::contract::virtual_*)>(&a::f), | |
97 | this, x | |
98 | ) | |
99 | .precondition([] { out << "a::f(int)::pre" << std::endl; }) | |
100 | .old([] { out << "a::f(int)::old" << std::endl; }) | |
101 | .postcondition([] { out << "a::f(int)::post" << std::endl; }) | |
102 | ; | |
103 | out << "a::f(int)::body" << std::endl; | |
104 | } | |
105 | ||
106 | // Test overload via argument type. | |
107 | void f(char const* x, boost::contract::virtual_* v = 0) /* override */ { | |
108 | boost::contract::check c = boost::contract::public_function<override_f>( | |
109 | v, | |
110 | static_cast<void (a::*)(char const*, boost::contract::virtual_*)>( | |
111 | &a::f), | |
112 | this, x | |
113 | ) | |
114 | .precondition([] { out << "a::f(char const*)::pre" << std::endl; }) | |
115 | .old([] { out << "a::f(char const*)::old" << std::endl; }) | |
116 | .postcondition( | |
117 | [] { out << "a::f(char const*)::post" << std::endl; }) | |
118 | ; | |
119 | out << "a::f(char const*)::body" << std::endl; | |
120 | } | |
121 | ||
122 | // Test overload via argument count. | |
123 | void f(int x, int y, boost::contract::virtual_* v = 0) /* override */ { | |
124 | boost::contract::check c = boost::contract::public_function<override_f>( | |
125 | v, | |
126 | static_cast<void (a::*)(int, int, boost::contract::virtual_*)>( | |
127 | &a::f), | |
128 | this, x, y | |
129 | ) | |
130 | .precondition([] { out << "a::f(int, int)::pre" << std::endl; }) | |
131 | .old([] { out << "a::f(int, int)::old" << std::endl; }) | |
132 | .postcondition([] { out << "a::f(int, int)::post" << std::endl; }) | |
133 | ; | |
134 | out << "a::f(int, int)::body" << std::endl; | |
135 | } | |
136 | ||
137 | // Test overload via template argument type. | |
138 | template<typename T> | |
92f5a8d4 | 139 | void f(T /* x */) { // Template cannot be virtual (or override) in C++. |
11fdf7f2 TL |
140 | boost::contract::check c = boost::contract::public_function(this) |
141 | .precondition([] { out << "a::f(T)::pre" << std::endl; }) | |
142 | .old([] { out << "a::f(T)::old" << std::endl; }) | |
143 | .postcondition([] { out << "a::f(T)::post" << std::endl; }) | |
144 | ; | |
145 | out << "a::f(T)::body" << std::endl; | |
146 | } | |
147 | ||
148 | // Test no overload ambiguity in public_function called by these two cases. | |
149 | ||
150 | // NOTE: In *all* other cases, public_function is always called with a | |
151 | // different number of arguments so there cannot be ambiguity either | |
152 | // (0 args for static, 1 arg for non-virtual, 2 or 3 args for virtual, | |
153 | // >= 3 for override, so only in cases below of 3 args for virtual and 3 | |
154 | // for override there could be ambiguity but there is not because of | |
155 | // presence or absence of override_... template parameter). | |
156 | ||
157 | typedef void (a::* f0_ptr)(boost::contract::virtual_*); | |
158 | ||
159 | void f(boost::contract::virtual_* v = 0) /* override */ { | |
160 | f0_ptr f0 = static_cast<f0_ptr>(&a::f); | |
161 | // Test this and public_function call in func below both take same 3 | |
162 | // args but they are ambiguous because of presence override_f. | |
163 | boost::contract::check c = boost::contract::public_function<override_f>( | |
164 | v, f0, this) | |
165 | .precondition([] { out << "a::f()::pre" << std::endl; }) | |
166 | .old([] { out << "a::f()::old" << std::endl; }) | |
167 | .postcondition([] { out << "a::f()::post" << std::endl; }) | |
168 | ; | |
169 | out << "a::f()::body" << std::endl; | |
170 | } | |
171 | ||
92f5a8d4 | 172 | virtual f0_ptr f(bool /* x */, boost::contract::virtual_* v = 0) |
11fdf7f2 TL |
173 | /* not an override */ { |
174 | f0_ptr f0 = static_cast<f0_ptr>(&a::f); | |
175 | // Test this and public_function call in func above both take same 3 | |
176 | // args but they are ambiguous because of lack of override_f. | |
177 | boost::contract::check c = boost::contract::public_function( | |
178 | v, f0, this) | |
179 | .precondition([] { out << "a::f(bool)::pre" << std::endl; }) | |
180 | .old([] { out << "a::f(bool)::old" << std::endl; }) | |
181 | .postcondition([] (f0_ptr const&) { | |
182 | out << "a::f(bool)::post" << std::endl; }) | |
183 | ; | |
184 | out << "a::f(bool)::body" << std::endl; | |
185 | return f0; | |
186 | } | |
187 | ||
188 | // Test overload with array parameter. | |
189 | void f(int x[2][3], boost::contract::virtual_* v = 0) /* override */ { | |
190 | boost::contract::check c = boost::contract::public_function<override_f>( | |
191 | v, | |
192 | static_cast<void (a::*)(int[2][3], boost::contract::virtual_*)>( | |
193 | &a::f), | |
194 | this, x | |
195 | ) | |
196 | .precondition([] { out << "a::f(int[2][3])::pre" << std::endl; }) | |
197 | .old([] { out << "a::f(int[2][3])::old" << std::endl; }) | |
198 | .postcondition([] { out << "a::f(int[2][3])::post" << std::endl; }) | |
199 | ; | |
200 | out << "a::f(int[2][3])::body" << std::endl; | |
201 | } | |
202 | ||
203 | // Test overload with function pointer parameter. | |
204 | void f(void (*x)(int), boost::contract::virtual_* v = 0) /* override */ { | |
205 | boost::contract::check c = boost::contract::public_function<override_f>( | |
206 | v, | |
207 | static_cast<void (a::*)(void (*)(int), boost::contract::virtual_*)>( | |
208 | &a::f), | |
209 | this, x | |
210 | ) | |
211 | .precondition( | |
212 | [] { out << "a::f(void (*)(int))::pre" << std::endl; }) | |
213 | .old( | |
214 | [] { out << "a::f(void (*)(int))::old" << std::endl; }) | |
215 | .postcondition( | |
216 | [] { out << "a::f(void (*)(int))::post" << std::endl; }) | |
217 | ; | |
218 | out << "a::f(void (*)(int))::body" << std::endl; | |
219 | } | |
220 | ||
221 | BOOST_CONTRACT_OVERRIDE(f) | |
222 | }; | |
223 | ||
224 | void g(int) {} | |
225 | ||
226 | std::string ok_args(std::string const& args) { | |
227 | std::ostringstream ok; ok | |
228 | #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS | |
229 | << "b::static_inv" << std::endl | |
230 | << "b::inv" << std::endl | |
231 | << "a::static_inv" << std::endl | |
232 | << "a::inv" << std::endl | |
233 | #endif | |
234 | #ifndef BOOST_CONTRACT_NO_PRECONDITIONS | |
235 | << "b::f(" << args << ")::pre" << std::endl | |
236 | #endif | |
237 | #ifndef BOOST_CONTRACT_NO_OLDS | |
238 | << "b::f(" << args << ")::old" << std::endl | |
239 | << "a::f(" << args << ")::old" << std::endl | |
240 | #endif | |
241 | << "a::f(" << args << ")::body" << std::endl | |
242 | #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS | |
243 | << "b::static_inv" << std::endl | |
244 | << "b::inv" << std::endl | |
245 | << "a::static_inv" << std::endl | |
246 | << "a::inv" << std::endl | |
247 | #endif | |
248 | #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS | |
249 | << "b::f(" << args << ")::old" << std::endl | |
250 | << "b::f(" << args << ")::post" << std::endl | |
251 | << "a::f(" << args << ")::post" << std::endl | |
252 | #endif | |
253 | ; | |
254 | return ok.str(); | |
255 | } | |
256 | ||
257 | int main() { | |
258 | std::ostringstream ok; | |
259 | a aa; | |
260 | ||
261 | out.str(""); | |
262 | aa.f(123); | |
263 | ok.str(""); ok << ok_args("int"); | |
264 | BOOST_TEST(out.eq(ok.str())); | |
265 | ||
266 | out.str(""); | |
267 | aa.f("abc"); | |
268 | ok.str(""); ok << ok_args("char const*"); | |
269 | BOOST_TEST(out.eq(ok.str())); | |
270 | ||
271 | out.str(""); | |
272 | aa.f(123, 456); | |
273 | ok.str(""); ok << ok_args("int, int"); | |
274 | BOOST_TEST(out.eq(ok.str())); | |
275 | ||
276 | out.str(""); | |
277 | struct {} zz; | |
278 | aa.f(zz); // Call template (so no override because no virtual). | |
279 | ok.str(""); ok | |
280 | #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS | |
281 | << "a::static_inv" << std::endl | |
282 | << "a::inv" << std::endl | |
283 | #endif | |
284 | #ifndef BOOST_CONTRACT_NO_PRECONDITIONS | |
285 | << "a::f(T)::pre" << std::endl | |
286 | #endif | |
287 | #ifndef BOOST_CONTRACT_NO_OLDS | |
288 | << "a::f(T)::old" << std::endl | |
289 | #endif | |
290 | << "a::f(T)::body" << std::endl | |
291 | #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS | |
292 | << "a::static_inv" << std::endl | |
293 | << "a::inv" << std::endl | |
294 | #endif | |
295 | #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS | |
296 | << "a::f(T)::post" << std::endl | |
297 | #endif | |
298 | ; | |
299 | BOOST_TEST(out.eq(ok.str())); | |
300 | ||
301 | out.str(""); | |
302 | aa.f(); | |
303 | ok.str(""); ok << ok_args(""); | |
304 | BOOST_TEST(out.eq(ok.str())); | |
305 | ||
306 | out.str(""); | |
307 | aa.f(true); // This does not override (public_function ambiguity testing). | |
308 | ok.str(""); ok | |
309 | #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS | |
310 | << "a::static_inv" << std::endl | |
311 | << "a::inv" << std::endl | |
312 | #endif | |
313 | #ifndef BOOST_CONTRACT_NO_PRECONDITIONS | |
314 | << "a::f(bool)::pre" << std::endl | |
315 | #endif | |
316 | #ifndef BOOST_CONTRACT_NO_OLDS | |
317 | << "a::f(bool)::old" << std::endl | |
318 | #endif | |
319 | << "a::f(bool)::body" << std::endl | |
320 | #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS | |
321 | << "a::static_inv" << std::endl | |
322 | << "a::inv" << std::endl | |
323 | #endif | |
324 | #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS | |
325 | << "a::f(bool)::post" << std::endl | |
326 | #endif | |
327 | ; | |
328 | BOOST_TEST(out.eq(ok.str())); | |
329 | ||
330 | out.str(""); | |
331 | int i[2][3]; | |
332 | aa.f(i); | |
333 | ok.str(""); ok << ok_args("int[2][3]"); | |
334 | BOOST_TEST(out.eq(ok.str())); | |
335 | ||
336 | out.str(""); | |
337 | aa.f(&g); | |
338 | ok.str(""); ok << ok_args("void (*)(int)"); | |
339 | BOOST_TEST(out.eq(ok.str())); | |
340 | ||
341 | return boost::report_errors(); | |
342 | } | |
343 |