RCP_UnitTests.cpp

Go to the documentation of this file.
00001 #include "Teuchos_RCP.hpp"
00002 #include "Teuchos_getConst.hpp"
00003 #include "Teuchos_getBaseObjVoidPtr.hpp"
00004 #ifdef HAVE_TEUCHOS_BOOST
00005 #  include "Teuchos_RCPBoostSharedPtrConversions.hpp"
00006 #endif
00007 
00008 #include "TestClasses.hpp"
00009 
00010 #include "Teuchos_UnitTestHarness.hpp"
00011 
00012 
00013 namespace {
00014 
00015 
00016 using Teuchos::as;
00017 using Teuchos::null;
00018 using Teuchos::Ptr;
00019 using Teuchos::RCP;
00020 using Teuchos::rcp;
00021 using Teuchos::rcpFromRef;
00022 using Teuchos::rcpFromUndefRef;
00023 using Teuchos::outArg;
00024 using Teuchos::rcpWithEmbeddedObj;
00025 using Teuchos::getEmbeddedObj;
00026 using Teuchos::getOptionalEmbeddedObj;
00027 using Teuchos::getOptionalNonconstEmbeddedObj;
00028 using Teuchos::set_extra_data;
00029 using Teuchos::get_optional_nonconst_extra_data;
00030 using Teuchos::getConst;
00031 using Teuchos::NullReferenceError;
00032 using Teuchos::DanglingReferenceError;
00033 using Teuchos::DuplicateOwningRCPError;
00034 using Teuchos::RCP_STRONG;
00035 using Teuchos::RCP_WEAK;
00036 using Teuchos::RCP_STRENGTH_INVALID;
00037 using Teuchos::RCPNodeTracer;
00038 
00039 
00040 TEUCHOS_UNIT_TEST( DeallocNull, free )
00041 {
00042   Teuchos::DeallocNull<A> d;
00043   d.free(0);
00044 }
00045 
00046 
00047 TEUCHOS_UNIT_TEST( RCP, assignSelf_null )
00048 {
00049   RCP<A> a_rcp;
00050   a_rcp = a_rcp;
00051   TEST_ASSERT(is_null(a_rcp));
00052 }
00053 
00054 
00055 TEUCHOS_UNIT_TEST( RCP, assignSelf_nonnull )
00056 {
00057   RCP<A> a_rcp(new A);
00058   A *a_raw_ptr = a_rcp.getRawPtr(); 
00059   a_rcp = a_rcp;
00060   TEST_ASSERT(nonnull(a_rcp));
00061   TEST_EQUALITY(a_rcp.getRawPtr(), a_raw_ptr);
00062 }
00063 
00064 
00065 TEUCHOS_UNIT_TEST( RCP, getConst )
00066 {
00067   RCP<A> a_rcp(new A);
00068   RCP<const A> ca_rcp = a_rcp.getConst();
00069   TEST_EQUALITY(a_rcp.getRawPtr(), ca_rcp.getRawPtr());
00070 }
00071 
00072 
00073 TEUCHOS_UNIT_TEST( RCP, explicit_null )
00074 {
00075   RCP<A> a_rcp(0);
00076   TEST_ASSERT(is_null(a_rcp));
00077 }
00078 
00079 
00080 TEUCHOS_UNIT_TEST( RCP, explicit_dealloc_null )
00081 {
00082   RCP<A> a_rcp = rcp<A>(0, Teuchos::DeallocNull<A>(), false);
00083   TEST_ASSERT(is_null(a_rcp));
00084 }
00085 
00086 
00087 TEUCHOS_UNIT_TEST( RCP, explicit_null_null )
00088 {
00089   RCP<A> a_rcp(0, null);
00090   TEST_ASSERT(is_null(a_rcp));
00091 }
00092 
00093 
00094 TEUCHOS_UNIT_TEST( RCP, explicit_null_nonnull )
00095 {
00096   A *a = new A;
00097   RCP<A> a_rcp(a, null);
00098   TEST_ASSERT(nonnull(a_rcp));
00099   delete a;
00100 }
00101 
00102 
00103 TEUCHOS_UNIT_TEST( RCP, rcpFromRef_raw_ref )
00104 {
00105   A a;
00106   RCP<A> a_rcp = rcpFromRef(a);
00107   TEST_EQUALITY(a_rcp.getRawPtr(), &a);
00108   TEST_ASSERT(nonnull(a_rcp));
00109 }
00110 
00111 
00112 TEUCHOS_UNIT_TEST( RCP, rcpFromRef_from_rcp )
00113 {
00114   RCP<A> a_rcp1 = rcp<A>(new A);
00115   RCP<A> a_rcp2 = rcpFromRef(*a_rcp1);
00116   TEST_EQUALITY(a_rcp2.getRawPtr(), a_rcp1.getRawPtr());
00117   if (RCPNodeTracer::isTracingActiveRCPNodes())
00118   {
00119     TEST_EQUALITY_CONST(a_rcp2.strong_count(), 1);
00120     TEST_EQUALITY_CONST(a_rcp2.weak_count(), 1);
00121     TEST_EQUALITY_CONST(a_rcp2.has_ownership(), true);
00122   }
00123   else {
00124     TEST_EQUALITY_CONST(a_rcp2.strong_count(), 1);
00125     TEST_EQUALITY_CONST(a_rcp2.weak_count(), 0);
00126     TEST_EQUALITY_CONST(a_rcp2.has_ownership(), false);
00127   }
00128 }
00129 
00130 
00131 TEUCHOS_UNIT_TEST( RCP, rcpFromUndefRef )
00132 {
00133   A a;
00134   RCP<A> a_rcp = rcpFromUndefRef(a);
00135   TEST_ASSERT(nonnull(a_rcp));
00136 }
00137 
00138 
00139 // Test that shows that we can detect trying to create two owning RCPs
00140 // pointing to the same polymorphic object but having different interfaces
00141 // with different addresses.  This happens due to virtual base classes. Only
00142 // works when we have a working getBaseObjVoidPtr(...) function.
00143 TEUCHOS_UNIT_TEST( RCP, duplicate_rcp_owning_polymorphic )
00144 {
00145   SET_RCPNODE_TRACING();
00146   ECHO(C *c_ptr = new C);
00147   ECHO(A *a_ptr = c_ptr);
00148   ECHO(RCP<C> c_rcp = rcp(c_ptr)); // Okay
00149 #if defined(TEUCHOS_DEBUG) && defined(HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR)
00150   // With determine they are pointed to the same object!
00151   TEST_THROW(RCP<A> a_rcp = rcp(a_ptr), DuplicateOwningRCPError);
00152 #else
00153   // Will not determine they are point to the same object!
00154   ECHO(RCP<A> a_rcp = rcp(a_ptr));
00155   TEST_EQUALITY(a_rcp.getRawPtr(), a_ptr);
00156   ECHO(a_rcp.release()); // Better or we will get a segfault!
00157 #endif
00158 }
00159 
00160 
00161 // Test that shows that we can detect trying to create two owning RCPs
00162 // pointing to the same polymorphic object with the same type and therefore
00163 // the same address.  This works even if these use virtual base classes.  This
00164 // works even without a working getBaseObjVoidPtr(...) function.
00165 TEUCHOS_UNIT_TEST( RCP, duplicate_rcp_owning_polymorphic_different_addr )
00166 {
00167   SET_RCPNODE_TRACING();
00168   ECHO(A *a_ptr1 = new C);
00169   ECHO(A *a_ptr2 = a_ptr1);
00170   ECHO(RCP<A> a_rcp1 = rcp(a_ptr1)); // Okay
00171 #if defined(TEUCHOS_DEBUG)
00172   // With determine they are pointed to the same object!
00173   TEST_THROW(RCP<A> a_rcp2 = rcp(a_ptr2), DuplicateOwningRCPError);
00174 #else
00175   // Will not determine they are point to the same object!
00176   ECHO(RCP<A> a_rcp2 = rcp(a_ptr2));
00177   TEST_EQUALITY(a_rcp2.getRawPtr(), a_ptr2);
00178   ECHO(a_rcp2.release()); // Better or we will get a segfault!
00179 #endif
00180 }
00181 
00182 
00183 // Test that shows that we can always detect trying to create two owning RCPs
00184 // pointing to the same nonpolymorphic object having different interfaces but
00185 // the same address (single non-virtual inheritance).  Works just fine without
00186 // a working getBaseObjVoidPtr(...) function.
00187 TEUCHOS_UNIT_TEST( RCP, duplicate_rcp_owning_nonpolymorphic_same_addr )
00188 {
00189   SET_RCPNODE_TRACING();
00190   ECHO(E *e_ptr = new E);
00191   ECHO(E *d_ptr = e_ptr);
00192   ECHO(RCP<E> e_rcp = rcp(e_ptr)); // Okay
00193 #if defined(TEUCHOS_DEBUG)
00194   // With determine they are pointed to the same object even without support
00195   // for getBaseObjVoidPtr(...) because no dynamic_cast is needed.
00196   TEST_THROW(RCP<D> d_rcp = rcp(d_ptr), DuplicateOwningRCPError);
00197 #else
00198   // Will not determine they are point to the same object!
00199   ECHO(RCP<D> d_rcp = rcp(d_ptr));
00200   TEST_EQUALITY(d_rcp.getRawPtr(), d_ptr);
00201   ECHO(d_rcp.release()); // Better or we will get a segfault!
00202 #endif
00203 }
00204 
00205 
00206 //
00207 // These next tests shows that we can detect when two RCPs are create to the same
00208 // object, one owning and the other non-owning.  When we have a working
00209 // getBaseObjVoidPtr(...) function, the new non-owning RCP will actually be a
00210 // weak RCP that can be used to detect circular dependencies.
00211 //
00212 
00213 
00214 // rcp
00215 
00216 
00217 TEUCHOS_UNIT_TEST( RCP, rcp_duplicate_rcp_nonowning_polymorphic_different_addr )
00218 {
00219   SET_RCPNODE_TRACING();
00220   ECHO(RCP<C> c_rcp(new C));
00221   ECHO(A &a_ref = *c_rcp);
00222   ECHO(RCP<A> a_rcp = rcp(&a_ref, false));
00223   ECHO(c_rcp = null);
00224 #if defined(TEUCHOS_DEBUG) && defined(HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR)
00225   TEST_THROW(a_rcp->A_g(), DanglingReferenceError);
00226 #else
00227   TEST_NOTHROW(a_rcp.getRawPtr());
00228 #endif
00229 }
00230 
00231 
00232 TEUCHOS_UNIT_TEST( RCP, rcp_duplicate_rcp_nonowning_polymorphic_same_addr )
00233 {
00234   SET_RCPNODE_TRACING();
00235   ECHO(RCP<A> a_rcp1(new C));
00236   ECHO(A &a_ref = *a_rcp1);
00237   ECHO(RCP<A> a_rcp2 = rcp(&a_ref, false));
00238   ECHO(a_rcp1 = null);
00239 #if defined(TEUCHOS_DEBUG)
00240   TEST_THROW(a_rcp2->A_g(), DanglingReferenceError);
00241 #else
00242   TEST_NOTHROW(a_rcp2.getRawPtr());
00243 #endif
00244 }
00245 
00246 
00247 TEUCHOS_UNIT_TEST( RCP, rcp_duplicate_rcp_nonowning_nonpolymorphic )
00248 {
00249   SET_RCPNODE_TRACING();
00250   ECHO(RCP<E> e_rcp(new E));
00251   ECHO(D &d_ref = *e_rcp);
00252   ECHO(RCP<D> d_rcp = rcp(&d_ref, false));
00253   ECHO(e_rcp = null);
00254 #if defined(TEUCHOS_DEBUG)
00255   TEST_THROW(d_rcp->D_g(), DanglingReferenceError);
00256 #else
00257   TEST_NOTHROW(d_rcp.getRawPtr());
00258 #endif
00259 }
00260 
00261 
00262 // rcpFromRef
00263 
00264 
00265 TEUCHOS_UNIT_TEST( RCP, rcpFromRef_duplicate_rcp_nonowning_polymorphic_different_addr )
00266 {
00267   SET_RCPNODE_TRACING();
00268   ECHO(RCP<C> c_rcp(new C));
00269   ECHO(A &a_ref = *c_rcp);
00270   ECHO(RCP<A> a_rcp = rcpFromRef(a_ref));
00271   ECHO(c_rcp = null);
00272 #if defined(TEUCHOS_DEBUG) && defined(HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR)
00273   TEST_THROW(a_rcp->A_g(), DanglingReferenceError);
00274 #else
00275   TEST_NOTHROW(a_rcp.getRawPtr());
00276 #endif
00277 }
00278 
00279 
00280 TEUCHOS_UNIT_TEST( RCP, rcpFromRef_duplicate_rcp_nonowning_polymorphic_same_addr )
00281 {
00282   SET_RCPNODE_TRACING();
00283   ECHO(RCP<A> a_rcp1(new C));
00284   ECHO(A &a_ref = *a_rcp1);
00285   ECHO(RCP<A> a_rcp2 = rcpFromRef(a_ref));
00286   ECHO(a_rcp1 = null);
00287 #if defined(TEUCHOS_DEBUG)
00288   TEST_THROW(a_rcp2->A_g(), DanglingReferenceError);
00289 #else
00290   TEST_NOTHROW(a_rcp2.getRawPtr());
00291 #endif
00292 }
00293 
00294 
00295 TEUCHOS_UNIT_TEST( RCP, rcpFromRef_duplicate_rcp_nonowning_nonpolymorphic )
00296 {
00297   SET_RCPNODE_TRACING();
00298   ECHO(RCP<E> e_rcp(new E));
00299   ECHO(D &d_ref = *e_rcp);
00300   ECHO(RCP<D> d_rcp = rcpFromRef(d_ref));
00301   ECHO(e_rcp = null);
00302 #if defined(TEUCHOS_DEBUG)
00303   TEST_THROW(d_rcp->D_g(), DanglingReferenceError);
00304 #else
00305   TEST_NOTHROW(d_rcp.getRawPtr());
00306 #endif
00307 }
00308 
00309 
00310 // rcpFromUndefRef (Can never detect dangling references)
00311 
00312 
00313 TEUCHOS_UNIT_TEST( RCP, rcpFromUndefRef_duplicate_rcp_nonowning_polymorphic_same_addr )
00314 {
00315   SET_RCPNODE_TRACING();
00316   ECHO(RCP<A> a_rcp1(new C));
00317   ECHO(A &a_ref = *a_rcp1);
00318   ECHO(RCP<A> a_rcp2 = rcpFromUndefRef(a_ref));
00319   ECHO(a_rcp1 = null);
00320   TEST_NOTHROW(a_rcp2.getRawPtr());
00321 }
00322 
00323 
00324 //
00325 // extra data and embedded objects tests
00326 //
00327 
00328 
00329 TEUCHOS_UNIT_TEST( RCP, get_optional_nonconst_extra_data )
00330 {
00331   RCP<A> a_rcp = rcp(new A);
00332   set_extra_data( as<int>(1), "blob", outArg(a_rcp) );
00333   TEST_EQUALITY_CONST(*get_optional_nonconst_extra_data<int>(a_rcp, "blob"), as<int>(1));
00334 }
00335 
00336 
00337 TEUCHOS_UNIT_TEST( RCP, getOptionalEmbeddedObj_null )
00338 {
00339   ECHO(RCP<A> a_rcp = rcp(new A));
00340   const Ptr<const RCP<C> > c_ptr_rcp_1 =
00341     getOptionalEmbeddedObj<A, RCP<C> >(a_rcp);
00342   TEST_EQUALITY_CONST( c_ptr_rcp_1, null );
00343   const Ptr<RCP<C> > c_ptr_rcp_2 =
00344     getOptionalNonconstEmbeddedObj<A, RCP<C> >(a_rcp);
00345   TEST_EQUALITY_CONST( c_ptr_rcp_2, null );
00346 }
00347 
00348 
00349 TEUCHOS_UNIT_TEST( RCP, getOptionalEmbeddedObj_default )
00350 {
00351 
00352   ECHO(RCP<C> c_rcp = rcp(new C));
00353   ECHO(RCP<A> a_rcp = rcpWithEmbeddedObj(new A, c_rcp));
00354 
00355   Ptr<const RCP<C> > c_ptr_rcp_1 =
00356     getOptionalEmbeddedObj<A, RCP<C> >(a_rcp);
00357   TEST_EQUALITY_CONST( is_null(c_ptr_rcp_1), false );
00358   TEST_EQUALITY( (*c_ptr_rcp_1).getRawPtr(), c_rcp.getRawPtr() );
00359   TEST_EQUALITY( (*c_ptr_rcp_1)->C_g(), C_g_return );
00360 
00361   Ptr<RCP<C> > c_ptr_rcp_2 =
00362     getOptionalNonconstEmbeddedObj<A, RCP<C> >(a_rcp);
00363   TEST_EQUALITY_CONST( is_null(c_ptr_rcp_2), false );
00364   TEST_EQUALITY( (*c_ptr_rcp_2).getRawPtr(), c_rcp.getRawPtr() );
00365   TEST_EQUALITY( (*c_ptr_rcp_2)->C_f(), C_f_return );
00366 
00367 }
00368 
00369 
00370 TEUCHOS_UNIT_TEST( RCP, reset_null )
00371 {
00372   RCP<A> a_rcp = rcp(new A);
00373   a_rcp.reset();
00374   TEST_ASSERT(is_null(a_rcp));
00375 }
00376 
00377 
00378 TEUCHOS_UNIT_TEST( RCP, reset_nonnull )
00379 {
00380   RCP<A> a_rcp = rcp(new A);
00381   C* c_rawp = new C;
00382   a_rcp.reset(c_rawp);
00383   A* a_rawp = c_rawp;
00384   TEST_EQUALITY( a_rcp.getRawPtr(), a_rawp );
00385 }
00386 
00387 
00388 TEUCHOS_UNIT_TEST( RCP, nonnull )
00389 {
00390   ECHO(RCP<A> a_rcp = rcp(new A));
00391   TEST_EQUALITY_CONST(is_null(a_rcp), false);
00392   TEST_EQUALITY_CONST(nonnull(a_rcp), true);
00393   ECHO(a_rcp = null);
00394   TEST_EQUALITY_CONST(is_null(a_rcp), true);
00395   TEST_EQUALITY_CONST(nonnull(a_rcp), false);
00396 }
00397 
00398 
00399 #ifdef HAVE_TEUCHOS_BOOST
00400 
00401 
00402 TEUCHOS_UNIT_TEST( shared_ptr, nonnull )
00403 {
00404   using boost::shared_ptr;
00405   ECHO(shared_ptr<A> a_sptr(new A));
00406   TEST_EQUALITY_CONST(is_null(a_sptr), false);
00407   TEST_EQUALITY_CONST(nonnull(a_sptr), true);
00408   ECHO(a_sptr = shared_ptr<A>());
00409   TEST_EQUALITY_CONST(is_null(a_sptr), true);
00410   TEST_EQUALITY_CONST(nonnull(a_sptr), false);
00411 }
00412 
00413 
00414 #endif // HAVE_TEUCHOS_BOOST
00415 
00416 
00417 TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( RCP, weakDelete, T )
00418 {
00419 
00420   ECHO(RCP<T> rcp_strong = rcp(new T));
00421 
00422   TEST_EQUALITY_CONST( rcp_strong.strength(), RCP_STRONG );
00423   TEST_EQUALITY_CONST( rcp_strong.is_null(), false );
00424   TEST_EQUALITY_CONST( rcp_strong.strong_count(), 1 );
00425   TEST_EQUALITY_CONST( rcp_strong.weak_count(), 0 );
00426   TEST_EQUALITY_CONST( rcp_strong.total_count(), 1 );
00427 
00428   ECHO(RCP<T> rcp_weak1 = rcp_strong.create_weak());
00429 
00430   TEST_EQUALITY_CONST( rcp_weak1.strength(), RCP_WEAK );
00431   TEST_EQUALITY_CONST( rcp_weak1.is_null(), false );
00432   TEST_EQUALITY_CONST( rcp_weak1.strong_count(), 1 );
00433   TEST_EQUALITY_CONST( rcp_weak1.weak_count(), 1 );
00434   TEST_EQUALITY_CONST( rcp_weak1.total_count(), 2 );
00435 
00436   TEST_EQUALITY_CONST( rcp_strong.strong_count(), 1 );
00437   TEST_EQUALITY_CONST( rcp_strong.is_null(), false );
00438   TEST_EQUALITY_CONST( rcp_strong.weak_count(), 1 );
00439   TEST_EQUALITY_CONST( rcp_strong.total_count(), 2 );
00440 
00441   TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_strong), true );
00442 
00443   TEST_EQUALITY( rcp_weak1.get(), rcp_weak1.getRawPtr() );
00444   TEST_EQUALITY( rcp_weak1.get(), rcp_strong.get() );
00445   TEST_EQUALITY( rcp_weak1.getRawPtr(), rcp_strong.getRawPtr() );
00446 
00447   ECHO(RCP<T> rcp_weak2 = rcp_weak1);
00448 
00449   TEST_EQUALITY_CONST( rcp_weak2.strength(), RCP_WEAK );
00450   TEST_EQUALITY_CONST( rcp_weak2.is_null(), false );
00451   TEST_EQUALITY_CONST( rcp_weak2.strong_count(), 1 );
00452   TEST_EQUALITY_CONST( rcp_weak2.weak_count(), 2 );
00453   TEST_EQUALITY_CONST( rcp_weak2.total_count(), 3 );
00454 
00455   TEST_EQUALITY_CONST( rcp_strong.strong_count(), 1 );
00456   TEST_EQUALITY_CONST( rcp_strong.is_null(), false );
00457   TEST_EQUALITY_CONST( rcp_strong.weak_count(), 2 );
00458   TEST_EQUALITY_CONST( rcp_strong.total_count(), 3 );
00459 
00460   TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_strong), true );
00461   TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_weak2), true );
00462   TEST_EQUALITY_CONST( rcp_weak2.shares_resource(rcp_strong), true );
00463 
00464   TEST_EQUALITY( rcp_weak2.get(), rcp_strong.get() );
00465   TEST_EQUALITY( rcp_weak2.getRawPtr(), rcp_strong.getRawPtr() );
00466 
00467   ECHO(rcp_strong = null); // This deletes the underlying object of type T!
00468 
00469   TEST_EQUALITY_CONST( rcp_strong.strength(), RCP_STRENGTH_INVALID );
00470   TEST_EQUALITY_CONST( rcp_strong.is_null(), true );
00471   TEST_EQUALITY_CONST( rcp_strong.count(), 0 );
00472   TEST_EQUALITY_CONST( rcp_strong.strong_count(), 0 );
00473   TEST_EQUALITY_CONST( rcp_strong.weak_count(), 0 );
00474   TEST_EQUALITY_CONST( rcp_strong.total_count(), 0 );
00475   TEST_EQUALITY_CONST( rcp_strong.is_valid_ptr(), true );
00476 
00477   TEST_EQUALITY_CONST( rcp_strong.shares_resource(rcp_weak1), false );
00478   TEST_EQUALITY_CONST( rcp_strong.shares_resource(rcp_weak2), false );
00479 
00480   TEST_EQUALITY_CONST( rcp_weak1.has_ownership(), true );
00481   TEST_EQUALITY_CONST( rcp_weak1.count(), 0 );
00482   TEST_EQUALITY_CONST( rcp_weak1.strong_count(), 0 );
00483   TEST_EQUALITY_CONST( rcp_weak1.weak_count(), 2 );
00484   TEST_EQUALITY_CONST( rcp_weak1.total_count(), 2 );
00485   TEST_EQUALITY_CONST( rcp_weak1.is_valid_ptr(), false );
00486 
00487   TEST_EQUALITY_CONST( rcp_weak2.has_ownership(), true );
00488   TEST_EQUALITY_CONST( rcp_weak2.count(), 0 );
00489   TEST_EQUALITY_CONST( rcp_weak2.strong_count(), 0 );
00490   TEST_EQUALITY_CONST( rcp_weak2.weak_count(), 2 );
00491   TEST_EQUALITY_CONST( rcp_weak2.total_count(), 2 );
00492   TEST_EQUALITY_CONST( rcp_weak2.is_valid_ptr(), false );
00493 
00494   TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_weak2), true );
00495 
00496   ECHO(rcp_weak1.assert_not_null()); // Does not throw!
00497   ECHO(rcp_weak2.assert_not_null()); // Does not throw!
00498 
00499   TEST_THROW( rcp_weak1.assert_valid_ptr(), DanglingReferenceError );
00500 #ifdef TEUCHOS_DEBUG
00501   TEST_THROW( rcp_weak1.operator->(), DanglingReferenceError );
00502   TEST_THROW( *rcp_weak1, DanglingReferenceError );
00503   TEST_THROW( rcp_weak1.create_weak(), DanglingReferenceError );
00504   TEST_THROW( rcp_weak1.get(), DanglingReferenceError );
00505   TEST_THROW( rcp_weak1.getRawPtr(), DanglingReferenceError );
00506   TEST_THROW( rcp_weak1(), DanglingReferenceError );
00507   TEST_THROW( rcp_weak1.release(), DanglingReferenceError );
00508 #endif // TEUCHOS_DEBUG
00509 
00510   ECHO(rcp_weak1 = null); // Just deicrements weak count!
00511 
00512   TEST_EQUALITY_CONST( rcp_weak1.strength(), RCP_STRENGTH_INVALID );
00513   TEST_EQUALITY_CONST( rcp_weak1.is_null(), true );
00514   TEST_EQUALITY_CONST( rcp_weak1.count(), 0 );
00515   TEST_EQUALITY_CONST( rcp_weak1.strong_count(), 0 );
00516   TEST_EQUALITY_CONST( rcp_weak1.weak_count(), 0 );
00517   TEST_EQUALITY_CONST( rcp_weak1.total_count(), 0 );
00518   TEST_EQUALITY_CONST( rcp_weak1.is_valid_ptr(), true );
00519 
00520   TEST_EQUALITY_CONST( rcp_weak2.has_ownership(), true );
00521   TEST_EQUALITY_CONST( rcp_weak2.count(), 0 );
00522   TEST_EQUALITY_CONST( rcp_weak2.strong_count(), 0 );
00523   TEST_EQUALITY_CONST( rcp_weak2.weak_count(), 1 );
00524   TEST_EQUALITY_CONST( rcp_weak2.total_count(), 1 );
00525   TEST_EQUALITY_CONST( rcp_weak2.is_valid_ptr(), false );
00526 
00527   TEST_EQUALITY_CONST( rcp_weak1.shares_resource(rcp_weak2), false );
00528 
00529   TEST_THROW( rcp_weak2.assert_valid_ptr(), DanglingReferenceError );
00530 #ifdef TEUCHOS_DEBUG
00531   TEST_THROW( rcp_weak2.operator->(), DanglingReferenceError );
00532   TEST_THROW( *rcp_weak2, DanglingReferenceError );
00533   TEST_THROW( rcp_weak2.create_weak(), DanglingReferenceError );
00534   TEST_THROW( rcp_weak2.get(), DanglingReferenceError );
00535   TEST_THROW( rcp_weak2.getRawPtr(), DanglingReferenceError );
00536   TEST_THROW( rcp_weak2(), DanglingReferenceError );
00537   TEST_THROW( rcp_weak2.release(), DanglingReferenceError );
00538 #endif // TEUCHOS_DEBUG
00539 
00540 }
00541 
00542 
00543 TEUCHOS_UNIT_TEST( RCP, weak_strong )
00544 {
00545 
00546   ECHO(RCP<A> rcp1(rcp(new A)));
00547   TEST_EQUALITY_CONST( rcp1.strength(), RCP_STRONG );
00548 
00549   ECHO(RCP<A> rcp2 = rcp1.create_weak());
00550 
00551   TEST_EQUALITY_CONST( rcp2.strength(), RCP_WEAK );
00552   TEST_EQUALITY_CONST( rcp1.strong_count(), 1 );
00553   TEST_EQUALITY_CONST( rcp1.weak_count(), 1 );
00554   TEST_EQUALITY_CONST( rcp2.strong_count(), 1 );
00555   TEST_EQUALITY_CONST( rcp2.weak_count(), 1 );
00556 
00557   ECHO(RCP<A> rcp3 = rcp2.create_strong());
00558 
00559   TEST_EQUALITY_CONST( rcp3.strength(), RCP_STRONG );
00560   TEST_EQUALITY_CONST( rcp1.strong_count(), 2 );
00561   TEST_EQUALITY_CONST( rcp1.weak_count(), 1 );
00562   TEST_EQUALITY_CONST( rcp2.strong_count(), 2 );
00563   TEST_EQUALITY_CONST( rcp2.weak_count(), 1 );
00564 
00565   // This will make the underlying object A gets deleted!
00566   ECHO(rcp1 = null);
00567   ECHO(rcp3 = null);
00568 
00569   ECHO(rcp2 = null); // Should make the underlying node go away
00570 
00571 }
00572 
00573 
00574 //
00575 // circularReference
00576 //
00577 
00578 
00579 TEUCHOS_UNIT_TEST( RCP, circularReference_a_then_c )
00580 {
00581 
00582   //TEST_EQUALITY_CONST(Teuchos::numActiveRCPNodes(), 0);
00583 
00584   {
00585 
00586     // Create objects a and c
00587 
00588     ECHO(RCP<A> a = rcp(new A));
00589     ECHO(RCP<C> c = rcp(new C));
00590 
00591     // Create a circular reference where 'a' owns 'c' strongly but 'c' only
00592     // owns 'a' weakly.
00593 
00594     ECHO(a->set_C(c));
00595     ECHO(c->set_A(a.create_weak()));
00596 
00597 #ifdef TEUCHOS_DEBUG
00598     ECHO(c->call_A_on_delete(true));
00599     // Here, we set 'c' to call 'a' when it is deleted which will result in an
00600     // exception being thrown in a call to delete.  NOTE: It is *very* bad
00601     // practice to allow exceptions to be thrown from destructors but I am
00602     // allowing it so that I can detect such bad bahavior below!
00603 #endif
00604 
00605     TEST_EQUALITY( a->call_C_f(), C_f_return );
00606     TEST_EQUALITY( c->call_A_g(), A_g_return );
00607 
00608     // Remove 'a' first and then remove 'c'.  Since 'a' is only weakly held by
00609     // 'c', this will result in 'a' being deleted right away.  In this case,
00610     // if anyone tries to access 'a' after this (like 'c' in its destructor),
00611     // then an exception will get thrown in debug mode!
00612 
00613     ECHO(a = null);
00614 
00615     // Now, remove 'c'.  In this case, since 'a' has already been deleted and
00616     // 'c' is going to try to call 'a' on its way out, this will thrown an
00617     // exception.
00618 
00619 #ifdef TEUCHOS_DEBUG
00620 
00621     TEST_THROW(c = null, DanglingReferenceError);
00622     // NOTE: Above, operator==(...) exhibits the 'strong' guarantee?
00623 
00624     // Since an exception was thrown, the 'c' object never got deleted.
00625     // Therefore, we need to disable 'c' calling 'a' on delete and the object
00626     // will get cleaned up correctly when this function exists (I hope).
00627     ECHO(c->call_A_on_delete(false));
00628 
00629     ECHO(c = null); // All memory should be cleaned up here!
00630 
00631 #endif // TEUCHOS_DEBUG
00632 
00633   }
00634 
00635 }
00636 
00637 
00638 TEUCHOS_UNIT_TEST( RCP, circularReference_c_then_a )
00639 {
00640 
00641   {
00642 
00643     // Create objects a and c
00644 
00645     ECHO(RCP<A> a = rcp(new A));
00646     ECHO(RCP<C> c = rcp(new C));
00647 
00648     // Create a circular reference where 'a' owns 'c' strongly but 'c' only
00649     // owns 'a' weakly.
00650 
00651     ECHO(a->set_C(c));
00652     ECHO(c->set_A(a.create_weak()));
00653 
00654     ECHO(c->call_A_on_delete(false));
00655     // Here, we set 'c' to not call 'a' when it is deleted.  It turns out that
00656     // the set of calls to delete and destructors that takes place is very
00657     // complex and in order to avoid trouble, an object that holds an RCP to
00658     // another object weakly should *never* try to call any members on the
00659     // wrapped object as it gets deleted!
00660     
00661     TEST_EQUALITY( a->call_C_f(), C_f_return );
00662     TEST_EQUALITY( c->call_A_g(), A_g_return );
00663 
00664     // Remove 'c' first and then remove 'a' implicitly at the end of the
00665     // block.  Since 'c' is held strongly by 'a' and since we are keeping the
00666     // strong pointer for 'a' alive, we can call functions on 'a' all we want
00667     // with no fear of accessing dead memory.
00668 
00669     ECHO(c = null);
00670 
00671     TEST_EQUALITY( a->call_C_f(), C_f_return ); // C is still alive!
00672 
00673     // Finally, when 'a' goes away implicitly, it will take 'c' with it.  In
00674     // the complex set of nested calls that take place due to the circular
00675     // reference, everything will get cleaned up correctly.  Also, if any
00676     // client code where to try to access an object as it is being deleted, an
00677     // exception will get thrown and no memory error will occur (unless an
00678     // abort(...) is called when an exception gets thrown from a destructor
00679     // when an exception is already active).
00680 
00681   }
00682 
00683 }
00684 
00685 
00686 TEUCHOS_UNIT_TEST( RCP, circularReference_self )
00687 {
00688   {
00689     // Create one 'c' object
00690     ECHO(RCP<C> c = rcp(new C));
00691     // Create a weak circular reference where 'c' points back to itself
00692     ECHO(c->set_A(c.create_weak()));
00693     // Now, try to set 'c' to null.
00694     ECHO(c = null); // All memory should be cleaned up here!
00695   }
00696 }
00697 
00698 
00699 TEUCHOS_UNIT_TEST( RCP, danglingPtr )
00700 {
00701   ECHO(RCP<A> a_rcp = rcp(new A));
00702   ECHO(Ptr<A> a_ptr = a_rcp());
00703   ECHO(A *badPtr = a_rcp.getRawPtr());
00704   ECHO(a_rcp = null);
00705 #ifdef TEUCHOS_DEBUG
00706   TEST_THROW( *a_ptr, DanglingReferenceError );
00707   (void)badPtr;
00708 #else
00709   TEST_EQUALITY( a_ptr.getRawPtr(), badPtr );
00710 #endif
00711 }
00712 
00713 
00714 #ifdef TEUCHOS_DEBUG
00715 
00716 /* ToDo: Comment this back in once I have everything working
00717 
00718 // Test that the RCPNode tracing machinary can detect if an owning RCPNode is
00719 // being created that would result in a double delete.
00720 TEUCHOS_UNIT_TEST( RCP, multiRcpCreateError )
00721 {
00722   C *c_ptr = new C;
00723 #if !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
00724   Teuchos::setTracingActiveRCPNodes(true);
00725 #endif
00726   RCP<C> c_rcp = rcp(c_ptr); // Okay
00727   RCP<C> c_rcp2;
00728   TEST_THROW(c_rcp2 = rcp(c_ptr), DuplicateOwningRCPError);
00729 #if !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
00730   Teuchos::setTracingActiveRCPNodes(false);
00731 #endif
00732   // Clean up memory so no leaks and not double deletes no matter what.
00733   c_rcp.release();
00734   c_rcp2.release();
00735   delete c_ptr;
00736 }
00737 
00738 */
00739 
00740 #endif // TEUCHOS_DEBUG
00741 
00742 
00743 //
00744 // invertObjectOwnership
00745 //
00746 
00747 
00748 RCP<C> createCAFactory()
00749 {
00750   RCP<C> c = rcp(new C);
00751   c->set_A(rcp(new A));
00752   return c;
00753 }
00754 
00755 
00756 RCP<A> createACFactory()
00757 {
00758   RCP<C> c = createCAFactory();
00759   return Teuchos::rcpWithInvertedObjOwnership(c->get_A(), c);
00760 }
00761 
00762 
00763 RCP<C> extractCFromA(const RCP<A> &a)
00764 {
00765   return Teuchos::getInvertedObjOwnershipParent<C>(a);
00766 }
00767 
00768 
00769 TEUCHOS_UNIT_TEST( RCP, invertObjectOwnership_basic )
00770 {
00771   RCP<A> a = createACFactory();
00772   RCP<C> c = extractCFromA(a);
00773   TEST_EQUALITY_CONST( a.strong_count(), 1 );
00774   TEST_EQUALITY_CONST( c->get_A().strong_count(), 3 );
00775   TEST_ASSERT( !a.shares_resource(c->get_A()) );
00776   TEST_EQUALITY( a.getRawPtr(), c->get_A().getRawPtr() );
00777   TEST_EQUALITY( a->A_g(), A_g_return );
00778   TEST_EQUALITY( c->C_g(), C_g_return );
00779 }
00780 
00781 
00782 // This unit test shows that you can remove the RCP in the C object
00783 // and the A object will still live on.
00784 TEUCHOS_UNIT_TEST( RCP, invertObjectOwnership_remove_A )
00785 {
00786   RCP<A> a = createACFactory();
00787   extractCFromA(a)->set_A(null);
00788   RCP<C> c = extractCFromA(a);
00789   TEST_EQUALITY_CONST( a.strong_count(), 1 );
00790   TEST_EQUALITY_CONST( c->get_A(), null );
00791   TEST_EQUALITY( a->A_g(), A_g_return );
00792   TEST_EQUALITY( c->C_g(), C_g_return );
00793 }
00794 
00795 
00796 //
00797 // createRCPWithBadDealloc
00798 //
00799 
00800 
00801 RCP<A> createRCPWithBadDealloc()
00802 {
00803   return rcp(new A[1]); // Will use delete but should use delete []!
00804 }
00805 
00806 
00807 template<typename T>
00808 class DeallocArrayDeleteExtraData {
00809 public:
00810   static RCP<DeallocArrayDeleteExtraData<T> > create(T *ptr)
00811     { return rcp(new DeallocArrayDeleteExtraData(ptr)); }
00812   ~DeallocArrayDeleteExtraData() { delete [] ptr_; }
00813 private:
00814   T *ptr_;
00815   DeallocArrayDeleteExtraData(T *ptr) : ptr_(ptr) {}
00816   // Not defined!
00817   DeallocArrayDeleteExtraData();
00818   DeallocArrayDeleteExtraData(const DeallocArrayDeleteExtraData&);
00819   DeallocArrayDeleteExtraData& operator=(const DeallocArrayDeleteExtraData&);
00820 };
00821 
00822 
00823 // This unit test shows how you can use extra data to fix a bad deallocation
00824 // policy
00825 TEUCHOS_UNIT_TEST( RCP, Fix_createRCPWithBadDealloc )
00826 {
00827   using Teuchos::inOutArg;
00828   using Teuchos::set_extra_data;
00829   // Create object with bad deallocator
00830   RCP<A> a = createRCPWithBadDealloc();
00831   TEST_ASSERT(nonnull(a));
00832   // Disable default (incorrect) dealloc and set a new deallocation policy as extra data!
00833   a.release();
00834   set_extra_data( DeallocArrayDeleteExtraData<A>::create(a.getRawPtr()), "dealloc",
00835     inOutArg(a));
00836 }
00837 
00838 
00839 //
00840 // Template Instantiations
00841 //
00842 
00843 
00844 #ifdef TEUCHOS_DEBUG
00845 
00846 #  define DEBUG_UNIT_TEST_GROUP( T ) \
00847 
00848 #else
00849 
00850 #  define DEBUG_UNIT_TEST_GROUP( T )
00851 
00852 #endif
00853 
00854 
00855 #define UNIT_TEST_GROUP( T ) \
00856   TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( RCP, weakDelete, T ) \
00857   DEBUG_UNIT_TEST_GROUP(T)
00858 
00859 
00860 UNIT_TEST_GROUP(A)
00861 UNIT_TEST_GROUP(C)
00862 UNIT_TEST_GROUP(D)
00863 UNIT_TEST_GROUP(E)
00864 
00865 
00866 } // namespace
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Wed Apr 13 09:57:28 2011 for Teuchos Package Browser (Single Doxygen Collection) by  doxygen 1.6.3