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