diff options
| author | Nat Goodspeed <nat@lindenlab.com> | 2016-08-30 11:36:06 -0400 | 
|---|---|---|
| committer | Nat Goodspeed <nat@lindenlab.com> | 2016-08-30 11:36:06 -0400 | 
| commit | c92eb7e59198d37698c70b5e3be50503f5174cf3 (patch) | |
| tree | b8c55c54ccb097c84300e717bbbef5f63650751b /indra/llcommon/tests | |
| parent | 4fb100ac7a33174883184f1320d0beac08ead3a7 (diff) | |
| parent | 11c428759e0b99fc34e219181d81d024b0323b4d (diff) | |
Automated merge with ssh://bitbucket.org/lindenlab/viewer-release
Diffstat (limited to 'indra/llcommon/tests')
| -rw-r--r-- | indra/llcommon/tests/llpounceable_test.cpp | 230 | ||||
| -rw-r--r-- | indra/llcommon/tests/llsingleton_test.cpp | 206 | 
2 files changed, 395 insertions, 41 deletions
diff --git a/indra/llcommon/tests/llpounceable_test.cpp b/indra/llcommon/tests/llpounceable_test.cpp new file mode 100644 index 0000000000..2f4915ce11 --- /dev/null +++ b/indra/llcommon/tests/llpounceable_test.cpp @@ -0,0 +1,230 @@ +/** + * @file   llpounceable_test.cpp + * @author Nat Goodspeed + * @date   2015-05-22 + * @brief  Test for llpounceable. + *  + * $LicenseInfo:firstyear=2015&license=viewerlgpl$ + * Copyright (c) 2015, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llpounceable.h" +// STL headers +// std headers +// external library headers +#include <boost/bind.hpp> +// other Linden headers +#include "../test/lltut.h" + +/*----------------------------- string testing -----------------------------*/ +void append(std::string* dest, const std::string& src) +{ +    dest->append(src); +} + +/*-------------------------- Data-struct testing ---------------------------*/ +struct Data +{ +    Data(const std::string& data): +        mData(data) +    {} +    const std::string mData; +}; + +void setter(Data** dest, Data* ptr) +{ +    *dest = ptr; +} + +static Data* static_check = 0; + +// Set up an extern pointer to an LLPounceableStatic so the linker will fill +// in the forward reference from below, before runtime. +extern LLPounceable<Data*, LLPounceableStatic> gForward; + +struct EnqueueCall +{ +    EnqueueCall() +    { +        // Intentionally use a forward reference to an LLPounceableStatic that +        // we believe is NOT YET CONSTRUCTED. This models the scenario in +        // which a constructor in another translation unit runs before +        // constructors in this one. We very specifically want callWhenReady() +        // to work even in that case: we need the LLPounceableQueueImpl to be +        // initialized even if the LLPounceable itself is not. +        gForward.callWhenReady(boost::bind(setter, &static_check, _1)); +    } +} nqcall; +// When this declaration is processed, we should enqueue the +// setter(&static_check, _1) call for when gForward is set non-NULL. Needless +// to remark, we want this call not to crash. + +// Now declare gForward. Its constructor should not run until after nqcall's. +LLPounceable<Data*, LLPounceableStatic> gForward; + +/***************************************************************************** +*   TUT +*****************************************************************************/ +namespace tut +{ +    struct llpounceable_data +    { +    }; +    typedef test_group<llpounceable_data> llpounceable_group; +    typedef llpounceable_group::object object; +    llpounceable_group llpounceablegrp("llpounceable"); + +    template<> template<> +    void object::test<1>() +    { +        set_test_name("LLPounceableStatic out-of-order test"); +        // LLPounceable<T, LLPounceableStatic>::callWhenReady() must work even +        // before LLPounceable's constructor runs. That's the whole point of +        // implementing it with an LLSingleton queue. This models (say) +        // LLPounceableStatic<LLMessageSystem*, LLPounceableStatic>. +        ensure("static_check should still be null", ! static_check); +        Data myData("test<1>"); +        gForward = &myData;         // should run setter +        ensure_equals("static_check should be &myData", static_check, &myData); +    } + +    template<> template<> +    void object::test<2>() +    { +        set_test_name("LLPounceableQueue different queues"); +        // We expect that LLPounceable<T, LLPounceableQueue> should have +        // different queues because that specialization stores the queue +        // directly in the LLPounceable instance. +        Data *aptr = 0, *bptr = 0; +        LLPounceable<Data*> a, b; +        a.callWhenReady(boost::bind(setter, &aptr, _1)); +        b.callWhenReady(boost::bind(setter, &bptr, _1)); +        ensure("aptr should be null", ! aptr); +        ensure("bptr should be null", ! bptr); +        Data adata("a"), bdata("b"); +        a = &adata; +        ensure_equals("aptr should be &adata", aptr, &adata); +        // but we haven't yet set b +        ensure("bptr should still be null", !bptr); +        b = &bdata; +        ensure_equals("bptr should be &bdata", bptr, &bdata); +    } + +    template<> template<> +    void object::test<3>() +    { +        set_test_name("LLPounceableStatic different queues"); +        // LLPounceable<T, LLPounceableStatic> should also have a distinct +        // queue for each instance, but that engages an additional map lookup +        // because there's only one LLSingleton for each T. +        Data *aptr = 0, *bptr = 0; +        LLPounceable<Data*, LLPounceableStatic> a, b; +        a.callWhenReady(boost::bind(setter, &aptr, _1)); +        b.callWhenReady(boost::bind(setter, &bptr, _1)); +        ensure("aptr should be null", ! aptr); +        ensure("bptr should be null", ! bptr); +        Data adata("a"), bdata("b"); +        a = &adata; +        ensure_equals("aptr should be &adata", aptr, &adata); +        // but we haven't yet set b +        ensure("bptr should still be null", !bptr); +        b = &bdata; +        ensure_equals("bptr should be &bdata", bptr, &bdata); +    } + +    template<> template<> +    void object::test<4>() +    { +        set_test_name("LLPounceable<T> looks like T"); +        // We want LLPounceable<T, TAG> to be drop-in replaceable for a plain +        // T for read constructs. In particular, it should behave like a dumb +        // pointer -- and with zero abstraction cost for such usage. +        Data* aptr = 0; +        Data a("a"); +        // should be able to initialize a pounceable (when its constructor +        // runs) +        LLPounceable<Data*> pounceable(&a); +        // should be able to pass LLPounceable<T> to function accepting T +        setter(&aptr, pounceable); +        ensure_equals("aptr should be &a", aptr, &a); +        // should be able to dereference with * +        ensure_equals("deref with *", (*pounceable).mData, "a"); +        // should be able to dereference with -> +        ensure_equals("deref with ->", pounceable->mData, "a"); +        // bool operations +        ensure("test with operator bool()", pounceable); +        ensure("test with operator !()", ! (! pounceable)); +    } + +    template<> template<> +    void object::test<5>() +    { +        set_test_name("Multiple callWhenReady() queue items"); +        Data *p1 = 0, *p2 = 0, *p3 = 0; +        Data a("a"); +        LLPounceable<Data*> pounceable; +        // queue up a couple setter() calls for later +        pounceable.callWhenReady(boost::bind(setter, &p1, _1)); +        pounceable.callWhenReady(boost::bind(setter, &p2, _1)); +        // should still be pending +        ensure("p1 should be null", !p1); +        ensure("p2 should be null", !p2); +        ensure("p3 should be null", !p3); +        pounceable = 0; +        // assigning a new empty value shouldn't flush the queue +        ensure("p1 should still be null", !p1); +        ensure("p2 should still be null", !p2); +        ensure("p3 should still be null", !p3); +        // using whichever syntax +        pounceable.reset(0); +        // try to make ensure messages distinct... tough to pin down which +        // ensure() failed if multiple ensure() calls in the same test<n> have +        // the same message! +        ensure("p1 should again be null", !p1); +        ensure("p2 should again be null", !p2); +        ensure("p3 should again be null", !p3); +        pounceable.reset(&a);       // should flush queue +        ensure_equals("p1 should be &a", p1, &a); +        ensure_equals("p2 should be &a", p2, &a); +        ensure("p3 still not set", !p3); +        // immediate call +        pounceable.callWhenReady(boost::bind(setter, &p3, _1)); +        ensure_equals("p3 should be &a", p3, &a); +    } + +    template<> template<> +    void object::test<6>() +    { +        set_test_name("queue order"); +        std::string data; +        LLPounceable<std::string*> pounceable; +        pounceable.callWhenReady(boost::bind(append, _1, "a")); +        pounceable.callWhenReady(boost::bind(append, _1, "b")); +        pounceable.callWhenReady(boost::bind(append, _1, "c")); +        pounceable = &data; +        ensure_equals("callWhenReady() must preserve chronological order", +                      data, "abc"); + +        std::string data2; +        pounceable = NULL; +        pounceable.callWhenReady(boost::bind(append, _1, "d")); +        pounceable.callWhenReady(boost::bind(append, _1, "e")); +        pounceable.callWhenReady(boost::bind(append, _1, "f")); +        pounceable = &data2; +        ensure_equals("LLPounceable must reset queue when fired", +                      data2, "def"); +    } + +    template<> template<> +    void object::test<7>() +    { +        set_test_name("compile-fail test, uncomment to check"); +        // The following declaration should fail: only LLPounceableQueue and +        // LLPounceableStatic should work as tags. +//      LLPounceable<Data*, int> pounceable; +    } +} // namespace tut diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp index 385289aefe..a05f650f25 100644 --- a/indra/llcommon/tests/llsingleton_test.cpp +++ b/indra/llcommon/tests/llsingleton_test.cpp @@ -30,47 +30,171 @@  #include "llsingleton.h"  #include "../test/lltut.h" + +// Capture execution sequence by appending to log string. +std::string sLog; + +#define DECLARE_CLASS(CLS)                      \ +struct CLS: public LLSingleton<CLS>             \ +{                                               \ +    static enum dep_flag {                      \ +        DEP_NONE, /* no dependency */           \ +        DEP_CTOR, /* dependency in ctor */      \ +        DEP_INIT  /* dependency in initSingleton */ \ +    } sDepFlag;                                 \ +                                                \ +    CLS();                                      \ +    void initSingleton();                       \ +    void cleanupSingleton();                    \ +    ~CLS();                                     \ +};                                              \ +                                                \ +CLS::dep_flag CLS::sDepFlag = DEP_NONE + +DECLARE_CLASS(A); +DECLARE_CLASS(B); + +#define DEFINE_MEMBERS(CLS, OTHER)              \ +CLS::CLS()                                      \ +{                                               \ +    sLog.append(#CLS);                          \ +    if (sDepFlag == DEP_CTOR)                   \ +    {                                           \ +        (void)OTHER::instance();                \ +    }                                           \ +}                                               \ +                                                \ +void CLS::initSingleton()                       \ +{                                               \ +    sLog.append("i" #CLS);                      \ +    if (sDepFlag == DEP_INIT)                   \ +    {                                           \ +        (void)OTHER::instance();                \ +    }                                           \ +}                                               \ +                                                \ +void CLS::cleanupSingleton()                    \ +{                                               \ +    sLog.append("x" #CLS);                      \ +}                                               \ +                                                \ +CLS::~CLS()                                     \ +{                                               \ +    sLog.append("~" #CLS);                      \ +} + +DEFINE_MEMBERS(A, B) +DEFINE_MEMBERS(B, A) +  namespace tut  { -	struct singleton -	{ -		// We need a class created with the LLSingleton template to test with. -		class LLSingletonTest: public LLSingleton<LLSingletonTest> -		{ - -		}; -	}; - -	typedef test_group<singleton> singleton_t; -	typedef singleton_t::object singleton_object_t; -	tut::singleton_t tut_singleton("LLSingleton"); - -	template<> template<> -	void singleton_object_t::test<1>() -	{ - -	} -	template<> template<> -	void singleton_object_t::test<2>() -	{ -		LLSingletonTest* singleton_test = LLSingletonTest::getInstance(); -		ensure(singleton_test); -	} -	template<> template<> -	void singleton_object_t::test<3>() -	{ -		//Construct the instance -		LLSingletonTest::getInstance(); -		ensure(LLSingletonTest::instanceExists()); - -		//Delete the instance -		LLSingletonTest::deleteSingleton(); -		ensure(LLSingletonTest::destroyed()); -		ensure(!LLSingletonTest::instanceExists()); - -		//Construct it again. -		LLSingletonTest* singleton_test = LLSingletonTest::getInstance(); -		ensure(singleton_test); -		ensure(LLSingletonTest::instanceExists()); -	} +    struct singleton +    { +        // We need a class created with the LLSingleton template to test with. +        class LLSingletonTest: public LLSingleton<LLSingletonTest> +        { + +        }; +    }; + +    typedef test_group<singleton> singleton_t; +    typedef singleton_t::object singleton_object_t; +    tut::singleton_t tut_singleton("LLSingleton"); + +    template<> template<> +    void singleton_object_t::test<1>() +    { + +    } +    template<> template<> +    void singleton_object_t::test<2>() +    { +        LLSingletonTest* singleton_test = LLSingletonTest::getInstance(); +        ensure(singleton_test); +    } + +    template<> template<> +    void singleton_object_t::test<3>() +    { +        //Construct the instance +        LLSingletonTest::getInstance(); +        ensure(LLSingletonTest::instanceExists()); + +        //Delete the instance +        LLSingletonTest::deleteSingleton(); +        ensure(!LLSingletonTest::instanceExists()); + +        //Construct it again. +        LLSingletonTest* singleton_test = LLSingletonTest::getInstance(); +        ensure(singleton_test); +        ensure(LLSingletonTest::instanceExists()); +    } + +#define TESTS(CLS, OTHER, N0, N1, N2, N3)                               \ +    template<> template<>                                               \ +    void singleton_object_t::test<N0>()                                 \ +    {                                                                   \ +        set_test_name("just " #CLS);                                    \ +        CLS::sDepFlag = CLS::DEP_NONE;                                  \ +        OTHER::sDepFlag = OTHER::DEP_NONE;                              \ +        sLog.clear();                                                   \ +                                                                        \ +        (void)CLS::instance();                                          \ +        ensure_equals(sLog, #CLS "i" #CLS);                             \ +        LLSingletonBase::cleanupAll();                                  \ +        ensure_equals(sLog, #CLS "i" #CLS "x" #CLS);                    \ +        LLSingletonBase::deleteAll();                                   \ +        ensure_equals(sLog, #CLS "i" #CLS "x" #CLS "~" #CLS);           \ +    }                                                                   \ +                                                                        \ +    template<> template<>                                               \ +    void singleton_object_t::test<N1>()                                 \ +    {                                                                   \ +        set_test_name(#CLS " ctor depends " #OTHER);                    \ +        CLS::sDepFlag = CLS::DEP_CTOR;                                  \ +        OTHER::sDepFlag = OTHER::DEP_NONE;                              \ +        sLog.clear();                                                   \ +                                                                        \ +        (void)CLS::instance();                                          \ +        ensure_equals(sLog, #CLS #OTHER "i" #OTHER "i" #CLS);           \ +        LLSingletonBase::cleanupAll();                                  \ +        ensure_equals(sLog, #CLS #OTHER "i" #OTHER "i" #CLS "x" #CLS "x" #OTHER); \ +        LLSingletonBase::deleteAll();                                   \ +        ensure_equals(sLog, #CLS #OTHER "i" #OTHER "i" #CLS "x" #CLS "x" #OTHER "~" #CLS "~" #OTHER); \ +    }                                                                   \ +                                                                        \ +    template<> template<>                                               \ +    void singleton_object_t::test<N2>()                                 \ +    {                                                                   \ +        set_test_name(#CLS " init depends " #OTHER);                    \ +        CLS::sDepFlag = CLS::DEP_INIT;                                  \ +        OTHER::sDepFlag = OTHER::DEP_NONE;                              \ +        sLog.clear();                                                   \ +                                                                        \ +        (void)CLS::instance();                                          \ +        ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER);           \ +        LLSingletonBase::cleanupAll();                                  \ +        ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER "x" #CLS "x" #OTHER); \ +        LLSingletonBase::deleteAll();                                   \ +        ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER "x" #CLS "x" #OTHER "~" #CLS "~" #OTHER); \ +    }                                                                   \ +                                                                        \ +    template<> template<>                                               \ +    void singleton_object_t::test<N3>()                                 \ +    {                                                                   \ +        set_test_name(#CLS " circular init");                           \ +        CLS::sDepFlag = CLS::DEP_INIT;                                  \ +        OTHER::sDepFlag = OTHER::DEP_CTOR;                              \ +        sLog.clear();                                                   \ +                                                                        \ +        (void)CLS::instance();                                          \ +        ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER);           \ +        LLSingletonBase::cleanupAll();                                  \ +        ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER "x" #CLS "x" #OTHER); \ +        LLSingletonBase::deleteAll();                                   \ +        ensure_equals(sLog, #CLS "i" #CLS #OTHER "i" #OTHER "x" #CLS "x" #OTHER "~" #CLS "~" #OTHER); \ +    } + +    TESTS(A, B, 4, 5, 6, 7) +    TESTS(B, A, 8, 9, 10, 11)  }  | 
