diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/tests/llinstancetracker_test.cpp | 62 | 
1 files changed, 62 insertions, 0 deletions
| diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index 294e21bac5..454695ff9f 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -35,6 +35,7 @@  #include <vector>  #include <set>  #include <algorithm>                // std::sort() +#include <stdexcept>  // std headers  // external library headers  #include <boost/scoped_ptr.hpp> @@ -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, std::string>  {      Keyed(const std::string& name): @@ -53,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); +        } +    }  };  /***************************************************************************** @@ -234,4 +251,49 @@ namespace tut          }          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); +        } +        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 | 
