• 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 overrides with mixed access levels from different (multiple) bases.
8 
9 #include <boost/config.hpp>
10 #ifdef BOOST_MSVC
11 
12 // WARNING: MSVC (at least up to VS 2015) gives a compile-time error if SFINAE
13 // cannot introspect a member because of its private or protected access level.
14 // That is incorrect, SFINAE should fail in these cases without generating
15 // compile-time errors like GCC and CLang do. Therefore, currently it is not
16 // possible to override a member that is public in one base but private or
17 // protected in other base using this library on MSVC (that can be done instead
18 // using this library on GCC or CLang).
main()19 int main() { return 0; } // This test trivially passes on MSVC.
20 
21 #else
22 
23 #include "../detail/oteststream.hpp"
24 #include <boost/contract/public_function.hpp>
25 #include <boost/contract/function.hpp>
26 #include <boost/contract/base_types.hpp>
27 #include <boost/contract/override.hpp>
28 #include <boost/contract/check.hpp>
29 #include <boost/detail/lightweight_test.hpp>
30 #include <sstream>
31 
32 boost::contract::test::detail::oteststream out;
33 
34 struct c { // Test public access different from base `b`'s access below.
statci_invc35     static void statci_inv() { out << "c::static_inv" << std::endl; }
invariantc36     void invariant() const { out << "c::inv" << std::endl; }
37 
fc38     virtual void f(boost::contract::virtual_* v = 0) {
39         boost::contract::check c = boost::contract::public_function(v, this)
40             .precondition([] { out << "c::f::pre" << std::endl; })
41             .old([] { out << "c::f::old" << std::endl; })
42             .postcondition([] { out << "c::f::post" << std::endl; })
43         ;
44         out << "c::f::body" << std::endl;
45     }
46 
gc47     virtual void g(boost::contract::virtual_* v = 0) {
48         boost::contract::check c = boost::contract::public_function(v, this)
49             .precondition([] { out << "c::g::pre" << std::endl; })
50             .old([] { out << "c::g::old" << std::endl; })
51             .postcondition([] { out << "c::g::post" << std::endl; })
52         ;
53         out << "c::g::body" << std::endl;
54     }
55 
hc56     virtual void h(boost::contract::virtual_* v = 0) {
57         boost::contract::check c = boost::contract::public_function(v, this)
58             .precondition([] { out << "c::h::pre" << std::endl; })
59             .old([] { out << "c::h::old" << std::endl; })
60             .postcondition([] { out << "c::h::post" << std::endl; })
61         ;
62         out << "c::h::body" << std::endl;
63     }
64 };
65 
66 struct b { // Test all access levels (public, protected, and private).
call(b & me)67     friend void call(b& me) { // Test polymorphic calls (object by &).
68         me.f();
69         me.g();
70         me.h();
71     }
72 
statci_invb73     static void statci_inv() { out << "b::static_inv" << std::endl; }
invariantb74     void invariant() const { out << "b::inv" << std::endl; }
75 
fb76     virtual void f(boost::contract::virtual_* v = 0) {
77         boost::contract::check c = boost::contract::public_function(v, this)
78             .precondition([] { out << "b::f::pre" << std::endl; })
79             .old([] { out << "b::f::old" << std::endl; })
80             .postcondition([] { out << "b::f::post" << std::endl; })
81         ;
82         out << "b::f::body" << std::endl;
83     }
84 
85     // NOTE: Both protected and private virtual members must declare
86     // extra `virtual_* = 0` parameter (otherwise they cannot be overridden in
87     // derived classes with contracts because C++ uses also default parameters
88     // to match signature of overriding functions).
89 
90 protected:
gb91     virtual void g(boost::contract::virtual_* /* v */ = 0) {
92         boost::contract::check c = boost::contract::function()
93             .precondition([] { out << "b::g::pre" << std::endl; })
94             .old([] { out << "b::g::old" << std::endl; })
95             .postcondition([] { out << "b::g::post" << std::endl; })
96         ;
97         out << "b::g::body" << std::endl;
98     }
99 
100 private:
hb101     virtual void h(boost::contract::virtual_* /* v */ = 0) {
102         boost::contract::check c = boost::contract::function()
103             .precondition([] { out << "b::h::pre" << std::endl; })
104             .old([] { out << "b::h::old" << std::endl; })
105             .postcondition([] { out << "b::h::post" << std::endl; })
106         ;
107         out << "b::h::body" << std::endl;
108     }
109 };
110 
111 struct a // Test overrides with mixed access levels from different bases.
112     #define BASES public b, public c
113     : BASES
114 {
115     typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
116     #undef BASES
117 
statci_inva118     static void statci_inv() { out << "a::static_inv" << std::endl; }
invarianta119     void invariant() const { out << "a::inv" << std::endl; }
120 
fa121     virtual void f(boost::contract::virtual_* v = 0) /* override */ {
122         boost::contract::check c = boost::contract::public_function<override_f>(
123                 v, &a::f, this)
124             .precondition([] { out << "a::f::pre" << std::endl; })
125             .old([] { out << "a::f::old" << std::endl; })
126             .postcondition([] { out << "a::f::post" << std::endl; })
127         ;
128         out << "a::f::body" << std::endl;
129     }
130 
ga131     virtual void g(boost::contract::virtual_* v = 0) /* override */ {
132         boost::contract::check c = boost::contract::public_function<override_g>(
133                 v, &a::g, this)
134             .precondition([] { out << "a::g::pre" << std::endl; })
135             .old([] { out << "a::g::old" << std::endl; })
136             .postcondition([] { out << "a::g::post" << std::endl; })
137         ;
138         out << "a::g::body" << std::endl;
139     }
140 
ha141     virtual void h(boost::contract::virtual_* v = 0) /* override */ {
142         boost::contract::check c = boost::contract::public_function<override_h>(
143                 v, &a::h, this)
144             .precondition([] { out << "a::h::pre" << std::endl; })
145             .old([] { out << "a::h::old" << std::endl; })
146             .postcondition([] { out << "a::h::post" << std::endl; })
147         ;
148         out << "a::h::body" << std::endl;
149     }
150 
151     BOOST_CONTRACT_OVERRIDES(f, g, h)
152 };
153 
main()154 int main() {
155     std::ostringstream ok;
156 
157     b bb;
158     out.str("");
159     call(bb);
160     ok.str(""); ok
161         #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
162             << "b::inv" << std::endl
163         #endif
164         #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
165             << "b::f::pre" << std::endl
166         #endif
167         #ifndef BOOST_CONTRACT_NO_OLDS
168             << "b::f::old" << std::endl
169         #endif
170         << "b::f::body" << std::endl
171         #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
172             << "b::inv" << std::endl
173         #endif
174         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
175             << "b::f::post" << std::endl
176         #endif
177 
178         #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
179             << "b::g::pre" << std::endl
180         #endif
181         #ifndef BOOST_CONTRACT_NO_OLDS
182             << "b::g::old" << std::endl
183         #endif
184         << "b::g::body" << std::endl
185         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
186             << "b::g::post" << std::endl
187         #endif
188 
189         #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
190             << "b::h::pre" << std::endl
191         #endif
192         #ifndef BOOST_CONTRACT_NO_OLDS
193             << "b::h::old" << std::endl
194         #endif
195         << "b::h::body" << std::endl
196         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
197             << "b::h::post" << std::endl
198         #endif
199     ;
200     BOOST_TEST(out.eq(ok.str()));
201 
202     a aa;
203     out.str("");
204     call(aa);
205     ok.str(""); ok
206         #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
207             << "b::inv" << std::endl
208             << "c::inv" << std::endl
209             << "a::inv" << std::endl
210         #endif
211         #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
212             << "b::f::pre" << std::endl
213         #endif
214         #ifndef BOOST_CONTRACT_NO_OLDS
215             << "b::f::old" << std::endl
216             << "c::f::old" << std::endl
217             << "a::f::old" << std::endl
218         #endif
219         << "a::f::body" << std::endl
220         #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
221             << "b::inv" << std::endl
222             << "c::inv" << std::endl
223             << "a::inv" << std::endl
224         #endif
225         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
226             << "b::f::old" << std::endl
227             << "b::f::post" << std::endl
228             << "c::f::old" << std::endl
229             << "c::f::post" << std::endl
230             << "a::f::post" << std::endl
231         #endif
232 
233         #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
234             << "c::inv" << std::endl
235             << "a::inv" << std::endl
236         #endif
237         #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
238             << "c::g::pre" << std::endl
239         #endif
240         #ifndef BOOST_CONTRACT_NO_OLDS
241             << "c::g::old" << std::endl
242             << "a::g::old" << std::endl
243         #endif
244         << "a::g::body" << std::endl
245         #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
246             << "c::inv" << std::endl
247             << "a::inv" << std::endl
248         #endif
249         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
250             << "c::g::old" << std::endl
251             << "c::g::post" << std::endl
252             << "a::g::post" << std::endl
253         #endif
254 
255         #ifndef BOOST_CONTRACT_NO_ENTRY_INVARIANTS
256             << "c::inv" << std::endl
257             << "a::inv" << std::endl
258         #endif
259         #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
260             << "c::h::pre" << std::endl
261         #endif
262         #ifndef BOOST_CONTRACT_NO_OLDS
263             << "c::h::old" << std::endl
264             << "a::h::old" << std::endl
265         #endif
266         << "a::h::body" << std::endl
267         #ifndef BOOST_CONTRACT_NO_EXIT_INVARIANTS
268             << "c::inv" << std::endl
269             << "a::inv" << std::endl
270         #endif
271         #ifndef BOOST_CONTRACT_NO_POSTCONDITIONS
272             << "c::h::old" << std::endl
273             << "c::h::post" << std::endl
274             << "a::h::post" << std::endl
275         #endif
276     ;
277     BOOST_TEST(out.eq(ok.str()));
278 
279     return boost::report_errors();
280 }
281 
282 #endif // MSVC
283 
284