]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. |
2 | // | |
3 | // Use, modification, and distribution is subject to the Boost Software | |
4 | // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
5 | // http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // See http://www.boost.org/lib/optional for documentation. | |
8 | // | |
9 | // You are welcome to contact the author at: | |
10 | // fernando_cacciola@hotmail.com | |
11 | // | |
12 | // Revisions: | |
13 | // 12 May 2008 (added more swap tests) | |
14 | // | |
15 | #include<iostream> | |
16 | #include<stdexcept> | |
17 | #include<string> | |
18 | ||
19 | #define BOOST_ENABLE_ASSERT_HANDLER | |
20 | ||
21 | #include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin | |
22 | #include "boost/mpl/bool.hpp" | |
23 | #include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ | |
24 | ||
25 | #include "boost/optional/optional.hpp" | |
26 | ||
27 | #ifdef __BORLANDC__ | |
28 | #pragma hdrstop | |
29 | #endif | |
30 | ||
31 | #include "boost/none.hpp" | |
32 | ||
33 | #include "boost/core/lightweight_test.hpp" | |
34 | ||
92f5a8d4 | 35 | #include "optional_test_common.hpp" |
7c673cae FG |
36 | |
37 | void test_implicit_construction ( optional<double> opt, double v, double z ) | |
38 | { | |
39 | check_value(opt,v,z); | |
40 | } | |
41 | ||
42 | void test_implicit_construction ( optional<X> opt, X const& v, X const& z ) | |
43 | { | |
44 | check_value(opt,v,z); | |
45 | } | |
46 | ||
47 | void test_default_implicit_construction ( double, optional<double> opt ) | |
48 | { | |
49 | BOOST_TEST(!opt); | |
50 | } | |
51 | ||
52 | void test_default_implicit_construction ( X const&, optional<X> opt ) | |
53 | { | |
54 | BOOST_TEST(!opt); | |
55 | } | |
56 | ||
57 | // | |
58 | // Basic test. | |
59 | // Check ordinary functionality: | |
60 | // Initialization, assignment, comparison and value-accessing. | |
61 | // | |
62 | template<class T> | |
63 | void test_basics( T const* ) | |
64 | { | |
65 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
66 | ||
67 | T z(0); | |
68 | ||
69 | T a(1); | |
70 | ||
71 | // Default construction. | |
72 | // 'def' state is Uninitialized. | |
73 | // T::T() is not called (and it is not even defined) | |
74 | optional<T> def ; | |
75 | check_uninitialized(def); | |
76 | ||
77 | // Implicit construction | |
78 | // The first parameter is implicitely converted to optional<T>(a); | |
79 | test_implicit_construction(a,a,z); | |
80 | ||
81 | // Direct initialization. | |
82 | // 'oa' state is Initialized with 'a' | |
83 | // T::T( T const& x ) is used. | |
84 | set_pending_copy( ARG(T) ) ; | |
85 | optional<T> oa ( a ) ; | |
86 | check_is_not_pending_copy( ARG(T) ); | |
87 | check_initialized(oa); | |
88 | check_value(oa,a,z); | |
89 | ||
90 | T b(2); | |
91 | ||
92 | optional<T> ob ; | |
93 | ||
94 | // Value-Assignment upon Uninitialized optional. | |
95 | // T::T( T const& x ) is used. | |
96 | set_pending_copy( ARG(T) ) ; | |
97 | ob = a ; | |
98 | check_is_not_pending_copy( ARG(T) ) ; | |
99 | check_initialized(ob); | |
100 | check_value(ob,a,z); | |
101 | ||
102 | // Value-Assignment upon Initialized optional. | |
103 | // T::operator=( T const& x ) is used | |
104 | set_pending_assign( ARG(T) ) ; | |
105 | set_pending_copy ( ARG(T) ) ; | |
106 | set_pending_dtor ( ARG(T) ) ; | |
107 | ob = b ; | |
108 | check_is_not_pending_assign( ARG(T) ) ; | |
109 | check_is_pending_copy ( ARG(T) ) ; | |
110 | check_is_pending_dtor ( ARG(T) ) ; | |
111 | check_initialized(ob); | |
112 | check_value(ob,b,z); | |
113 | ||
114 | // Assignment initialization. | |
115 | // T::T ( T const& x ) is used to copy new value. | |
116 | set_pending_copy( ARG(T) ) ; | |
117 | optional<T> const oa2 ( oa ) ; | |
118 | check_is_not_pending_copy( ARG(T) ) ; | |
119 | check_initialized_const(oa2); | |
120 | check_value_const(oa2,a,z); | |
121 | ||
122 | // Assignment | |
123 | // T::operator= ( T const& x ) is used to copy new value. | |
124 | set_pending_assign( ARG(T) ) ; | |
125 | oa = ob ; | |
126 | check_is_not_pending_assign( ARG(T) ) ; | |
127 | check_initialized(oa); | |
128 | check_value(oa,b,z); | |
129 | ||
130 | // Uninitializing Assignment upon Initialized Optional | |
131 | // T::~T() is used to destroy previous value in oa. | |
132 | set_pending_dtor( ARG(T) ) ; | |
133 | set_pending_copy( ARG(T) ) ; | |
134 | oa = def ; | |
135 | check_is_not_pending_dtor( ARG(T) ) ; | |
136 | check_is_pending_copy ( ARG(T) ) ; | |
137 | check_uninitialized(oa); | |
138 | ||
139 | // Uninitializing Assignment upon Uninitialized Optional | |
140 | // (Dtor is not called this time) | |
141 | set_pending_dtor( ARG(T) ) ; | |
142 | set_pending_copy( ARG(T) ) ; | |
143 | oa = def ; | |
144 | check_is_pending_dtor( ARG(T) ) ; | |
145 | check_is_pending_copy( ARG(T) ) ; | |
146 | check_uninitialized(oa); | |
147 | ||
148 | // Deinitialization of Initialized Optional | |
149 | // T::~T() is used to destroy previous value in ob. | |
150 | set_pending_dtor( ARG(T) ) ; | |
151 | ob.reset(); | |
152 | check_is_not_pending_dtor( ARG(T) ) ; | |
153 | check_uninitialized(ob); | |
154 | ||
155 | // Deinitialization of Uninitialized Optional | |
156 | // (Dtor is not called this time) | |
157 | set_pending_dtor( ARG(T) ) ; | |
158 | ob.reset(); | |
159 | check_is_pending_dtor( ARG(T) ) ; | |
160 | check_uninitialized(ob); | |
161 | ||
162 | } | |
163 | ||
164 | template<class T> | |
165 | void test_conditional_ctor_and_get_valur_or ( T const* ) | |
166 | { | |
167 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
168 | ||
169 | T a(321); | |
170 | ||
171 | T z(123); | |
172 | ||
173 | optional<T> const cdef0(false,a); | |
174 | ||
175 | optional<T> def0(false,a); | |
176 | optional<T> def1 = boost::make_optional(false,a); // T is not within boost so ADL won't find make_optional unqualified | |
177 | check_uninitialized(def0); | |
178 | check_uninitialized(def1); | |
179 | ||
180 | optional<T> const co0(true,a); | |
181 | ||
182 | optional<T> o0(true,a); | |
183 | optional<T> o1 = boost::make_optional(true,a); // T is not within boost so ADL won't find make_optional unqualified | |
184 | ||
185 | check_initialized(o0); | |
186 | check_initialized(o1); | |
187 | check_value(o0,a,z); | |
188 | check_value(o1,a,z); | |
189 | ||
190 | T b = def0.get_value_or(z); | |
191 | BOOST_TEST( b == z ) ; | |
192 | ||
193 | b = get_optional_value_or(def0,z); | |
194 | BOOST_TEST( b == z ) ; | |
195 | ||
196 | b = o0.get_value_or(z); | |
197 | BOOST_TEST( b == a ) ; | |
198 | ||
199 | b = get_optional_value_or(o0,z); | |
200 | BOOST_TEST( b == a ) ; | |
201 | ||
202 | ||
203 | T const& crz = z ; | |
204 | T& rz = z ; | |
205 | ||
206 | T const& crzz = def0.get_value_or(crz); | |
207 | BOOST_TEST( crzz == crz ) ; | |
208 | ||
209 | T& rzz = def0.get_value_or(rz); | |
210 | BOOST_TEST( rzz == rz ) ; | |
211 | ||
212 | T const& crzzz = get_optional_value_or(cdef0,crz); | |
213 | BOOST_TEST( crzzz == crz ) ; | |
214 | ||
215 | T& rzzz = get_optional_value_or(def0,rz); | |
216 | BOOST_TEST( rzzz == rz ) ; | |
217 | ||
218 | T const& crb = o0.get_value_or(crz); | |
219 | BOOST_TEST( crb == a ) ; | |
220 | ||
221 | T& rb = o0.get_value_or(rz); | |
222 | BOOST_TEST( rb == b ) ; | |
223 | ||
224 | T const& crbb = get_optional_value_or(co0,crz); | |
225 | BOOST_TEST( crbb == b ) ; | |
226 | ||
227 | T const& crbbb = get_optional_value_or(o0,crz); | |
228 | BOOST_TEST( crbbb == b ) ; | |
229 | ||
230 | T& rbb = get_optional_value_or(o0,rz); | |
231 | BOOST_TEST( rbb == b ) ; | |
232 | ||
233 | T& ra = a ; | |
234 | ||
235 | optional<T&> defref(false,ra); | |
236 | BOOST_TEST(!defref); | |
237 | ||
238 | optional<T&> ref(true,ra); | |
239 | BOOST_TEST(!!ref); | |
240 | ||
241 | a = T(432); | |
242 | ||
243 | BOOST_TEST( *ref == a ) ; | |
244 | ||
245 | T& r1 = defref.get_value_or(z); | |
246 | BOOST_TEST( r1 == z ) ; | |
247 | ||
248 | T& r2 = ref.get_value_or(z); | |
249 | BOOST_TEST( r2 == a ) ; | |
250 | } | |
251 | ||
252 | // | |
253 | // Test Direct Value Manipulation | |
254 | // | |
255 | template<class T> | |
256 | void test_direct_value_manip( T const* ) | |
257 | { | |
258 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
259 | ||
260 | T x(3); | |
261 | ||
262 | optional<T> const c_opt0(x) ; | |
263 | optional<T> opt0(x); | |
264 | ||
265 | BOOST_TEST( c_opt0.get().V() == x.V() ) ; | |
266 | BOOST_TEST( opt0.get().V() == x.V() ) ; | |
267 | ||
268 | BOOST_TEST( c_opt0->V() == x.V() ) ; | |
269 | BOOST_TEST( opt0->V() == x.V() ) ; | |
270 | ||
271 | BOOST_TEST( (*c_opt0).V() == x.V() ) ; | |
272 | BOOST_TEST( (* opt0).V() == x.V() ) ; | |
273 | ||
274 | T y(4); | |
275 | opt0 = y ; | |
276 | BOOST_TEST( get(opt0).V() == y.V() ) ; | |
277 | } | |
278 | ||
279 | // | |
280 | // Test Uninitialized access assert | |
281 | // | |
282 | template<class T> | |
283 | void test_uninitialized_access( T const* ) | |
284 | { | |
285 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
286 | ||
287 | optional<T> def ; | |
288 | ||
289 | bool passed = false ; | |
290 | try | |
291 | { | |
292 | // This should throw because 'def' is uninitialized | |
293 | T const& n = def.get() ; | |
294 | boost::ignore_unused(n); | |
295 | passed = true ; | |
296 | } | |
297 | catch (...) {} | |
298 | BOOST_TEST(!passed); | |
299 | ||
300 | passed = false ; | |
301 | try | |
302 | { | |
303 | // This should throw because 'def' is uninitialized | |
304 | T const& n = *def ; | |
305 | boost::ignore_unused(n); | |
306 | passed = true ; | |
307 | } | |
308 | catch (...) {} | |
309 | BOOST_TEST(!passed); | |
310 | ||
311 | passed = false ; | |
312 | try | |
313 | { | |
314 | T v(5) ; | |
315 | boost::ignore_unused(v); | |
316 | // This should throw because 'def' is uninitialized | |
317 | *def = v ; | |
318 | passed = true ; | |
319 | } | |
320 | catch (...) {} | |
321 | BOOST_TEST(!passed); | |
322 | ||
323 | passed = false ; | |
324 | try | |
325 | { | |
326 | // This should throw because 'def' is uninitialized | |
327 | T v = *(def.operator->()) ; | |
328 | boost::ignore_unused(v); | |
329 | passed = true ; | |
330 | } | |
331 | catch (...) {} | |
332 | BOOST_TEST(!passed); | |
333 | } | |
334 | ||
335 | #if BOOST_WORKAROUND( BOOST_INTEL_CXX_VERSION, <= 700) // Intel C++ 7.0 | |
336 | void prevent_buggy_optimization( bool v ) {} | |
337 | #endif | |
338 | ||
339 | // | |
340 | // Test Direct Initialization of optional for a T with throwing copy-ctor. | |
341 | // | |
342 | template<class T> | |
343 | void test_throwing_direct_init( T const* ) | |
344 | { | |
345 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
346 | ||
347 | T a(6); | |
348 | ||
349 | int count = get_instance_count( ARG(T) ) ; | |
350 | ||
351 | set_throw_on_copy( ARG(T) ) ; | |
352 | ||
353 | bool passed = false ; | |
354 | try | |
355 | { | |
356 | // This should: | |
357 | // Attempt to copy construct 'a' and throw. | |
358 | // 'opt' won't be constructed. | |
359 | set_pending_copy( ARG(T) ) ; | |
360 | ||
361 | #if BOOST_WORKAROUND( BOOST_INTEL_CXX_VERSION, <= 700) // Intel C++ 7.0 | |
362 | // Intel C++ 7.0 specific: | |
363 | // For some reason, when "check_is_not_pending_copy", | |
364 | // after the exception block is reached, | |
365 | // X::pending_copy==true even though X's copy ctor set it to false. | |
366 | // I guessed there is some sort of optimization bug, | |
367 | // and it seems to be the since the following additional line just | |
368 | // solves the problem (!?) | |
369 | prevent_buggy_optimization(X::pending_copy); | |
370 | #endif | |
371 | ||
372 | optional<T> opt(a) ; | |
373 | passed = true ; | |
374 | } | |
375 | catch ( ... ){} | |
376 | ||
377 | BOOST_TEST(!passed); | |
378 | check_is_not_pending_copy( ARG(T) ); | |
379 | check_instance_count(count, ARG(T) ); | |
380 | ||
381 | reset_throw_on_copy( ARG(T) ) ; | |
382 | ||
383 | } | |
384 | ||
385 | // | |
386 | // Test Value Assignment to an Uninitialized optional for a T with a throwing copy-ctor | |
387 | // | |
388 | template<class T> | |
389 | void test_throwing_val_assign_on_uninitialized( T const* ) | |
390 | { | |
391 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
392 | ||
393 | T a(7); | |
394 | ||
395 | int count = get_instance_count( ARG(T) ) ; | |
396 | ||
397 | set_throw_on_copy( ARG(T) ) ; | |
398 | ||
399 | optional<T> opt ; | |
400 | ||
401 | bool passed = false ; | |
402 | try | |
403 | { | |
404 | // This should: | |
405 | // Attempt to copy construct 'a' and throw. | |
406 | // opt should be left uninitialized. | |
407 | set_pending_copy( ARG(T) ) ; | |
408 | opt.reset( a ); | |
409 | passed = true ; | |
410 | } | |
411 | catch ( ... ) {} | |
412 | ||
413 | BOOST_TEST(!passed); | |
414 | ||
415 | check_is_not_pending_copy( ARG(T) ); | |
416 | check_instance_count(count, ARG(T) ); | |
417 | check_uninitialized(opt); | |
418 | ||
419 | reset_throw_on_copy( ARG(T) ) ; | |
420 | } | |
421 | ||
422 | // | |
423 | // Test Value Reset on an Initialized optional for a T with a throwing copy-ctor | |
424 | // | |
425 | template<class T> | |
426 | void test_throwing_val_assign_on_initialized( T const* ) | |
427 | { | |
428 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
429 | ||
430 | T z(0); | |
431 | T a(8); | |
432 | T b(9); | |
433 | T x(-1); | |
434 | ||
435 | int count = get_instance_count( ARG(T) ) ; | |
436 | ||
437 | optional<T> opt ( b ) ; | |
438 | ++ count ; | |
439 | ||
440 | check_instance_count(count, ARG(T) ); | |
441 | ||
442 | check_value(opt,b,z); | |
443 | ||
444 | set_throw_on_assign( ARG(T) ) ; | |
445 | ||
446 | bool passed = false ; | |
447 | try | |
448 | { | |
449 | // This should: | |
450 | // Attempt to assign 'a' and throw. | |
451 | // opt is kept initialized but its value not neccesarily fully assigned | |
452 | // (in this test, incompletely assigned is flaged with the value -1 being set) | |
453 | set_pending_assign( ARG(T) ) ; | |
454 | opt.reset ( a ) ; | |
455 | passed = true ; | |
456 | } | |
457 | catch ( ... ) {} | |
458 | ||
459 | BOOST_TEST(!passed); | |
460 | ||
461 | check_is_not_pending_assign( ARG(T) ); | |
462 | check_instance_count(count, ARG(T) ); | |
463 | check_initialized(opt); | |
464 | check_value(opt,x,z); | |
465 | ||
466 | reset_throw_on_assign ( ARG(T) ) ; | |
467 | } | |
468 | ||
469 | // | |
470 | // Test Copy Initialization from an Initialized optional for a T with a throwing copy-ctor | |
471 | // | |
472 | template<class T> | |
473 | void test_throwing_copy_initialization( T const* ) | |
474 | { | |
475 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
476 | ||
477 | T z(0); | |
478 | T a(10); | |
479 | ||
480 | optional<T> opt (a); | |
481 | ||
482 | int count = get_instance_count( ARG(T) ) ; | |
483 | ||
484 | set_throw_on_copy( ARG(T) ) ; | |
485 | ||
486 | bool passed = false ; | |
487 | try | |
488 | { | |
489 | // This should: | |
490 | // Attempt to copy construct 'opt' and throw. | |
491 | // opt1 won't be constructed. | |
492 | set_pending_copy( ARG(T) ) ; | |
493 | optional<T> opt1 = opt ; | |
494 | passed = true ; | |
495 | } | |
496 | catch ( ... ) {} | |
497 | ||
498 | BOOST_TEST(!passed); | |
499 | ||
500 | check_is_not_pending_copy( ARG(T) ); | |
501 | check_instance_count(count, ARG(T) ); | |
502 | ||
503 | // Nothing should have happened to the source optional. | |
504 | check_initialized(opt); | |
505 | check_value(opt,a,z); | |
506 | ||
507 | reset_throw_on_copy( ARG(T) ) ; | |
508 | } | |
509 | ||
510 | // | |
511 | // Test Assignment to an Uninitialized optional from an Initialized optional | |
512 | // for a T with a throwing copy-ctor | |
513 | // | |
514 | template<class T> | |
515 | void test_throwing_assign_to_uninitialized( T const* ) | |
516 | { | |
517 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
518 | ||
519 | T z(0); | |
520 | T a(11); | |
521 | ||
522 | optional<T> opt0 ; | |
523 | optional<T> opt1(a) ; | |
524 | ||
525 | int count = get_instance_count( ARG(T) ) ; | |
526 | ||
527 | set_throw_on_copy( ARG(T) ) ; | |
528 | ||
529 | bool passed = false ; | |
530 | try | |
531 | { | |
532 | // This should: | |
533 | // Attempt to copy construct 'opt1.value()' into opt0 and throw. | |
534 | // opt0 should be left uninitialized. | |
535 | set_pending_copy( ARG(T) ) ; | |
536 | opt0 = opt1 ; | |
537 | passed = true ; | |
538 | } | |
539 | catch ( ... ) {} | |
540 | ||
541 | BOOST_TEST(!passed); | |
542 | ||
543 | check_is_not_pending_copy( ARG(T) ); | |
544 | check_instance_count(count, ARG(T) ); | |
545 | check_uninitialized(opt0); | |
546 | ||
547 | reset_throw_on_copy( ARG(T) ) ; | |
548 | } | |
549 | ||
550 | // | |
551 | // Test Assignment to an Initialized optional from an Initialized optional | |
552 | // for a T with a throwing copy-ctor | |
553 | // | |
554 | template<class T> | |
555 | void test_throwing_assign_to_initialized( T const* ) | |
556 | { | |
557 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
558 | ||
559 | T z(0); | |
560 | T a(12); | |
561 | T b(13); | |
562 | T x(-1); | |
563 | ||
564 | optional<T> opt0(a) ; | |
565 | optional<T> opt1(b) ; | |
566 | ||
567 | int count = get_instance_count( ARG(T) ) ; | |
568 | ||
569 | set_throw_on_assign( ARG(T) ) ; | |
570 | ||
571 | bool passed = false ; | |
572 | try | |
573 | { | |
574 | // This should: | |
575 | // Attempt to copy construct 'opt1.value()' into opt0 and throw. | |
576 | // opt0 is kept initialized but its value not neccesarily fully assigned | |
577 | // (in this test, incompletely assigned is flaged with the value -1 being set) | |
578 | set_pending_assign( ARG(T) ) ; | |
579 | opt0 = opt1 ; | |
580 | passed = true ; | |
581 | } | |
582 | catch ( ... ) {} | |
583 | ||
584 | BOOST_TEST(!passed); | |
585 | ||
586 | // opt0 was left uninitialized | |
587 | check_is_not_pending_assign( ARG(T) ); | |
588 | check_instance_count(count, ARG(T) ); | |
589 | check_initialized(opt0); | |
590 | check_value(opt0,x,z); | |
591 | ||
592 | reset_throw_on_assign( ARG(T) ) ; | |
593 | } | |
594 | ||
595 | // | |
596 | // Test swap in a no-throwing case | |
597 | // | |
598 | template<class T> | |
599 | void test_no_throwing_swap( T const* ) | |
600 | { | |
601 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
602 | ||
603 | T z(0); | |
604 | T a(14); | |
605 | T b(15); | |
606 | ||
607 | optional<T> def0 ; | |
608 | optional<T> def1 ; | |
609 | optional<T> opt0(a) ; | |
610 | optional<T> opt1(b) ; | |
611 | ||
612 | int count = get_instance_count( ARG(T) ) ; | |
613 | ||
614 | swap(def0,def1); | |
615 | check_uninitialized(def0); | |
616 | check_uninitialized(def1); | |
617 | ||
618 | swap(def0,opt0); | |
619 | check_uninitialized(opt0); | |
620 | check_initialized(def0); | |
621 | check_value(def0,a,z); | |
622 | ||
623 | // restore def0 and opt0 | |
624 | swap(def0,opt0); | |
625 | ||
626 | swap(opt0,opt1); | |
627 | check_instance_count(count, ARG(T) ); | |
628 | check_initialized(opt0); | |
629 | check_initialized(opt1); | |
630 | check_value(opt0,b,z); | |
631 | check_value(opt1,a,z); | |
632 | } | |
633 | ||
634 | // | |
635 | // Test swap in a throwing case | |
636 | // | |
637 | template<class T> | |
638 | void test_throwing_swap( T const* ) | |
639 | { | |
640 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
641 | ||
642 | T a(16); | |
643 | T b(17); | |
644 | T x(-1); | |
645 | ||
646 | optional<T> opt0(a) ; | |
647 | optional<T> opt1(b) ; | |
648 | ||
649 | set_throw_on_assign( ARG(T) ) ; | |
650 | ||
651 | // | |
652 | // Case 1: Both Initialized. | |
653 | // | |
654 | bool passed = false ; | |
655 | try | |
656 | { | |
657 | // This should attempt to swap optionals and fail at swap(X&,X&). | |
658 | swap(opt0,opt1); | |
659 | ||
660 | passed = true ; | |
661 | } | |
662 | catch ( ... ) {} | |
663 | ||
664 | BOOST_TEST(!passed); | |
665 | ||
666 | // optional's swap doesn't affect the initialized states of the arguments. Therefore, | |
667 | // the following must hold: | |
668 | check_initialized(opt0); | |
669 | check_initialized(opt1); | |
670 | check_value(opt0,x,a); | |
671 | check_value(opt1,b,x); | |
672 | ||
673 | ||
674 | // | |
675 | // Case 2: Only one Initialized. | |
676 | // | |
677 | reset_throw_on_assign( ARG(T) ) ; | |
678 | ||
679 | opt0.reset(); | |
680 | opt1.reset(a); | |
681 | ||
682 | set_throw_on_copy( ARG(T) ) ; | |
683 | ||
684 | passed = false ; | |
685 | try | |
686 | { | |
687 | // This should attempt to swap optionals and fail at opt0.reset(*opt1) | |
688 | // Both opt0 and op1 are left unchanged (unswaped) | |
689 | swap(opt0,opt1); | |
690 | ||
691 | passed = true ; | |
692 | } | |
693 | catch ( ... ) {} | |
694 | ||
695 | BOOST_TEST(!passed); | |
696 | ||
697 | check_uninitialized(opt0); | |
698 | check_initialized(opt1); | |
699 | check_value(opt1,a,x); | |
700 | ||
701 | reset_throw_on_copy( ARG(T) ) ; | |
702 | } | |
703 | ||
704 | // | |
705 | // This verifies relational operators. | |
706 | // | |
707 | template<class T> | |
708 | void test_relops( T const* ) | |
709 | { | |
710 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
711 | ||
712 | T v0(0); | |
713 | T v1(1); | |
714 | T v2(1); | |
715 | ||
716 | optional<T> def0 ; | |
717 | optional<T> def1 ; | |
718 | optional<T> opt0(v0); | |
719 | optional<T> opt1(v1); | |
720 | optional<T> opt2(v2); | |
721 | ||
722 | // Check identity | |
723 | BOOST_TEST ( def0 == def0 ) ; | |
724 | BOOST_TEST ( opt0 == opt0 ) ; | |
725 | BOOST_TEST ( !(def0 != def0) ) ; | |
726 | BOOST_TEST ( !(opt0 != opt0) ) ; | |
727 | ||
728 | // Check when both are uininitalized. | |
729 | BOOST_TEST ( def0 == def1 ) ; // both uninitialized compare equal | |
730 | BOOST_TEST ( !(def0 < def1) ) ; // uninitialized is never less than uninitialized | |
731 | BOOST_TEST ( !(def0 > def1) ) ; // uninitialized is never greater than uninitialized | |
732 | BOOST_TEST ( !(def0 != def1) ) ; | |
733 | BOOST_TEST ( def0 <= def1 ) ; | |
734 | BOOST_TEST ( def0 >= def1 ) ; | |
735 | ||
736 | // Check when only lhs is uninitialized. | |
737 | BOOST_TEST ( def0 != opt0 ) ; // uninitialized is never equal to initialized | |
738 | BOOST_TEST ( !(def0 == opt0) ) ; | |
739 | BOOST_TEST ( def0 < opt0 ) ; // uninitialized is always less than initialized | |
740 | BOOST_TEST ( !(def0 > opt0) ) ; | |
741 | BOOST_TEST ( def0 <= opt0 ) ; | |
742 | BOOST_TEST ( !(def0 >= opt0) ) ; | |
743 | ||
744 | // Check when only rhs is uninitialized. | |
745 | BOOST_TEST ( opt0 != def0 ) ; // initialized is never equal to uninitialized | |
746 | BOOST_TEST ( !(opt0 == def0) ) ; | |
747 | BOOST_TEST ( !(opt0 < def0) ) ; // initialized is never less than uninitialized | |
748 | BOOST_TEST ( opt0 > def0 ) ; | |
749 | BOOST_TEST ( !(opt0 <= def0) ) ; | |
750 | BOOST_TEST ( opt0 >= opt0 ) ; | |
751 | ||
752 | // If both are initialized, values are compared | |
753 | BOOST_TEST ( opt0 != opt1 ) ; | |
754 | BOOST_TEST ( opt1 == opt2 ) ; | |
755 | BOOST_TEST ( opt0 < opt1 ) ; | |
756 | BOOST_TEST ( opt1 > opt0 ) ; | |
757 | BOOST_TEST ( opt1 <= opt2 ) ; | |
758 | BOOST_TEST ( opt1 >= opt0 ) ; | |
759 | ||
760 | // Compare against a value directly | |
761 | BOOST_TEST ( opt0 == v0 ) ; | |
762 | BOOST_TEST ( opt0 != v1 ) ; | |
763 | BOOST_TEST ( opt1 == v2 ) ; | |
764 | BOOST_TEST ( opt0 < v1 ) ; | |
765 | BOOST_TEST ( opt1 > v0 ) ; | |
766 | BOOST_TEST ( opt1 <= v2 ) ; | |
767 | BOOST_TEST ( opt1 >= v0 ) ; | |
768 | BOOST_TEST ( v0 != opt1 ) ; | |
769 | BOOST_TEST ( v1 == opt2 ) ; | |
770 | BOOST_TEST ( v0 < opt1 ) ; | |
771 | BOOST_TEST ( v1 > opt0 ) ; | |
772 | BOOST_TEST ( v1 <= opt2 ) ; | |
773 | BOOST_TEST ( v1 >= opt0 ) ; | |
774 | BOOST_TEST ( def0 != v0 ) ; | |
775 | BOOST_TEST ( !(def0 == v0) ) ; | |
776 | BOOST_TEST ( def0 < v0 ) ; | |
777 | BOOST_TEST ( !(def0 > v0) ) ; | |
778 | BOOST_TEST ( def0 <= v0 ) ; | |
779 | BOOST_TEST ( !(def0 >= v0) ) ; | |
780 | BOOST_TEST ( v0 != def0 ) ; | |
781 | BOOST_TEST ( !(v0 == def0) ) ; | |
782 | BOOST_TEST ( !(v0 < def0) ) ; | |
783 | BOOST_TEST ( v0 > def0 ) ; | |
784 | BOOST_TEST ( !(v0 <= def0) ) ; | |
785 | BOOST_TEST ( v0 >= opt0 ) ; | |
786 | } | |
787 | ||
788 | template<class T> | |
789 | void test_none( T const* ) | |
790 | { | |
791 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
792 | ||
793 | using boost::none ; | |
794 | ||
795 | optional<T> def0 ; | |
796 | optional<T> def1(none) ; | |
797 | optional<T> non_def( T(1234) ) ; | |
798 | ||
799 | BOOST_TEST ( def0 == none ) ; | |
800 | BOOST_TEST ( non_def != none ) ; | |
801 | BOOST_TEST ( !def1 ) ; | |
802 | BOOST_TEST ( !(non_def < none) ) ; | |
803 | BOOST_TEST ( non_def > none ) ; | |
804 | BOOST_TEST ( !(non_def <= none) ) ; | |
805 | BOOST_TEST ( non_def >= none ) ; | |
806 | ||
807 | non_def = none ; | |
808 | BOOST_TEST ( !non_def ) ; | |
809 | ||
810 | test_default_implicit_construction(T(1),none); | |
811 | } | |
812 | ||
813 | template<class T> | |
814 | void test_arrow( T const* ) | |
815 | { | |
816 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
817 | ||
818 | T a(1234); | |
819 | ||
820 | optional<T> oa(a) ; | |
821 | optional<T> const coa(a) ; | |
822 | ||
823 | BOOST_TEST ( coa->V() == 1234 ) ; | |
824 | ||
825 | oa->V() = 4321 ; | |
826 | ||
827 | BOOST_TEST ( a.V() = 1234 ) ; | |
828 | BOOST_TEST ( (*oa).V() = 4321 ) ; | |
829 | } | |
830 | ||
831 | void test_with_builtin_types() | |
832 | { | |
833 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
834 | ||
835 | test_basics( ARG(double) ); | |
836 | test_conditional_ctor_and_get_valur_or( ARG(double) ); | |
837 | test_uninitialized_access( ARG(double) ); | |
838 | test_no_throwing_swap( ARG(double) ); | |
839 | test_relops( ARG(double) ) ; | |
840 | test_none( ARG(double) ) ; | |
841 | } | |
842 | ||
843 | // MSVC < 11.0 doesn't destroy X when we call ptr->VBase::VBase. | |
844 | // Make sure that we work around this bug. | |
845 | struct VBase : virtual X | |
846 | { | |
847 | VBase(int v) : X(v) {} | |
848 | // MSVC 8.0 doesn't generate this correctly... | |
849 | VBase(const VBase& other) : X(static_cast<const X&>(other)) {} | |
850 | }; | |
851 | ||
852 | void test_with_class_type() | |
853 | { | |
854 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
855 | ||
856 | test_basics( ARG(X) ); | |
857 | test_basics( ARG(VBase) ); | |
858 | test_conditional_ctor_and_get_valur_or( ARG(X) ); | |
859 | test_direct_value_manip( ARG(X) ); | |
860 | test_uninitialized_access( ARG(X) ); | |
861 | test_throwing_direct_init( ARG(X) ); | |
862 | test_throwing_val_assign_on_uninitialized( ARG(X) ); | |
863 | test_throwing_val_assign_on_initialized( ARG(X) ); | |
864 | test_throwing_copy_initialization( ARG(X) ); | |
865 | test_throwing_assign_to_uninitialized( ARG(X) ); | |
866 | test_throwing_assign_to_initialized( ARG(X) ); | |
867 | test_no_throwing_swap( ARG(X) ); | |
868 | test_throwing_swap( ARG(X) ); | |
869 | test_relops( ARG(X) ) ; | |
870 | test_none( ARG(X) ) ; | |
871 | test_arrow( ARG(X) ) ; | |
872 | BOOST_TEST ( X::count == 0 ) ; | |
873 | } | |
874 | ||
875 | int eat ( bool ) { return 1 ; } | |
876 | int eat ( char ) { return 1 ; } | |
877 | int eat ( int ) { return 1 ; } | |
878 | int eat ( void const* ) { return 1 ; } | |
879 | ||
880 | template<class T> int eat ( T ) { return 0 ; } | |
881 | ||
882 | // | |
883 | // This verifies that operator safe_bool() behaves properly. | |
884 | // | |
885 | template<class T> | |
886 | void test_no_implicit_conversions_impl( T const& ) | |
887 | { | |
888 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
889 | ||
890 | optional<T> def ; | |
891 | BOOST_TEST ( eat(def) == 0 ) ; | |
892 | } | |
893 | ||
894 | void test_no_implicit_conversions() | |
895 | { | |
896 | TRACE( std::endl << BOOST_CURRENT_FUNCTION ); | |
897 | ||
898 | bool b = false ; | |
899 | char c = 0 ; | |
900 | int i = 0 ; | |
901 | void const* p = 0 ; | |
902 | ||
903 | test_no_implicit_conversions_impl(b); | |
904 | test_no_implicit_conversions_impl(c); | |
905 | test_no_implicit_conversions_impl(i); | |
906 | test_no_implicit_conversions_impl(p); | |
907 | } | |
908 | ||
909 | ||
910 | // Test for support for classes with overridden operator& | |
911 | class CustomAddressOfClass | |
912 | { | |
913 | int n; | |
914 | ||
915 | public: | |
916 | CustomAddressOfClass() : n(0) {} | |
917 | CustomAddressOfClass(CustomAddressOfClass const& that) : n(that.n) {} | |
918 | explicit CustomAddressOfClass(int m) : n(m) {} | |
919 | int* operator& () { return &n; } | |
920 | bool operator== (CustomAddressOfClass const& that) const { return n == that.n; } | |
921 | }; | |
922 | ||
923 | void test_custom_addressof_operator() | |
924 | { | |
925 | boost::optional< CustomAddressOfClass > o1(CustomAddressOfClass(10)); | |
926 | BOOST_TEST(!!o1); | |
927 | BOOST_TEST(o1.get() == CustomAddressOfClass(10)); | |
928 | ||
929 | o1 = CustomAddressOfClass(20); | |
930 | BOOST_TEST(!!o1); | |
931 | BOOST_TEST(o1.get() == CustomAddressOfClass(20)); | |
932 | ||
933 | o1 = boost::none; | |
934 | BOOST_TEST(!o1); | |
935 | } | |
936 | ||
937 | int main() | |
938 | { | |
939 | try | |
940 | { | |
941 | test_with_class_type(); | |
942 | test_with_builtin_types(); | |
943 | test_no_implicit_conversions(); | |
944 | test_custom_addressof_operator(); | |
945 | } | |
946 | catch ( ... ) | |
947 | { | |
948 | BOOST_ERROR("Unexpected Exception caught!"); | |
949 | } | |
950 | ||
951 | return boost::report_errors(); | |
952 | } | |
953 | ||
954 |