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