RCP_UnitTests.cpp

Go to the documentation of this file.
00001 #include "Teuchos_RCP.hpp"
00002 #include "Teuchos_getConst.hpp"
00003 #ifdef HAVE_TEUCHOS_BOOST
00004 #  include "Teuchos_RCPBoostSharedPtrConversions.hpp"
00005 #endif
00006 
00007 #include "TestClasses.hpp"
00008 
00009 #include "Teuchos_UnitTestHarness.hpp"
00010 
00011 
00012 namespace {
00013 
00014 
00015 using Teuchos::as;
00016 using Teuchos::null;
00017 using Teuchos::Ptr;
00018 using Teuchos::RCP;
00019 using Teuchos::rcp;
00020 using Teuchos::outArg;
00021 using Teuchos::rcpWithEmbeddedObj;
00022 using Teuchos::getOptionalEmbeddedObj;
00023 using Teuchos::getOptionalNonconstEmbeddedObj;
00024 using Teuchos::set_extra_data;
00025 using Teuchos::get_optional_nonconst_extra_data;
00026 using Teuchos::getConst;
00027 using Teuchos::NullReferenceError;
00028 using Teuchos::DanglingReferenceError;
00029 using Teuchos::RCP_STRONG;
00030 using Teuchos::RCP_WEAK;
00031 using Teuchos::RCP_STRENGTH_INVALID;
00032 
00033 
00034 TEUCHOS_UNIT_TEST( DeallocNull, free )
00035 {
00036   Teuchos::DeallocNull<A> d;
00037   d.free(0);
00038 }
00039 
00040 
00041 TEUCHOS_UNIT_TEST( RCP, assignSelf )
00042 {
00043   RCP<A> a_rcp;
00044   a_rcp = a_rcp;
00045   TEST_ASSERT(is_null(a_rcp));
00046 }
00047 
00048 
00049 TEUCHOS_UNIT_TEST( RCP, explicit_null )
00050 {
00051   RCP<A> a_rcp(0, false);
00052   TEST_ASSERT(is_null(a_rcp));
00053 }
00054 
00055 
00056 TEUCHOS_UNIT_TEST( RCP, explicit_dealloc_null )
00057 {
00058   RCP<A> a_rcp = rcp<A>(0, Teuchos::DeallocNull<A>(), false);
00059   TEST_ASSERT(is_null(a_rcp));
00060 }
00061 
00062 
00063 TEUCHOS_UNIT_TEST( RCP, explicit_null_null )
00064 {
00065   RCP<A> a_rcp(0, null);
00066   TEST_ASSERT(is_null(a_rcp));
00067 }
00068 
00069 
00070 TEUCHOS_UNIT_TEST( RCP, explicit_null_nonnull )
00071 {
00072   A *a = new A;
00073   RCP<A> a_rcp(a, null);
00074   TEST_ASSERT(nonnull(a_rcp));
00075   delete a;
00076 }
00077 
00078 
00079 TEUCHOS_UNIT_TEST( RCP, get_optional_nonconst_extra_data )
00080 {
00081   RCP<A> a_rcp = rcp(new A);
00082   set_extra_data( as<int>(1), "blob", outArg(a_rcp) );
00083   TEST_EQUALITY_CONST(*get_optional_nonconst_extra_data<int>(a_rcp, "blob"), as<int>(1));
00084 }
00085 
00086 
00087 TEUCHOS_UNIT_TEST( RCP, getOptionalEmbeddedObj_null )
00088 {
00089   ECHO(RCP<A> a_rcp = rcp(new A));
00090   const Ptr<const RCP<C> > c_ptr_rcp_1 =
00091     getOptionalEmbeddedObj<A, RCP<C> >(a_rcp);
00092   TEST_EQUALITY_CONST( c_ptr_rcp_1, null );
00093   const Ptr<RCP<C> > c_ptr_rcp_2 =
00094     getOptionalNonconstEmbeddedObj<A, RCP<C> >(a_rcp);
00095   TEST_EQUALITY_CONST( c_ptr_rcp_2, null );
00096 }
00097 
00098 
00099 TEUCHOS_UNIT_TEST( RCP, getOptionalEmbeddedObj_default )
00100 {
00101 
00102   ECHO(RCP<C> c_rcp = rcp(new C));
00103   ECHO(RCP<A> a_rcp = rcpWithEmbeddedObj(new A, c_rcp));
00104 
00105   Ptr<const RCP<C> > c_ptr_rcp_1 =
00106     getOptionalEmbeddedObj<A, RCP<C> >(a_rcp);
00107   TEST_EQUALITY_CONST( is_null(c_ptr_rcp_1), false );
00108   TEST_EQUALITY( (*c_ptr_rcp_1).getRawPtr(), c_rcp.getRawPtr() );
00109   TEST_EQUALITY( (*c_ptr_rcp_1)->C_g(), C_g_return );
00110 
00111   Ptr<RCP<C> > c_ptr_rcp_2 =
00112     getOptionalNonconstEmbeddedObj<A, RCP<C> >(a_rcp);
00113   TEST_EQUALITY_CONST( is_null(c_ptr_rcp_2), false );
00114   TEST_EQUALITY( (*c_ptr_rcp_2).getRawPtr(), c_rcp.getRawPtr() );
00115   TEST_EQUALITY( (*c_ptr_rcp_2)->C_f(), C_f_return );
00116 
00117 }
00118 
00119 
00120 TEUCHOS_UNIT_TEST( RCP, reset )
00121 {
00122   RCP<A> a_rcp = rcp(new A);
00123   C* c_rawp = new C;
00124   a_rcp.reset(c_rawp);
00125   A* a_rawp = c_rawp;
00126   TEST_EQUALITY( a_rcp.getRawPtr(), a_rawp );
00127 }
00128 
00129 
00130 TEUCHOS_UNIT_TEST( RCP, nonnull )
00131 {
00132   ECHO(RCP<A> a_rcp = rcp(new A));
00133   TEST_EQUALITY_CONST(is_null(a_rcp), false);
00134   TEST_EQUALITY_CONST(nonnull(a_rcp), true);
00135   ECHO(a_rcp = null);
00136   TEST_EQUALITY_CONST(is_null(a_rcp), true);
00137   TEST_EQUALITY_CONST(nonnull(a_rcp), false);
00138 }
00139 
00140 
00141 #ifdef HAVE_TEUCHOS_BOOST
00142 
00143 
00144 TEUCHOS_UNIT_TEST( shared_ptr, nonnull )
00145 {
00146   using boost::shared_ptr;
00147   ECHO(shared_ptr<A> a_sptr(new A));
00148   TEST_EQUALITY_CONST(is_null(a_sptr), false);
00149   TEST_EQUALITY_CONST(nonnull(a_sptr), true);
00150   ECHO(a_sptr = shared_ptr<A>());
00151   TEST_EQUALITY_CONST(is_null(a_sptr), true);
00152   TEST_EQUALITY_CONST(nonnull(a_sptr), false);
00153 }
00154 
00155 
00156 #endif // HAVE_TEUCHOS_BOOST
00157 
00158 
00159 TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( RCP, weakDelete, T )
00160 {
00161 
00162   ECHO(RCP<T> rcp_strong = rcp(new T));
00163 
00164   TEST_EQUALITY_CONST( rcp_strong.strength(), RCP_STRONG );
00165   TEST_EQUALITY_CONST( rcp_strong.is_null(), false );
00166   TEST_EQUALITY_CONST( rcp_strong.strong_count(), 1 );
00167   TEST_EQUALITY_CONST( rcp_strong.weak_count(), 0 );
00168   TEST_EQUALITY_CONST( rcp_strong.total_count(), 1 );
00169 
00170   ECHO(RCP<T> rcp_weak1 = rcp_strong.create_weak());
00171 
00172   TEST_EQUALITY_CONST( rcp_weak1.strength(), RCP_WEAK );
00173   TEST_EQUALITY_CONST( rcp_weak1.is_null(), false );
00174   TEST_EQUALITY_CONST( rcp_weak1.strong_count(), 1 );
00175   TEST_EQUALITY_CONST( rcp_weak1.weak_count(), 1 );
00176   TEST_EQUALITY_CONST( rcp_weak1.total_count(), 2 );
00177 
00178   TEST_EQUALITY_CONST( rcp_strong.strong_count(), 1 );
00179   TEST_EQUALITY_CONST( rcp_strong.is_null(), false );
00180   TEST_EQUALITY_CONST( rcp_strong.weak_count(), 1 );
00181   TEST_EQUALITY_CONST( rcp_strong.total_count(), 2 );
00182 
00183   TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_strong), true );
00184 
00185   TEST_EQUALITY( rcp_weak1.get(), rcp_weak1.getRawPtr() );
00186   TEST_EQUALITY( rcp_weak1.get(), rcp_strong.get() );
00187   TEST_EQUALITY( rcp_weak1.getRawPtr(), rcp_strong.getRawPtr() );
00188 
00189   ECHO(RCP<T> rcp_weak2 = rcp_weak1);
00190 
00191   TEST_EQUALITY_CONST( rcp_weak2.strength(), RCP_WEAK );
00192   TEST_EQUALITY_CONST( rcp_weak2.is_null(), false );
00193   TEST_EQUALITY_CONST( rcp_weak2.strong_count(), 1 );
00194   TEST_EQUALITY_CONST( rcp_weak2.weak_count(), 2 );
00195   TEST_EQUALITY_CONST( rcp_weak2.total_count(), 3 );
00196 
00197   TEST_EQUALITY_CONST( rcp_strong.strong_count(), 1 );
00198   TEST_EQUALITY_CONST( rcp_strong.is_null(), false );
00199   TEST_EQUALITY_CONST( rcp_strong.weak_count(), 2 );
00200   TEST_EQUALITY_CONST( rcp_strong.total_count(), 3 );
00201 
00202   TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_strong), true );
00203   TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_weak2), true );
00204   TEST_EQUALITY_CONST( rcp_weak2.shares_resource(rcp_strong), true );
00205 
00206   TEST_EQUALITY( rcp_weak2.get(), rcp_strong.get() );
00207   TEST_EQUALITY( rcp_weak2.getRawPtr(), rcp_strong.getRawPtr() );
00208 
00209   ECHO(rcp_strong = null); // This deletes the underlying object of type T!
00210 
00211   TEST_EQUALITY_CONST( rcp_strong.strength(), RCP_STRENGTH_INVALID );
00212   TEST_EQUALITY_CONST( rcp_strong.is_null(), true );
00213   TEST_EQUALITY_CONST( rcp_strong.count(), 0 );
00214   TEST_EQUALITY_CONST( rcp_strong.strong_count(), 0 );
00215   TEST_EQUALITY_CONST( rcp_strong.weak_count(), 0 );
00216   TEST_EQUALITY_CONST( rcp_strong.total_count(), 0 );
00217   TEST_EQUALITY_CONST( rcp_strong.is_valid_ptr(), true );
00218 
00219   TEST_EQUALITY_CONST( rcp_strong.shares_resource(rcp_weak1), false );
00220   TEST_EQUALITY_CONST( rcp_strong.shares_resource(rcp_weak2), false );
00221 
00222   TEST_EQUALITY_CONST( rcp_weak1.has_ownership(), true );
00223   TEST_EQUALITY_CONST( rcp_weak1.count(), 0 );
00224   TEST_EQUALITY_CONST( rcp_weak1.strong_count(), 0 );
00225   TEST_EQUALITY_CONST( rcp_weak1.weak_count(), 2 );
00226   TEST_EQUALITY_CONST( rcp_weak1.total_count(), 2 );
00227   TEST_EQUALITY_CONST( rcp_weak1.is_valid_ptr(), false );
00228 
00229   TEST_EQUALITY_CONST( rcp_weak2.has_ownership(), true );
00230   TEST_EQUALITY_CONST( rcp_weak2.count(), 0 );
00231   TEST_EQUALITY_CONST( rcp_weak2.strong_count(), 0 );
00232   TEST_EQUALITY_CONST( rcp_weak2.weak_count(), 2 );
00233   TEST_EQUALITY_CONST( rcp_weak2.total_count(), 2 );
00234   TEST_EQUALITY_CONST( rcp_weak2.is_valid_ptr(), false );
00235 
00236   TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_weak2), true );
00237 
00238   ECHO(rcp_weak1.assert_not_null()); // Does not throw!
00239   ECHO(rcp_weak2.assert_not_null()); // Does not throw!
00240 
00241   TEST_THROW( rcp_weak1.assert_valid_ptr(), DanglingReferenceError );
00242 #ifdef TEUCHOS_DEBUG
00243   TEST_THROW( rcp_weak1.operator->(), DanglingReferenceError );
00244   TEST_THROW( *rcp_weak1, DanglingReferenceError );
00245   TEST_THROW( rcp_weak1.create_weak(), DanglingReferenceError );
00246   TEST_THROW( rcp_weak1.get(), DanglingReferenceError );
00247   TEST_THROW( rcp_weak1.getRawPtr(), DanglingReferenceError );
00248   TEST_THROW( rcp_weak1.ptr(), DanglingReferenceError );
00249   TEST_THROW( rcp_weak1.release(), DanglingReferenceError );
00250 #endif // TEUCHOS_DEBUG
00251 
00252   ECHO(rcp_weak1 = null); // Just deicrements weak count!
00253 
00254   TEST_EQUALITY_CONST( rcp_weak1.strength(), RCP_STRENGTH_INVALID );
00255   TEST_EQUALITY_CONST( rcp_weak1.is_null(), true );
00256   TEST_EQUALITY_CONST( rcp_weak1.count(), 0 );
00257   TEST_EQUALITY_CONST( rcp_weak1.strong_count(), 0 );
00258   TEST_EQUALITY_CONST( rcp_weak1.weak_count(), 0 );
00259   TEST_EQUALITY_CONST( rcp_weak1.total_count(), 0 );
00260   TEST_EQUALITY_CONST( rcp_weak1.is_valid_ptr(), true );
00261 
00262   TEST_EQUALITY_CONST( rcp_weak2.has_ownership(), true );
00263   TEST_EQUALITY_CONST( rcp_weak2.count(), 0 );
00264   TEST_EQUALITY_CONST( rcp_weak2.strong_count(), 0 );
00265   TEST_EQUALITY_CONST( rcp_weak2.weak_count(), 1 );
00266   TEST_EQUALITY_CONST( rcp_weak2.total_count(), 1 );
00267   TEST_EQUALITY_CONST( rcp_weak2.is_valid_ptr(), false );
00268 
00269   TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_weak2), false );
00270 
00271   TEST_THROW( rcp_weak2.assert_valid_ptr(), DanglingReferenceError );
00272 #ifdef TEUCHOS_DEBUG
00273   TEST_THROW( rcp_weak2.operator->(), DanglingReferenceError );
00274   TEST_THROW( *rcp_weak2, DanglingReferenceError );
00275   TEST_THROW( rcp_weak2.create_weak(), DanglingReferenceError );
00276   TEST_THROW( rcp_weak2.get(), DanglingReferenceError );
00277   TEST_THROW( rcp_weak2.getRawPtr(), DanglingReferenceError );
00278   TEST_THROW( rcp_weak2.ptr(), DanglingReferenceError );
00279   TEST_THROW( rcp_weak2.release(), DanglingReferenceError );
00280 #endif // TEUCHOS_DEBUG
00281 
00282 }
00283 
00284 
00285 TEUCHOS_UNIT_TEST( RCP, weak_strong )
00286 {
00287 
00288   ECHO(RCP<A> rcp1(rcp(new A)));
00289   TEST_EQUALITY_CONST( rcp1.strength(), RCP_STRONG );
00290 
00291   ECHO(RCP<A> rcp2 = rcp1.create_weak());
00292 
00293   TEST_EQUALITY_CONST( rcp2.strength(), RCP_WEAK );
00294   TEST_EQUALITY_CONST( rcp1.strong_count(), 1 );
00295   TEST_EQUALITY_CONST( rcp1.weak_count(), 1 );
00296   TEST_EQUALITY_CONST( rcp2.strong_count(), 1 );
00297   TEST_EQUALITY_CONST( rcp2.weak_count(), 1 );
00298 
00299   ECHO(RCP<A> rcp3 = rcp2.create_strong());
00300 
00301   TEST_EQUALITY_CONST( rcp3.strength(), RCP_STRONG );
00302   TEST_EQUALITY_CONST( rcp1.strong_count(), 2 );
00303   TEST_EQUALITY_CONST( rcp1.weak_count(), 1 );
00304   TEST_EQUALITY_CONST( rcp2.strong_count(), 2 );
00305   TEST_EQUALITY_CONST( rcp2.weak_count(), 1 );
00306 
00307   // This will make the underlying object A gets deleted!
00308   ECHO(rcp1 = null);
00309   ECHO(rcp3 = null);
00310 
00311   ECHO(rcp2 = null); // Should make the underlying node go away
00312 
00313 }
00314 
00315 
00316 TEUCHOS_UNIT_TEST( RCP, circularReference_a_then_c )
00317 {
00318 
00319   //TEST_EQUALITY_CONST(Teuchos::numActiveRCPNodes(), 0);
00320 
00321   {
00322 
00323     // Create objects a and c
00324 
00325     ECHO(RCP<A> a = rcp(new A));
00326     ECHO(RCP<C> c = rcp(new C));
00327 
00328     // Create a circular reference where 'a' owns 'c' strongly but 'c' only
00329     // owns 'a' weakly.
00330 
00331     ECHO(a->set_C(c));
00332     ECHO(c->set_A(a.create_weak()));
00333 
00334 #ifdef TEUCHOS_DEBUG
00335     ECHO(c->call_A_on_delete(true));
00336     // Here, we set 'c' to call 'a' when it is deleted which will result in an
00337     // exception being thrown in a call to delete.  NOTE: It is *very* bad
00338     // practice to allow exceptions to be thrown from destructors but I am
00339     // allowing it so that I can detect such bad bahavior below!
00340 #endif
00341 
00342     TEST_EQUALITY( a->call_C_f(), C_f_return );
00343     TEST_EQUALITY( c->call_A_g(), A_g_return );
00344 
00345     // Remove 'a' first and then remove 'c'.  Since 'a' is only weakly held by
00346     // 'c', this will result in 'a' being deleted right away.  In this case,
00347     // if anyone tries to access 'a' after this (like 'c' in its destructor),
00348     // then an exception will get thrown in debug mode!
00349 
00350     ECHO(a = null);
00351 
00352     // Now, remove 'c'.  In this case, since 'a' has already been deleted and
00353     // 'c' is going to try to call 'a' on its way out, this will thrown an
00354     // exception.
00355 
00356 #ifdef TEUCHOS_DEBUG
00357 
00358     TEST_THROW(c = null, DanglingReferenceError);
00359     // NOTE: Above, operator==(...) exhibits the 'strong' guarantee?
00360 
00361     // Since an exception was thrown, the 'c' object never got deleted.
00362     // Therefore, we need to disable 'c' calling 'a' on delete and the object
00363     // will get cleaned up correctly when this function exists (I hope).
00364     ECHO(c->call_A_on_delete(false));
00365 
00366     ECHO(c = null); // All memory should be cleaned up here!
00367 
00368 #endif // TEUCHOS_DEBUG
00369 
00370   }
00371 
00372 }
00373 
00374 
00375 TEUCHOS_UNIT_TEST( RCP, circularReference_c_then_a )
00376 {
00377 
00378   {
00379 
00380     // Create objects a and c
00381 
00382     ECHO(RCP<A> a = rcp(new A));
00383     ECHO(RCP<C> c = rcp(new C));
00384 
00385     // Create a circular reference where 'a' owns 'c' strongly but 'c' only
00386     // owns 'a' weakly.
00387 
00388     ECHO(a->set_C(c));
00389     ECHO(c->set_A(a.create_weak()));
00390 
00391     ECHO(c->call_A_on_delete(false));
00392     // Here, we set 'c' to not call 'a' when it is deleted.  It turns out that
00393     // the set of calls to delete and destructors that takes place is very
00394     // complex and in order to avoid trouble, an object that holds an RCP to
00395     // another object weakly should *never* try to call any members on the
00396     // wrapped object as it gets deleted!
00397     
00398     TEST_EQUALITY( a->call_C_f(), C_f_return );
00399     TEST_EQUALITY( c->call_A_g(), A_g_return );
00400 
00401     // Remove 'c' first and then remove 'a' implicitly at the end of the
00402     // block.  Since 'c' is held strongly by 'a' and since we are keeping the
00403     // strong pointer for 'a' alive, we can call functions on 'a' all we want
00404     // with no fear of accessing dead memory.
00405 
00406     ECHO(c = null);
00407 
00408     TEST_EQUALITY( a->call_C_f(), C_f_return ); // C is still alive!
00409 
00410     // Finally, when 'a' goes away implicitly, it will take 'c' with it.  In
00411     // the complex set of nested calls that take place due to the circular
00412     // reference, everything will get cleaned up correctly.  Also, if any
00413     // client code where to try to access an object as it is being deleted, an
00414     // exception will get thrown and no memory error will occur (unless an
00415     // abort(...) is called when an exception gets thrown from a destructor
00416     // when an exception is already active).
00417 
00418   }
00419 
00420 }
00421 
00422 
00423 TEUCHOS_UNIT_TEST( RCP, circularReference_self )
00424 {
00425 
00426   {
00427 
00428     // Create one 'c' object
00429 
00430     ECHO(RCP<C> c = rcp(new C));
00431 
00432     // Create a weak circular reference where 'c' points back to itself
00433 
00434     ECHO(c->set_A(c.create_weak()));
00435 
00436     // Now, try to set 'c' to null.
00437 
00438     ECHO(c = null); // All memory should be cleaned up here!
00439 
00440   }
00441 
00442 }
00443 
00444 
00445 TEUCHOS_UNIT_TEST( RCP, danglingPtr )
00446 {
00447   ECHO(RCP<A> a_rcp = rcp(new A));
00448   ECHO(Ptr<A> a_ptr = a_rcp.ptr());
00449   ECHO(A *badPtr = a_rcp.getRawPtr());
00450   ECHO(a_rcp = null);
00451 #ifdef TEUCHOS_DEBUG
00452   TEST_THROW( *a_ptr, DanglingReferenceError );
00453   (void)badPtr;
00454 #else
00455   TEST_EQUALITY( a_ptr.getRawPtr(), badPtr );
00456 #endif
00457 }
00458 
00459 
00460 //
00461 // Template Instantiations
00462 //
00463 
00464 
00465 #ifdef TEUCHOS_DEBUG
00466 
00467 #  define DEBUG_UNIT_TEST_GROUP( T ) \
00468 
00469 #else
00470 
00471 #  define DEBUG_UNIT_TEST_GROUP( T )
00472 
00473 #endif
00474 
00475 
00476 #define UNIT_TEST_GROUP( T ) \
00477   TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( RCP, weakDelete, T ) \
00478   DEBUG_UNIT_TEST_GROUP(T)
00479 
00480 
00481 UNIT_TEST_GROUP(A)
00482 UNIT_TEST_GROUP(C)
00483 UNIT_TEST_GROUP(D)
00484 UNIT_TEST_GROUP(E)
00485 
00486 
00487 } // namespace
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Tue Oct 20 10:13:59 2009 for Teuchos Package Browser (Single Doxygen Collection) by  doxygen 1.6.1