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