From 66083f9e7a65367fad5bf17dec9a89f9b14c5985 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 1 Feb 2011 15:52:32 -0500 Subject: Replace ad-hoc test functions/methods with systematic enumeration. Previous tests involved a small handful of functions with only a couple different parameter types. Now we exhaustively invoke every registration case, plus every metadata query case. Call cases still pending. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 1023 +++++++++++++++++------ 1 file changed, 780 insertions(+), 243 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index a1d7cf9ead..35a3188507 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -23,30 +23,6 @@ #include "stringize.h" #include "tests/wrapllerrs.h" -// http://www.boost.org/doc/libs/1_45_0/libs/function_types/example/interpreter.hpp -// downloaded 2011-01-20 by NRG and adapted with example usage -// (C) Copyright Tobias Schwinger -// -// Use modification and distribution are subject to the boost Software License, -// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt). - -//------------------------------------------------------------------------------ -// -// This example implements a simple batch-style dispatcher that is capable of -// calling functions previously registered with it. The parameter types of the -// functions are used to control the parsing of the input. -// -// Implementation description -// ========================== -// -// When a function is registered, an 'invoker' template is instantiated with -// the function's type. The 'invoker' fetches a value from the 'arg_source' -// for each parameter of the function into a tuple and finally invokes the the -// function with these values as arguments. The invoker's entrypoint, which -// is a function of the callable builtin that describes the function to call and -// a reference to the 'arg_source', is partially bound to the registered -// function and put into a map so it can be found by name during parsing. - #include #include #include @@ -58,6 +34,7 @@ #include #include +#include using boost::lambda::constant; using boost::lambda::constant_ref; @@ -75,98 +52,244 @@ static std::ostringstream cout; /***************************************************************************** * Example data, functions, classes *****************************************************************************/ -// sensing globals -static std::string gs; -static float gf; -static int gi; -static LLSD gl; - -void clear() +// We don't need a whole lot of different arbitrary-params methods, just (no | +// (const LLSD&) | arbitrary) args (function | static method | non-static +// method), where 'arbitrary' is (every LLSD datatype + (const char*)). +// But we need to register each one under different names for the different +// registration styles. Don't forget LLEventDispatcher subclass methods(const +// LLSD&). + +// However, the number of target parameter conversions we want to try exceeds +// boost::fusion::invoke()'s supported parameter-list size. Break out two +// different lists. +#define NPARAMSa bool b, int i, float f, double d, const char* cp +#define NPARAMSb const std::string& s, const LLUUID& uuid, const LLDate& date, \ + const LLURI& uri, const std::vector& bin +#define NARGSa b, i, f, d, cp +#define NARGSb s, uuid, date, uri, bin + +// For some registration methods we need methods on a subclass of +// LLEventDispatcher. To simplify things, we'll use this Dispatcher subclass +// for all our testing, including testing its own methods. +class Dispatcher: public LLEventDispatcher { - gs.clear(); - gf = 0; - gi = 0; - gl = LLSD(); -} +public: + Dispatcher(const std::string& name, const std::string& key): + LLEventDispatcher(name, key) + {} -void abc(const std::string& message) -{ - cout << "abc('" << message << "')\n"; - gs = message; -} + // sensing member, mutable because we want to know when we've reached our + // const method too + mutable LLSD llsd; -void def(float value, std::string desc) -{ - cout << "def(" << value << ", '" << desc << "')\n"; - gf = value; - gs = desc; -} + void method1(const LLSD& obj) { llsd = obj; } + void cmethod1(const LLSD& obj) const { llsd = obj; } +}; -void ghi(const std::string& foo, int bar) +// sensing vars, captured in a struct to make it convenient to clear them +struct Vars { - cout << "ghi('" << foo << "', " << bar << ")\n"; - gs = foo; - gi = bar; -} + LLSD llsd; + bool b; + int i; + float f; + double d; + const char* cp; + std::string s; + LLUUID uuid; + LLDate date; + LLURI uri; + std::vector bin; + + Vars(): + // Only need to initialize the POD types, the rest should take care of + // default-constructing themselves. + b(false), + i(0), + f(0), + d(0), + cp(NULL) + {} + + // Detect any non-default values for convenient testing + LLSD inspect() const + { + LLSD result; + + if (llsd.isDefined()) + result["llsd"] = llsd; + if (b) + result["b"] = b; + if (i) + result["i"] = i; + if (f) + result["f"] = f; + if (d) + result["d"] = d; + if (cp) + result["cp"] = cp; + if (! s.empty()) + result["s"] = s; + if (uuid != LLUUID()) + result["uuid"] = uuid; + if (date != LLDate()) + result["date"] = date; + if (uri != LLURI()) + result["uri"] = uri; + if (! bin.empty()) + result["bin"] = bin; + + return result; + } -void jkl(const char* message) -{ - cout << "jkl('" << message << "')\n"; - gs = message; -} + /*------------- no-args (non-const, const, static) methods -------------*/ + void method0() + { + cout << "method0()\n"; + i = 17; + } -void somefunc(const LLSD& value) -{ - cout << "somefunc(" << value << ")\n"; - gl = value; -} + void cmethod0() const + { + cout << 'c'; + const_cast(this)->method0(); + } -class Dummy -{ -public: - Dummy(): _id("Dummy") {} + static void smethod0(); - void mno(const std::string& message) + /*------------ Callable (non-const, const, static) methods -------------*/ + void method1(const LLSD& obj) { - cout << _id << "::mno('" << message << "')\n"; - s = message; + cout << "method1(" << obj << ")\n"; + llsd = obj; } - void pqr(float value, std::string desc) + void cmethod1(const LLSD& obj) const { - cout << _id << "::pqr(" << value << ", '" << desc << "')\n"; - f = value; - s = desc; + cout << 'c'; + const_cast(this)->method1(obj); } - void stu(const std::string& foo, int bar) + static void smethod1(const LLSD& obj); + + /*-------- Arbitrary-params (non-const, const, static) methods ---------*/ + void methodna(NPARAMSa) { - cout << _id << "::stu('" << foo << "', " << bar << ")\n"; - s = foo; - i = bar; + std::string vcp; + if (cp == NULL) + vcp = "NULL"; + else + vcp = std::string("'") + cp + "'"; + + cout << "methodna(" << b + << ", " << i + << ", " << f + << ", " << d + << ", " << vcp + << ")\n"; + + this->b = b; + this->i = i; + this->f = f; + this->d = d; + this->cp = cp; } - void vwx(const char* message) + void methodnb(NPARAMSb) { - cout << _id << "::vwx('" << message << "')\n"; - s = message; + std::ostringstream vbin; + for (size_t ix = 0, ixend = bin.size(); ix < ixend; ++ix) + { + vbin << std::hex << std::setfill('0') << std::setw(2) << bin[ix]; + } + + cout << "methodnb(" << "'" << s << "'" + << ", " << uuid + << ", " << date + << ", '" << uri << "'" + << ", " << vbin.str() + << ")\n"; + + this->s = s; + this->uuid = uuid; + this->date = date; + this->uri = uri; + this->bin = bin; } - static void yz1(const std::string& message) + void cmethodna(NPARAMSa) const { - cout << "Dummy::yz1('" << message << "')\n"; - // can't access sensing members... - gs = message; + cout << 'c'; + const_cast(this)->methodna(NARGSa); } - // sensing members - std::string s; - float f; - int i; + void cmethodnb(NPARAMSb) const + { + cout << 'c'; + const_cast(this)->methodnb(NARGSb); + } -private: - std::string _id; + static void smethodna(NPARAMSa); + static void smethodnb(NPARAMSb); }; +/*------- Global Vars instance for free functions and static methods -------*/ +static Vars g; + +/*------------ Static Vars method implementations reference 'g' ------------*/ +void Vars::smethod0() +{ + cout << "smethod0() -> "; + g.method0(); +} + +void Vars::smethod1(const LLSD& obj) +{ + cout << "smethod1(" << obj << ") -> "; + g.method1(obj); +} + +void Vars::smethodna(NPARAMSa) +{ + cout << "smethodna(...) -> "; + g.methodna(NARGSa); +} + +void Vars::smethodnb(NPARAMSb) +{ + cout << "smethodnb(...) -> "; + g.methodnb(NARGSb); +} + +/*--------------------------- Reset global Vars ----------------------------*/ +void clear() +{ + g = Vars(); +} + +/*------------------- Free functions also reference 'g' --------------------*/ +void free0() +{ + cout << "free0() -> "; + g.method0(); +} + +void free1(const LLSD& obj) +{ + cout << "free1(" << obj << ") -> "; + g.method1(obj); +} + +void freena(NPARAMSa) +{ + cout << "freena(...) -> "; + g.methodna(NARGSa); +} + +void freenb(NPARAMSb) +{ + cout << "freenb(...) -> "; + g.methodnb(NARGSb); +} /***************************************************************************** * TUT @@ -176,30 +299,300 @@ namespace tut struct lleventdispatcher_data { WrapLL_ERRS redirect; - LLEventDispatcher work; - Dummy dummy; + Dispatcher work; + Vars v; + std::string name, desc; + typedef std::map FuncMap; + FuncMap funcs; + // Required structure for Callables with requirements + LLSD required; + // Parameter names for freena(), freenb() + LLSD paramsa, paramsb; + // Full defaults arrays for params for freena(), freenb() + LLSD dfta_array_full, dftb_array_full; + // Start index of partial defaults arrays + const LLSD::Integer partial_offset; + // Full defaults maps for params for freena(), freenb() + LLSD dfta_map_full, dftb_map_full; + // Partial defaults maps for params for freena(), freenb() + LLSD dfta_map_partial, dftb_map_partial; lleventdispatcher_data(): - work("test dispatcher", "op") + work("test dispatcher", "op"), + // map {d=double, array=[3 elements]} + required(LLSDMap("d", LLSD::Real(0))("array", LLSDArray(LLSD())(LLSD())(LLSD()))), + // first several params are required, last couple optional + partial_offset(3) { // This object is reconstructed for every test method. But // clear global variables every time too. ::clear(); - work.add("abc", "abc", abc, LLSDArray("message")); - work.add("def", "def", def); - work.add("ghi", "ghi", ghi); - work.add("jkl", "jkl", jkl); - work.add("yz1", "yz1", &Dummy::yz1); - work.add("mno", "mno", &Dummy::mno, var(dummy), - LLSDArray("message"), LLSDArray("default message")); - work.add("mnoptr", "mno", &Dummy::mno, constant(&dummy)); - work.add("pqr", "pqr", &Dummy::pqr, var(dummy), - LLSDArray("value")("desc")); - work.add("stu", "stu", &Dummy::stu, var(dummy), - LLSDArray("foo")("bar"), LLSDArray(-1)); - work.add("vwx", "vwx", &Dummy::vwx, var(dummy), - LLSDArray("message")); + // Registration cases: + // - (Callable | subclass const method | subclass non-const method | + // non-subclass method) (with | without) required + // - (Free function | static method | non-static method), (no | arbitrary) params, + // array style + // - (Free function | static method | non-static method), (no | arbitrary) params, + // map style, (empty | partial | full) (array | map) defaults + // - Map-style errors: + // - (scalar | map) param names + // - defaults scalar + // - defaults array longer than params array + // - defaults map with plural unknown param names + + // I hate to have to write things twice, because of having to keep + // them consistent. If we had variadic functions, addf() would be + // a variadic method, capturing the name and desc and passing them + // plus "everything else" to work.add(). If I could return a pair + // and use that pair as the first two args to work.add(), I'd do + // that. But the best I can do with present C++ is to set two + // instance variables as a side effect of addf(), and pass those + // variables to each work.add() call. :-P + + /*------------------------- Callables --------------------------*/ + + // Arbitrary Callable with/out required params + addf("free1", "free1"); + work.add(name, desc, free1); + addf("free1_req", "free1"); + work.add(name, desc, free1, required); + // Subclass non-const method with/out required params + addf("Dmethod1", "method1"); + work.add(name, desc, &Dispatcher::method1); + addf("Dmethod1_req", "method1"); + work.add(name, desc, &Dispatcher::method1, required); + // Subclass const method with/out required params + addf("Dcmethod1", "cmethod1"); + work.add(name, desc, &Dispatcher::cmethod1); + addf("Dcmethod1_req", "cmethod1"); + work.add(name, desc, &Dispatcher::cmethod1, required); + // Non-subclass method with/out required params + addf("method1", "method1"); + work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1)); + addf("method1_req", "method1"); + work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1), required); + + /*--------------- Arbitrary params, array style ----------------*/ + + // (Free function | static method) with (no | arbitrary) params, array style + addf("free0_array", "free0"); + work.add(name, desc, free0); + addf("freena_array", "freena"); + work.add(name, desc, freena); + addf("freenb_array", "freenb"); + work.add(name, desc, freenb); + addf("smethod0_array", "smethod0"); + work.add(name, desc, &Vars::smethod0); + addf("smethodna_array", "smethodna"); + work.add(name, desc, &Vars::smethodna); + addf("smethodnb_array", "smethodnb"); + work.add(name, desc, &Vars::smethodnb); + // Non-static method with (no | arbitrary) params, array style + addf("method0_array", "method0"); + work.add(name, desc, &Vars::method0, boost::lambda::var(v)); + addf("methodna_array", "methodna"); + work.add(name, desc, &Vars::methodna, boost::lambda::var(v)); + addf("methodnb_array", "methodnb"); + work.add(name, desc, &Vars::methodnb, boost::lambda::var(v)); + + /*---------------- Arbitrary params, map style -----------------*/ + + // freena(), methodna(), cmethodna(), smethodna() all take same param list + paramsa = LLSDArray("b")("i")("f")("d")("cp"); + // same for freenb() et al. + paramsb = LLSDArray("s")("uuid")("date")("uri")("bin"); + // Full defaults arrays. + dfta_array_full = LLSDArray(true)(17)(3.14)(123456.78)("classic"); + // default LLSD::Binary value + std::vector binary; + for (size_t ix = 0, h = 0xaa; ix < 6; ++ix, h += 0x11) + { + binary.push_back(h); + } + // We actually don't care what the LLUUID or LLDate values are, as + // long as they're non-default. + dftb_array_full = LLSDArray("string")(LLUUID::generateNewID())(LLDate::now()) + (LLURI("http://www.ietf.org/rfc/rfc3986.txt"))(binary); + // Partial defaults arrays. + LLSD dfta_array_partial(llsd_copy_array(dfta_array_full.beginArray() + partial_offset, + dfta_array_full.endArray())); + LLSD dftb_array_partial(llsd_copy_array(dftb_array_full.beginArray() + partial_offset, + dftb_array_full.endArray())); + + // Generate full defaults maps by zipping (params, dftx_array_full). + LLSD zipped(LLSDArray(LLSDArray(paramsa)(dfta_array_full)) + (LLSDArray(paramsb)(dftb_array_full))); +// std::cout << "zipped:\n" << zipped << '\n'; + LLSD dft_maps_full, dft_maps_partial; + for (LLSD::array_const_iterator ai(zipped.beginArray()), aend(zipped.endArray()); + ai != aend; ++ai) + { + LLSD dft_map_full; + LLSD params((*ai)[0]); + LLSD dft_array_full((*ai)[1]); +// std::cout << "params:\n" << params << "\ndft_array_full:\n" << dft_array_full << '\n'; + for (LLSD::Integer ix = 0, ixend = params.size(); ix < ixend; ++ix) + { + dft_map_full[params[ix].asString()] = dft_array_full[ix]; + } +// std::cout << "dft_map_full:\n" << dft_map_full << '\n'; + // Generate partial defaults map by zipping alternate entries from + // (params, dft_array_full). Part of the point of using map-style + // defaults is to allow any subset of the target function's + // parameters to be optional, not just the rightmost. + LLSD dft_map_partial; + for (LLSD::Integer ix = 0, ixend = params.size(); ix < ixend; ix += 2) + { + dft_map_partial[params[ix].asString()] = dft_array_full[ix]; + } +// std::cout << "dft_map_partial:\n" << dft_map_partial << '\n'; + dft_maps_full.append(dft_map_full); + dft_maps_partial.append(dft_map_partial); + } +// std::cout << "dft_maps_full:\n" << dft_maps_full << "\ndft_maps_partial:\n" << dft_maps_partial << '\n'; + dfta_map_full = dft_maps_full[0]; + dftb_map_full = dft_maps_full[1]; + dfta_map_partial = dft_maps_partial[0]; + dftb_map_partial = dft_maps_partial[1]; +// std::cout << "dfta_map_full:\n" << dfta_map_full +// << "\ndftb_map_full:\n" << dftb_map_full +// << "\ndfta_map_partial:\n" << dfta_map_partial +// << "\ndftb_map_partial:\n" << dftb_map_partial << '\n'; + + // (Free function | static method) with (no | arbitrary) params, + // map style, no (empty array) defaults + addf("free0_map", "free0"); + work.add(name, desc, free0, LLSD::emptyArray()); + addf("smethod0_map", "smethod0"); + work.add(name, desc, &Vars::smethod0, LLSD::emptyArray()); + addf("freena_map_allreq", "freena"); + work.add(name, desc, freena, paramsa); + addf("freenb_map_allreq", "freenb"); + work.add(name, desc, freenb, paramsb); + addf("smethodna_map_allreq", "smethodna"); + work.add(name, desc, &Vars::smethodna, paramsa); + addf("smethodnb_map_allreq", "smethodnb"); + work.add(name, desc, &Vars::smethodnb, paramsb); + // Non-static method with (no | arbitrary) params, map style, no + // (empty array) defaults + addf("method0_map", "method0"); + work.add(name, desc, &Vars::method0, var(v), LLSD::emptyArray()); + addf("methodna_map_allreq", "methodna"); + work.add(name, desc, &Vars::methodna, var(v), paramsa); + addf("methodnb_map_allreq", "methodnb"); + work.add(name, desc, &Vars::methodnb, var(v), paramsb); + + // Except for the "more (array | map) defaults than params" error + // cases, tested separately below, the (partial | full)(array | + // map) defaults cases don't apply to no-params functions/methods. + // So eliminate free0, smethod0, method0 from the cases below. + + // (Free function | static method) with arbitrary params, map + // style, partial (array | map) defaults + addf("freena_map_leftreq", "freena"); + work.add(name, desc, freena, paramsa, dfta_array_partial); + addf("freenb_map_leftreq", "freenb"); + work.add(name, desc, freenb, paramsb, dftb_array_partial); + addf("smethodna_map_leftreq", "smethodna"); + work.add(name, desc, &Vars::smethodna, paramsa, dfta_array_partial); + addf("smethodnb_map_leftreq", "smethodnb"); + work.add(name, desc, &Vars::smethodnb, paramsb, dftb_array_partial); + addf("freena_map_skipreq", "freena"); + work.add(name, desc, freena, paramsa, dfta_map_partial); + addf("freenb_map_skipreq", "freenb"); + work.add(name, desc, freenb, paramsb, dftb_map_partial); + addf("smethodna_map_skipreq", "smethodna"); + work.add(name, desc, &Vars::smethodna, paramsa, dfta_map_partial); + addf("smethodnb_map_skipreq", "smethodnb"); + work.add(name, desc, &Vars::smethodnb, paramsb, dftb_map_partial); + // Non-static method with arbitrary params, map style, partial + // (array | map) defaults + addf("methodna_map_leftreq", "methodna"); + work.add(name, desc, &Vars::methodna, var(v), paramsa, dfta_array_partial); + addf("methodnb_map_leftreq", "methodnb"); + work.add(name, desc, &Vars::methodnb, var(v), paramsb, dftb_array_partial); + addf("methodna_map_skipreq", "methodna"); + work.add(name, desc, &Vars::methodna, var(v), paramsa, dfta_map_partial); + addf("methodnb_map_skipreq", "methodnb"); + work.add(name, desc, &Vars::methodnb, var(v), paramsb, dftb_map_partial); + + // (Free function | static method) with arbitrary params, map + // style, full (array | map) defaults + addf("freena_map_adft", "freena"); + work.add(name, desc, freena, paramsa, dfta_array_full); + addf("freenb_map_adft", "freenb"); + work.add(name, desc, freenb, paramsb, dftb_array_full); + addf("smethodna_map_adft", "smethodna"); + work.add(name, desc, &Vars::smethodna, paramsa, dfta_array_full); + addf("smethodnb_map_adft", "smethodnb"); + work.add(name, desc, &Vars::smethodnb, paramsb, dftb_array_full); + addf("freena_map_mdft", "freena"); + work.add(name, desc, freena, paramsa, dfta_map_full); + addf("freenb_map_mdft", "freenb"); + work.add(name, desc, freenb, paramsb, dftb_map_full); + addf("smethodna_map_mdft", "smethodna"); + work.add(name, desc, &Vars::smethodna, paramsa, dfta_map_full); + addf("smethodnb_map_mdft", "smethodnb"); + work.add(name, desc, &Vars::smethodnb, paramsb, dftb_map_full); + // Non-static method with arbitrary params, map style, full + // (array | map) defaults + addf("methodna_map_adft", "methodna"); + work.add(name, desc, &Vars::methodna, var(v), paramsa, dfta_array_full); + addf("methodnb_map_adft", "methodnb"); + work.add(name, desc, &Vars::methodnb, var(v), paramsb, dftb_array_full); + addf("methodna_map_mdft", "methodna"); + work.add(name, desc, &Vars::methodna, var(v), paramsa, dfta_map_full); + addf("methodnb_map_mdft", "methodnb"); + work.add(name, desc, &Vars::methodnb, var(v), paramsb, dftb_map_full); + + // All the above are expected to succeed, and are setup for the + // tests to follow. Registration error cases are exercised as + // tests rather than as test setup. + } + + void addf(const std::string& n, const std::string& d) + { + // This method is to capture in our own FuncMap the name and + // description of every registered function, for metadata query + // testing. + funcs[n] = d; + // See constructor for rationale for setting these instance vars. + this->name = n; + this->desc = d; + } + + void verify_funcs() + { + // Copy funcs to a temp map of same type. + FuncMap forgotten(funcs.begin(), funcs.end()); + for (LLEventDispatcher::const_iterator edi(work.begin()), edend(work.end()); + edi != edend; ++edi) + { + FuncMap::iterator found = forgotten.find(edi->first); + ensure(STRINGIZE("LLEventDispatcher records function '" << edi->first + << "' we didn't enter"), + found != forgotten.end()); + ensure_equals(STRINGIZE("LLEventDispatcher desc '" << edi->second << + "' doesn't match what we entered: '" << found->second << "'"), + edi->second, found->second); + // found in our map the name from LLEventDispatcher, good, erase + // our map entry + forgotten.erase(found); + } + if (! forgotten.empty()) + { + std::ostringstream out; + out << "LLEventDispatcher failed to report"; + const char* delim = ": "; + for (FuncMap::const_iterator fmi(forgotten.begin()), fmend(forgotten.end()); + fmi != fmend; ++fmi) + { + out << delim << fmi->first; + delim = ", "; + } + ensure(out.str(), false); + } } void ensure_has(const std::string& outer, const std::string& inner) @@ -222,215 +615,359 @@ namespace tut } ensure_has(threw, exc_frag); } + + LLSD getMetadata(const std::string& name) + { + LLSD meta(work.getMetadata(name)); + ensure(STRINGIZE("No metadata for " << name), meta.isDefined()); + return meta; + } }; typedef test_group lleventdispatcher_group; typedef lleventdispatcher_group::object object; lleventdispatcher_group lleventdispatchergrp("lleventdispatcher"); + // Call cases: + // - (try_call | call) (explicit name | event key) (real | bogus) name + // - Callable with args that (do | do not) match required + // - (Free function | non-static method) array style with + // (scalar | map | array (too short | too long | just right)) + // [trap LL_WARNS for too-long case?] + // - (Free function | non-static method) map style with + // (scalar | array | map (all | too many | holes (with | without) defaults)) + // - const char* param gets ("" | NULL) + + // Query cases: + // - Iterate over all (with | without) remove() + // - getDispatchKey() + // - Callable style (with | without) required + // - (Free function | non-static method), array style, (no | arbitrary) params + // - (Free function | non-static method), map style, (no | arbitrary) params, + // (empty | full | partial (array | map)) defaults + template<> template<> void object::test<1>() { - LLSD hello("Hello test!"); -// cout << std::string(hello) << "\n"; - clear(); - jkl(LLSDParam(hello)); - ensure_equals(gs, hello.asString()); + set_test_name("map-style registration with non-array params"); + // Pass "param names" as scalar or as map + LLSD attempts(LLSDArray(17)(LLSDMap("pi", 3.14)("two", 2))); + for (LLSD::array_const_iterator ai(attempts.beginArray()), aend(attempts.endArray()); + ai != aend; ++ai) + { + std::string threw; + try + { + work.add("freena_err", "freena", freena, *ai); + } + catch (const std::exception& e) + { + threw = e.what(); + } + ensure_has(threw, "must be an array"); + } } template<> template<> void object::test<2>() { - somefunc("abc"); - ensure_equals(gl.asString(), "abc"); - - somefunc(17); - ensure_equals(gl.asInteger(), 17); - - somefunc(3.14); - // 7 bits is 128, just enough to express two decimal places. - ensure_approximately_equals(gl.asReal(), 3.14, 7); - - somefunc(LLSD().with(0, "abc").with(1, 17).with(2, 3.14)); - ensure(gl.isArray()); - ensure_equals(gl.size(), 4); // !!! bug in LLSD::with(Integer, const LLSD&) !!! - ensure_equals(gl[1].asInteger(), 17); - - somefunc(LLSD().with("alpha", "abc").with("random", 17).with("pi", 3.14)); - ensure(gl.isMap()); - ensure_equals(gl.size(), 3); - ensure_equals(gl["random"].asInteger(), 17); - - somefunc(LLSDArray("abc")(17)(3.14)); - ensure(gl.isArray()); - ensure_equals(gl.size(), 3); - ensure_equals(gl[0].asString(), "abc"); - - somefunc(LLSDMap("alpha", "abc")("random", 17)("pi", 3.14)); - ensure(gl.isMap()); - ensure_equals(gl.size(), 3); - ensure_equals(gl["alpha"].asString(), "abc"); + 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(); + } + ensure_has(threw, "must be a map or an array"); } template<> template<> void object::test<3>() { - call_exc("gofish", LLSDArray(1), "not found"); + 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(); + } + ensure_has(threw, "shorter than"); } template<> template<> void object::test<4>() { - call_exc("abc", LLSD(), "missing required"); + 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(); + } + ensure_has(threw, "nonexistent params"); + ensure_has(threw, "foo"); + ensure_has(threw, "bar"); } template<> template<> void object::test<5>() { - work("abc", LLSDMap("message", "something")); - ensure_equals(gs, "something"); + set_test_name("query all"); + verify_funcs(); } template<> template<> void object::test<6>() { - work("abc", LLSDMap("message", "something")("plus", "more")); - ensure_equals(gs, "something"); + set_test_name("query all with remove()"); + ensure("remove('bogus') returned true", ! work.remove("bogus")); + ensure("remove('real') returned false", work.remove("free1")); + // Of course, remove that from 'funcs' too... + funcs.erase("free1"); + verify_funcs(); } template<> template<> void object::test<7>() { - call_exc("def", LLSDMap("value", 20)("desc", "questions"), "needs an args array"); + set_test_name("getDispatchKey()"); + ensure_equals(work.getDispatchKey(), "op"); } template<> template<> void object::test<8>() { - work("def", LLSDArray(20)("questions")); - ensure_equals(gf, 20); - ensure_equals(gs, "questions"); + set_test_name("query Callables with/out required params"); + LLSD names(LLSDArray("free1")("Dmethod1")("Dcmethod1")("method1")); + for (LLSD::array_const_iterator ai(names.beginArray()), aend(names.endArray()); + ai != aend; ++ai) + { + LLSD metadata(getMetadata(*ai)); + ensure_equals("name mismatch", metadata["name"], *ai); + ensure_equals(metadata["desc"].asString(), funcs[*ai]); + ensure("should not have required structure", metadata["required"].isUndefined()); + ensure("should not have optional", metadata["optional"].isUndefined()); + + std::string name_req(ai->asString() + "_req"); + metadata = getMetadata(name_req); + ensure_equals(metadata["name"].asString(), name_req); + ensure_equals(metadata["desc"].asString(), funcs[name_req]); + ensure_equals("required mismatch", required, metadata["required"]); + ensure("should not have optional", metadata["optional"].isUndefined()); + } } template<> template<> void object::test<9>() { - work("def", LLSDArray(3.14)("pies")); - ensure_approximately_equals(gf, 3.14, 7); - ensure_equals(gs, "pies"); + set_test_name("query array-style functions/methods"); + // Associate each registered name with expected arity. + LLSD expected(LLSDArray + (LLSDArray + (0)(LLSDArray("free0_array")("smethod0_array")("method0_array"))) + (LLSDArray + (5)(LLSDArray("freena_array")("smethodna_array")("methodna_array"))) + (LLSDArray + (5)(LLSDArray("freenb_array")("smethodnb_array")("methodnb_array")))); + for (LLSD::array_const_iterator ai(expected.beginArray()), aend(expected.endArray()); + ai != aend; ++ai) + { + LLSD::Integer arity((*ai)[0].asInteger()); + LLSD names((*ai)[1]); + LLSD req(LLSD::emptyArray()); + if (arity) + req[arity - 1] = LLSD(); + for (LLSD::array_const_iterator ni(names.beginArray()), nend(names.endArray()); + ni != nend; ++ni) + { + LLSD metadata(getMetadata(*ni)); + ensure_equals("name mismatch", metadata["name"], *ni); + ensure_equals(metadata["desc"].asString(), funcs[*ni]); + ensure_equals(STRINGIZE("mismatched required for " << ni->asString()), + metadata["required"], req); + ensure("should not have optional", metadata["optional"].isUndefined()); + } + } } template<> template<> void object::test<10>() { - work("ghi", LLSDArray("answer")(17)); - ensure_equals(gs, "answer"); - ensure_equals(gi, 17); + set_test_name("query map-style no-params functions/methods"); + // - (Free function | non-static method), map style, no params (ergo + // no defaults) + LLSD names(LLSDArray("free0_map")("smethod0_map")("method0_map")); + for (LLSD::array_const_iterator ni(names.beginArray()), nend(names.endArray()); + ni != nend; ++ni) + { + LLSD metadata(getMetadata(*ni)); + ensure_equals("name mismatch", metadata["name"], *ni); + ensure_equals(metadata["desc"].asString(), funcs[*ni]); + ensure("should not have required", + (metadata["required"].isUndefined() || metadata["required"].size() == 0)); + ensure("should not have optional", metadata["optional"].isUndefined()); + } } template<> template<> void object::test<11>() { - work("ghi", LLSDArray("answer")(3.14)); - ensure_equals(gs, "answer"); - ensure_equals(gi, 3); + set_test_name("query map-style arbitrary-params functions/methods: " + "full array defaults vs. full map defaults"); + // With functions registered with no defaults ("_allreq" suffixes), + // there is of course no difference between array defaults and map + // defaults. (We don't even bother registering with LLSD::emptyArray() + // vs. LLSD::emptyMap().) With functions registered with all defaults, + // there should (!) be no difference beween array defaults and map + // defaults. Verify, so we can ignore the distinction for all other + // tests. + LLSD equivalences(LLSDArray + (LLSDArray("freena_map_adft")("freena_map_mdft")) + (LLSDArray("freenb_map_adft")("freenb_map_mdft")) + (LLSDArray("smethodna_map_adft")("smethodna_map_mdft")) + (LLSDArray("smethodnb_map_adft")("smethodnb_map_mdft")) + (LLSDArray("methodna_map_adft")("methodna_map_mdft")) + (LLSDArray("methodnb_map_adft")("methodnb_map_mdft"))); + for (LLSD::array_const_iterator + ei(equivalences.beginArray()), eend(equivalences.endArray()); + ei != eend; ++ei) + { + LLSD adft((*ei)[0]); + LLSD mdft((*ei)[1]); + // We can't just compare the results of the two getMetadata() + // calls, because they contain ["name"], which are different. So + // capture them, verify that each ["name"] is as expected, then + // remove for comparing the rest. + LLSD ameta(getMetadata(adft)); + LLSD mmeta(getMetadata(mdft)); + ensure_equals("adft name", adft, ameta["name"]); + ensure_equals("mdft name", mdft, mmeta["name"]); + ameta.erase("name"); + mmeta.erase("name"); + ensure_equals(STRINGIZE("metadata for " << adft.asString() + << " vs. " << mdft.asString()), + ameta, mmeta); + } } template<> template<> void object::test<12>() { - work("jkl", LLSDArray("sample message")); - ensure_equals(gs, "sample message"); - } - - template<> template<> - void object::test<13>() - { - work("yz1", LLSDArray("w00t")); - ensure_equals(gs, "w00t"); - } - - template<> template<> - void object::test<14>() - { - std::string msg("nonstatic member function"); - work("mno", LLSDMap("message", msg)); - ensure_equals(dummy.s, msg); - } + set_test_name("query map-style arbitrary-params functions/methods"); + // - (Free function | non-static method), map style, arbitrary params, + // (empty | full | partial (array | map)) defaults + + // Generate maps containing all parameter names for cases in which all + // params are required. Also maps containing left requirements for + // partial defaults arrays. Also defaults maps from defaults arrays. + LLSD allreqa, allreqb, leftreqa, leftreqb, rightdfta, rightdftb; + for (LLSD::Integer pi(0), pend(std::min(partial_offset, paramsa.size())); + pi < pend; ++pi) + { + allreqa[paramsa[pi].asString()] = LLSD(); + leftreqa[paramsa[pi].asString()] = LLSD(); + } + for (LLSD::Integer pi(partial_offset), pend(paramsa.size()); pi < pend; ++pi) + { + allreqa[paramsa[pi].asString()] = LLSD(); + rightdfta[paramsa[pi].asString()] = dfta_array_full[pi]; + } + for (LLSD::Integer pi(0), pend(std::min(partial_offset, paramsb.size())); + pi < pend; ++pi) + { + allreqb[paramsb[pi].asString()] = LLSD(); + leftreqb[paramsb[pi].asString()] = LLSD(); + } + for (LLSD::Integer pi(partial_offset), pend(paramsb.size()); pi < pend; ++pi) + { + allreqb[paramsb[pi].asString()] = LLSD(); + rightdftb[paramsb[pi].asString()] = dftb_array_full[pi]; + } - template<> template<> - void object::test<15>() - { - std::string msg("nonstatic member function reached by ptr"); - work("mnoptr", LLSDArray(msg)); - ensure_equals(dummy.s, msg); - } + // Generate maps containing parameter names not provided by the + // dft[ab]_map_partial maps. + LLSD skipreqa(allreqa), skipreqb(allreqb); + for (LLSD::map_const_iterator mi(dfta_map_partial.beginMap()), + mend(dfta_map_partial.endMap()); + mi != mend; ++mi) + { + skipreqa.erase(mi->first); + } + for (LLSD::map_const_iterator mi(dftb_map_partial.beginMap()), + mend(dftb_map_partial.endMap()); + mi != mend; ++mi) + { + skipreqb.erase(mi->first); + } - template<> template<> - void object::test<16>() - { - work("mno", LLSD()); - ensure_equals(dummy.s, "default message"); - } + LLSD groups(LLSDArray // array of groups - template<> template<> - void object::test<17>() - { - work("pqr", LLSDMap("value", 3.14)("desc", "pies")); - ensure_approximately_equals(dummy.f, 3.14, 7); - ensure_equals(dummy.s, "pies"); - } + (LLSDArray // group + (LLSDArray("freena_map_allreq")("smethodna_map_allreq")("methodna_map_allreq")) + (LLSDArray(allreqa)(LLSD()))) // required, optional - template<> template<> - void object::test<18>() - { - call_exc("pqr", LLSD(), "missing required"); - } + (LLSDArray // group + (LLSDArray("freenb_map_allreq")("smethodnb_map_allreq")("methodnb_map_allreq")) + (LLSDArray(allreqb)(LLSD()))) // required, optional - template<> template<> - void object::test<19>() - { - call_exc("pqr", LLSDMap("value", 3.14), "missing required"); - } + (LLSDArray // group + (LLSDArray("freena_map_leftreq")("smethodna_map_leftreq")("methodna_map_leftreq")) + (LLSDArray(leftreqa)(rightdfta))) // required, optional - template<> template<> - void object::test<20>() - { - call_exc("pqr", LLSDMap("desc", "pies"), "missing required"); - } + (LLSDArray // group + (LLSDArray("freenb_map_leftreq")("smethodnb_map_leftreq")("methodnb_map_leftreq")) + (LLSDArray(leftreqb)(rightdftb))) // required, optional - template<> template<> - void object::test<21>() - { - work("stu", LLSDMap("bar", 3.14)("foo", "pies")); - ensure_equals(dummy.s, "pies"); - ensure_equals(dummy.i, 3); - } + (LLSDArray // group + (LLSDArray("freena_map_skipreq")("smethodna_map_skipreq")("methodna_map_skipreq")) + (LLSDArray(skipreqa)(dfta_map_partial))) // required, optional - template<> template<> - void object::test<22>() - { - call_exc("stu", LLSD(), "missing required"); - } + (LLSDArray // group + (LLSDArray("freenb_map_skipreq")("smethodnb_map_skipreq")("methodnb_map_skipreq")) + (LLSDArray(skipreqb)(dftb_map_partial))) // required, optional - template<> template<> - void object::test<23>() - { - call_exc("stu", LLSDMap("bar", 3.14), "missing required"); - } + // We only need mention the full-map-defaults ("_mdft" suffix) + // registrations, having established their equivalence with the + // full-array-defaults ("_adft" suffix) registrations in another test. + (LLSDArray // group + (LLSDArray("freena_map_mdft")("smethodna_map_mdft")("methodna_map_mdft")) + (LLSDArray(LLSD::emptyMap())(dfta_map_full))) // required, optional - template<> template<> - void object::test<24>() - { - work("stu", LLSDMap("foo", "pies")); - ensure_equals(dummy.s, "pies"); - ensure_equals(dummy.i, -1); - } + (LLSDArray // group + (LLSDArray("freenb_map_mdft")("smethodnb_map_mdft")("methodnb_map_mdft")) + (LLSDArray(LLSD::emptyMap())(dftb_map_full)))); // required, optional - template<> template<> - void object::test<25>() - { - std::string msg("nonstatic method(const char*)"); - work("vwx", LLSDMap("message", msg)); - ensure_equals(dummy.s, msg); + for (LLSD::array_const_iterator gi(groups.beginArray()), gend(groups.endArray()); + gi != gend; ++gi) + { + // Internal structure of each group in 'groups': + LLSD names((*gi)[0]); + LLSD required((*gi)[1][0]); + LLSD optional((*gi)[1][1]); + std::cout << "For " << names << ",\n" << "required:\n" << required << "\noptional:\n" << optional << std::endl; + + // Loop through 'names' + for (LLSD::array_const_iterator ni(names.beginArray()), nend(names.endArray()); + ni != nend; ++ni) + { + LLSD metadata(getMetadata(*ni)); + ensure_equals("name mismatch", metadata["name"], *ni); + ensure_equals(metadata["desc"].asString(), funcs[*ni]); + ensure_equals("required mismatch", metadata["required"], required); + ensure_equals("optional mismatch", metadata["optional"], optional); + } + } } } // namespace tut -- cgit v1.2.3 From f1262c83fc9be45c4b5cd1678c127b601634fb29 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 2 Feb 2011 11:13:07 -0500 Subject: First few LLEventDispatcher call cases: try_call(), call Callables --- indra/llcommon/tests/lleventdispatcher_test.cpp | 88 ++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 35a3188507..30878beae4 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -956,7 +956,7 @@ namespace tut LLSD names((*gi)[0]); LLSD required((*gi)[1][0]); LLSD optional((*gi)[1][1]); - std::cout << "For " << names << ",\n" << "required:\n" << required << "\noptional:\n" << optional << std::endl; + cout << "For " << names << ",\n" << "required:\n" << required << "\noptional:\n" << optional << std::endl; // Loop through 'names' for (LLSD::array_const_iterator ni(names.beginArray()), nend(names.endArray()); @@ -970,4 +970,90 @@ namespace tut } } } + + template<> template<> + void object::test<13>() + { + set_test_name("try_call()"); + ensure("try_call(bogus name, LLSD()) returned true", ! work.try_call("freek", LLSD())); + ensure("try_call(bogus name) returned true", ! work.try_call(LLSDMap("op", "freek"))); + ensure("try_call(real name, LLSD()) returned false", work.try_call("free0_array", LLSD())); + ensure("try_call(real name) returned false", work.try_call(LLSDMap("op", "free0_map"))); + } + + template<> template<> + void object::test<14>() + { + 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; + try + { + work(LLSDMap("op", "freek")); + } + catch (const std::runtime_error& e) + { + cout << "*** " << e.what() << "\n"; + threw = e.what(); + } + ensure_has(threw, "bad"); + ensure_has(threw, "op"); + ensure_has(threw, "freek"); + } + + template<> template<> + void object::test<15>() + { + set_test_name("call with event key"); + // We don't need a separate test for operator()(string, LLSD) with + // valid name, because all the rest of the tests exercise that case. + // The one we don't exercise elsewhere is operator()(LLSD) with valid + // name, so here it is. + work(LLSDMap("op", "free0_map")); + ensure_equals(g.i, 17); + } + + // Cannot be defined inside function body... remind me again why we use C++... :-P + struct Triple + { + std::string name, name_req; + LLSD& llsd; + }; + + template<> template<> + void object::test<16>() + { + set_test_name("call Callables"); + Triple tests[] = + { + { "free1", "free1_req", g.llsd }, + { "Dmethod1", "Dmethod1_req", work.llsd }, + { "Dcmethod1", "Dcmethod1_req", work.llsd }, + { "method1", "method1_req", v.llsd } + }; + // Arbitrary LLSD value that we should be able to pass to Callables + // without 'required', but should not be able to pass to Callables + // with 'required'. + LLSD answer(42); + // LLSD value matching 'required' according to llsd_matches() rules. + LLSD matching(LLSDMap("d", 3.14)("array", LLSDArray("answer")(true)(answer))); + // Okay, walk through 'tests'. + for (const Triple *ti(boost::begin(tests)), *tend(boost::end(tests)); ti != tend; ++ti) + { + // Should be able to pass 'answer' to Callables registered + // without 'required'. + work(ti->name, answer); + ensure_equals("answer mismatch", ti->llsd, answer); + // Should NOT be able to pass 'answer' to Callables registered + // with 'required'. + call_exc(ti->name_req, answer, "bad request"); + // But SHOULD be able to pass 'matching' to Callables registered + // with 'required'. + work(ti->name_req, matching); + ensure_equals("matching mismatch", ti->llsd, matching); + } + } } // namespace tut -- cgit v1.2.3 From 63f81d59f6e736c5fdd30d8297d64d1677987d3c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 2 Feb 2011 17:17:41 -0500 Subject: Add test to exercise map/array args mismatch validation. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 30878beae4..2f2188a121 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -1056,4 +1056,24 @@ namespace tut ensure_equals("matching mismatch", ti->llsd, matching); } } + + template<> template<> + void object::test<17>() + { + 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); + + std::string map_exc("needs a map"); + call_exc("free0_map", 17, map_exc); + call_exc("free0_map", LLSDArray("a")("b"), map_exc); + } } // namespace tut -- cgit v1.2.3 From 84a402adf181165b4fef0ab8f1c0e63cc81a57ee Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 2 Feb 2011 17:42:26 -0500 Subject: Add test to call no-args functions using (map | array)-style calls --- indra/llcommon/tests/lleventdispatcher_test.cpp | 43 +++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 2f2188a121..63a130a94b 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -1017,7 +1017,7 @@ namespace tut } // Cannot be defined inside function body... remind me again why we use C++... :-P - struct Triple + struct CallablesTriple { std::string name, name_req; LLSD& llsd; @@ -1027,7 +1027,7 @@ namespace tut void object::test<16>() { set_test_name("call Callables"); - Triple tests[] = + CallablesTriple tests[] = { { "free1", "free1_req", g.llsd }, { "Dmethod1", "Dmethod1_req", work.llsd }, @@ -1041,7 +1041,8 @@ namespace tut // LLSD value matching 'required' according to llsd_matches() rules. LLSD matching(LLSDMap("d", 3.14)("array", LLSDArray("answer")(true)(answer))); // Okay, walk through 'tests'. - for (const Triple *ti(boost::begin(tests)), *tend(boost::end(tests)); ti != tend; ++ti) + for (const CallablesTriple *ti(boost::begin(tests)), *tend(boost::end(tests)); + ti != tend; ++ti) { // Should be able to pass 'answer' to Callables registered // without 'required'. @@ -1076,4 +1077,40 @@ namespace tut call_exc("free0_map", 17, map_exc); call_exc("free0_map", LLSDArray("a")("b"), map_exc); } + + struct FunctionsTriple + { + std::string name_array, name_map; + Vars& vars; + }; + + template<> template<> + void object::test<18>() + { + set_test_name("call no-args functions"); + FunctionsTriple tests[] = + { + { "free0_array", "free0_map", g }, + { "smethod0_array", "smethod0_map", g }, + { "method0_array", "method0_map", v } + }; + for (const FunctionsTriple *ti(boost::begin(tests)), *tend(boost::end(tests)); + ti != tend; ++ti) + { + // Both the global and stack Vars instances are automatically + // cleared at the start of each test method. But since we're + // calling these things several different times in the same + // test method, manually reset the Vars between each. + ti->vars = Vars(); + ensure_equals(ti->vars.i, 0); + // array-style call with empty array (or LLSD(), should be equivalent) + work(ti->name_array, LLSD()); + ensure_equals(ti->vars.i, 17); + + ti->vars = Vars(); + // map-style call with empty map (or LLSD(), should be equivalent) + work(ti->name_map, LLSD()); + ensure_equals(ti->vars.i, 17); + } + } } // namespace tut -- cgit v1.2.3 From 3cdd1931c67ae3be26549d05889e19ba26d3db03 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 3 Feb 2011 19:38:41 -0500 Subject: Add test to call array-style functions with too-short array. Also, finally got sick of hand-writing the official iterator-loop idiom and dragged in BOOST_FOREACH(). Because LLSD has two completely different iteration styles, added inArray and inMap helper classes to be able to write: BOOST_FOREACH(LLSD item, inArray(someArray)) { ... } --- indra/llcommon/tests/lleventdispatcher_test.cpp | 218 +++++++++++++++--------- 1 file changed, 137 insertions(+), 81 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 63a130a94b..2975707860 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#define foreach BOOST_FOREACH #include @@ -49,6 +51,52 @@ using std::cout; static std::ostringstream cout; #endif +/***************************************************************************** +* BOOST_FOREACH() helpers for LLSD +*****************************************************************************/ +/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... } +class inArray +{ +public: + inArray(const LLSD& array): + _array(array) + {} + + typedef LLSD::array_const_iterator const_iterator; + typedef LLSD::array_iterator iterator; + + iterator begin() { return _array.beginArray(); } + iterator end() { return _array.endArray(); } + const_iterator begin() const { return _array.beginArray(); } + const_iterator end() const { return _array.endArray(); } + +private: + LLSD _array; +}; + +/// MapEntry is what you get from dereferencing an LLSD::map_[const_]iterator. +typedef std::pair MapEntry; + +/// Usage: BOOST_FOREACH([const] MapEntry& e, inMap(someLLSDmap)) { ... } +class inMap +{ +public: + inMap(const LLSD& map): + _map(map) + {} + + typedef LLSD::map_const_iterator const_iterator; + typedef LLSD::map_iterator iterator; + + iterator begin() { return _map.beginMap(); } + iterator end() { return _map.endMap(); } + const_iterator begin() const { return _map.beginMap(); } + const_iterator end() const { return _map.endMap(); } + +private: + LLSD _map; +}; + /***************************************************************************** * Example data, functions, classes *****************************************************************************/ @@ -198,9 +246,9 @@ struct Vars void methodnb(NPARAMSb) { std::ostringstream vbin; - for (size_t ix = 0, ixend = bin.size(); ix < ixend; ++ix) + foreach(U8 byte, bin) { - vbin << std::hex << std::setfill('0') << std::setw(2) << bin[ix]; + vbin << std::hex << std::setfill('0') << std::setw(2) << byte; } cout << "methodnb(" << "'" << s << "'" @@ -425,12 +473,11 @@ namespace tut (LLSDArray(paramsb)(dftb_array_full))); // std::cout << "zipped:\n" << zipped << '\n'; LLSD dft_maps_full, dft_maps_partial; - for (LLSD::array_const_iterator ai(zipped.beginArray()), aend(zipped.endArray()); - ai != aend; ++ai) + foreach(LLSD ae, inArray(zipped)) { LLSD dft_map_full; - LLSD params((*ai)[0]); - LLSD dft_array_full((*ai)[1]); + LLSD params(ae[0]); + LLSD dft_array_full(ae[1]); // std::cout << "params:\n" << params << "\ndft_array_full:\n" << dft_array_full << '\n'; for (LLSD::Integer ix = 0, ixend = params.size(); ix < ixend; ++ix) { @@ -566,16 +613,20 @@ namespace tut { // Copy funcs to a temp map of same type. FuncMap forgotten(funcs.begin(), funcs.end()); - for (LLEventDispatcher::const_iterator edi(work.begin()), edend(work.end()); - edi != edend; ++edi) + // 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(work)) { - FuncMap::iterator found = forgotten.find(edi->first); - ensure(STRINGIZE("LLEventDispatcher records function '" << edi->first + FuncMap::iterator found = forgotten.find(nd.first); + ensure(STRINGIZE("LLEventDispatcher records function '" << nd.first << "' we didn't enter"), found != forgotten.end()); - ensure_equals(STRINGIZE("LLEventDispatcher desc '" << edi->second << + ensure_equals(STRINGIZE("LLEventDispatcher desc '" << nd.second << "' doesn't match what we entered: '" << found->second << "'"), - edi->second, found->second); + nd.second, found->second); // found in our map the name from LLEventDispatcher, good, erase // our map entry forgotten.erase(found); @@ -585,10 +636,9 @@ namespace tut std::ostringstream out; out << "LLEventDispatcher failed to report"; const char* delim = ": "; - for (FuncMap::const_iterator fmi(forgotten.begin()), fmend(forgotten.end()); - fmi != fmend; ++fmi) + foreach(const FuncMap::value_type& fme, forgotten) { - out << delim << fmi->first; + out << delim << fme.first; delim = ", "; } ensure(out.str(), false); @@ -630,10 +680,11 @@ namespace tut // Call cases: // - (try_call | call) (explicit name | event key) (real | bogus) name // - Callable with args that (do | do not) match required - // - (Free function | non-static method) array style with + // - (Free function | non-static method), no args, (array | map) style + // - (Free function | non-static method), arbitrary args, array style with // (scalar | map | array (too short | too long | just right)) // [trap LL_WARNS for too-long case?] - // - (Free function | non-static method) map style with + // - (Free function | non-static method), arbitrary args, map style with // (scalar | array | map (all | too many | holes (with | without) defaults)) // - const char* param gets ("" | NULL) @@ -651,13 +702,12 @@ namespace tut set_test_name("map-style registration with non-array params"); // Pass "param names" as scalar or as map LLSD attempts(LLSDArray(17)(LLSDMap("pi", 3.14)("two", 2))); - for (LLSD::array_const_iterator ai(attempts.beginArray()), aend(attempts.endArray()); - ai != aend; ++ai) + foreach(LLSD ae, inArray(attempts)) { std::string threw; try { - work.add("freena_err", "freena", freena, *ai); + work.add("freena_err", "freena", freena, ae); } catch (const std::exception& e) { @@ -751,16 +801,15 @@ namespace tut { set_test_name("query Callables with/out required params"); LLSD names(LLSDArray("free1")("Dmethod1")("Dcmethod1")("method1")); - for (LLSD::array_const_iterator ai(names.beginArray()), aend(names.endArray()); - ai != aend; ++ai) + foreach(LLSD ae, inArray(names)) { - LLSD metadata(getMetadata(*ai)); - ensure_equals("name mismatch", metadata["name"], *ai); - ensure_equals(metadata["desc"].asString(), funcs[*ai]); + LLSD metadata(getMetadata(ae)); + ensure_equals("name mismatch", metadata["name"], ae); + ensure_equals(metadata["desc"].asString(), funcs[ae]); ensure("should not have required structure", metadata["required"].isUndefined()); ensure("should not have optional", metadata["optional"].isUndefined()); - std::string name_req(ai->asString() + "_req"); + std::string name_req(ae.asString() + "_req"); metadata = getMetadata(name_req); ensure_equals(metadata["name"].asString(), name_req); ensure_equals(metadata["desc"].asString(), funcs[name_req]); @@ -781,21 +830,19 @@ namespace tut (5)(LLSDArray("freena_array")("smethodna_array")("methodna_array"))) (LLSDArray (5)(LLSDArray("freenb_array")("smethodnb_array")("methodnb_array")))); - for (LLSD::array_const_iterator ai(expected.beginArray()), aend(expected.endArray()); - ai != aend; ++ai) + foreach(LLSD ae, inArray(expected)) { - LLSD::Integer arity((*ai)[0].asInteger()); - LLSD names((*ai)[1]); + LLSD::Integer arity(ae[0].asInteger()); + LLSD names(ae[1]); LLSD req(LLSD::emptyArray()); if (arity) req[arity - 1] = LLSD(); - for (LLSD::array_const_iterator ni(names.beginArray()), nend(names.endArray()); - ni != nend; ++ni) + foreach(LLSD nm, inArray(names)) { - LLSD metadata(getMetadata(*ni)); - ensure_equals("name mismatch", metadata["name"], *ni); - ensure_equals(metadata["desc"].asString(), funcs[*ni]); - ensure_equals(STRINGIZE("mismatched required for " << ni->asString()), + LLSD metadata(getMetadata(nm)); + ensure_equals("name mismatch", metadata["name"], nm); + ensure_equals(metadata["desc"].asString(), funcs[nm]); + ensure_equals(STRINGIZE("mismatched required for " << nm.asString()), metadata["required"], req); ensure("should not have optional", metadata["optional"].isUndefined()); } @@ -809,12 +856,11 @@ namespace tut // - (Free function | non-static method), map style, no params (ergo // no defaults) LLSD names(LLSDArray("free0_map")("smethod0_map")("method0_map")); - for (LLSD::array_const_iterator ni(names.beginArray()), nend(names.endArray()); - ni != nend; ++ni) + foreach(LLSD nm, inArray(names)) { - LLSD metadata(getMetadata(*ni)); - ensure_equals("name mismatch", metadata["name"], *ni); - ensure_equals(metadata["desc"].asString(), funcs[*ni]); + LLSD metadata(getMetadata(nm)); + ensure_equals("name mismatch", metadata["name"], nm); + ensure_equals(metadata["desc"].asString(), funcs[nm]); ensure("should not have required", (metadata["required"].isUndefined() || metadata["required"].size() == 0)); ensure("should not have optional", metadata["optional"].isUndefined()); @@ -840,12 +886,10 @@ namespace tut (LLSDArray("smethodnb_map_adft")("smethodnb_map_mdft")) (LLSDArray("methodna_map_adft")("methodna_map_mdft")) (LLSDArray("methodnb_map_adft")("methodnb_map_mdft"))); - for (LLSD::array_const_iterator - ei(equivalences.beginArray()), eend(equivalences.endArray()); - ei != eend; ++ei) + foreach(LLSD eq, inArray(equivalences)) { - LLSD adft((*ei)[0]); - LLSD mdft((*ei)[1]); + LLSD adft(eq[0]); + LLSD mdft(eq[1]); // We can't just compare the results of the two getMetadata() // calls, because they contain ["name"], which are different. So // capture them, verify that each ["name"] is as expected, then @@ -899,17 +943,13 @@ namespace tut // Generate maps containing parameter names not provided by the // dft[ab]_map_partial maps. LLSD skipreqa(allreqa), skipreqb(allreqb); - for (LLSD::map_const_iterator mi(dfta_map_partial.beginMap()), - mend(dfta_map_partial.endMap()); - mi != mend; ++mi) + foreach(const MapEntry& me, inMap(dfta_map_partial)) { - skipreqa.erase(mi->first); + skipreqa.erase(me.first); } - for (LLSD::map_const_iterator mi(dftb_map_partial.beginMap()), - mend(dftb_map_partial.endMap()); - mi != mend; ++mi) + foreach(const MapEntry& me, inMap(dftb_map_partial)) { - skipreqb.erase(mi->first); + skipreqb.erase(me.first); } LLSD groups(LLSDArray // array of groups @@ -949,22 +989,20 @@ namespace tut (LLSDArray("freenb_map_mdft")("smethodnb_map_mdft")("methodnb_map_mdft")) (LLSDArray(LLSD::emptyMap())(dftb_map_full)))); // required, optional - for (LLSD::array_const_iterator gi(groups.beginArray()), gend(groups.endArray()); - gi != gend; ++gi) + foreach(LLSD grp, inArray(groups)) { // Internal structure of each group in 'groups': - LLSD names((*gi)[0]); - LLSD required((*gi)[1][0]); - LLSD optional((*gi)[1][1]); + LLSD names(grp[0]); + LLSD required(grp[1][0]); + LLSD optional(grp[1][1]); cout << "For " << names << ",\n" << "required:\n" << required << "\noptional:\n" << optional << std::endl; // Loop through 'names' - for (LLSD::array_const_iterator ni(names.beginArray()), nend(names.endArray()); - ni != nend; ++ni) + foreach(LLSD nm, inArray(names)) { - LLSD metadata(getMetadata(*ni)); - ensure_equals("name mismatch", metadata["name"], *ni); - ensure_equals(metadata["desc"].asString(), funcs[*ni]); + LLSD metadata(getMetadata(nm)); + ensure_equals("name mismatch", metadata["name"], nm); + ensure_equals(metadata["desc"].asString(), funcs[nm]); ensure_equals("required mismatch", metadata["required"], required); ensure_equals("optional mismatch", metadata["optional"], optional); } @@ -1041,20 +1079,19 @@ namespace tut // LLSD value matching 'required' according to llsd_matches() rules. LLSD matching(LLSDMap("d", 3.14)("array", LLSDArray("answer")(true)(answer))); // Okay, walk through 'tests'. - for (const CallablesTriple *ti(boost::begin(tests)), *tend(boost::end(tests)); - ti != tend; ++ti) + foreach(const CallablesTriple& tr, tests) { // Should be able to pass 'answer' to Callables registered // without 'required'. - work(ti->name, answer); - ensure_equals("answer mismatch", ti->llsd, answer); + work(tr.name, answer); + ensure_equals("answer mismatch", tr.llsd, answer); // Should NOT be able to pass 'answer' to Callables registered // with 'required'. - call_exc(ti->name_req, answer, "bad request"); + call_exc(tr.name_req, answer, "bad request"); // But SHOULD be able to pass 'matching' to Callables registered // with 'required'. - work(ti->name_req, matching); - ensure_equals("matching mismatch", ti->llsd, matching); + work(tr.name_req, matching); + ensure_equals("matching mismatch", tr.llsd, matching); } } @@ -1080,7 +1117,7 @@ namespace tut struct FunctionsTriple { - std::string name_array, name_map; + std::string name1, name2; Vars& vars; }; @@ -1094,23 +1131,42 @@ namespace tut { "smethod0_array", "smethod0_map", g }, { "method0_array", "method0_map", v } }; - for (const FunctionsTriple *ti(boost::begin(tests)), *tend(boost::end(tests)); - ti != tend; ++ti) + foreach(const FunctionsTriple& tr, tests) { // Both the global and stack Vars instances are automatically // cleared at the start of each test method. But since we're // calling these things several different times in the same // test method, manually reset the Vars between each. - ti->vars = Vars(); - ensure_equals(ti->vars.i, 0); + tr.vars = Vars(); + ensure_equals(tr.vars.i, 0); // array-style call with empty array (or LLSD(), should be equivalent) - work(ti->name_array, LLSD()); - ensure_equals(ti->vars.i, 17); + work(tr.name1, LLSD()); + ensure_equals(tr.vars.i, 17); - ti->vars = Vars(); + tr.vars = Vars(); // map-style call with empty map (or LLSD(), should be equivalent) - work(ti->name_map, LLSD()); - ensure_equals(ti->vars.i, 17); + work(tr.name2, LLSD()); + ensure_equals(tr.vars.i, 17); + } + } + + template<> template<> + void object::test<19>() + { + set_test_name("call array-style functions with too-short arrays"); + FunctionsTriple tests[] = + { + { "freena_array", "freenb_array", g }, + { "smethodna_array", "smethodnb_array", g }, + { "methodna_array", "methodnb_array", v } + }; + // Could have two different too-short arrays, one for *na and one for + // *nb, but since they both take 5 params... + LLSD tooshort(LLSDArray("this")("array")("too")("short")); + foreach(const FunctionsTriple& tr, tests) + { + call_exc(tr.name1, tooshort, "requires more arguments"); + call_exc(tr.name2, tooshort, "requires more arguments"); } } } // namespace tut -- cgit v1.2.3 From d814e76cad49d6ebeb8f34b13d5d946d9f675b76 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 3 Feb 2011 22:54:16 -0500 Subject: Introduce BOOST_FOREACH() helpers for LLSD in llsdutil.h. You can't directly write: BOOST_FOREACH(LLSD item, someLLSDarray) { ... } because LLSD has two distinct iteration mechanisms, one for arrays and one for maps, neither using the standard [const_]iterator typedefs or begin()/end() methods. But with these helpers, you can write: BOOST_FOREACH(LLSD item, llsd::inArray(someLLSDarray)) { ... } or BOOST_FOREACH(const llsd::MapEntry& pair, llsd::inMap(someLLSDmap)) { ... } These are in namespace llsd instead of being (e.g.) llsd_inMap because with a namespace at least your .cpp file can have a local 'using': using namespace llsd; BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... } It's namespace llsd rather than LLSD because LLSD can't be both a namespace and a class name. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 68 ++++--------------------- 1 file changed, 11 insertions(+), 57 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 2975707860..2241dea4ba 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -51,52 +51,6 @@ using std::cout; static std::ostringstream cout; #endif -/***************************************************************************** -* BOOST_FOREACH() helpers for LLSD -*****************************************************************************/ -/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... } -class inArray -{ -public: - inArray(const LLSD& array): - _array(array) - {} - - typedef LLSD::array_const_iterator const_iterator; - typedef LLSD::array_iterator iterator; - - iterator begin() { return _array.beginArray(); } - iterator end() { return _array.endArray(); } - const_iterator begin() const { return _array.beginArray(); } - const_iterator end() const { return _array.endArray(); } - -private: - LLSD _array; -}; - -/// MapEntry is what you get from dereferencing an LLSD::map_[const_]iterator. -typedef std::pair MapEntry; - -/// Usage: BOOST_FOREACH([const] MapEntry& e, inMap(someLLSDmap)) { ... } -class inMap -{ -public: - inMap(const LLSD& map): - _map(map) - {} - - typedef LLSD::map_const_iterator const_iterator; - typedef LLSD::map_iterator iterator; - - iterator begin() { return _map.beginMap(); } - iterator end() { return _map.endMap(); } - const_iterator begin() const { return _map.beginMap(); } - const_iterator end() const { return _map.endMap(); } - -private: - LLSD _map; -}; - /***************************************************************************** * Example data, functions, classes *****************************************************************************/ @@ -473,7 +427,7 @@ namespace tut (LLSDArray(paramsb)(dftb_array_full))); // std::cout << "zipped:\n" << zipped << '\n'; LLSD dft_maps_full, dft_maps_partial; - foreach(LLSD ae, inArray(zipped)) + foreach(LLSD ae, llsd::inArray(zipped)) { LLSD dft_map_full; LLSD params(ae[0]); @@ -702,7 +656,7 @@ namespace tut set_test_name("map-style registration with non-array params"); // Pass "param names" as scalar or as map LLSD attempts(LLSDArray(17)(LLSDMap("pi", 3.14)("two", 2))); - foreach(LLSD ae, inArray(attempts)) + foreach(LLSD ae, llsd::inArray(attempts)) { std::string threw; try @@ -801,7 +755,7 @@ namespace tut { set_test_name("query Callables with/out required params"); LLSD names(LLSDArray("free1")("Dmethod1")("Dcmethod1")("method1")); - foreach(LLSD ae, inArray(names)) + foreach(LLSD ae, llsd::inArray(names)) { LLSD metadata(getMetadata(ae)); ensure_equals("name mismatch", metadata["name"], ae); @@ -830,14 +784,14 @@ namespace tut (5)(LLSDArray("freena_array")("smethodna_array")("methodna_array"))) (LLSDArray (5)(LLSDArray("freenb_array")("smethodnb_array")("methodnb_array")))); - foreach(LLSD ae, inArray(expected)) + foreach(LLSD ae, llsd::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)) + foreach(LLSD nm, llsd::inArray(names)) { LLSD metadata(getMetadata(nm)); ensure_equals("name mismatch", metadata["name"], nm); @@ -856,7 +810,7 @@ namespace tut // - (Free function | non-static method), map style, no params (ergo // no defaults) LLSD names(LLSDArray("free0_map")("smethod0_map")("method0_map")); - foreach(LLSD nm, inArray(names)) + foreach(LLSD nm, llsd::inArray(names)) { LLSD metadata(getMetadata(nm)); ensure_equals("name mismatch", metadata["name"], nm); @@ -886,7 +840,7 @@ namespace tut (LLSDArray("smethodnb_map_adft")("smethodnb_map_mdft")) (LLSDArray("methodna_map_adft")("methodna_map_mdft")) (LLSDArray("methodnb_map_adft")("methodnb_map_mdft"))); - foreach(LLSD eq, inArray(equivalences)) + foreach(LLSD eq, llsd::inArray(equivalences)) { LLSD adft(eq[0]); LLSD mdft(eq[1]); @@ -943,11 +897,11 @@ namespace tut // Generate maps containing parameter names not provided by the // dft[ab]_map_partial maps. LLSD skipreqa(allreqa), skipreqb(allreqb); - foreach(const MapEntry& me, inMap(dfta_map_partial)) + foreach(const llsd::MapEntry& me, llsd::inMap(dfta_map_partial)) { skipreqa.erase(me.first); } - foreach(const MapEntry& me, inMap(dftb_map_partial)) + foreach(const llsd::MapEntry& me, llsd::inMap(dftb_map_partial)) { skipreqb.erase(me.first); } @@ -989,7 +943,7 @@ namespace tut (LLSDArray("freenb_map_mdft")("smethodnb_map_mdft")("methodnb_map_mdft")) (LLSDArray(LLSD::emptyMap())(dftb_map_full)))); // required, optional - foreach(LLSD grp, inArray(groups)) + foreach(LLSD grp, llsd::inArray(groups)) { // Internal structure of each group in 'groups': LLSD names(grp[0]); @@ -998,7 +952,7 @@ namespace tut cout << "For " << names << ",\n" << "required:\n" << required << "\noptional:\n" << optional << std::endl; // Loop through 'names' - foreach(LLSD nm, inArray(names)) + foreach(LLSD nm, llsd::inArray(names)) { LLSD metadata(getMetadata(nm)); ensure_equals("name mismatch", metadata["name"], nm); -- cgit v1.2.3 From f2bb1b451cc37bcc2c09687fd52515d8b791d97a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 3 Feb 2011 23:04:40 -0500 Subject: BOOST_FOREACH(LLSD) helpers more readable with 'using namespace'. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 2241dea4ba..f9202307f7 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -42,6 +42,8 @@ using boost::lambda::constant; using boost::lambda::constant_ref; using boost::lambda::var; +using namespace llsd; + /***************************************************************************** * Output control *****************************************************************************/ @@ -427,7 +429,7 @@ namespace tut (LLSDArray(paramsb)(dftb_array_full))); // std::cout << "zipped:\n" << zipped << '\n'; LLSD dft_maps_full, dft_maps_partial; - foreach(LLSD ae, llsd::inArray(zipped)) + foreach(LLSD ae, inArray(zipped)) { LLSD dft_map_full; LLSD params(ae[0]); @@ -656,7 +658,7 @@ namespace tut set_test_name("map-style registration with non-array params"); // Pass "param names" as scalar or as map LLSD attempts(LLSDArray(17)(LLSDMap("pi", 3.14)("two", 2))); - foreach(LLSD ae, llsd::inArray(attempts)) + foreach(LLSD ae, inArray(attempts)) { std::string threw; try @@ -755,7 +757,7 @@ namespace tut { set_test_name("query Callables with/out required params"); LLSD names(LLSDArray("free1")("Dmethod1")("Dcmethod1")("method1")); - foreach(LLSD ae, llsd::inArray(names)) + foreach(LLSD ae, inArray(names)) { LLSD metadata(getMetadata(ae)); ensure_equals("name mismatch", metadata["name"], ae); @@ -784,14 +786,14 @@ namespace tut (5)(LLSDArray("freena_array")("smethodna_array")("methodna_array"))) (LLSDArray (5)(LLSDArray("freenb_array")("smethodnb_array")("methodnb_array")))); - foreach(LLSD ae, llsd::inArray(expected)) + foreach(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, llsd::inArray(names)) + foreach(LLSD nm, inArray(names)) { LLSD metadata(getMetadata(nm)); ensure_equals("name mismatch", metadata["name"], nm); @@ -810,7 +812,7 @@ namespace tut // - (Free function | non-static method), map style, no params (ergo // no defaults) LLSD names(LLSDArray("free0_map")("smethod0_map")("method0_map")); - foreach(LLSD nm, llsd::inArray(names)) + foreach(LLSD nm, inArray(names)) { LLSD metadata(getMetadata(nm)); ensure_equals("name mismatch", metadata["name"], nm); @@ -840,7 +842,7 @@ namespace tut (LLSDArray("smethodnb_map_adft")("smethodnb_map_mdft")) (LLSDArray("methodna_map_adft")("methodna_map_mdft")) (LLSDArray("methodnb_map_adft")("methodnb_map_mdft"))); - foreach(LLSD eq, llsd::inArray(equivalences)) + foreach(LLSD eq, inArray(equivalences)) { LLSD adft(eq[0]); LLSD mdft(eq[1]); @@ -897,11 +899,11 @@ namespace tut // Generate maps containing parameter names not provided by the // dft[ab]_map_partial maps. LLSD skipreqa(allreqa), skipreqb(allreqb); - foreach(const llsd::MapEntry& me, llsd::inMap(dfta_map_partial)) + foreach(const MapEntry& me, inMap(dfta_map_partial)) { skipreqa.erase(me.first); } - foreach(const llsd::MapEntry& me, llsd::inMap(dftb_map_partial)) + foreach(const MapEntry& me, inMap(dftb_map_partial)) { skipreqb.erase(me.first); } @@ -943,7 +945,7 @@ namespace tut (LLSDArray("freenb_map_mdft")("smethodnb_map_mdft")("methodnb_map_mdft")) (LLSDArray(LLSD::emptyMap())(dftb_map_full)))); // required, optional - foreach(LLSD grp, llsd::inArray(groups)) + foreach(LLSD grp, inArray(groups)) { // Internal structure of each group in 'groups': LLSD names(grp[0]); @@ -952,7 +954,7 @@ namespace tut cout << "For " << names << ",\n" << "required:\n" << required << "\noptional:\n" << optional << std::endl; // Loop through 'names' - foreach(LLSD nm, llsd::inArray(names)) + foreach(LLSD nm, inArray(names)) { LLSD metadata(getMetadata(nm)); ensure_equals("name mismatch", metadata["name"], nm); -- cgit v1.2.3 From f0c1c4f5b0b7ab37f0830e2b9e3dab09935c2700 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 4 Feb 2011 10:57:48 -0500 Subject: Move FunctionsTriple data to function returning vector. We want to break out a couple different test methods that both need the same data. While we could define a std::vector in the lleventdispatcher_data class and initialize it using a classic {} initializer as in array_funcs(), using a separate function puts it closer to the tests consuming that data, and helps reduce clutter in the central data class. Either way, it's cool that BOOST_FOREACH() handles the gory details of iterating over a std::vector vs. a classic-C array. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index f9202307f7..f8cf93f838 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -1098,7 +1098,7 @@ namespace tut // array-style call with empty array (or LLSD(), should be equivalent) work(tr.name1, LLSD()); ensure_equals(tr.vars.i, 17); - + tr.vars = Vars(); // map-style call with empty map (or LLSD(), should be equivalent) work(tr.name2, LLSD()); @@ -1106,20 +1106,27 @@ namespace tut } } - template<> template<> - void object::test<19>() + // Break out function to return this data because we use it in a couple + // different tests. + std::vector array_funcs(Vars& v) { - set_test_name("call array-style functions with too-short arrays"); FunctionsTriple tests[] = { { "freena_array", "freenb_array", g }, { "smethodna_array", "smethodnb_array", g }, { "methodna_array", "methodnb_array", v } }; + return std::vector(boost::begin(tests), boost::end(tests)); + } + + 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... LLSD tooshort(LLSDArray("this")("array")("too")("short")); - foreach(const FunctionsTriple& tr, tests) + foreach(const FunctionsTriple& tr, array_funcs(v)) { call_exc(tr.name1, tooshort, "requires more arguments"); call_exc(tr.name2, tooshort, "requires more arguments"); -- cgit v1.2.3 From f18885e55df025059e279605d997364575c1561a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 4 Feb 2011 14:54:20 -0500 Subject: Change FunctionsTriple refs to pointers to facilitate passing. A certain popular-but-dumb compiler seems to think that initializing a std::vector from a pair of iterators requires assignment. A struct containing a reference cannot be assigned. Pointers get us past this issue. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index f8cf93f838..9de0819b66 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -1074,7 +1074,7 @@ namespace tut struct FunctionsTriple { std::string name1, name2; - Vars& vars; + Vars* vars; }; template<> template<> @@ -1083,9 +1083,9 @@ namespace tut set_test_name("call no-args functions"); FunctionsTriple tests[] = { - { "free0_array", "free0_map", g }, - { "smethod0_array", "smethod0_map", g }, - { "method0_array", "method0_map", v } + { "free0_array", "free0_map", &g }, + { "smethod0_array", "smethod0_map", &g }, + { "method0_array", "method0_map", &v } }; foreach(const FunctionsTriple& tr, tests) { @@ -1093,16 +1093,16 @@ namespace tut // cleared at the start of each test method. But since we're // calling these things several different times in the same // test method, manually reset the Vars between each. - tr.vars = Vars(); - ensure_equals(tr.vars.i, 0); + *tr.vars = Vars(); + ensure_equals(tr.vars->i, 0); // array-style call with empty array (or LLSD(), should be equivalent) work(tr.name1, LLSD()); - ensure_equals(tr.vars.i, 17); + ensure_equals(tr.vars->i, 17); - tr.vars = Vars(); + *tr.vars = Vars(); // map-style call with empty map (or LLSD(), should be equivalent) work(tr.name2, LLSD()); - ensure_equals(tr.vars.i, 17); + ensure_equals(tr.vars->i, 17); } } @@ -1112,9 +1112,9 @@ namespace tut { FunctionsTriple tests[] = { - { "freena_array", "freenb_array", g }, - { "smethodna_array", "smethodnb_array", g }, - { "methodna_array", "methodnb_array", v } + { "freena_array", "freenb_array", &g }, + { "smethodna_array", "smethodnb_array", &g }, + { "methodna_array", "methodnb_array", &v } }; return std::vector(boost::begin(tests), boost::end(tests)); } -- cgit v1.2.3 From 950cac24ccfe963b5af1dc4f7b07acda1e8bd062 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 5 Feb 2011 11:11:20 -0500 Subject: Add successful calls to array-style functions. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 70 +++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 9de0819b66..c8f45290d6 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -628,6 +628,26 @@ namespace tut ensure(STRINGIZE("No metadata for " << name), meta.isDefined()); return meta; } + + // If I call this ensure_equals(), it blocks visibility of all other + // ensure_equals() overloads. Normally I could say 'using + // baseclass::ensure_equals;' and fix that, but I don't know what the + // base class is! + void ensure_llsd(const std::string& msg, const LLSD& actual, const LLSD& expected, U32 bits) + { + std::ostringstream out; + if (! msg.empty()) + { + out << msg << ": "; + } + out << "expected " << expected << ", actual " << actual; + ensure(out.str(), llsd_equals(actual, expected, bits)); + } + + void ensure_llsd(const LLSD& actual, const LLSD& expected, U32 bits) + { + ensure_llsd("", actual, expected, bits); + } }; typedef test_group lleventdispatcher_group; typedef lleventdispatcher_group::object object; @@ -1132,4 +1152,54 @@ namespace tut call_exc(tr.name2, tooshort, "requires more arguments"); } } + + template<> template<> + void object::test<20>() + { + set_test_name("call array-style functions with (just right | too long) arrays"); + std::vector binary; + for (size_t h(0x01), i(0); i < 5; h+= 0x22, ++i) + { + binary.push_back(h); + } + LLSD argsa(LLSDArray(true)(17)(3.14)(123.456)("char*")); + LLSD argsb(LLSDArray("string")(LLUUID("01234567-89ab-cdef-0123-456789abcdef")) + (LLDate("2011-02-03T15:07:00Z"))(LLURI("http://secondlife.com"))(binary)); + LLSD argsaplus(argsa), argsbplus(argsb); + argsaplus.append("bogus"); + argsbplus.append("bogus"); + LLSD expecta, expectb; + for (LLSD::Integer i(0), iend(paramsa.size()); i < iend; ++i) + { + expecta[paramsa[i].asString()] = argsa[i]; + } + for (LLSD::Integer i(0), iend(paramsb.size()); i < iend; ++i) + { + expectb[paramsb[i].asString()] = argsb[i]; + } + cout << "expecta: " << expecta << "\nexpectb: " << expectb << '\n'; + foreach(const FunctionsTriple& tr, array_funcs(v)) + { + *tr.vars = Vars(); + work(tr.name1, argsa); + ensure_llsd(STRINGIZE(tr.name1 << ": expecta mismatch"), + tr.vars->inspect(), expecta, 7); + + *tr.vars = Vars(); + work(tr.name2, argsb); + ensure_llsd(STRINGIZE(tr.name2 << ": expectb mismatch"), + tr.vars->inspect(), expectb, 7); + + // TODO: argsaplus, argsbplus, check LL_WARNS output? + } + } + + // TODO: + // - refactor params-related data as {'a':arraya, 'b':arrayb} + // - function to build a map from keys array, values array (or + // vice-versa?) + // - Vars formatting for char* and for binary should be done in setter + // method, storing each as std::string. We should NOT NOT NOT store + // char*! The string data we receive through the param list will be gone + // by the time we try to inspect()! } // namespace tut -- cgit v1.2.3 From 230d22ceb2ccc9e82aec0a37f1647636fb5ee310 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 5 Feb 2011 11:30:52 -0500 Subject: Fix Vars::cp dangling-pointer problem. Naively storing a const char* param in a const char* data member ignores the fact that once the caller's done, the string data referenced by that pointer will probably be freed. Store the referenced string in a std::string instead. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 26 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index c8f45290d6..afc2d01729 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -98,7 +98,13 @@ struct Vars int i; float f; double d; - const char* cp; + // Capture param passed as char*. But merely storing a char* received from + // our caller, possibly the .c_str() from a concatenation expression, + // would be Bad: the pointer will be invalidated long before we can query + // it. We could allocate a new chunk of memory, copy the string data and + // point to that instead -- but hey, guess what, we already have a class + // that does that! + std::string cp; std::string s; LLUUID uuid; LLDate date; @@ -111,8 +117,7 @@ struct Vars b(false), i(0), f(0), - d(0), - cp(NULL) + d(0) {} // Detect any non-default values for convenient testing @@ -130,7 +135,7 @@ struct Vars result["f"] = f; if (d) result["d"] = d; - if (cp) + if (! cp.empty()) result["cp"] = cp; if (! s.empty()) result["s"] = s; @@ -179,6 +184,11 @@ struct Vars /*-------- Arbitrary-params (non-const, const, static) methods ---------*/ void methodna(NPARAMSa) { + // 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 + // easy for a human reader: enclose any non-NULL value in single + // quotes, reserving the unquoted string "NULL" to represent a NULL ptr. std::string vcp; if (cp == NULL) vcp = "NULL"; @@ -196,7 +206,7 @@ struct Vars this->i = i; this->f = f; this->d = d; - this->cp = cp; + this->cp = vcp; } void methodnb(NPARAMSb) @@ -1177,6 +1187,8 @@ namespace tut { expectb[paramsb[i].asString()] = argsb[i]; } + // Adjust expecta["cp"] for special Vars::cp treatment. + expecta["cp"] = std::string("'") + expecta["cp"].asString() + "'"; cout << "expecta: " << expecta << "\nexpectb: " << expectb << '\n'; foreach(const FunctionsTriple& tr, array_funcs(v)) { @@ -1198,8 +1210,4 @@ namespace tut // - refactor params-related data as {'a':arraya, 'b':arrayb} // - function to build a map from keys array, values array (or // vice-versa?) - // - Vars formatting for char* and for binary should be done in setter - // method, storing each as std::string. We should NOT NOT NOT store - // char*! The string data we receive through the param list will be gone - // by the time we try to inspect()! } // namespace tut -- cgit v1.2.3 From 54b1db2f6587acd11254f30addd8c53e00e05518 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 5 Feb 2011 22:29:43 -0500 Subject: Consolidate paramsa, paramsb, et al., into ["a"], ["b"] arrays. Following the C++ convention of having two distinct somethigna, somethingb names, initially we introduced paramsa, paramsb LLSD arrays, following that convention all the way down the line. This led to two distinct loops every time we wanted to walk both arrays, since we didn't want to assume that they were both the same size. But leveraging the fact that distinct LLSD arrays stored in the same LLSD container can in fact be of different lengths, refactored all the pairs of vars into top-level LLSD maps keyed by ["a"] and ["b"]. That lets us perform nested loops rather than duplicating the logic, making test code much less messy. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 287 ++++++++++++------------ 1 file changed, 141 insertions(+), 146 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index afc2d01729..32ba0cd16f 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -321,15 +321,18 @@ namespace tut // Required structure for Callables with requirements LLSD required; // Parameter names for freena(), freenb() - LLSD paramsa, paramsb; + LLSD params; // Full defaults arrays for params for freena(), freenb() - LLSD dfta_array_full, dftb_array_full; + LLSD dft_array_full; // Start index of partial defaults arrays const LLSD::Integer partial_offset; // Full defaults maps for params for freena(), freenb() - LLSD dfta_map_full, dftb_map_full; + LLSD dft_map_full; // Partial defaults maps for params for freena(), freenb() - LLSD dfta_map_partial, dftb_map_partial; + LLSD dft_map_partial; + // Most of the above are indexed by "a" or "b". Useful to have an + // array containing those strings for iterating. + std::vector ab; lleventdispatcher_data(): work("test dispatcher", "op"), @@ -342,6 +345,9 @@ namespace tut // clear global variables every time too. ::clear(); + const char* abs[] = { "a", "b" }; + ab.assign(boost::begin(abs), boost::end(abs)); + // Registration cases: // - (Callable | subclass const method | subclass non-const method | // non-subclass method) (with | without) required @@ -412,66 +418,59 @@ namespace tut /*---------------- Arbitrary params, map style -----------------*/ - // freena(), methodna(), cmethodna(), smethodna() all take same param list - paramsa = LLSDArray("b")("i")("f")("d")("cp"); - // same for freenb() et al. - paramsb = LLSDArray("s")("uuid")("date")("uri")("bin"); - // Full defaults arrays. - dfta_array_full = LLSDArray(true)(17)(3.14)(123456.78)("classic"); + // We lay out each params list as an array, also each array of + // default values we'll register. We'll zip these into + // (param=value) maps. Why not define them as maps and just + // extract the keys and values to arrays? Because that wouldn't + // give us the right params-list order. + + // freena(), methodna(), cmethodna(), smethodna() all take same param list. + // Same for freenb() et al. + params = LLSDMap("a", LLSDArray("b")("i")("f")("d")("cp")) + ("b", LLSDArray("s")("uuid")("date")("uri")("bin")); + cout << "params:\n" << params << "\nparams[\"a\"]:\n" << params["a"] << "\nparams[\"b\"]:\n" << params["b"] << std::endl; // default LLSD::Binary value std::vector binary; for (size_t ix = 0, h = 0xaa; ix < 6; ++ix, h += 0x11) { binary.push_back(h); } - // We actually don't care what the LLUUID or LLDate values are, as - // long as they're non-default. - dftb_array_full = LLSDArray("string")(LLUUID::generateNewID())(LLDate::now()) - (LLURI("http://www.ietf.org/rfc/rfc3986.txt"))(binary); + // Full defaults arrays. We actually don't care what the LLUUID or + // LLDate values are, as long as they're different from the + // LLUUID() and LLDate() default values so inspect() will report + // them. + dft_array_full = LLSDMap("a", LLSDArray(true)(17)(3.14)(123456.78)("classic")) + ("b", LLSDArray("string") + (LLUUID::generateNewID()) + (LLDate::now()) + (LLURI("http://www.ietf.org/rfc/rfc3986.txt")) + (binary)); + cout << "dft_array_full:\n" << dft_array_full << std::endl; // Partial defaults arrays. - LLSD dfta_array_partial(llsd_copy_array(dfta_array_full.beginArray() + partial_offset, - dfta_array_full.endArray())); - LLSD dftb_array_partial(llsd_copy_array(dftb_array_full.beginArray() + partial_offset, - dftb_array_full.endArray())); - - // Generate full defaults maps by zipping (params, dftx_array_full). - LLSD zipped(LLSDArray(LLSDArray(paramsa)(dfta_array_full)) - (LLSDArray(paramsb)(dftb_array_full))); -// std::cout << "zipped:\n" << zipped << '\n'; - LLSD dft_maps_full, dft_maps_partial; - foreach(LLSD ae, inArray(zipped)) + LLSD dft_array_partial( + LLSDMap("a", llsd_copy_array(dft_array_full["a"].beginArray() + partial_offset, + dft_array_full["a"].endArray())) + ("b", llsd_copy_array(dft_array_full["b"].beginArray() + partial_offset, + dft_array_full["b"].endArray()))); + cout << "dft_array_partial:\n" << dft_array_partial << std::endl; + + // Generate full defaults maps by zipping (params, dft_array_full). + foreach(LLSD::String a, ab) { - LLSD dft_map_full; - LLSD params(ae[0]); - LLSD dft_array_full(ae[1]); -// std::cout << "params:\n" << params << "\ndft_array_full:\n" << dft_array_full << '\n'; - for (LLSD::Integer ix = 0, ixend = params.size(); ix < ixend; ++ix) + for (LLSD::Integer ix = 0, ixend = params[a].size(); ix < ixend; ++ix) { - dft_map_full[params[ix].asString()] = dft_array_full[ix]; + dft_map_full[a][params[a][ix].asString()] = dft_array_full[a][ix]; } -// std::cout << "dft_map_full:\n" << dft_map_full << '\n'; // Generate partial defaults map by zipping alternate entries from // (params, dft_array_full). Part of the point of using map-style // defaults is to allow any subset of the target function's // parameters to be optional, not just the rightmost. - LLSD dft_map_partial; - for (LLSD::Integer ix = 0, ixend = params.size(); ix < ixend; ix += 2) + for (LLSD::Integer ix = 0, ixend = params[a].size(); ix < ixend; ix += 2) { - dft_map_partial[params[ix].asString()] = dft_array_full[ix]; + dft_map_partial[a][params[a][ix].asString()] = dft_array_full[a][ix]; } -// std::cout << "dft_map_partial:\n" << dft_map_partial << '\n'; - dft_maps_full.append(dft_map_full); - dft_maps_partial.append(dft_map_partial); } -// std::cout << "dft_maps_full:\n" << dft_maps_full << "\ndft_maps_partial:\n" << dft_maps_partial << '\n'; - dfta_map_full = dft_maps_full[0]; - dftb_map_full = dft_maps_full[1]; - dfta_map_partial = dft_maps_partial[0]; - dftb_map_partial = dft_maps_partial[1]; -// std::cout << "dfta_map_full:\n" << dfta_map_full -// << "\ndftb_map_full:\n" << dftb_map_full -// << "\ndfta_map_partial:\n" << dfta_map_partial -// << "\ndftb_map_partial:\n" << dftb_map_partial << '\n'; + cout << "dft_map_full:\n" << dft_map_full << "\ndft_map_partial:\n" << dft_map_partial << '\n'; // (Free function | static method) with (no | arbitrary) params, // map style, no (empty array) defaults @@ -480,21 +479,21 @@ namespace tut addf("smethod0_map", "smethod0"); work.add(name, desc, &Vars::smethod0, LLSD::emptyArray()); addf("freena_map_allreq", "freena"); - work.add(name, desc, freena, paramsa); + work.add(name, desc, freena, params["a"]); addf("freenb_map_allreq", "freenb"); - work.add(name, desc, freenb, paramsb); + work.add(name, desc, freenb, params["b"]); addf("smethodna_map_allreq", "smethodna"); - work.add(name, desc, &Vars::smethodna, paramsa); + work.add(name, desc, &Vars::smethodna, params["a"]); addf("smethodnb_map_allreq", "smethodnb"); - work.add(name, desc, &Vars::smethodnb, paramsb); + work.add(name, desc, &Vars::smethodnb, params["b"]); // Non-static method with (no | arbitrary) params, map style, no // (empty array) defaults addf("method0_map", "method0"); work.add(name, desc, &Vars::method0, var(v), LLSD::emptyArray()); addf("methodna_map_allreq", "methodna"); - work.add(name, desc, &Vars::methodna, var(v), paramsa); + work.add(name, desc, &Vars::methodna, var(v), params["a"]); addf("methodnb_map_allreq", "methodnb"); - work.add(name, desc, &Vars::methodnb, var(v), paramsb); + work.add(name, desc, &Vars::methodnb, var(v), params["b"]); // Except for the "more (array | map) defaults than params" error // cases, tested separately below, the (partial | full)(array | @@ -504,60 +503,60 @@ namespace tut // (Free function | static method) with arbitrary params, map // style, partial (array | map) defaults addf("freena_map_leftreq", "freena"); - work.add(name, desc, freena, paramsa, dfta_array_partial); + work.add(name, desc, freena, params["a"], dft_array_partial["a"]); addf("freenb_map_leftreq", "freenb"); - work.add(name, desc, freenb, paramsb, dftb_array_partial); + work.add(name, desc, freenb, params["b"], dft_array_partial["b"]); addf("smethodna_map_leftreq", "smethodna"); - work.add(name, desc, &Vars::smethodna, paramsa, dfta_array_partial); + work.add(name, desc, &Vars::smethodna, params["a"], dft_array_partial["a"]); addf("smethodnb_map_leftreq", "smethodnb"); - work.add(name, desc, &Vars::smethodnb, paramsb, dftb_array_partial); + work.add(name, desc, &Vars::smethodnb, params["b"], dft_array_partial["b"]); addf("freena_map_skipreq", "freena"); - work.add(name, desc, freena, paramsa, dfta_map_partial); + work.add(name, desc, freena, params["a"], dft_map_partial["a"]); addf("freenb_map_skipreq", "freenb"); - work.add(name, desc, freenb, paramsb, dftb_map_partial); + work.add(name, desc, freenb, params["b"], dft_map_partial["b"]); addf("smethodna_map_skipreq", "smethodna"); - work.add(name, desc, &Vars::smethodna, paramsa, dfta_map_partial); + work.add(name, desc, &Vars::smethodna, params["a"], dft_map_partial["a"]); addf("smethodnb_map_skipreq", "smethodnb"); - work.add(name, desc, &Vars::smethodnb, paramsb, dftb_map_partial); + work.add(name, desc, &Vars::smethodnb, params["b"], dft_map_partial["b"]); // Non-static method with arbitrary params, map style, partial // (array | map) defaults addf("methodna_map_leftreq", "methodna"); - work.add(name, desc, &Vars::methodna, var(v), paramsa, dfta_array_partial); + work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_array_partial["a"]); addf("methodnb_map_leftreq", "methodnb"); - work.add(name, desc, &Vars::methodnb, var(v), paramsb, dftb_array_partial); + work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_array_partial["b"]); addf("methodna_map_skipreq", "methodna"); - work.add(name, desc, &Vars::methodna, var(v), paramsa, dfta_map_partial); + work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_map_partial["a"]); addf("methodnb_map_skipreq", "methodnb"); - work.add(name, desc, &Vars::methodnb, var(v), paramsb, dftb_map_partial); + work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_map_partial["b"]); // (Free function | static method) with arbitrary params, map // style, full (array | map) defaults addf("freena_map_adft", "freena"); - work.add(name, desc, freena, paramsa, dfta_array_full); + work.add(name, desc, freena, params["a"], dft_array_full["a"]); addf("freenb_map_adft", "freenb"); - work.add(name, desc, freenb, paramsb, dftb_array_full); + work.add(name, desc, freenb, params["b"], dft_array_full["b"]); addf("smethodna_map_adft", "smethodna"); - work.add(name, desc, &Vars::smethodna, paramsa, dfta_array_full); + work.add(name, desc, &Vars::smethodna, params["a"], dft_array_full["a"]); addf("smethodnb_map_adft", "smethodnb"); - work.add(name, desc, &Vars::smethodnb, paramsb, dftb_array_full); + work.add(name, desc, &Vars::smethodnb, params["b"], dft_array_full["b"]); addf("freena_map_mdft", "freena"); - work.add(name, desc, freena, paramsa, dfta_map_full); + work.add(name, desc, freena, params["a"], dft_map_full["a"]); addf("freenb_map_mdft", "freenb"); - work.add(name, desc, freenb, paramsb, dftb_map_full); + work.add(name, desc, freenb, params["b"], dft_map_full["b"]); addf("smethodna_map_mdft", "smethodna"); - work.add(name, desc, &Vars::smethodna, paramsa, dfta_map_full); + work.add(name, desc, &Vars::smethodna, params["a"], dft_map_full["a"]); addf("smethodnb_map_mdft", "smethodnb"); - work.add(name, desc, &Vars::smethodnb, paramsb, dftb_map_full); + work.add(name, desc, &Vars::smethodnb, params["b"], dft_map_full["b"]); // Non-static method with arbitrary params, map style, full // (array | map) defaults addf("methodna_map_adft", "methodna"); - work.add(name, desc, &Vars::methodna, var(v), paramsa, dfta_array_full); + work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_array_full["a"]); addf("methodnb_map_adft", "methodnb"); - work.add(name, desc, &Vars::methodnb, var(v), paramsb, dftb_array_full); + work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_array_full["b"]); addf("methodna_map_mdft", "methodna"); - work.add(name, desc, &Vars::methodna, var(v), paramsa, dfta_map_full); + work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_map_full["a"]); addf("methodnb_map_mdft", "methodnb"); - work.add(name, desc, &Vars::methodnb, var(v), paramsb, dftb_map_full); + work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_map_full["b"]); // All the above are expected to succeed, and are setup for the // tests to follow. Registration error cases are exercised as @@ -787,15 +786,15 @@ namespace tut { set_test_name("query Callables with/out required params"); LLSD names(LLSDArray("free1")("Dmethod1")("Dcmethod1")("method1")); - foreach(LLSD ae, inArray(names)) + foreach(LLSD nm, inArray(names)) { - LLSD metadata(getMetadata(ae)); - ensure_equals("name mismatch", metadata["name"], ae); - ensure_equals(metadata["desc"].asString(), funcs[ae]); + LLSD metadata(getMetadata(nm)); + ensure_equals("name mismatch", metadata["name"], nm); + ensure_equals(metadata["desc"].asString(), funcs[nm]); ensure("should not have required structure", metadata["required"].isUndefined()); ensure("should not have optional", metadata["optional"].isUndefined()); - std::string name_req(ae.asString() + "_req"); + std::string name_req(nm.asString() + "_req"); metadata = getMetadata(name_req); ensure_equals(metadata["name"].asString(), name_req); ensure_equals(metadata["desc"].asString(), funcs[name_req]); @@ -902,78 +901,71 @@ namespace tut // Generate maps containing all parameter names for cases in which all // params are required. Also maps containing left requirements for // partial defaults arrays. Also defaults maps from defaults arrays. - LLSD allreqa, allreqb, leftreqa, leftreqb, rightdfta, rightdftb; - for (LLSD::Integer pi(0), pend(std::min(partial_offset, paramsa.size())); - pi < pend; ++pi) - { - allreqa[paramsa[pi].asString()] = LLSD(); - leftreqa[paramsa[pi].asString()] = LLSD(); - } - for (LLSD::Integer pi(partial_offset), pend(paramsa.size()); pi < pend; ++pi) - { - allreqa[paramsa[pi].asString()] = LLSD(); - rightdfta[paramsa[pi].asString()] = dfta_array_full[pi]; - } - for (LLSD::Integer pi(0), pend(std::min(partial_offset, paramsb.size())); - pi < pend; ++pi) + LLSD allreq, leftreq, rightdft; + foreach(LLSD::String a, ab) { - allreqb[paramsb[pi].asString()] = LLSD(); - leftreqb[paramsb[pi].asString()] = LLSD(); - } - for (LLSD::Integer pi(partial_offset), pend(paramsb.size()); pi < pend; ++pi) - { - allreqb[paramsb[pi].asString()] = LLSD(); - rightdftb[paramsb[pi].asString()] = dftb_array_full[pi]; + for (LLSD::Integer pi(0), pend(std::min(partial_offset, params[a].size())); + pi < pend; ++pi) + { + allreq [a][params[a][pi].asString()] = LLSD(); + leftreq[a][params[a][pi].asString()] = LLSD(); + } + for (LLSD::Integer pi(partial_offset), pend(params[a].size()); pi < pend; ++pi) + { + allreq [a][params[a][pi].asString()] = LLSD(); + rightdft[a][params[a][pi].asString()] = dft_array_full[a][pi]; + } } + cout << "allreq:\n" << allreq << "\nleftreq:\n" << leftreq << "\nrightdft:\n" << rightdft << std::endl; // Generate maps containing parameter names not provided by the - // dft[ab]_map_partial maps. - LLSD skipreqa(allreqa), skipreqb(allreqb); - foreach(const MapEntry& me, inMap(dfta_map_partial)) + // dft_map_partial maps. + LLSD skipreq(allreq); + foreach(LLSD::String a, ab) { - skipreqa.erase(me.first); - } - foreach(const MapEntry& me, inMap(dftb_map_partial)) - { - skipreqb.erase(me.first); + foreach(const MapEntry& me, inMap(dft_map_partial[a])) + { + skipreq[a].erase(me.first); + } } + cout << "skipreq:\n" << skipreq << std::endl; LLSD groups(LLSDArray // array of groups (LLSDArray // group (LLSDArray("freena_map_allreq")("smethodna_map_allreq")("methodna_map_allreq")) - (LLSDArray(allreqa)(LLSD()))) // required, optional + (LLSDArray(allreq["a"])(LLSD()))) // required, optional (LLSDArray // group (LLSDArray("freenb_map_allreq")("smethodnb_map_allreq")("methodnb_map_allreq")) - (LLSDArray(allreqb)(LLSD()))) // required, optional + (LLSDArray(allreq["b"])(LLSD()))) // required, optional (LLSDArray // group (LLSDArray("freena_map_leftreq")("smethodna_map_leftreq")("methodna_map_leftreq")) - (LLSDArray(leftreqa)(rightdfta))) // required, optional + (LLSDArray(leftreq["a"])(rightdft["a"]))) // required, optional (LLSDArray // group (LLSDArray("freenb_map_leftreq")("smethodnb_map_leftreq")("methodnb_map_leftreq")) - (LLSDArray(leftreqb)(rightdftb))) // required, optional + (LLSDArray(leftreq["b"])(rightdft["b"]))) // required, optional (LLSDArray // group (LLSDArray("freena_map_skipreq")("smethodna_map_skipreq")("methodna_map_skipreq")) - (LLSDArray(skipreqa)(dfta_map_partial))) // required, optional + (LLSDArray(skipreq["a"])(dft_map_partial["a"]))) // required, optional (LLSDArray // group (LLSDArray("freenb_map_skipreq")("smethodnb_map_skipreq")("methodnb_map_skipreq")) - (LLSDArray(skipreqb)(dftb_map_partial))) // required, optional + (LLSDArray(skipreq["b"])(dft_map_partial["b"]))) // required, optional // We only need mention the full-map-defaults ("_mdft" suffix) // registrations, having established their equivalence with the // full-array-defaults ("_adft" suffix) registrations in another test. (LLSDArray // group (LLSDArray("freena_map_mdft")("smethodna_map_mdft")("methodna_map_mdft")) - (LLSDArray(LLSD::emptyMap())(dfta_map_full))) // required, optional + (LLSDArray(LLSD::emptyMap())(dft_map_full["a"]))) // required, optional (LLSDArray // group (LLSDArray("freenb_map_mdft")("smethodnb_map_mdft")("methodnb_map_mdft")) - (LLSDArray(LLSD::emptyMap())(dftb_map_full)))); // required, optional + (LLSDArray(LLSD::emptyMap())(dft_map_full["b"])))); // required, optional foreach(LLSD grp, inArray(groups)) { @@ -988,9 +980,11 @@ namespace tut { LLSD metadata(getMetadata(nm)); ensure_equals("name mismatch", metadata["name"], nm); - ensure_equals(metadata["desc"].asString(), funcs[nm]); - ensure_equals("required mismatch", metadata["required"], required); - ensure_equals("optional mismatch", metadata["optional"], optional); + ensure_equals(nm.asString(), metadata["desc"].asString(), funcs[nm]); + ensure_equals(STRINGIZE(nm << " required mismatch"), + metadata["required"], required); + ensure_equals(STRINGIZE(nm << " optional mismatch"), + metadata["optional"], optional); } } } @@ -1172,42 +1166,43 @@ namespace tut { binary.push_back(h); } - LLSD argsa(LLSDArray(true)(17)(3.14)(123.456)("char*")); - LLSD argsb(LLSDArray("string")(LLUUID("01234567-89ab-cdef-0123-456789abcdef")) - (LLDate("2011-02-03T15:07:00Z"))(LLURI("http://secondlife.com"))(binary)); - LLSD argsaplus(argsa), argsbplus(argsb); - argsaplus.append("bogus"); - argsbplus.append("bogus"); - LLSD expecta, expectb; - for (LLSD::Integer i(0), iend(paramsa.size()); i < iend; ++i) - { - expecta[paramsa[i].asString()] = argsa[i]; - } - for (LLSD::Integer i(0), iend(paramsb.size()); i < iend; ++i) + LLSD args(LLSDMap("a", LLSDArray(true)(17)(3.14)(123.456)("char*")) + ("b", LLSDArray("string") + (LLUUID("01234567-89ab-cdef-0123-456789abcdef")) + (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) { - expectb[paramsb[i].asString()] = argsb[i]; + for (LLSD::Integer i(0), iend(params[a].size()); i < iend; ++i) + { + expect[a][params[a][i].asString()] = args[a][i]; + } } - // Adjust expecta["cp"] for special Vars::cp treatment. - expecta["cp"] = std::string("'") + expecta["cp"].asString() + "'"; - cout << "expecta: " << expecta << "\nexpectb: " << expectb << '\n'; + // Adjust expect["a"]["cp"] for special Vars::cp treatment. + expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'"; + cout << "expect: " << expect << '\n'; foreach(const FunctionsTriple& tr, array_funcs(v)) { *tr.vars = Vars(); - work(tr.name1, argsa); - ensure_llsd(STRINGIZE(tr.name1 << ": expecta mismatch"), - tr.vars->inspect(), expecta, 7); + work(tr.name1, args["a"]); + ensure_llsd(STRINGIZE(tr.name1 << ": expect[\"a\"] mismatch"), + tr.vars->inspect(), expect["a"], 7); // 7 bits ~= 2 decimal digits *tr.vars = Vars(); - work(tr.name2, argsb); - ensure_llsd(STRINGIZE(tr.name2 << ": expectb mismatch"), - tr.vars->inspect(), expectb, 7); + work(tr.name2, args["b"]); + ensure_llsd(STRINGIZE(tr.name2 << ": expect[\"b\"] mismatch"), + tr.vars->inspect(), expect["b"], 7); - // TODO: argsaplus, argsbplus, check LL_WARNS output? + // TODO: argsplus, check LL_WARNS output? } } // TODO: - // - refactor params-related data as {'a':arraya, 'b':arrayb} // - function to build a map from keys array, values array (or // vice-versa?) } // namespace tut -- cgit v1.2.3 From 934e8c39761bd4f4b7c04eb8b29e0a305182e4ed Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 5 Feb 2011 22:49:53 -0500 Subject: Make array-funcs success test exercise args-array-too-long case too. Streamline a bit more redundancy from the code in that test. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 37 +++++++++++++++++-------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 32ba0cd16f..c31f037d7f 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -1186,19 +1186,34 @@ namespace tut // Adjust expect["a"]["cp"] for special Vars::cp treatment. expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'"; cout << "expect: " << expect << '\n'; - foreach(const FunctionsTriple& tr, array_funcs(v)) - { - *tr.vars = Vars(); - work(tr.name1, args["a"]); - ensure_llsd(STRINGIZE(tr.name1 << ": expect[\"a\"] mismatch"), - tr.vars->inspect(), expect["a"], 7); // 7 bits ~= 2 decimal digits - *tr.vars = Vars(); - work(tr.name2, args["b"]); - ensure_llsd(STRINGIZE(tr.name2 << ": expect[\"b\"] mismatch"), - tr.vars->inspect(), expect["b"], 7); + // Use substantially the same logic for args and argsplus + LLSD argsarrays(LLSDArray(args)(argsplus)); + // So i==0 selects 'args', i==1 selects argsplus + for (LLSD::Integer i(0), iend(argsarrays.size()); i < iend; ++i) + { + foreach(const FunctionsTriple& tr, array_funcs(v)) + { + // Get tr.name1 and tr.name2 into a map keyed by ["a"] and ["b"] + LLSD funcs(LLSDMap("a", tr.name1)("b", tr.name2)); - // TODO: argsplus, check LL_WARNS output? + // So now we can call tr.name1 (as funcs["a"]) with the "a" + // params, etc. + foreach(LLSD::String a, ab) + { + // Reset the Vars instance before each call + *tr.vars = Vars(); + work(funcs[a], argsarrays[i][a]); + ensure_llsd(STRINGIZE(funcs[a].asString() << + ": expect[\"" << a << "\"] mismatch"), + tr.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. + } + } } } -- cgit v1.2.3 From e51ccdac0e3595a476dbc2d8580a3fb1780cdb4c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 5 Feb 2011 23:31:11 -0500 Subject: Introduce zipmap() function and use it in place of frequent loops. One operation we often use is to take an LLSD array of param names, a corresponding LLSD array of values, and create from them a name=value LLSD map. Instead of doing that "by hand" every time, use a function. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 79 ++++++++++++++----------- 1 file changed, 44 insertions(+), 35 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index c31f037d7f..30d3c42554 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -322,14 +322,12 @@ namespace tut LLSD required; // Parameter names for freena(), freenb() LLSD params; - // Full defaults arrays for params for freena(), freenb() - LLSD dft_array_full; + // Full, partial defaults arrays for params for freena(), freenb() + LLSD dft_array_full, dft_array_partial; // Start index of partial defaults arrays const LLSD::Integer partial_offset; - // Full defaults maps for params for freena(), freenb() - LLSD dft_map_full; - // Partial defaults maps for params for freena(), freenb() - LLSD dft_map_partial; + // Full, partial defaults maps for params for freena(), freenb() + LLSD dft_map_full, dft_map_partial; // Most of the above are indexed by "a" or "b". Useful to have an // array containing those strings for iterating. std::vector ab; @@ -447,20 +445,20 @@ namespace tut (binary)); cout << "dft_array_full:\n" << dft_array_full << std::endl; // Partial defaults arrays. - LLSD dft_array_partial( - LLSDMap("a", llsd_copy_array(dft_array_full["a"].beginArray() + partial_offset, - dft_array_full["a"].endArray())) - ("b", llsd_copy_array(dft_array_full["b"].beginArray() + partial_offset, - dft_array_full["b"].endArray()))); + foreach(LLSD::String a, ab) + { + LLSD::Integer partition(std::min(partial_offset, dft_array_full[a].size())); + dft_array_partial[a] = + llsd_copy_array(dft_array_full[a].beginArray() + partition, + dft_array_full[a].endArray()); + } cout << "dft_array_partial:\n" << dft_array_partial << std::endl; - // Generate full defaults maps by zipping (params, dft_array_full). foreach(LLSD::String a, ab) { - for (LLSD::Integer ix = 0, ixend = params[a].size(); ix < ixend; ++ix) - { - dft_map_full[a][params[a][ix].asString()] = dft_array_full[a][ix]; - } + // Generate full defaults maps by zipping (params, dft_array_full). + dft_map_full[a] = zipmap(params[a], dft_array_full[a]); + // Generate partial defaults map by zipping alternate entries from // (params, dft_array_full). Part of the point of using map-style // defaults is to allow any subset of the target function's @@ -638,6 +636,20 @@ namespace tut return meta; } + // From two related LLSD arrays, e.g. a param-names array and a values + // array, zip them together into an LLSD map. + LLSD zipmap(const LLSD& keys, const LLSD& values) + { + LLSD map; + for (LLSD::Integer i = 0, iend = keys.size(); i < iend; ++i) + { + // Have to select asString() since you can index an LLSD + // object with either String or Integer. + map[keys[i].asString()] = values[i]; + } + return map; + } + // If I call this ensure_equals(), it blocks visibility of all other // ensure_equals() overloads. Normally I could say 'using // baseclass::ensure_equals;' and fix that, but I don't know what the @@ -904,17 +916,21 @@ namespace tut LLSD allreq, leftreq, rightdft; foreach(LLSD::String a, ab) { - for (LLSD::Integer pi(0), pend(std::min(partial_offset, params[a].size())); - pi < pend; ++pi) - { - allreq [a][params[a][pi].asString()] = LLSD(); - leftreq[a][params[a][pi].asString()] = LLSD(); - } - for (LLSD::Integer pi(partial_offset), pend(params[a].size()); pi < pend; ++pi) - { - allreq [a][params[a][pi].asString()] = LLSD(); - rightdft[a][params[a][pi].asString()] = dft_array_full[a][pi]; - } + // The map in which all params are required uses params[a] as + // keys, with all isUndefined() as values. We can accomplish that + // by passing zipmap() an empty values array. + allreq[a] = zipmap(params[a], LLSD::emptyArray()); + // Same for leftreq, save that we use the subset of the params not + // supplied by dft_array_partial[a]. + LLSD::Integer partition(params[a].size() - dft_array_partial[a].size()); + leftreq[a] = zipmap(llsd_copy_array(params[a].beginArray(), + params[a].beginArray() + partition), + LLSD::emptyArray()); + // Generate map pairing dft_array_partial[a] values with their + // param names. + rightdft[a] = zipmap(llsd_copy_array(params[a].beginArray() + partition, + params[a].endArray()), + dft_array_partial[a]); } cout << "allreq:\n" << allreq << "\nleftreq:\n" << leftreq << "\nrightdft:\n" << rightdft << std::endl; @@ -1178,10 +1194,7 @@ namespace tut LLSD expect; foreach(LLSD::String a, ab) { - for (LLSD::Integer i(0), iend(params[a].size()); i < iend; ++i) - { - expect[a][params[a][i].asString()] = args[a][i]; - } + 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() + "'"; @@ -1216,8 +1229,4 @@ namespace tut } } } - - // TODO: - // - function to build a map from keys array, values array (or - // vice-versa?) } // namespace tut -- cgit v1.2.3 From f4f3791a5ff1cc76b9d1054c269e69d44cdaf8d6 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sun, 6 Feb 2011 11:57:19 -0500 Subject: Add test verifying passing LLSD() to const char* parameter. LLSDParam is coded to pass NULL for an isUndefined() LLSD value, so event-based caller can choose whether to pass NULL, "" or whatever string value to such a parameter. Ensure this behavior. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 30d3c42554..bdd8c16cec 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -1229,4 +1229,18 @@ namespace tut } } } + + template<> template<> + void object::test<21>() + { + set_test_name("verify that passing LLSD() to const char* sends NULL"); + + ensure_equals("Vars::cp init", v.cp, ""); + work("methodna_map_mdft", LLSDMap("cp", LLSD())); + ensure_equals("passing LLSD()", v.cp, "NULL"); + work("methodna_map_mdft", LLSDMap("cp", "")); + ensure_equals("passing \"\"", v.cp, "''"); + work("methodna_map_mdft", LLSDMap("cp", "non-NULL")); + ensure_equals("passing \"non-NULL\"", v.cp, "'non-NULL'"); + } } // namespace tut -- cgit v1.2.3 From 1a1563bb154102c09a172235081d8db62e4fbec9 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sun, 6 Feb 2011 21:32:25 -0500 Subject: Untested support for passing array to map-registered function. An array-registered function has no param names, so you can only pass an array: a map would be meaningless. Initial implementation of map-registered functions assumed that since you CAN pass a map, you MUST pass a map. But in fact it's meaningful to pass an array as well -- for whatever reason -- and easy to implement, so there you are. Tests to follow. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index bdd8c16cec..c599672bc5 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -682,7 +682,7 @@ namespace tut // (scalar | map | array (too short | too long | just right)) // [trap LL_WARNS for too-long case?] // - (Free function | non-static method), arbitrary args, map style with - // (scalar | array | map (all | too many | holes (with | without) defaults)) + // (scalar | (array | map) (all | too many | holes (with | without) defaults)) // - const char* param gets ("" | NULL) // Query cases: @@ -1108,7 +1108,9 @@ namespace tut std::string map_exc("needs a map"); call_exc("free0_map", 17, map_exc); - call_exc("free0_map", LLSDArray("a")("b"), map_exc); + // Passing an array to a map-style function works now! No longer an + // error case! +// call_exc("free0_map", LLSDArray("a")("b"), map_exc); } struct FunctionsTriple -- cgit v1.2.3 From a4d0a29c4942f9a4ba423358805e2dfe042144a1 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 7 Feb 2011 11:53:58 -0500 Subject: For test purposes, capture at registration each function's Vars*. We'd introduced FunctionsTriple to associate a pair of registered function names with the Vars* on which those functions should operate. But with more different tests coming up, it became clear that restating the Vars* every time a given function name appeared in any such context was redundant. Instead, extended addf() to accept and store the relevant Vars* for each registered function, be it the global Vars for the free functions and static methods or the stack Vars for the non-static methods. Added varsfor() function to retrieve and validate the Vars* for a given function name. Eliminated array_funcs() function, restating aggregates of names to test as LLSD collections. Where before these were coerced into a separate LLSD map with ["a"] and ["b"] keys, that map can now be part of the original structure. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 228 ++++++++++++------------ 1 file changed, 111 insertions(+), 117 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index c599672bc5..157160ae3e 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -316,8 +316,12 @@ namespace tut Dispatcher work; Vars v; std::string name, desc; - typedef std::map FuncMap; - FuncMap funcs; + // Capture our own copy of all registered functions' descriptions + typedef std::map DescMap; + DescMap descs; + // Capture the Vars instance on which we expect each function to operate + typedef std::map VarsMap; + VarsMap funcvars; // Required structure for Callables with requirements LLSD required; // Parameter names for freena(), freenb() @@ -371,47 +375,47 @@ namespace tut /*------------------------- Callables --------------------------*/ // Arbitrary Callable with/out required params - addf("free1", "free1"); + addf("free1", "free1", &g); work.add(name, desc, free1); - addf("free1_req", "free1"); + addf("free1_req", "free1", &g); work.add(name, desc, free1, required); // Subclass non-const method with/out required params - addf("Dmethod1", "method1"); + addf("Dmethod1", "method1", NULL); work.add(name, desc, &Dispatcher::method1); - addf("Dmethod1_req", "method1"); + addf("Dmethod1_req", "method1", NULL); work.add(name, desc, &Dispatcher::method1, required); // Subclass const method with/out required params - addf("Dcmethod1", "cmethod1"); + addf("Dcmethod1", "cmethod1", NULL); work.add(name, desc, &Dispatcher::cmethod1); - addf("Dcmethod1_req", "cmethod1"); + addf("Dcmethod1_req", "cmethod1", NULL); work.add(name, desc, &Dispatcher::cmethod1, required); // Non-subclass method with/out required params - addf("method1", "method1"); + addf("method1", "method1", &v); work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1)); - addf("method1_req", "method1"); + addf("method1_req", "method1", &v); work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1), required); /*--------------- Arbitrary params, array style ----------------*/ // (Free function | static method) with (no | arbitrary) params, array style - addf("free0_array", "free0"); + addf("free0_array", "free0", &g); work.add(name, desc, free0); - addf("freena_array", "freena"); + addf("freena_array", "freena", &g); work.add(name, desc, freena); - addf("freenb_array", "freenb"); + addf("freenb_array", "freenb", &g); work.add(name, desc, freenb); - addf("smethod0_array", "smethod0"); + addf("smethod0_array", "smethod0", &g); work.add(name, desc, &Vars::smethod0); - addf("smethodna_array", "smethodna"); + addf("smethodna_array", "smethodna", &g); work.add(name, desc, &Vars::smethodna); - addf("smethodnb_array", "smethodnb"); + addf("smethodnb_array", "smethodnb", &g); work.add(name, desc, &Vars::smethodnb); // Non-static method with (no | arbitrary) params, array style - addf("method0_array", "method0"); + addf("method0_array", "method0", &v); work.add(name, desc, &Vars::method0, boost::lambda::var(v)); - addf("methodna_array", "methodna"); + addf("methodna_array", "methodna", &v); work.add(name, desc, &Vars::methodna, boost::lambda::var(v)); - addf("methodnb_array", "methodnb"); + addf("methodnb_array", "methodnb", &v); work.add(name, desc, &Vars::methodnb, boost::lambda::var(v)); /*---------------- Arbitrary params, map style -----------------*/ @@ -472,25 +476,25 @@ namespace tut // (Free function | static method) with (no | arbitrary) params, // map style, no (empty array) defaults - addf("free0_map", "free0"); + addf("free0_map", "free0", &g); work.add(name, desc, free0, LLSD::emptyArray()); - addf("smethod0_map", "smethod0"); + addf("smethod0_map", "smethod0", &g); work.add(name, desc, &Vars::smethod0, LLSD::emptyArray()); - addf("freena_map_allreq", "freena"); + addf("freena_map_allreq", "freena", &g); work.add(name, desc, freena, params["a"]); - addf("freenb_map_allreq", "freenb"); + addf("freenb_map_allreq", "freenb", &g); work.add(name, desc, freenb, params["b"]); - addf("smethodna_map_allreq", "smethodna"); + addf("smethodna_map_allreq", "smethodna", &g); work.add(name, desc, &Vars::smethodna, params["a"]); - addf("smethodnb_map_allreq", "smethodnb"); + addf("smethodnb_map_allreq", "smethodnb", &g); work.add(name, desc, &Vars::smethodnb, params["b"]); // Non-static method with (no | arbitrary) params, map style, no // (empty array) defaults - addf("method0_map", "method0"); + addf("method0_map", "method0", &v); work.add(name, desc, &Vars::method0, var(v), LLSD::emptyArray()); - addf("methodna_map_allreq", "methodna"); + addf("methodna_map_allreq", "methodna", &v); work.add(name, desc, &Vars::methodna, var(v), params["a"]); - addf("methodnb_map_allreq", "methodnb"); + addf("methodnb_map_allreq", "methodnb", &v); work.add(name, desc, &Vars::methodnb, var(v), params["b"]); // Except for the "more (array | map) defaults than params" error @@ -500,60 +504,60 @@ namespace tut // (Free function | static method) with arbitrary params, map // style, partial (array | map) defaults - addf("freena_map_leftreq", "freena"); + addf("freena_map_leftreq", "freena", &g); work.add(name, desc, freena, params["a"], dft_array_partial["a"]); - addf("freenb_map_leftreq", "freenb"); + addf("freenb_map_leftreq", "freenb", &g); work.add(name, desc, freenb, params["b"], dft_array_partial["b"]); - addf("smethodna_map_leftreq", "smethodna"); + addf("smethodna_map_leftreq", "smethodna", &g); work.add(name, desc, &Vars::smethodna, params["a"], dft_array_partial["a"]); - addf("smethodnb_map_leftreq", "smethodnb"); + addf("smethodnb_map_leftreq", "smethodnb", &g); work.add(name, desc, &Vars::smethodnb, params["b"], dft_array_partial["b"]); - addf("freena_map_skipreq", "freena"); + addf("freena_map_skipreq", "freena", &g); work.add(name, desc, freena, params["a"], dft_map_partial["a"]); - addf("freenb_map_skipreq", "freenb"); + addf("freenb_map_skipreq", "freenb", &g); work.add(name, desc, freenb, params["b"], dft_map_partial["b"]); - addf("smethodna_map_skipreq", "smethodna"); + addf("smethodna_map_skipreq", "smethodna", &g); work.add(name, desc, &Vars::smethodna, params["a"], dft_map_partial["a"]); - addf("smethodnb_map_skipreq", "smethodnb"); + addf("smethodnb_map_skipreq", "smethodnb", &g); work.add(name, desc, &Vars::smethodnb, params["b"], dft_map_partial["b"]); // Non-static method with arbitrary params, map style, partial // (array | map) defaults - addf("methodna_map_leftreq", "methodna"); + addf("methodna_map_leftreq", "methodna", &v); work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_array_partial["a"]); - addf("methodnb_map_leftreq", "methodnb"); + addf("methodnb_map_leftreq", "methodnb", &v); work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_array_partial["b"]); - addf("methodna_map_skipreq", "methodna"); + addf("methodna_map_skipreq", "methodna", &v); work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_map_partial["a"]); - addf("methodnb_map_skipreq", "methodnb"); + addf("methodnb_map_skipreq", "methodnb", &v); work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_map_partial["b"]); // (Free function | static method) with arbitrary params, map // style, full (array | map) defaults - addf("freena_map_adft", "freena"); + addf("freena_map_adft", "freena", &g); work.add(name, desc, freena, params["a"], dft_array_full["a"]); - addf("freenb_map_adft", "freenb"); + addf("freenb_map_adft", "freenb", &g); work.add(name, desc, freenb, params["b"], dft_array_full["b"]); - addf("smethodna_map_adft", "smethodna"); + addf("smethodna_map_adft", "smethodna", &g); work.add(name, desc, &Vars::smethodna, params["a"], dft_array_full["a"]); - addf("smethodnb_map_adft", "smethodnb"); + addf("smethodnb_map_adft", "smethodnb", &g); work.add(name, desc, &Vars::smethodnb, params["b"], dft_array_full["b"]); - addf("freena_map_mdft", "freena"); + addf("freena_map_mdft", "freena", &g); work.add(name, desc, freena, params["a"], dft_map_full["a"]); - addf("freenb_map_mdft", "freenb"); + addf("freenb_map_mdft", "freenb", &g); work.add(name, desc, freenb, params["b"], dft_map_full["b"]); - addf("smethodna_map_mdft", "smethodna"); + addf("smethodna_map_mdft", "smethodna", &g); work.add(name, desc, &Vars::smethodna, params["a"], dft_map_full["a"]); - addf("smethodnb_map_mdft", "smethodnb"); + addf("smethodnb_map_mdft", "smethodnb", &g); work.add(name, desc, &Vars::smethodnb, params["b"], dft_map_full["b"]); // Non-static method with arbitrary params, map style, full // (array | map) defaults - addf("methodna_map_adft", "methodna"); + addf("methodna_map_adft", "methodna", &v); work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_array_full["a"]); - addf("methodnb_map_adft", "methodnb"); + addf("methodnb_map_adft", "methodnb", &v); work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_array_full["b"]); - addf("methodna_map_mdft", "methodna"); + addf("methodna_map_mdft", "methodna", &v); work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_map_full["a"]); - addf("methodnb_map_mdft", "methodnb"); + addf("methodnb_map_mdft", "methodnb", &v); work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_map_full["b"]); // All the above are expected to succeed, and are setup for the @@ -561,21 +565,23 @@ namespace tut // tests rather than as test setup. } - void addf(const std::string& n, const std::string& d) + void addf(const std::string& n, const std::string& d, Vars* v) { - // This method is to capture in our own FuncMap the name and + // This method is to capture in our own DescMap the name and // description of every registered function, for metadata query // testing. - funcs[n] = d; + descs[n] = d; + // Also capture the Vars instance on which each function should operate. + funcvars[n] = v; // See constructor for rationale for setting these instance vars. this->name = n; this->desc = d; } - void verify_funcs() + void verify_descs() { - // Copy funcs to a temp map of same type. - FuncMap forgotten(funcs.begin(), funcs.end()); + // 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 @@ -583,7 +589,7 @@ namespace tut // use non-const iterators. Persuade it to use the const_iterator. foreach(LLEventDispatcher::NameDesc nd, const_cast(work)) { - FuncMap::iterator found = forgotten.find(nd.first); + DescMap::iterator found = forgotten.find(nd.first); ensure(STRINGIZE("LLEventDispatcher records function '" << nd.first << "' we didn't enter"), found != forgotten.end()); @@ -599,7 +605,7 @@ namespace tut std::ostringstream out; out << "LLEventDispatcher failed to report"; const char* delim = ": "; - foreach(const FuncMap::value_type& fme, forgotten) + foreach(const DescMap::value_type& fme, forgotten) { out << delim << fme.first; delim = ", "; @@ -608,6 +614,14 @@ namespace tut } } + 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); + return found->second; + } + void ensure_has(const std::string& outer, const std::string& inner) { ensure(STRINGIZE("'" << outer << "' does not contain '" << inner << "'").c_str(), @@ -772,7 +786,7 @@ namespace tut void object::test<5>() { set_test_name("query all"); - verify_funcs(); + verify_descs(); } template<> template<> @@ -781,9 +795,9 @@ namespace tut set_test_name("query all with remove()"); ensure("remove('bogus') returned true", ! work.remove("bogus")); ensure("remove('real') returned false", work.remove("free1")); - // Of course, remove that from 'funcs' too... - funcs.erase("free1"); - verify_funcs(); + // Of course, remove that from 'descs' too... + descs.erase("free1"); + verify_descs(); } template<> template<> @@ -802,14 +816,14 @@ namespace tut { LLSD metadata(getMetadata(nm)); ensure_equals("name mismatch", metadata["name"], nm); - ensure_equals(metadata["desc"].asString(), funcs[nm]); + ensure_equals(metadata["desc"].asString(), descs[nm]); ensure("should not have required structure", metadata["required"].isUndefined()); ensure("should not have optional", metadata["optional"].isUndefined()); std::string name_req(nm.asString() + "_req"); metadata = getMetadata(name_req); ensure_equals(metadata["name"].asString(), name_req); - ensure_equals(metadata["desc"].asString(), funcs[name_req]); + ensure_equals(metadata["desc"].asString(), descs[name_req]); ensure_equals("required mismatch", required, metadata["required"]); ensure("should not have optional", metadata["optional"].isUndefined()); } @@ -838,7 +852,7 @@ namespace tut { LLSD metadata(getMetadata(nm)); ensure_equals("name mismatch", metadata["name"], nm); - ensure_equals(metadata["desc"].asString(), funcs[nm]); + ensure_equals(metadata["desc"].asString(), descs[nm]); ensure_equals(STRINGIZE("mismatched required for " << nm.asString()), metadata["required"], req); ensure("should not have optional", metadata["optional"].isUndefined()); @@ -857,7 +871,7 @@ namespace tut { LLSD metadata(getMetadata(nm)); ensure_equals("name mismatch", metadata["name"], nm); - ensure_equals(metadata["desc"].asString(), funcs[nm]); + ensure_equals(metadata["desc"].asString(), descs[nm]); ensure("should not have required", (metadata["required"].isUndefined() || metadata["required"].size() == 0)); ensure("should not have optional", metadata["optional"].isUndefined()); @@ -996,7 +1010,7 @@ namespace tut { LLSD metadata(getMetadata(nm)); ensure_equals("name mismatch", metadata["name"], nm); - ensure_equals(nm.asString(), metadata["desc"].asString(), funcs[nm]); + ensure_equals(nm.asString(), metadata["desc"].asString(), descs[nm]); ensure_equals(STRINGIZE(nm << " required mismatch"), metadata["required"], required); ensure_equals(STRINGIZE(nm << " optional mismatch"), @@ -1113,53 +1127,35 @@ namespace tut // call_exc("free0_map", LLSDArray("a")("b"), map_exc); } - struct FunctionsTriple - { - std::string name1, name2; - Vars* vars; - }; - template<> template<> void object::test<18>() { set_test_name("call no-args functions"); - FunctionsTriple tests[] = - { - { "free0_array", "free0_map", &g }, - { "smethod0_array", "smethod0_map", &g }, - { "method0_array", "method0_map", &v } - }; - foreach(const FunctionsTriple& tr, tests) + LLSD names(LLSDArray + ("free0_array")("free0_map") + ("smethod0_array")("smethod0_map") + ("method0_array")("method0_map")); + foreach(LLSD name, inArray(names)) { + // Look up the Vars instance for this function. + Vars* vars(varsfor(name)); // Both the global and stack Vars instances are automatically // cleared at the start of each test method. But since we're // calling these things several different times in the same // test method, manually reset the Vars between each. - *tr.vars = Vars(); - ensure_equals(tr.vars->i, 0); - // array-style call with empty array (or LLSD(), should be equivalent) - work(tr.name1, LLSD()); - ensure_equals(tr.vars->i, 17); - - *tr.vars = Vars(); - // map-style call with empty map (or LLSD(), should be equivalent) - work(tr.name2, LLSD()); - ensure_equals(tr.vars->i, 17); + *vars = Vars(); + ensure_equals(vars->i, 0); + // call function with empty array (or LLSD(), should be equivalent) + work(name, LLSD()); + ensure_equals(vars->i, 17); } } - // Break out function to return this data because we use it in a couple - // different tests. - std::vector array_funcs(Vars& v) - { - FunctionsTriple tests[] = - { - { "freena_array", "freenb_array", &g }, - { "smethodna_array", "smethodnb_array", &g }, - { "methodna_array", "methodnb_array", &v } - }; - return std::vector(boost::begin(tests), boost::end(tests)); - } + // Break out this data because we use it in a couple different tests. + LLSD array_funcs(LLSDArray + (LLSDMap("a", "freena_array") ("b", "freenb_array")) + (LLSDMap("a", "smethodna_array")("b", "smethodnb_array")) + (LLSDMap("a", "methodna_array") ("b", "methodnb_array"))); template<> template<> void object::test<19>() @@ -1168,10 +1164,12 @@ namespace tut // Could have two different too-short arrays, one for *na and one for // *nb, but since they both take 5 params... LLSD tooshort(LLSDArray("this")("array")("too")("short")); - foreach(const FunctionsTriple& tr, array_funcs(v)) + foreach(const LLSD& funcsab, inArray(array_funcs)) { - call_exc(tr.name1, tooshort, "requires more arguments"); - call_exc(tr.name2, tooshort, "requires more arguments"); + foreach(const llsd::MapEntry& e, inMap(funcsab)) + { + call_exc(e.second, tooshort, "requires more arguments"); + } } } @@ -1207,21 +1205,17 @@ namespace tut // So i==0 selects 'args', i==1 selects argsplus for (LLSD::Integer i(0), iend(argsarrays.size()); i < iend; ++i) { - foreach(const FunctionsTriple& tr, array_funcs(v)) + foreach(const LLSD& funcsab, inArray(array_funcs)) { - // Get tr.name1 and tr.name2 into a map keyed by ["a"] and ["b"] - LLSD funcs(LLSDMap("a", tr.name1)("b", tr.name2)); - - // So now we can call tr.name1 (as funcs["a"]) with the "a" - // params, etc. foreach(LLSD::String a, ab) { // Reset the Vars instance before each call - *tr.vars = Vars(); - work(funcs[a], argsarrays[i][a]); - ensure_llsd(STRINGIZE(funcs[a].asString() << + Vars* vars(varsfor(funcsab[a])); + *vars = Vars(); + work(funcsab[a], argsarrays[i][a]); + ensure_llsd(STRINGIZE(funcsab[a].asString() << ": expect[\"" << a << "\"] mismatch"), - tr.vars->inspect(), expect[a], 7); // 7 bits ~= 2 decimal digits + 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 -- cgit v1.2.3 From dad558250f645ef9d2eea88e0ad18a54ad0402ee Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 9 Feb 2011 23:28:10 -0500 Subject: Add test to call map-style functions with full map/array params. Test also passes overlong arrays and maps with extraneous keys; in all cases we expect the same set of values to be passed to the registered functions. --- indra/llcommon/tests/lleventdispatcher_test.cpp | 88 ++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 3 deletions(-) (limited to 'indra/llcommon/tests/lleventdispatcher_test.cpp') diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 157160ae3e..263c9b171f 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -214,7 +214,7 @@ struct Vars std::ostringstream vbin; foreach(U8 byte, bin) { - vbin << std::hex << std::setfill('0') << std::setw(2) << byte; + vbin << std::hex << std::setfill('0') << std::setw(2) << unsigned(byte); } cout << "methodnb(" << "'" << s << "'" @@ -692,11 +692,13 @@ namespace tut // - (try_call | call) (explicit name | event key) (real | bogus) name // - Callable with args that (do | do not) match required // - (Free function | non-static method), no args, (array | map) style + // - (Free function | non-static method), arbitrary args, + // (array style with (scalar | map) | map style with scalar) // - (Free function | non-static method), arbitrary args, array style with - // (scalar | map | array (too short | too long | just right)) + // array (too short | too long | just right) // [trap LL_WARNS for too-long case?] // - (Free function | non-static method), arbitrary args, map style with - // (scalar | (array | map) (all | too many | holes (with | without) defaults)) + // (array | map) (all | too many | holes (with | without) defaults) // - const char* param gets ("" | NULL) // Query cases: @@ -1239,4 +1241,84 @@ namespace tut work("methodna_map_mdft", LLSDMap("cp", "non-NULL")); ensure_equals("passing \"non-NULL\"", v.cp, "'non-NULL'"); } + + template<> template<> + void object::test<22>() + { + set_test_name("call map-style functions with (full | oversized) (arrays | maps)"); + const char binary[] = "\x99\x88\x77\x66\x55"; + LLSD array_full(LLSDMap + ("a", LLSDArray(false)(255)(98.6)(1024.5)("pointer")) + ("b", LLSDArray("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) + { + array_overfull[a].append("bogus"); + } + cout << "array_full: " << array_full << "\narray_overfull: " << array_overfull << std::endl; + // We rather hope that LLDate::now() will generate a timestamp + // distinct from the one it generated in the constructor, moments ago. + ensure_not_equals("Timestamps too close", + array_full["b"][2].asDate(), dft_array_full["b"][2].asDate()); + // We /insist/ that LLUUID::generateNewID() do so. + 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) + { + map_full[a] = zipmap(params[a], array_full[a]); + map_overfull[a] = map_full[a]; + map_overfull[a]["extra"] = "ignore"; + } + cout << "map_full: " << map_full << "\nmap_overfull: " << map_overfull << std::endl; + LLSD expect(map_full); + // Twiddle the const char* param. + expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'"; + // Another adjustment. For each data type, we're trying to distinguish + // three values: the Vars member's initial value (member wasn't + // stored; control never reached the set function), the registered + // default param value from dft_array_full, and the array_full value + // in this test. But bool can only distinguish two values. In this + // case, we want to differentiate the local array_full value from the + // dft_array_full value, so we use 'false'. However, that means + // Vars::inspect() doesn't differentiate it from the initial value, + // so won't bother returning it. Predict that behavior to match the + // LLSD values. + expect["a"].erase("b"); + cout << "expect: " << expect << std::endl; + // For this test, calling functions registered with different sets of + // parameter defaults should make NO DIFFERENCE WHATSOEVER. Every call + // should pass all params. + LLSD names(LLSDMap + ("a", LLSDArray + ("freena_map_allreq") ("smethodna_map_allreq") ("methodna_map_allreq") + ("freena_map_leftreq")("smethodna_map_leftreq")("methodna_map_leftreq") + ("freena_map_skipreq")("smethodna_map_skipreq")("methodna_map_skipreq") + ("freena_map_adft") ("smethodna_map_adft") ("methodna_map_adft") + ("freena_map_mdft") ("smethodna_map_mdft") ("methodna_map_mdft")) + ("b", LLSDArray + ("freenb_map_allreq") ("smethodnb_map_allreq") ("methodnb_map_allreq") + ("freenb_map_leftreq")("smethodnb_map_leftreq")("methodnb_map_leftreq") + ("freenb_map_skipreq")("smethodnb_map_skipreq")("methodnb_map_skipreq") + ("freenb_map_adft") ("smethodnb_map_adft") ("methodnb_map_adft") + ("freenb_map_mdft") ("smethodnb_map_mdft") ("methodnb_map_mdft"))); + // Treat (full | overfull) (array | map) the same. + LLSD argssets(LLSDArray(array_full)(array_overfull)(map_full)(map_overfull)); + foreach(const LLSD& args, inArray(argssets)) + { + foreach(LLSD::String a, ab) + { + foreach(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"), + vars->inspect(), expect[a], 7); // 7 bits, 2 decimal digits + // intercept LL_WARNS for the two overfull cases? + } + } + } + } } // namespace tut -- cgit v1.2.3