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