diff options
| author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2023-12-14 02:47:44 +0200 | 
|---|---|---|
| committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2023-12-14 02:47:44 +0200 | 
| commit | 4b98ae6e8a4c54fa70246beb5d7ff28a5590e819 (patch) | |
| tree | 11e49d0cb85d8420ac614f039b32e5ec16202de3 /indra/llcommon/tests | |
| parent | 0db9bcf21fd4b7172e8a35cdb2805ccdc736e273 (diff) | |
| parent | 07ace73c49918ffb70e99c2239849eaaabc1fe45 (diff) | |
Merge branch 'DRTVWR-587-maint-V' into DRTVWR-588-maint-W
# Conflicts:
#	indra/newview/llspatialpartition.cpp
Diffstat (limited to 'indra/llcommon/tests')
| -rw-r--r-- | indra/llcommon/tests/apply_test.cpp | 240 | ||||
| -rw-r--r-- | indra/llcommon/tests/lazyeventapi_test.cpp | 136 | ||||
| -rw-r--r-- | indra/llcommon/tests/lleventdispatcher_test.cpp | 569 | ||||
| -rw-r--r-- | indra/llcommon/tests/wrapllerrs.h | 5 | 
4 files changed, 845 insertions, 105 deletions
diff --git a/indra/llcommon/tests/apply_test.cpp b/indra/llcommon/tests/apply_test.cpp new file mode 100644 index 0000000000..56b497e0c8 --- /dev/null +++ b/indra/llcommon/tests/apply_test.cpp @@ -0,0 +1,240 @@ +/** + * @file   apply_test.cpp + * @author Nat Goodspeed + * @date   2022-12-19 + * @brief  Test for apply. + *  + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Copyright (c) 2022, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "apply.h" +// STL headers +// std headers +#include <iomanip> +// external library headers +// other Linden headers +#include "llsd.h" +#include "llsdutil.h" +#include <array> +#include <string> +#include <vector> + +// for ensure_equals +std::ostream& operator<<(std::ostream& out, const std::vector<std::string>& stringvec) +{ +    const char* delim = "["; +    for (const auto& str : stringvec) +    { +        out << delim << std::quoted(str); +        delim = ", "; +    } +    return out << ']'; +} + +// the above must be declared BEFORE ensure_equals(std::vector<std::string>) +#include "../test/lltut.h" + +/***************************************************************************** +*   TUT +*****************************************************************************/ +namespace tut +{ +    namespace statics +    { +        /*------------------------------ data ------------------------------*/ +        // Although we're using types from the LLSD namespace, we're not +        // constructing LLSD values, but rather instances of the C++ types +        // supported by LLSD. +        static LLSD::Boolean b{true}; +        static LLSD::Integer i{17}; +        static LLSD::Real    f{3.14}; +        static LLSD::String  s{ "hello" }; +        static LLSD::UUID    uu{ "baadf00d-dead-beef-baad-feedb0ef" }; +        static LLSD::Date    dt{ "2022-12-19" }; +        static LLSD::URI     uri{ "http://secondlife.com" }; +        static LLSD::Binary  bin{ 0x01, 0x02, 0x03, 0x04, 0x05 }; + +        static std::vector<LLSD::String> quick +        { +            "The", "quick", "brown", "fox", "etc." +        }; + +        static std::array<int, 5> fibs +        { +            0, 1, 1, 2, 3 +        }; + +        // ensure that apply() actually reaches the target method -- +        // lack of ensure_equals() failure could be due to no-op apply() +        bool called{ false }; +        // capture calls from collect() +        std::vector<std::string> collected; + +        /*------------------------- test functions -------------------------*/ +        void various(LLSD::Boolean b, LLSD::Integer i, LLSD::Real f, const LLSD::String& s, +                     const LLSD::UUID& uu, const LLSD::Date& dt, +                     const LLSD::URI& uri, const LLSD::Binary& bin) +        { +            called = true; +            ensure_equals(  "b mismatch", b,   statics::b); +            ensure_equals(  "i mismatch", i,   statics::i); +            ensure_equals(  "f mismatch", f,   statics::f); +            ensure_equals(  "s mismatch", s,   statics::s); +            ensure_equals( "uu mismatch", uu,  statics::uu); +            ensure_equals( "dt mismatch", dt,  statics::dt); +            ensure_equals("uri mismatch", uri, statics::uri); +            ensure_equals("bin mismatch", bin, statics::bin); +        } + +        void strings(std::string s0, std::string s1, std::string s2, std::string s3, std::string s4) +        { +            called = true; +            ensure_equals("s0 mismatch", s0, statics::quick[0]); +            ensure_equals("s1 mismatch", s1, statics::quick[1]); +            ensure_equals("s2 mismatch", s2, statics::quick[2]); +            ensure_equals("s3 mismatch", s3, statics::quick[3]); +            ensure_equals("s4 mismatch", s4, statics::quick[4]); +        } + +        void ints(int i0, int i1, int i2, int i3, int i4) +        { +            called = true; +            ensure_equals("i0 mismatch", i0, statics::fibs[0]); +            ensure_equals("i1 mismatch", i1, statics::fibs[1]); +            ensure_equals("i2 mismatch", i2, statics::fibs[2]); +            ensure_equals("i3 mismatch", i3, statics::fibs[3]); +            ensure_equals("i4 mismatch", i4, statics::fibs[4]); +        } + +        void sdfunc(const LLSD& sd) +        { +            called = true; +            ensure_equals("sd mismatch", sd.asInteger(), statics::i); +        } + +        void intfunc(int i) +        { +            called = true; +            ensure_equals("i mismatch", i, statics::i); +        } + +        void voidfunc() +        { +            called = true; +        } + +        // recursion tail +        void collect() +        { +            called = true; +        } + +        // collect(arbitrary) +        template <typename... ARGS> +        void collect(const std::string& first, ARGS&&... rest) +        { +            statics::collected.push_back(first); +            collect(std::forward<ARGS>(rest)...); +        } +    } // namespace statics + +    struct apply_data +    { +        apply_data() +        { +            // reset called before each test +            statics::called = false; +            statics::collected.clear(); +        } +    }; +    typedef test_group<apply_data> apply_group; +    typedef apply_group::object object; +    apply_group applygrp("apply"); + +    template<> template<> +    void object::test<1>() +    { +        set_test_name("apply(tuple)"); +        LL::apply(statics::various, +                  std::make_tuple(statics::b, statics::i, statics::f, statics::s, +                                  statics::uu, statics::dt, statics::uri, statics::bin)); +        ensure("apply(tuple) failed", statics::called); +    } + +    template<> template<> +    void object::test<2>() +    { +        set_test_name("apply(array)"); +        LL::apply(statics::ints, statics::fibs); +        ensure("apply(array) failed", statics::called); +    } + +    template<> template<> +    void object::test<3>() +    { +        set_test_name("apply(vector)"); +        LL::apply(statics::strings, statics::quick); +        ensure("apply(vector) failed", statics::called); +    } + +    // The various apply(LLSD) tests exercise only the success cases because +    // the failure cases trigger assert() fail, which is hard to catch. +    template<> template<> +    void object::test<4>() +    { +        set_test_name("apply(LLSD())"); +        LL::apply(statics::voidfunc, LLSD()); +        ensure("apply(LLSD()) failed", statics::called); +    } + +    template<> template<> +    void object::test<5>() +    { +        set_test_name("apply(fn(int), LLSD scalar)"); +        LL::apply(statics::intfunc, LLSD(statics::i)); +        ensure("apply(fn(int), LLSD scalar) failed", statics::called); +    } + +    template<> template<> +    void object::test<6>() +    { +        set_test_name("apply(fn(LLSD), LLSD scalar)"); +        // This test verifies that LLSDParam<LLSD> doesn't send the compiler +        // into infinite recursion when the target is itself LLSD. +        LL::apply(statics::sdfunc, LLSD(statics::i)); +        ensure("apply(fn(LLSD), LLSD scalar) failed", statics::called); +    } + +    template<> template<> +    void object::test<7>() +    { +        set_test_name("apply(LLSD array)"); +        LL::apply(statics::various, +                  llsd::array(statics::b, statics::i, statics::f, statics::s, +                              statics::uu, statics::dt, statics::uri, statics::bin)); +        ensure("apply(LLSD array) failed", statics::called); +    } + +    template<> template<> +    void object::test<8>() +    { +        set_test_name("VAPPLY()"); +        // Make a std::array<std::string> from statics::quick. We can't call a +        // variadic function with a data structure of dynamic length. +        std::array<std::string, 5> strray; +        for (size_t i = 0; i < strray.size(); ++i) +            strray[i] = statics::quick[i]; +        // This doesn't work: the compiler doesn't know which overload of +        // collect() to pass to LL::apply(). +        // LL::apply(statics::collect, strray); +        // That's what VAPPLY() is for. +        VAPPLY(statics::collect, strray); +        ensure("VAPPLY() failed", statics::called); +        ensure_equals("collected mismatch", statics::collected, statics::quick); +    } +} // namespace tut diff --git a/indra/llcommon/tests/lazyeventapi_test.cpp b/indra/llcommon/tests/lazyeventapi_test.cpp new file mode 100644 index 0000000000..31b2d6d17f --- /dev/null +++ b/indra/llcommon/tests/lazyeventapi_test.cpp @@ -0,0 +1,136 @@ +/** + * @file   lazyeventapi_test.cpp + * @author Nat Goodspeed + * @date   2022-06-18 + * @brief  Test for lazyeventapi. + *  + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Copyright (c) 2022, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "lazyeventapi.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "../test/lltut.h" +#include "llevents.h" +#include "llsdutil.h" + +// observable side effect, solely for testing +static LLSD data; + +// LLEventAPI listener subclass +class MyListener: public LLEventAPI +{ +public: +    // need this trivial forwarding constructor +    // (of course do any other initialization your subclass requires) +    MyListener(const LL::LazyEventAPIParams& params): +        LLEventAPI(params) +    {} + +    // example operation, registered by LazyEventAPI subclass below +    void set_data(const LLSD& event) +    { +        data = event["data"]; +    } +}; + +// LazyEventAPI registrar subclass +class MyRegistrar: public LL::LazyEventAPI<MyListener> +{ +    using super = LL::LazyEventAPI<MyListener>; +    using super::listener; +public: +    // LazyEventAPI subclass initializes like a classic LLEventAPI subclass +    // constructor, with API name and desc plus add() calls for the defined +    // operations +    MyRegistrar(): +        super("Test", "This is a test LLEventAPI") +    { +        add("set", "This is a set operation", &listener::set_data); +    } +}; +// Normally we'd declare a static instance of MyRegistrar -- but because we +// want to test both with and without, defer declaration to individual test +// methods. + +/***************************************************************************** +*   TUT +*****************************************************************************/ +namespace tut +{ +    struct lazyeventapi_data +    { +        lazyeventapi_data() +        { +            // before every test, reset 'data' +            data.clear(); +        } +        ~lazyeventapi_data() +        { +            // after every test, reset LLEventPumps +            LLEventPumps::deleteSingleton(); +        } +    }; +    typedef test_group<lazyeventapi_data> lazyeventapi_group; +    typedef lazyeventapi_group::object object; +    lazyeventapi_group lazyeventapigrp("lazyeventapi"); + +    template<> template<> +    void object::test<1>() +    { +        set_test_name("LazyEventAPI"); +        // this is where the magic (should) happen +        // 'register' still a keyword until C++17 +        MyRegistrar regster; +        LLEventPumps::instance().obtain("Test").post(llsd::map("op", "set", "data", "hey")); +        ensure_equals("failed to set data", data.asString(), "hey"); +    } + +    template<> template<> +    void object::test<2>() +    { +        set_test_name("No LazyEventAPI"); +        // Because the MyRegistrar declaration in test<1>() is local, because +        // it has been destroyed, we fully expect NOT to reach a MyListener +        // instance with this post. +        LLEventPumps::instance().obtain("Test").post(llsd::map("op", "set", "data", "moot")); +        ensure("accidentally set data", ! data.isDefined()); +    } + +    template<> template<> +    void object::test<3>() +    { +        set_test_name("LazyEventAPI metadata"); +        MyRegistrar regster; +        // Of course we have 'regster' in hand; we don't need to search for +        // it. But this next test verifies that we can find (all) LazyEventAPI +        // instances using LazyEventAPIBase::instance_snapshot. Normally we +        // wouldn't search; normally we'd just look at each instance in the +        // loop body. +        const MyRegistrar* found = nullptr; +        for (const auto& registrar : LL::LazyEventAPIBase::instance_snapshot()) +            if ((found = dynamic_cast<const MyRegistrar*>(®istrar))) +                break; +        ensure("Failed to find MyRegistrar via LLInstanceTracker", found); + +        ensure_equals("wrong API name", found->getName(), "Test"); +        ensure_contains("wrong API desc", found->getDesc(), "test LLEventAPI"); +        ensure_equals("wrong API field", found->getDispatchKey(), "op"); +        // Normally we'd just iterate over *found. But for test purposes, +        // actually capture the range of NameDesc pairs in a vector. +        std::vector<LL::LazyEventAPIBase::NameDesc> ops{ found->begin(), found->end() }; +        ensure_equals("failed to find operations", ops.size(), 1); +        ensure_equals("wrong operation name", ops[0].first, "set"); +        ensure_contains("wrong operation desc", ops[0].second, "set operation"); +        LLSD metadata{ found->getMetadata(ops[0].first) }; +        ensure_equals("bad metadata name", metadata["name"].asString(), ops[0].first); +        ensure_equals("bad metadata desc", metadata["desc"].asString(), ops[0].second); +    } +} // namespace tut diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 466f11f52a..b0c532887c 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -18,9 +18,12 @@  // external library headers  // other Linden headers  #include "../test/lltut.h" +#include "lleventfilter.h"  #include "llsd.h"  #include "llsdutil.h" +#include "llevents.h"  #include "stringize.h" +#include "StringVec.h"  #include "tests/wrapllerrs.h"  #include "../test/catch_and_store_what_in.h"  #include "../test/debug.h" @@ -32,8 +35,6 @@  #include <boost/bind.hpp>  #include <boost/function.hpp>  #include <boost/range.hpp> -#include <boost/foreach.hpp> -#define foreach BOOST_FOREACH  #include <boost/lambda/lambda.hpp> @@ -177,6 +178,7 @@ struct Vars      /*-------- Arbitrary-params (non-const, const, static) methods ---------*/      void methodna(NPARAMSa)      { +        DEBUG;          // Because our const char* param cp might be NULL, and because we          // intend to capture the value in a std::string, have to distinguish          // between the NULL value and any non-NULL value. Use a convention @@ -188,7 +190,7 @@ struct Vars          else              vcp = std::string("'") + cp + "'"; -        debug()("methodna(", b, +        this->debug()("methodna(", b,                ", ", i,                ", ", f,                ", ", d, @@ -205,7 +207,7 @@ struct Vars      void methodnb(NPARAMSb)      {          std::ostringstream vbin; -        foreach(U8 byte, bin) +        for (U8 byte: bin)          {              vbin << std::hex << std::setfill('0') << std::setw(2) << unsigned(byte);          } @@ -226,7 +228,8 @@ struct Vars      void cmethodna(NPARAMSa) const      { -        debug()('c', NONL); +        DEBUG; +        this->debug()('c', NONL);          const_cast<Vars*>(this)->methodna(NARGSa);      } @@ -315,6 +318,31 @@ void freenb(NPARAMSb)  *****************************************************************************/  namespace tut  { +    void ensure_has(const std::string& outer, const std::string& inner) +    { +        ensure(stringize("'", outer, "' does not contain '", inner, "'"), +               outer.find(inner) != std::string::npos); +    } + +    template <typename CALLABLE> +    std::string call_exc(CALLABLE&& func, const std::string& exc_frag) +    { +        std::string what = +            catch_what<LLEventDispatcher::DispatchError>(std::forward<CALLABLE>(func)); +        ensure_has(what, exc_frag); +        return what; +    } + +    template <typename CALLABLE> +    void call_logerr(CALLABLE&& func, const std::string& frag) +    { +        CaptureLog capture; +        // the error should be logged; we just need to stop the exception +        // propagating +        catch_what<LLEventDispatcher::DispatchError>(std::forward<CALLABLE>(func)); +        capture.messageWith(frag); +    } +      struct lleventdispatcher_data      {          Debug debug{"test"}; @@ -397,9 +425,9 @@ namespace tut              work.add(name, desc, &Dispatcher::cmethod1, required);              // Non-subclass method with/out required params              addf("method1", "method1", &v); -            work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1)); +            work.add(name, desc, [this](const LLSD& args){ return v.method1(args); });              addf("method1_req", "method1", &v); -            work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1), required); +            work.add(name, desc, [this](const LLSD& args){ return v.method1(args); }, required);              /*--------------- Arbitrary params, array style ----------------*/ @@ -461,7 +489,7 @@ namespace tut              debug("dft_array_full:\n",                    dft_array_full);              // Partial defaults arrays. -            foreach(LLSD::String a, ab) +            for (LLSD::String a: ab)              {                  LLSD::Integer partition(std::min(partial_offset, dft_array_full[a].size()));                  dft_array_partial[a] = @@ -471,7 +499,7 @@ namespace tut              debug("dft_array_partial:\n",                    dft_array_partial); -            foreach(LLSD::String a, ab) +            for(LLSD::String a: ab)              {                  // Generate full defaults maps by zipping (params, dft_array_full).                  dft_map_full[a] = zipmap(params[a], dft_array_full[a]); @@ -583,6 +611,7 @@ namespace tut          void addf(const std::string& n, const std::string& d, Vars* v)          { +            debug("addf('", n, "', '", d, "')");              // This method is to capture in our own DescMap the name and              // description of every registered function, for metadata query              // testing. @@ -598,19 +627,14 @@ namespace tut          {              // Copy descs to a temp map of same type.              DescMap forgotten(descs.begin(), descs.end()); -            // LLEventDispatcher intentionally provides only const_iterator: -            // since dereferencing that iterator generates values on the fly, -            // it's meaningless to have a modifiable iterator. But since our -            // 'work' object isn't const, by default BOOST_FOREACH() wants to -            // use non-const iterators. Persuade it to use the const_iterator. -            foreach(LLEventDispatcher::NameDesc nd, const_cast<const Dispatcher&>(work)) +            for (LLEventDispatcher::NameDesc nd: work)              {                  DescMap::iterator found = forgotten.find(nd.first); -                ensure(STRINGIZE("LLEventDispatcher records function '" << nd.first -                                 << "' we didn't enter"), +                ensure(stringize("LLEventDispatcher records function '", nd.first, +                                 "' we didn't enter"),                         found != forgotten.end()); -                ensure_equals(STRINGIZE("LLEventDispatcher desc '" << nd.second << -                                        "' doesn't match what we entered: '" << found->second << "'"), +                ensure_equals(stringize("LLEventDispatcher desc '", nd.second, +                                        "' doesn't match what we entered: '", found->second, "'"),                                nd.second, found->second);                  // found in our map the name from LLEventDispatcher, good, erase                  // our map entry @@ -621,41 +645,49 @@ namespace tut                  std::ostringstream out;                  out << "LLEventDispatcher failed to report";                  const char* delim = ": "; -                foreach(const DescMap::value_type& fme, forgotten) +                for (const DescMap::value_type& fme: forgotten)                  {                      out << delim << fme.first;                      delim = ", ";                  } -                ensure(out.str(), false); +                throw failure(out.str());              }          }          Vars* varsfor(const std::string& name)          {              VarsMap::const_iterator found = funcvars.find(name); -            ensure(STRINGIZE("No Vars* for " << name), found != funcvars.end()); -            ensure(STRINGIZE("NULL Vars* for " << name), found->second); +            ensure(stringize("No Vars* for ", name), found != funcvars.end()); +            ensure(stringize("NULL Vars* for ", name), found->second);              return found->second;          } -        void ensure_has(const std::string& outer, const std::string& inner) +        std::string call_exc(const std::string& func, const LLSD& args, const std::string& exc_frag)          { -            ensure(STRINGIZE("'" << outer << "' does not contain '" << inner << "'").c_str(), -                   outer.find(inner) != std::string::npos); +            return tut::call_exc( +                [this, func, args]() +                { +                    if (func.empty()) +                    { +                        work(args); +                    } +                    else +                    { +                        work(func, args); +                    } +                }, +                exc_frag);          } -        void call_exc(const std::string& func, const LLSD& args, const std::string& exc_frag) +        void call_logerr(const std::string& func, const LLSD& args, const std::string& frag)          { -            std::string threw = catch_what<std::runtime_error>([this, &func, &args](){ -                    work(func, args); -                }); -            ensure_has(threw, exc_frag); +            tut::call_logerr([this, func, args](){ work(func, args); }, frag);          }          LLSD getMetadata(const std::string& name)          {              LLSD meta(work.getMetadata(name)); -            ensure(STRINGIZE("No metadata for " << name), meta.isDefined()); +            ensure(stringize("No metadata for ", name), meta.isDefined());              return meta;          } @@ -724,7 +756,7 @@ namespace tut          set_test_name("map-style registration with non-array params");          // Pass "param names" as scalar or as map          LLSD attempts(llsd::array(17, LLSDMap("pi", 3.14)("two", 2))); -        foreach(LLSD ae, inArray(attempts)) +        for (LLSD ae: inArray(attempts))          {              std::string threw = catch_what<std::exception>([this, &ae](){                      work.add("freena_err", "freena", freena, ae); @@ -799,7 +831,7 @@ namespace tut      {          set_test_name("query Callables with/out required params");          LLSD names(llsd::array("free1", "Dmethod1", "Dcmethod1", "method1")); -        foreach(LLSD nm, inArray(names)) +        for (LLSD nm: inArray(names))          {              LLSD metadata(getMetadata(nm));              ensure_equals("name mismatch", metadata["name"], nm); @@ -828,19 +860,19 @@ namespace tut                         (5, llsd::array("freena_array", "smethodna_array", "methodna_array")),                         llsd::array                         (5, llsd::array("freenb_array", "smethodnb_array", "methodnb_array")))); -        foreach(LLSD ae, inArray(expected)) +        for (LLSD ae: inArray(expected))          {              LLSD::Integer arity(ae[0].asInteger());              LLSD names(ae[1]);              LLSD req(LLSD::emptyArray());              if (arity)                  req[arity - 1] = LLSD(); -            foreach(LLSD nm, inArray(names)) +            for (LLSD nm: inArray(names))              {                  LLSD metadata(getMetadata(nm));                  ensure_equals("name mismatch", metadata["name"], nm);                  ensure_equals(metadata["desc"].asString(), descs[nm]); -                ensure_equals(STRINGIZE("mismatched required for " << nm.asString()), +                ensure_equals(stringize("mismatched required for ", nm.asString()),                                metadata["required"], req);                  ensure("should not have optional", metadata["optional"].isUndefined());              } @@ -854,7 +886,7 @@ namespace tut          // - (Free function | non-static method), map style, no params (ergo          //   no defaults)          LLSD names(llsd::array("free0_map", "smethod0_map", "method0_map")); -        foreach(LLSD nm, inArray(names)) +        for (LLSD nm: inArray(names))          {              LLSD metadata(getMetadata(nm));              ensure_equals("name mismatch", metadata["name"], nm); @@ -884,7 +916,7 @@ namespace tut                             llsd::array("smethodnb_map_adft", "smethodnb_map_mdft"),                             llsd::array("methodna_map_adft", "methodna_map_mdft"),                             llsd::array("methodnb_map_adft", "methodnb_map_mdft"))); -        foreach(LLSD eq, inArray(equivalences)) +        for (LLSD eq: inArray(equivalences))          {              LLSD adft(eq[0]);              LLSD mdft(eq[1]); @@ -898,8 +930,8 @@ namespace tut              ensure_equals("mdft name", mdft, mmeta["name"]);              ameta.erase("name");              mmeta.erase("name"); -            ensure_equals(STRINGIZE("metadata for " << adft.asString() -                                    << " vs. " << mdft.asString()), +            ensure_equals(stringize("metadata for ", adft.asString(), +                                    " vs. ", mdft.asString()),                            ameta, mmeta);          }      } @@ -915,7 +947,7 @@ namespace tut          // params are required. Also maps containing left requirements for          // partial defaults arrays. Also defaults maps from defaults arrays.          LLSD allreq, leftreq, rightdft; -        foreach(LLSD::String a, ab) +        for (LLSD::String a: ab)          {              // The map in which all params are required uses params[a] as              // keys, with all isUndefined() as values. We can accomplish that @@ -943,9 +975,9 @@ namespace tut          // Generate maps containing parameter names not provided by the          // dft_map_partial maps.          LLSD skipreq(allreq); -        foreach(LLSD::String a, ab) +        for (LLSD::String a: ab)          { -            foreach(const MapEntry& me, inMap(dft_map_partial[a])) +            for (const MapEntry& me: inMap(dft_map_partial[a]))              {                  skipreq[a].erase(me.first);              } @@ -990,7 +1022,7 @@ namespace tut                       (llsd::array("freenb_map_mdft", "smethodnb_map_mdft", "methodnb_map_mdft"),                        llsd::array(LLSD::emptyMap(), dft_map_full["b"])))); // required, optional -        foreach(LLSD grp, inArray(groups)) +        for (LLSD grp: inArray(groups))          {              // Internal structure of each group in 'groups':              LLSD names(grp[0]); @@ -1003,14 +1035,14 @@ namespace tut                    optional);              // Loop through 'names' -            foreach(LLSD nm, inArray(names)) +            for (LLSD nm: inArray(names))              {                  LLSD metadata(getMetadata(nm));                  ensure_equals("name mismatch", metadata["name"], nm);                  ensure_equals(nm.asString(), metadata["desc"].asString(), descs[nm]); -                ensure_equals(STRINGIZE(nm << " required mismatch"), +                ensure_equals(stringize(nm, " required mismatch"),                                metadata["required"], required); -                ensure_equals(STRINGIZE(nm << " optional mismatch"), +                ensure_equals(stringize(nm, " optional mismatch"),                                metadata["optional"], optional);              }          } @@ -1031,13 +1063,7 @@ namespace tut      {          set_test_name("call with bad name");          call_exc("freek", LLSD(), "not found"); -        // 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 = catch_what<std::runtime_error>([this](){ -                work(LLSDMap("op", "freek")); -            }); -        ensure_has(threw, "bad"); +        std::string threw = call_exc("", LLSDMap("op", "freek"), "bad");          ensure_has(threw, "op");          ensure_has(threw, "freek");      } @@ -1079,7 +1105,7 @@ namespace tut          // LLSD value matching 'required' according to llsd_matches() rules.          LLSD matching(LLSDMap("d", 3.14)("array", llsd::array("answer", true, answer)));          // Okay, walk through 'tests'. -        foreach(const CallablesTriple& tr, tests) +        for (const CallablesTriple& tr: tests)          {              // Should be able to pass 'answer' to Callables registered              // without 'required'. @@ -1087,7 +1113,7 @@ namespace tut              ensure_equals("answer mismatch", tr.llsd, answer);              // Should NOT be able to pass 'answer' to Callables registered              // with 'required'. -            call_exc(tr.name_req, answer, "bad request"); +            call_logerr(tr.name_req, answer, "bad request");              // But SHOULD be able to pass 'matching' to Callables registered              // with 'required'.              work(tr.name_req, matching); @@ -1101,17 +1127,20 @@ namespace tut          set_test_name("passing wrong args to (map | array)-style registrations");          // Pass scalar/map to array-style functions, scalar/array to map-style -        // functions. As that validation happens well before we engage the -        // argument magic, it seems pointless to repeat this with every -        // variation: (free function | non-static method), (no | arbitrary) -        // args. We should only need to engage it for one map-style -        // registration and one array-style registration. -        std::string array_exc("needs an args array"); -        call_exc("free0_array", 17, array_exc); -        call_exc("free0_array", LLSDMap("pi", 3.14), array_exc); +        // functions. It seems pointless to repeat this with every variation: +        // (free function | non-static method), (no | arbitrary) args. We +        // should only need to engage it for one map-style registration and +        // one array-style registration. +        // Now that LLEventDispatcher has been extended to treat an LLSD +        // scalar as a single-entry array, the error we expect in this case is +        // that apply() is trying to pass that non-empty array to a nullary +        // function. +        call_logerr("free0_array", 17, "LL::apply"); +        // similarly, apply() doesn't accept an LLSD Map +        call_logerr("free0_array", LLSDMap("pi", 3.14), "unsupported");          std::string map_exc("needs a map"); -        call_exc("free0_map", 17, map_exc); +        call_logerr("free0_map", 17, map_exc);          // Passing an array to a map-style function works now! No longer an          // error case!  //      call_exc("free0_map", llsd::array("a", "b"), map_exc); @@ -1125,7 +1154,7 @@ namespace tut                     ("free0_array", "free0_map",                      "smethod0_array", "smethod0_map",                      "method0_array", "method0_map")); -        foreach(LLSD name, inArray(names)) +        for (LLSD name: inArray(names))          {              // Look up the Vars instance for this function.              Vars* vars(varsfor(name)); @@ -1150,15 +1179,21 @@ namespace tut      template<> template<>      void object::test<19>()      { -        set_test_name("call array-style functions with too-short arrays"); -        // Could have two different too-short arrays, one for *na and one for -        // *nb, but since they both take 5 params... +        set_test_name("call array-style functions with wrong-length arrays"); +        // Could have different wrong-length arrays for *na and for *nb, but +        // since they both take 5 params...          LLSD tooshort(llsd::array("this", "array", "too", "short")); -        foreach(const LLSD& funcsab, inArray(array_funcs)) +        LLSD toolong (llsd::array("this", "array", "is",  "one", "too", "long")); +        LLSD badargs (llsd::array(tooshort, toolong)); +        for (const LLSD& toosomething: inArray(badargs))          { -            foreach(const llsd::MapEntry& e, inMap(funcsab)) +            for (const LLSD& funcsab: inArray(array_funcs))              { -                call_exc(e.second, tooshort, "requires more arguments"); +                for (const llsd::MapEntry& e: inMap(funcsab)) +                { +                    // apply() complains about wrong number of array entries +                    call_logerr(e.second, toosomething, "LL::apply"); +                }              }          }      } @@ -1166,7 +1201,7 @@ namespace tut      template<> template<>      void object::test<20>()      { -        set_test_name("call array-style functions with (just right | too long) arrays"); +        set_test_name("call array-style functions with right-size arrays");          std::vector<U8> binary;          for (size_t h(0x01), i(0); i < 5; h+= 0x22, ++i)          { @@ -1178,40 +1213,25 @@ namespace tut                                             LLDate("2011-02-03T15:07:00Z"),                                             LLURI("http://secondlife.com"),                                             binary))); -        LLSD argsplus(args); -        argsplus["a"].append("bogus"); -        argsplus["b"].append("bogus");          LLSD expect; -        foreach(LLSD::String a, ab) +        for (LLSD::String a: ab)          {              expect[a] = zipmap(params[a], args[a]);          }          // Adjust expect["a"]["cp"] for special Vars::cp treatment. -        expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'"; +        expect["a"]["cp"] = stringize("'", expect["a"]["cp"].asString(), "'");          debug("expect: ", expect); -        // Use substantially the same logic for args and argsplus -        LLSD argsarrays(llsd::array(args, argsplus)); -        // So i==0 selects 'args', i==1 selects argsplus -        for (LLSD::Integer i(0), iend(argsarrays.size()); i < iend; ++i) +        for (const LLSD& funcsab: inArray(array_funcs))          { -            foreach(const LLSD& funcsab, inArray(array_funcs)) +            for (LLSD::String a: ab)              { -                foreach(LLSD::String a, ab) -                { -                    // Reset the Vars instance before each call -                    Vars* vars(varsfor(funcsab[a])); -                    *vars = Vars(); -                    work(funcsab[a], argsarrays[i][a]); -                    ensure_llsd(STRINGIZE(funcsab[a].asString() << -                                          ": expect[\"" << a << "\"] mismatch"), -                                vars->inspect(), expect[a], 7); // 7 bits ~= 2 decimal digits - -                    // TODO: in the i==1 or argsplus case, intercept LL_WARNS -                    // output? Even without that, using argsplus verifies that -                    // passing too many args isn't fatal; it works -- but -                    // would be nice to notice the warning too. -                } +                // Reset the Vars instance before each call +                Vars* vars(varsfor(funcsab[a])); +                *vars = Vars(); +                work(funcsab[a], args[a]); +                ensure_llsd(stringize(funcsab[a].asString(), ": expect[\"", a, "\"] mismatch"), +                            vars->inspect(), expect[a], 7); // 7 bits ~= 2 decimal digits              }          }      } @@ -1239,7 +1259,7 @@ namespace tut                          ("a", llsd::array(false, 255, 98.6, 1024.5, "pointer"))                          ("b", llsd::array("object", LLUUID::generateNewID(), LLDate::now(), LLURI("http://wiki.lindenlab.com/wiki"), LLSD::Binary(boost::begin(binary), boost::end(binary)))));          LLSD array_overfull(array_full); -        foreach(LLSD::String a, ab) +        for (LLSD::String a: ab)          {              array_overfull[a].append("bogus");          } @@ -1253,7 +1273,7 @@ namespace tut          ensure_not_equals("UUID collision",                            array_full["b"][1].asUUID(), dft_array_full["b"][1].asUUID());          LLSD map_full, map_overfull; -        foreach(LLSD::String a, ab) +        for (LLSD::String a: ab)          {              map_full[a] = zipmap(params[a], array_full[a]);              map_overfull[a] = map_full[a]; @@ -1294,21 +1314,360 @@ namespace tut                       "freenb_map_mdft",    "smethodnb_map_mdft",    "methodnb_map_mdft")));          // Treat (full | overfull) (array | map) the same.          LLSD argssets(llsd::array(array_full, array_overfull, map_full, map_overfull)); -        foreach(const LLSD& args, inArray(argssets)) +        for (const LLSD& args: inArray(argssets))          { -            foreach(LLSD::String a, ab) +            for (LLSD::String a: ab)              { -                foreach(LLSD::String name, inArray(names[a])) +                for (LLSD::String name: inArray(names[a]))                  {                      // Reset the Vars instance                      Vars* vars(varsfor(name));                      *vars = Vars();                      work(name, args[a]); -                    ensure_llsd(STRINGIZE(name << ": expect[\"" << a << "\"] mismatch"), +                    ensure_llsd(stringize(name, ": expect[\"", a, "\"] mismatch"),                                  vars->inspect(), expect[a], 7); // 7 bits, 2 decimal digits                      // intercept LL_WARNS for the two overfull cases?                  }              }          }      } + +    struct DispatchResult: public LLDispatchListener +    { +        using DR = DispatchResult; + +        DispatchResult(): LLDispatchListener("results", "op") +        { +            add("strfunc",   "return string",       &DR::strfunc); +            add("voidfunc",  "void function",       &DR::voidfunc); +            add("emptyfunc", "return empty LLSD",   &DR::emptyfunc); +            add("intfunc",   "return Integer LLSD", &DR::intfunc); +            add("llsdfunc",  "return passed LLSD",  &DR::llsdfunc); +            add("mapfunc",   "return map LLSD",     &DR::mapfunc); +            add("arrayfunc", "return array LLSD",   &DR::arrayfunc); +        } + +        std::string strfunc(const std::string& str) const { return "got " + str; } +        void voidfunc()                  const {} +        LLSD emptyfunc()                 const { return {}; } +        int  intfunc(int i)              const { return -i; } +        LLSD llsdfunc(const LLSD& event) const +        { +            LLSD result{ event }; +            result["with"] = "string"; +            return result; +        } +        LLSD mapfunc(int i, const std::string& str) const +        { +            return llsd::map("i", intfunc(i), "str", strfunc(str)); +        } +        LLSD arrayfunc(int i, const std::string& str) const +        { +            return llsd::array(intfunc(i), strfunc(str)); +        } +    }; + +    template<> template<> +    void object::test<23>() +    { +        set_test_name("string result"); +        DispatchResult service; +        LLSD result{ service("strfunc", "a string") }; +        ensure_equals("strfunc() mismatch", result.asString(), "got a string"); +    } + +    template<> template<> +    void object::test<24>() +    { +        set_test_name("void result"); +        DispatchResult service; +        LLSD result{ service("voidfunc", LLSD()) }; +        ensure("voidfunc() returned defined", result.isUndefined()); +    } + +    template<> template<> +    void object::test<25>() +    { +        set_test_name("Integer result"); +        DispatchResult service; +        LLSD result{ service("intfunc", -17) }; +        ensure_equals("intfunc() mismatch", result.asInteger(), 17); +    } + +    template<> template<> +    void object::test<26>() +    { +        set_test_name("LLSD echo"); +        DispatchResult service; +        LLSD result{ service("llsdfunc", llsd::map("op", "llsdfunc", "reqid", 17)) }; +        ensure_equals("llsdfunc() mismatch", result, +                      llsd::map("op", "llsdfunc", "reqid", 17, "with", "string")); +    } + +    template<> template<> +    void object::test<27>() +    { +        set_test_name("map LLSD result"); +        DispatchResult service; +        LLSD result{ service("mapfunc", llsd::array(-12, "value")) }; +        ensure_equals("mapfunc() mismatch", result, llsd::map("i", 12, "str", "got value")); +    } + +    template<> template<> +    void object::test<28>() +    { +        set_test_name("array LLSD result"); +        DispatchResult service; +        LLSD result{ service("arrayfunc", llsd::array(-8, "word")) }; +        ensure_equals("arrayfunc() mismatch", result, llsd::array(8, "got word")); +    } + +    template<> template<> +    void object::test<29>() +    { +        set_test_name("listener error, no reply"); +        DispatchResult service; +        tut::call_exc( +            [&service]() +            { service.post(llsd::map("op", "nosuchfunc", "reqid", 17)); }, +            "nosuchfunc"); +    } + +    template<> template<> +    void object::test<30>() +    { +        set_test_name("listener error with reply"); +        DispatchResult service; +        LLCaptureListener<LLSD> result; +        service.post(llsd::map("op", "nosuchfunc", "reqid", 17, "reply", result.getName())); +        LLSD reply{ result.get() }; +        ensure("no reply", reply.isDefined()); +        ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17); +        ensure_has(reply["error"].asString(), "nosuchfunc"); +    } + +    template<> template<> +    void object::test<31>() +    { +        set_test_name("listener call to void function"); +        DispatchResult service; +        LLCaptureListener<LLSD> result; +        result.set("non-empty"); +        for (const auto& func: StringVec{ "voidfunc", "emptyfunc" }) +        { +            service.post(llsd::map( +                             "op", func, +                             "reqid", 17, +                             "reply", result.getName())); +            ensure_equals("reply from " + func, result.get().asString(), "non-empty"); +        } +    } + +    template<> template<> +    void object::test<32>() +    { +        set_test_name("listener call to string function"); +        DispatchResult service; +        LLCaptureListener<LLSD> result; +        service.post(llsd::map( +                         "op", "strfunc", +                         "args", llsd::array("a string"), +                         "reqid", 17, +                         "reply", result.getName())); +        LLSD reply{ result.get() }; +        ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17); +        ensure_equals("bad reply from strfunc", reply["data"].asString(), "got a string"); +    } + +    template<> template<> +    void object::test<33>() +    { +        set_test_name("listener call to map function"); +        DispatchResult service; +        LLCaptureListener<LLSD> result; +        service.post(llsd::map( +                         "op", "mapfunc", +                         "args", llsd::array(-7, "value"), +                         "reqid", 17, +                         "reply", result.getName())); +        LLSD reply{ result.get() }; +        ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17); +        ensure_equals("bad i from mapfunc", reply["i"].asInteger(), 7); +        ensure_equals("bad str from mapfunc", reply["str"], "got value"); +    } + +    template<> template<> +    void object::test<34>() +    { +        set_test_name("batched map success"); +        DispatchResult service; +        LLCaptureListener<LLSD> result; +        service.post(llsd::map( +                         "op", llsd::map( +                             "strfunc", "some string", +                             "intfunc", 2, +                             "voidfunc", LLSD(), +                             "arrayfunc", llsd::array(-5, "other string")), +                         "reqid", 17, +                         "reply", result.getName())); +        LLSD reply{ result.get() }; +        ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17); +        reply.erase("reqid"); +        ensure_equals( +            "bad map batch", +            reply, +            llsd::map( +                "strfunc", "got some string", +                "intfunc", -2, +                "voidfunc", LLSD(), +                "arrayfunc", llsd::array(5, "got other string"))); +    } + +    template<> template<> +    void object::test<35>() +    { +        set_test_name("batched map error"); +        DispatchResult service; +        LLCaptureListener<LLSD> result; +        service.post(llsd::map( +                         "op", llsd::map( +                             "badfunc", 34, // ! +                             "strfunc", "some string", +                             "intfunc", 2, +                             "missing", LLSD(), // ! +                             "voidfunc", LLSD(), +                             "arrayfunc", llsd::array(-5, "other string")), +                         "reqid", 17, +                         "reply", result.getName())); +        LLSD reply{ result.get() }; +        ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17); +        reply.erase("reqid"); +        auto error{ reply["error"].asString() }; +        reply.erase("error"); +        ensure_has(error, "badfunc"); +        ensure_has(error, "missing"); +        ensure_equals( +            "bad partial batch", +            reply, +            llsd::map( +                "strfunc", "got some string", +                "intfunc", -2, +                "voidfunc", LLSD(), +                "arrayfunc", llsd::array(5, "got other string"))); +    } + +    template<> template<> +    void object::test<36>() +    { +        set_test_name("batched map exception"); +        DispatchResult service; +        auto error = tut::call_exc( +            [&service]() +            { +                service.post(llsd::map( +                                 "op", llsd::map( +                                     "badfunc", 34, // ! +                                     "strfunc", "some string", +                                     "intfunc", 2, +                                     "missing", LLSD(), // ! +                                     "voidfunc", LLSD(), +                                     "arrayfunc", llsd::array(-5, "other string")), +                                 "reqid", 17)); +                // no "reply" +            }, +            "badfunc"); +        ensure_has(error, "missing"); +    } + +    template<> template<> +    void object::test<37>() +    { +        set_test_name("batched array success"); +        DispatchResult service; +        LLCaptureListener<LLSD> result; +        service.post(llsd::map( +                         "op", llsd::array( +                             llsd::array("strfunc", "some string"), +                             llsd::array("intfunc", 2), +                             "arrayfunc", +                             "voidfunc"), +                         "args", llsd::array( +                             LLSD(), +                             LLSD(), +                             llsd::array(-5, "other string")), +                         // args array deliberately short, since the default +                         // [3] is undefined, which should work for voidfunc +                         "reqid", 17, +                         "reply", result.getName())); +        LLSD reply{ result.get() }; +        ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17); +        reply.erase("reqid"); +        ensure_equals( +            "bad array batch", +            reply, +            llsd::map( +                "data", llsd::array( +                    "got some string", +                    -2, +                    llsd::array(5, "got other string"), +                    LLSD()))); +    } + +    template<> template<> +    void object::test<38>() +    { +        set_test_name("batched array error"); +        DispatchResult service; +        LLCaptureListener<LLSD> result; +        service.post(llsd::map( +                         "op", llsd::array( +                             llsd::array("strfunc", "some string"), +                             llsd::array("intfunc", 2, "whoops"), // bad form +                             "arrayfunc", +                             "voidfunc"), +                         "args", llsd::array( +                             LLSD(), +                             LLSD(), +                             llsd::array(-5, "other string")), +                         // args array deliberately short, since the default +                         // [3] is undefined, which should work for voidfunc +                         "reqid", 17, +                         "reply", result.getName())); +        LLSD reply{ result.get() }; +        ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17); +        reply.erase("reqid"); +        auto error{ reply["error"] }; +        reply.erase("error"); +        ensure_has(error, "[1]"); +        ensure_has(error, "unsupported"); +        ensure_equals("bad array batch", reply, +                      llsd::map("data", llsd::array("got some string"))); +    } + +    template<> template<> +    void object::test<39>() +    { +        set_test_name("batched array exception"); +        DispatchResult service; +        auto error = tut::call_exc( +            [&service]() +            { +                service.post(llsd::map( +                                 "op", llsd::array( +                                     llsd::array("strfunc", "some string"), +                                     llsd::array("intfunc", 2, "whoops"), // bad form +                                     "arrayfunc", +                                     "voidfunc"), +                                 "args", llsd::array( +                                     LLSD(), +                                     LLSD(), +                                     llsd::array(-5, "other string")), +                                 // args array deliberately short, since the default +                                 // [3] is undefined, which should work for voidfunc +                                 "reqid", 17)); +                // no "reply" +            }, +            "[1]"); +        ensure_has(error, "unsupported"); +    }  } // namespace tut diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index 3779fb41bc..d657b329bb 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -226,6 +226,11 @@ public:          return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out);      } +    friend inline std::ostream& operator<<(std::ostream& out, const CaptureLog& self) +    { +        return self.streamto(out); +    } +  private:      LLError::FatalFunction mFatalFunction;      LLError::SettingsStoragePtr mOldSettings;  | 
