From c0318d1bf988217e1fbb0593d03c4f0235a13ea3 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 27 Feb 2012 11:50:47 -0500 Subject: Make LLInstanceTracker::getInstance(T*) validate passed T*. For the T* specialization (no string, or whatever, key), the original getInstance() method simply returned the passed-in T* value. It was defined, as the comments noted, for completeness of the analogy with the keyed LLInstanceTracker specialization. It turns out, though, that getInstance(T*) can still be useful to ask whether the T* you have in hand still references a valid T instance. Support that usage. --- indra/llcommon/tests/llinstancetracker_test.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'indra/llcommon/tests/llinstancetracker_test.cpp') diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index b34d1c5fd3..294e21bac5 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -95,6 +95,7 @@ namespace tut void object::test<2>() { ensure_equals(Unkeyed::instanceCount(), 0); + Unkeyed* dangling = NULL; { Unkeyed one; ensure_equals(Unkeyed::instanceCount(), 1); @@ -107,7 +108,11 @@ namespace tut ensure_equals(found, two.get()); } ensure_equals(Unkeyed::instanceCount(), 1); - } + // store an unwise pointer to a temp Unkeyed instance + dangling = &one; + } // make that instance vanish + // check the now-invalid pointer to the destroyed instance + ensure("getInstance(T*) failed to track destruction", ! Unkeyed::getInstance(dangling)); ensure_equals(Unkeyed::instanceCount(), 0); } -- cgit v1.2.3 From 6f53796ccf4dc29368920a322baeaceb3fd2266f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 27 Feb 2012 14:47:40 -0500 Subject: Add LLInstanceTracker test for exception in subclass constructor. We want to verify the sequence: LLInstanceTracker constructor adds instance to underlying container Subclass constructor throws exception LLInstanceTracker destructor removes instance from underlying container. --- indra/llcommon/tests/llinstancetracker_test.cpp | 62 +++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'indra/llcommon/tests/llinstancetracker_test.cpp') diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index b34d1c5fd3..fda932c355 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -35,6 +35,7 @@ #include #include #include // std::sort() +#include // std headers // external library headers #include @@ -42,6 +43,11 @@ #include "../test/lltut.h" #include "wrapllerrs.h" +struct Badness: public std::runtime_error +{ + Badness(const std::string& what): std::runtime_error(what) {} +}; + struct Keyed: public LLInstanceTracker { Keyed(const std::string& name): @@ -53,6 +59,17 @@ struct Keyed: public LLInstanceTracker struct Unkeyed: public LLInstanceTracker { + Unkeyed(const std::string& thrw="") + { + // LLInstanceTracker should respond appropriately if a subclass + // constructor throws an exception. Specifically, it should run + // LLInstanceTracker's destructor and remove itself from the + // underlying container. + if (! thrw.empty()) + { + throw Badness(thrw); + } + } }; /***************************************************************************** @@ -229,4 +246,49 @@ namespace tut } ensure(! what.empty()); } + + template<> template<> + void object::test<8>() + { + set_test_name("exception in subclass ctor"); + typedef std::set InstanceSet; + InstanceSet existing; + // We can't use the iterator-range InstanceSet constructor because + // beginInstances() returns an iterator that dereferences to an + // Unkeyed&, not an Unkeyed*. + for (Unkeyed::instance_iter uki(Unkeyed::beginInstances()), + ukend(Unkeyed::endInstances()); + uki != ukend; ++uki) + { + existing.insert(&*uki); + } + Unkeyed* puk = NULL; + try + { + // We don't expect the assignment to take place because we expect + // Unkeyed to respond to the non-empty string param by throwing. + // We know the LLInstanceTracker base-class constructor will have + // run before Unkeyed's constructor, therefore the new instance + // will have added itself to the underlying set. The whole + // question is, when Unkeyed's constructor throws, will + // LLInstanceTracker's destructor remove it from the set? I + // realize we're testing the C++ implementation more than + // Unkeyed's implementation, but this seems an important point to + // nail down. + puk = new Unkeyed("throw"); + } + catch (const Badness&) + { + } + // Ensure that every member of the new, updated set of Unkeyed + // instances was also present in the original set. If that's not true, + // it's because our new Unkeyed ended up in the updated set despite + // its constructor exception. + for (Unkeyed::instance_iter uki(Unkeyed::beginInstances()), + ukend(Unkeyed::endInstances()); + uki != ukend; ++uki) + { + ensure("failed to remove instance", existing.find(&*uki) != existing.end()); + } + } } // namespace tut -- cgit v1.2.3