diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/llsingleton.h | 30 | ||||
| -rw-r--r-- | indra/llcommon/tests/lleventcoro_test.cpp | 33 | ||||
| -rw-r--r-- | indra/llcommon/tests/lleventdispatcher_test.cpp | 83 | ||||
| -rw-r--r-- | indra/llcommon/tests/lleventfilter_test.cpp | 12 | ||||
| -rw-r--r-- | indra/llcommon/tests/llinstancetracker_test.cpp | 33 | ||||
| -rw-r--r-- | indra/llcommon/tests/lllazy_test.cpp | 13 | ||||
| -rw-r--r-- | indra/llcommon/tests/llleap_test.cpp | 20 | ||||
| -rw-r--r-- | indra/llcommon/tests/llprocess_test.cpp | 16 | ||||
| -rw-r--r-- | indra/llcommon/tests/llsingleton_test.cpp | 129 | ||||
| -rw-r--r-- | indra/llcommon/tests/wrapllerrs.h | 26 | 
10 files changed, 232 insertions, 163 deletions
| diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 9be02f7e7d..596a2388a1 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -491,9 +491,6 @@ typename LLSingleton<T>::SingletonData LLSingleton<T>::sData;   * * However, distinct initParamSingleton() calls can be used to engage   *   different constructors, as long as only one such call is executed at   *   runtime. - * * Circularity is not permitted. No LLSingleton referenced by an - *   LLParamSingleton's constructor or initSingleton() method may call this - *   LLParamSingleton's instance() or getInstance() methods.   * * Unlike LLSingleton, an LLParamSingleton cannot be "revived" by an   *   instance() or getInstance() call after deleteSingleton().   * @@ -508,7 +505,6 @@ private:  public:      using super::deleteSingleton; -    using super::instance;      using super::instanceExists;      using super::wasDeleted; @@ -519,7 +515,7 @@ public:          // In case racing threads both call initParamSingleton() at the same          // time, serialize them. One should initialize; the other should see          // mInitState already set. -        std::unique_lock<std::mutex> lk(mMutex); +        std::unique_lock<decltype(mMutex)> lk(mMutex);          // For organizational purposes this function shouldn't be called twice          if (super::sData.mInitState != super::UNINITIALIZED)          { @@ -539,7 +535,7 @@ public:      {          // In case racing threads call getInstance() at the same moment as          // initParamSingleton(), serialize the calls. -        std::unique_lock<std::mutex> lk(mMutex); +        std::unique_lock<decltype(mMutex)> lk(mMutex);          switch (super::sData.mInitState)          { @@ -551,15 +547,10 @@ public:          case super::CONSTRUCTING:              super::logerrs("Tried to access param singleton ",                             super::demangle(typeid(DERIVED_TYPE).name()).c_str(), -                " from singleton constructor!"); +                           " from singleton constructor!");              break;          case super::INITIALIZING: -            super::logerrs("Tried to access param singleton ", -                           super::demangle(typeid(DERIVED_TYPE).name()).c_str(), -                           " from initSingleton() method!"); -            break; -          case super::INITIALIZED:              return super::sData.mInstance; @@ -574,12 +565,23 @@ public:          return nullptr;      } +    // instance() is replicated here so it calls +    // LLParamSingleton::getInstance() rather than LLSingleton::getInstance() +    // -- avoid making getInstance() virtual +    static DERIVED_TYPE& instance() +    { +        return *getInstance(); +    } +  private: -    static std::mutex mMutex; +    // Use a recursive_mutex in case of constructor circularity. With a +    // non-recursive mutex, that would result in deadlock rather than the +    // logerrs() call coded above. +    static std::recursive_mutex mMutex;  };  template<typename T> -typename std::mutex LLParamSingleton<T>::mMutex; +typename std::recursive_mutex LLParamSingleton<T>::mMutex;  /**   * Initialization locked singleton, only derived class can decide when to initialize. diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index a459d17fb8..fa02d2bb1a 100644 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -506,16 +506,10 @@ namespace tut              replyName = waiter.getName0();              errorName = waiter.getName1();              WrapLLErrs capture; -            try -            { -                result = waiter.suspendWithLog(); -                debug("no exception"); -            } -            catch (const WrapLLErrs::FatalException& e) -            { -                debug(STRINGIZE("exception " << e.what())); -                threw = e.what(); -            } +            threw = capture.catch_llerrs([&waiter, &debug](){ +                    result = waiter.suspendWithLog(); +                    debug("no exception"); +                });          }          END      } @@ -762,18 +756,13 @@ namespace tut          {              LLCoroEventPumps waiter;              WrapLLErrs capture; -            try -            { -                result = waiter.postAndSuspendWithLog( -                    LLSDMap("value", 31)("fail", LLSD()), -                    immediateAPI.getPump(), "reply", "error"); -                debug("no exception"); -            } -            catch (const WrapLLErrs::FatalException& e) -            { -                debug(STRINGIZE("exception " << e.what())); -                threw = e.what(); -            } +            threw = capture.catch_llerrs( +                [&waiter, &debug](){ +                    result = waiter.postAndSuspendWithLog( +                        LLSDMap("value", 31)("fail", LLSD()), +                        immediateAPI.getPump(), "reply", "error"); +                    debug("no exception"); +                });          }          END      } diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 5a4df81bf1..a181d5c941 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -22,6 +22,7 @@  #include "llsdutil.h"  #include "stringize.h"  #include "tests/wrapllerrs.h" +#include "../test/catch_and_store_what_in.h"  #include <map>  #include <string> @@ -630,16 +631,9 @@ namespace tut          void call_exc(const std::string& func, const LLSD& args, const std::string& exc_frag)          { -            std::string threw; -            try -            { -                work(func, args); -            } -            catch (const std::runtime_error& e) -            { -                cout << "*** " << e.what() << '\n'; -                threw = e.what(); -            } +            std::string threw = catch_what<std::runtime_error>([this, &func, &args](){ +                    work(func, args); +                });              ensure_has(threw, exc_frag);          } @@ -717,15 +711,9 @@ namespace tut          LLSD attempts(LLSDArray(17)(LLSDMap("pi", 3.14)("two", 2)));          foreach(LLSD ae, inArray(attempts))          { -            std::string threw; -            try -            { -                work.add("freena_err", "freena", freena, ae); -            } -            catch (const std::exception& e) -            { -                threw = e.what(); -            } +            std::string threw = catch_what<std::exception>([this, &ae](){ +                    work.add("freena_err", "freena", freena, ae); +                });              ensure_has(threw, "must be an array");          }      } @@ -734,15 +722,9 @@ namespace tut      void object::test<2>()      {          set_test_name("map-style registration with badly-formed defaults"); -        std::string threw; -        try -        { -            work.add("freena_err", "freena", freena, LLSDArray("a")("b"), 17); -        } -        catch (const std::exception& e) -        { -            threw = e.what(); -        } +        std::string threw = catch_what<std::exception>([this](){ +                work.add("freena_err", "freena", freena, LLSDArray("a")("b"), 17); +            });          ensure_has(threw, "must be a map or an array");      } @@ -750,17 +732,11 @@ namespace tut      void object::test<3>()      {          set_test_name("map-style registration with too many array defaults"); -        std::string threw; -        try -        { -            work.add("freena_err", "freena", freena, -                     LLSDArray("a")("b"), -                     LLSDArray(17)(0.9)("gack")); -        } -        catch (const std::exception& e) -        { -            threw = e.what(); -        } +        std::string threw = catch_what<std::exception>([this](){ +                work.add("freena_err", "freena", freena, +                         LLSDArray("a")("b"), +                         LLSDArray(17)(0.9)("gack")); +            });          ensure_has(threw, "shorter than");      } @@ -768,17 +744,11 @@ namespace tut      void object::test<4>()      {          set_test_name("map-style registration with too many map defaults"); -        std::string threw; -        try -        { -            work.add("freena_err", "freena", freena, -                     LLSDArray("a")("b"), -                     LLSDMap("b", 17)("foo", 3.14)("bar", "sinister")); -        } -        catch (const std::exception& e) -        { -            threw = e.what(); -        } +        std::string threw = catch_what<std::exception>([this](){ +                work.add("freena_err", "freena", freena, +                         LLSDArray("a")("b"), +                         LLSDMap("b", 17)("foo", 3.14)("bar", "sinister")); +            });          ensure_has(threw, "nonexistent params");          ensure_has(threw, "foo");          ensure_has(threw, "bar"); @@ -1039,16 +1009,9 @@ namespace tut          // We don't have a comparable helper function for the one-arg          // operator() method, and it's not worth building one just for this          // case. Write it out. -        std::string threw; -        try -        { -            work(LLSDMap("op", "freek")); -        } -        catch (const std::runtime_error& e) -        { -            cout << "*** " << e.what() << "\n"; -            threw = e.what(); -        } +        std::string threw = catch_what<std::runtime_error>([this](){ +                work(LLSDMap("op", "freek")); +            });          ensure_has(threw, "bad");          ensure_has(threw, "op");          ensure_has(threw, "freek"); diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp index eb98b12ef5..1875013794 100644 --- a/indra/llcommon/tests/lleventfilter_test.cpp +++ b/indra/llcommon/tests/lleventfilter_test.cpp @@ -350,15 +350,9 @@ namespace tut          // Now let the timer expire.          filter.forceTimeout();          // Notice the timeout. -        std::string threw; -        try -        { -            mainloop.post(17); -        } -        catch (const WrapLLErrs::FatalException& e) -        { -            threw = e.what(); -        } +        std::string threw = capture.catch_llerrs([this](){ +                mainloop.post(17); +            });          ensure_contains("errorAfter() timeout exception", threw, "timeout");          // Timing out cancels the timer. Verify that.          listener0.reset(0); diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index c7d4b8a06b..d94fc0c56d 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -198,14 +198,9 @@ namespace tut          {              WrapLLErrs wrapper;              Keyed::instance_iter i(Keyed::beginInstances()); -            try -            { -                delete keyed; -            } -            catch (const WrapLLErrs::FatalException& e) -            { -                what = e.what(); -            } +            what = wrapper.catch_llerrs([&keyed](){ +                    delete keyed; +                });          }          ensure(! what.empty());      } @@ -219,14 +214,9 @@ namespace tut          {              WrapLLErrs wrapper;              Keyed::key_iter i(Keyed::beginKeys()); -            try -            { -                delete keyed; -            } -            catch (const WrapLLErrs::FatalException& e) -            { -                what = e.what(); -            } +            what = wrapper.catch_llerrs([&keyed](){ +                    delete keyed; +                });          }          ensure(! what.empty());      } @@ -240,14 +230,9 @@ namespace tut          {              WrapLLErrs wrapper;              Unkeyed::instance_iter i(Unkeyed::beginInstances()); -            try -            { -                delete unkeyed; -            } -            catch (const WrapLLErrs::FatalException& e) -            { -                what = e.what(); -            } +            what = wrapper.catch_llerrs([&unkeyed](){ +                    delete unkeyed; +                });          }          ensure(! what.empty());      } diff --git a/indra/llcommon/tests/lllazy_test.cpp b/indra/llcommon/tests/lllazy_test.cpp index 32a717f4fc..542306ee22 100644 --- a/indra/llcommon/tests/lllazy_test.cpp +++ b/indra/llcommon/tests/lllazy_test.cpp @@ -38,6 +38,7 @@  #include <boost/lambda/bind.hpp>  // other Linden headers  #include "../test/lltut.h" +#include "../test/catch_and_store_what_in.h"  namespace bll = boost::lambda; @@ -200,15 +201,9 @@ namespace tut      void lllazy_object::test<2>()      {          TestNeedsTesting tnt; -        std::string threw; -        try -        { -            tnt.toolate(); -        } -        catch (const LLLazyCommon::InstanceChange& e) -        { -            threw = e.what(); -        } +        std::string threw = catch_what<LLLazyCommon::InstanceChange>([&tnt](){ +                tnt.toolate(); +            });          ensure_contains("InstanceChange exception", threw, "replace LLLazy instance");      } diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 45648536c4..bf0a74d10d 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -23,7 +23,7 @@  #include "../test/lltut.h"  #include "../test/namedtempfile.h"  #include "../test/catch_and_store_what_in.h" -#include "wrapllerrs.h" +#include "wrapllerrs.h"             // CaptureLog  #include "llevents.h"  #include "llprocess.h"  #include "llstring.h" @@ -290,12 +290,9 @@ namespace tut      void object::test<6>()      {          set_test_name("empty plugin vector"); -        std::string threw; -        try -        { -            LLLeap::create("empty", StringVec()); -        } -        CATCH_AND_STORE_WHAT_IN(threw, LLLeap::Error) +        std::string threw = catch_what<LLLeap::Error>([](){ +                LLLeap::create("empty", StringVec()); +            });          ensure_contains("LLLeap::Error", threw, "no plugin");          // try the suppress-exception variant          ensure("bad launch returned non-NULL", ! LLLeap::create("empty", StringVec(), false)); @@ -308,12 +305,9 @@ namespace tut          // Synthesize bogus executable name          std::string BADPYTHON(PYTHON.substr(0, PYTHON.length()-1) + "x");          CaptureLog log; -        std::string threw; -        try -        { -            LLLeap::create("bad exe", BADPYTHON); -        } -        CATCH_AND_STORE_WHAT_IN(threw, LLLeap::Error) +        std::string threw = catch_what<LLLeap::Error>([&BADPYTHON](){ +                LLLeap::create("bad exe", BADPYTHON); +            });          ensure_contains("LLLeap::create() didn't throw", threw, "failed");          log.messageWith("failed");          log.messageWith(BADPYTHON); diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index 5c87cdabd9..222d832084 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -25,8 +25,6 @@  #include <boost/function.hpp>  #include <boost/algorithm/string/find_iterator.hpp>  #include <boost/algorithm/string/finder.hpp> -//#include <boost/lambda/lambda.hpp> -//#include <boost/lambda/bind.hpp>  // other Linden headers  #include "../test/lltut.h"  #include "../test/namedtempfile.h" @@ -35,7 +33,7 @@  #include "llsdutil.h"  #include "llevents.h"  #include "llstring.h" -#include "wrapllerrs.h" +#include "wrapllerrs.h"             // CaptureLog  #if defined(LL_WINDOWS)  #define sleep(secs) _sleep((secs) * 1000) @@ -45,8 +43,7 @@  #include <sys/wait.h>  #endif -//namespace lambda = boost::lambda; - std::string apr_strerror_helper(apr_status_t rv) +std::string apr_strerror_helper(apr_status_t rv)  {      char errbuf[256];      apr_strerror(rv, errbuf, sizeof(errbuf)); @@ -960,12 +957,9 @@ namespace tut  #define CATCH_IN(THREW, EXCEPTION, CODE)                                \      do                                                                  \      {                                                                   \ -        (THREW).clear();                                                \ -        try                                                             \ -        {                                                               \ -            CODE;                                                       \ -        }                                                               \ -        CATCH_AND_STORE_WHAT_IN(THREW, EXCEPTION)                       \ +        (THREW) = catch_what<EXCEPTION>([&](){                          \ +                CODE;                                                   \ +            });                                                         \          ensure("failed to throw " #EXCEPTION ": " #CODE, ! (THREW).empty()); \      } while (0) diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp index 56886bc73f..da7bc6355c 100644 --- a/indra/llcommon/tests/llsingleton_test.cpp +++ b/indra/llcommon/tests/llsingleton_test.cpp @@ -29,7 +29,8 @@  #include "llsingleton.h"  #include "../test/lltut.h" - +#include "wrapllerrs.h" +#include "llsd.h"  // Capture execution sequence by appending to log string.  std::string sLog; @@ -198,4 +199,130 @@ namespace tut      TESTS(A, B, 4, 5, 6, 7)      TESTS(B, A, 8, 9, 10, 11) + +#define PARAMSINGLETON(cls)                                             \ +    class cls: public LLParamSingleton<cls>                             \ +    {                                                                   \ +        LLSINGLETON(cls, const LLSD::String& str): mDesc(str) {}        \ +        cls(LLSD::Integer i): mDesc(i) {}                               \ +                                                                        \ +    public:                                                             \ +        std::string desc() const { return mDesc.asString(); }           \ +                                                                        \ +    private:                                                            \ +        LLSD mDesc;                                                     \ +    } + +    // Declare two otherwise-identical LLParamSingleton classes so we can +    // validly initialize each using two different constructors. If we tried +    // to test that with a single LLParamSingleton class within the same test +    // program, we'd get 'trying to use deleted LLParamSingleton' errors. +    PARAMSINGLETON(PSing1); +    PARAMSINGLETON(PSing2); + +    template<> template<> +    void singleton_object_t::test<12>() +    { +        set_test_name("LLParamSingleton"); + +        WrapLLErrs catcherr; +        // query methods +        ensure("false positive on instanceExists()", ! PSing1::instanceExists()); +        ensure("false positive on wasDeleted()", ! PSing1::wasDeleted()); +        // try to reference before initializing +        std::string threw = catcherr.catch_llerrs([](){ +                (void)PSing1::instance(); +            }); +        ensure_contains("too-early instance() didn't throw", threw, "Uninitialized"); +        // getInstance() behaves the same as instance() +        threw = catcherr.catch_llerrs([](){ +                (void)PSing1::getInstance(); +            }); +        ensure_contains("too-early getInstance() didn't throw", threw, "Uninitialized"); +        // initialize using LLSD::String constructor +        PSing1::initParamSingleton("string"); +        ensure_equals(PSing1::instance().desc(), "string"); +        ensure("false negative on instanceExists()", PSing1::instanceExists()); +        // try to initialize again +        threw = catcherr.catch_llerrs([](){ +                PSing1::initParamSingleton("again"); +            }); +        ensure_contains("second ctor(string) didn't throw", threw, "twice"); +        // try to initialize using the other constructor -- should be +        // well-formed, but illegal at runtime +        threw = catcherr.catch_llerrs([](){ +                PSing1::initParamSingleton(17); +            }); +        ensure_contains("other ctor(int) didn't throw", threw, "twice"); +        PSing1::deleteSingleton(); +        ensure("false negative on wasDeleted()", PSing1::wasDeleted()); +        threw = catcherr.catch_llerrs([](){ +                (void)PSing1::instance(); +            }); +        ensure_contains("accessed deleted LLParamSingleton", threw, "deleted"); +    } + +    template<> template<> +    void singleton_object_t::test<13>() +    { +        set_test_name("LLParamSingleton alternate ctor"); + +        WrapLLErrs catcherr; +        // We don't have to restate all the tests for PSing1. Only test validly +        // using the other constructor. +        PSing2::initParamSingleton(17); +        ensure_equals(PSing2::instance().desc(), "17"); +        // can't do it twice +        std::string threw = catcherr.catch_llerrs([](){ +                PSing2::initParamSingleton(34); +            }); +        ensure_contains("second ctor(int) didn't throw", threw, "twice"); +        // can't use the other constructor either +        threw = catcherr.catch_llerrs([](){ +                PSing2::initParamSingleton("string"); +            }); +        ensure_contains("other ctor(string) didn't throw", threw, "twice"); +    } + +    class CircularPCtor: public LLParamSingleton<CircularPCtor> +    { +        LLSINGLETON(CircularPCtor) +        { +            // never mind indirection, just go straight for the circularity +            (void)instance(); +        } +    }; + +    template<> template<> +    void singleton_object_t::test<14>() +    { +        set_test_name("Circular LLParamSingleton constructor"); +        WrapLLErrs catcherr; +        std::string threw = catcherr.catch_llerrs([](){ +                CircularPCtor::initParamSingleton(); +            }); +        ensure_contains("constructor circularity didn't throw", threw, "constructor"); +    } + +    class CircularPInit: public LLParamSingleton<CircularPInit> +    { +        LLSINGLETON_EMPTY_CTOR(CircularPInit); +    public: +        virtual void initSingleton() +        { +            // never mind indirection, just go straight for the circularity +            (void)instance(); +        } +    }; + +    template<> template<> +    void singleton_object_t::test<15>() +    { +        set_test_name("Circular LLParamSingleton initSingleton()"); +        WrapLLErrs catcherr; +        std::string threw = catcherr.catch_llerrs([](){ +                CircularPInit::initParamSingleton(); +            }); +        ensure("initSingleton() circularity threw", threw.empty()); +    }  } diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index 08fbf19b1c..b07d5afbd8 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -37,6 +37,7 @@  #include "llerrorcontrol.h"  #include "llexception.h"  #include "stringize.h" +#include "../test/catch_and_store_what_in.h"  #include <boost/bind.hpp>  #include <boost/noncopyable.hpp>  #include <boost/shared_ptr.hpp> @@ -81,6 +82,31 @@ struct WrapLLErrs          LLTHROW(FatalException(message));      } +    /// Convenience wrapper for catch_what<FatalException>() +    // +    // The implementation makes it clear that this function need not be a +    // member; it could easily be a free function. It is a member because it +    // makes no sense to attempt to catch FatalException unless there is a +    // WrapLLErrs instance in scope. Without a live WrapLLErrs instance, any +    // LL_ERRS() reached by code within 'func' would terminate the test +    // program instead of throwing FatalException. +    // +    // We were tempted to introduce a free function, likewise accepting +    // arbitrary 'func', that would instantiate WrapLLErrs and then call +    // catch_llerrs() on that instance. We decided against it, for this +    // reason: on extending a test function containing a single call to that +    // free function, a maintainer would most likely make additional calls to +    // that free function, instead of switching to an explicit WrapLLErrs +    // declaration with several calls to its catch_llerrs() member function. +    // Even a construct such as WrapLLErrs().catch_llerrs(...) would make the +    // object declaration more visible; it's not unreasonable to expect a +    // maintainer to extend that by naming and reusing the WrapLLErrs instance. +    template <typename FUNC> +    std::string catch_llerrs(FUNC func) +    { +        return catch_what<FatalException>(func); +    } +      std::string error;      LLError::SettingsStoragePtr mPriorErrorSettings;      LLError::FatalFunction mPriorFatal; | 
