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 
35 #include "optional_test_common.hpp"
36 
test_implicit_construction(optional<double> opt,double v,double z)37 void test_implicit_construction ( optional<double> opt, double v, double z )
38 {
39   check_value(opt,v,z);
40 }
41 
test_implicit_construction(optional<X> opt,X const & v,X const & z)42 void test_implicit_construction ( optional<X> opt, X const& v, X const& z )
43 {
44   check_value(opt,v,z);
45 }
46 
test_default_implicit_construction(double,optional<double> opt)47 void test_default_implicit_construction ( double, optional<double> opt )
48 {
49   BOOST_TEST(!opt);
50 }
51 
test_default_implicit_construction(X const &,optional<X> opt)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>
test_basics(T const *)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>
test_conditional_ctor_and_get_valur_or(T const *)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>
test_direct_value_manip(T const *)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>
test_uninitialized_access(T const *)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
prevent_buggy_optimization(bool v)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>
test_throwing_direct_init(T const *)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>
test_throwing_val_assign_on_uninitialized(T const *)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>
test_throwing_val_assign_on_initialized(T const *)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>
test_throwing_copy_initialization(T const *)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>
test_throwing_assign_to_uninitialized(T const *)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>
test_throwing_assign_to_initialized(T const *)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>
test_no_throwing_swap(T const *)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>
test_throwing_swap(T const *)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>
test_relops(T const *)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>
test_none(T const *)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>
test_arrow(T const *)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 
test_with_builtin_types()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 {
VBaseVBase847     VBase(int v) : X(v) {}
848     // MSVC 8.0 doesn't generate this correctly...
VBaseVBase849     VBase(const VBase& other) : X(static_cast<const X&>(other)) {}
850 };
851 
test_with_class_type()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 
eat(bool)875 int eat ( bool ) { return 1 ; }
eat(char)876 int eat ( char ) { return 1 ; }
eat(int)877 int eat ( int  ) { return 1 ; }
eat(void const *)878 int eat ( void const* ) { return 1 ; }
879 
eat(T)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>
test_no_implicit_conversions_impl(T const &)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 
test_no_implicit_conversions()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:
CustomAddressOfClass()916     CustomAddressOfClass() : n(0) {}
CustomAddressOfClass(CustomAddressOfClass const & that)917     CustomAddressOfClass(CustomAddressOfClass const& that) : n(that.n) {}
CustomAddressOfClass(int m)918     explicit CustomAddressOfClass(int m) : n(m) {}
operator &()919     int* operator& () { return &n; }
operator ==(CustomAddressOfClass const & that) const920     bool operator== (CustomAddressOfClass const& that) const { return n == that.n; }
921 };
922 
test_custom_addressof_operator()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 
main()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 
955