• 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 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 {
static_invariantb21     static void static_invariant() { out << "b::static_inv" << std::endl; }
invariantb22     void invariant() const { out << "b::inv" << std::endl; }
23 
fb24     virtual void f(int /* x */, boost::contract::virtual_* v = 0) {
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 
fb33     virtual void f(char const* /* x */, boost::contract::virtual_* v = 0) {
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 
fb43     virtual void f(int /* x */, int /* y */, boost::contract::virtual_* v = 0) {
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 
fb52     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 
fb61     void f(int /* x */[2][3], boost::contract::virtual_* v = 0) {
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 
fb70     void f(void (* /* x */)(int), boost::contract::virtual_* v = 0) {
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 
static_invarianta90     static void static_invariant() { out << "a::static_inv" << std::endl; }
invarianta91     void invariant() const { out << "a::inv" << std::endl; }
92 
fa93     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.
fa107     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.
fa123     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>
fa139     void f(T /* x */) { // Template cannot be virtual (or override) in C++.
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 
fa159     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 
fa172     virtual f0_ptr f(bool /* x */, boost::contract::virtual_* v = 0)
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.
fa189     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.
fa204     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 
g(int)224 void g(int) {}
225 
ok_args(std::string const & args)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 
main()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 
344