diff options
Diffstat (limited to 'indra/llcommon/tests/llinstancetracker_test.cpp')
-rwxr-xr-x[-rw-r--r--] | indra/llcommon/tests/llinstancetracker_test.cpp | 176 |
1 files changed, 154 insertions, 22 deletions
diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index 4bb3ec2922..c7d4b8a06b 100644..100755 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -4,8 +4,25 @@ * @date 2009-11-10 * @brief Test for llinstancetracker. * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * Copyright (c) 2009, Linden Research, Inc. + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -18,11 +35,18 @@ #include <vector> #include <set> #include <algorithm> // std::sort() +#include <stdexcept> // std headers // external library headers #include <boost/scoped_ptr.hpp> // other Linden headers #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, std::string> { @@ -35,6 +59,17 @@ struct Keyed: public LLInstanceTracker<Keyed, std::string> struct Unkeyed: public LLInstanceTracker<Unkeyed> { + 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); + } + } }; /***************************************************************************** @@ -77,6 +112,7 @@ namespace tut void object::test<2>() { ensure_equals(Unkeyed::instanceCount(), 0); + Unkeyed* dangling = NULL; { Unkeyed one; ensure_equals(Unkeyed::instanceCount(), 1); @@ -89,7 +125,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); } @@ -134,33 +174,125 @@ namespace tut { Unkeyed one, two, three; typedef std::set<Unkeyed*> KeySet; - KeySet keys; - keys.insert(&one); - keys.insert(&two); - keys.insert(&three); - { - Unkeyed::LLInstanceTrackerScopedGuard guard; - for (Unkeyed::key_iter ki(guard.beginKeys()), kend(guard.endKeys()); - ki != kend; ++ki) - { - ensure_equals("spurious key", keys.erase(*ki), 1); - } - } - ensure_equals("unreported key", keys.size(), 0); - + KeySet instances; instances.insert(&one); instances.insert(&two); instances.insert(&three); - { - Unkeyed::LLInstanceTrackerScopedGuard guard; - for (Unkeyed::instance_iter ii(guard.beginInstances()), iend(guard.endInstances()); - ii != iend; ++ii) + + for (Unkeyed::instance_iter ii(Unkeyed::beginInstances()), iend(Unkeyed::endInstances()); ii != iend; ++ii) { Unkeyed& ref = *ii; ensure_equals("spurious instance", instances.erase(&ref), 1); } - } + ensure_equals("unreported instance", instances.size(), 0); } + + template<> template<> + void object::test<5>() + { + set_test_name("delete Keyed with outstanding instance_iter"); + std::string what; + Keyed* keyed = new Keyed("delete Keyed with outstanding instance_iter"); + { + WrapLLErrs wrapper; + Keyed::instance_iter i(Keyed::beginInstances()); + try + { + delete keyed; + } + catch (const WrapLLErrs::FatalException& e) + { + what = e.what(); + } + } + ensure(! what.empty()); + } + + template<> template<> + void object::test<6>() + { + set_test_name("delete Keyed with outstanding key_iter"); + std::string what; + Keyed* keyed = new Keyed("delete Keyed with outstanding key_it"); + { + WrapLLErrs wrapper; + Keyed::key_iter i(Keyed::beginKeys()); + try + { + delete keyed; + } + catch (const WrapLLErrs::FatalException& e) + { + what = e.what(); + } + } + ensure(! what.empty()); + } + + template<> template<> + void object::test<7>() + { + set_test_name("delete Unkeyed with outstanding instance_iter"); + std::string what; + Unkeyed* unkeyed = new Unkeyed; + { + WrapLLErrs wrapper; + Unkeyed::instance_iter i(Unkeyed::beginInstances()); + try + { + delete unkeyed; + } + catch (const WrapLLErrs::FatalException& e) + { + what = e.what(); + } + } + ensure(! what.empty()); + } + + template<> template<> + void object::test<8>() + { + set_test_name("exception in subclass ctor"); + typedef std::set<Unkeyed*> 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); + } + 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. + 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 |