summaryrefslogtreecommitdiff
path: root/indra/llcommon/tests
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-04-25 09:13:23 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-04-25 09:13:23 -0400
commitf162693a23fe5cfda8dab3857718624033812d30 (patch)
tree0768f9ea570b248b48e4caa33103e3d55c625466 /indra/llcommon/tests
parentd8931c9269a90cd01f6f6ff4de83b8fb41df11d3 (diff)
parentd98fc504a1d4bc292ba86acdda053c8b4598a193 (diff)
Merge Maint YZ branch 'main' into DRTVWR-588-cleanup-timers
Diffstat (limited to 'indra/llcommon/tests')
-rw-r--r--indra/llcommon/tests/apply_test.cpp240
-rw-r--r--indra/llcommon/tests/lazyeventapi_test.cpp136
-rw-r--r--indra/llcommon/tests/llerror_test.cpp30
-rw-r--r--indra/llcommon/tests/lleventcoro_test.cpp8
-rw-r--r--indra/llcommon/tests/lleventdispatcher_test.cpp569
-rw-r--r--indra/llcommon/tests/llinstancetracker_test.cpp4
-rw-r--r--indra/llcommon/tests/llleap_test.cpp7
-rw-r--r--indra/llcommon/tests/llprocess_test.cpp9
-rw-r--r--indra/llcommon/tests/llrand_test.cpp53
-rw-r--r--indra/llcommon/tests/llsdserialize_test.cpp125
-rw-r--r--indra/llcommon/tests/llsingleton_test.cpp6
-rw-r--r--indra/llcommon/tests/llstreamqueue_test.cpp9
-rw-r--r--indra/llcommon/tests/lltreeiterators_test.cpp23
-rw-r--r--indra/llcommon/tests/threadsafeschedule_test.cpp5
-rw-r--r--indra/llcommon/tests/workqueue_test.cpp32
-rw-r--r--indra/llcommon/tests/wrapllerrs.h9
16 files changed, 1015 insertions, 250 deletions
diff --git a/indra/llcommon/tests/apply_test.cpp b/indra/llcommon/tests/apply_test.cpp
new file mode 100644
index 0000000000..56b497e0c8
--- /dev/null
+++ b/indra/llcommon/tests/apply_test.cpp
@@ -0,0 +1,240 @@
+/**
+ * @file apply_test.cpp
+ * @author Nat Goodspeed
+ * @date 2022-12-19
+ * @brief Test for apply.
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Copyright (c) 2022, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "apply.h"
+// STL headers
+// std headers
+#include <iomanip>
+// external library headers
+// other Linden headers
+#include "llsd.h"
+#include "llsdutil.h"
+#include <array>
+#include <string>
+#include <vector>
+
+// for ensure_equals
+std::ostream& operator<<(std::ostream& out, const std::vector<std::string>& stringvec)
+{
+ const char* delim = "[";
+ for (const auto& str : stringvec)
+ {
+ out << delim << std::quoted(str);
+ delim = ", ";
+ }
+ return out << ']';
+}
+
+// the above must be declared BEFORE ensure_equals(std::vector<std::string>)
+#include "../test/lltut.h"
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ namespace statics
+ {
+ /*------------------------------ data ------------------------------*/
+ // Although we're using types from the LLSD namespace, we're not
+ // constructing LLSD values, but rather instances of the C++ types
+ // supported by LLSD.
+ static LLSD::Boolean b{true};
+ static LLSD::Integer i{17};
+ static LLSD::Real f{3.14};
+ static LLSD::String s{ "hello" };
+ static LLSD::UUID uu{ "baadf00d-dead-beef-baad-feedb0ef" };
+ static LLSD::Date dt{ "2022-12-19" };
+ static LLSD::URI uri{ "http://secondlife.com" };
+ static LLSD::Binary bin{ 0x01, 0x02, 0x03, 0x04, 0x05 };
+
+ static std::vector<LLSD::String> quick
+ {
+ "The", "quick", "brown", "fox", "etc."
+ };
+
+ static std::array<int, 5> fibs
+ {
+ 0, 1, 1, 2, 3
+ };
+
+ // ensure that apply() actually reaches the target method --
+ // lack of ensure_equals() failure could be due to no-op apply()
+ bool called{ false };
+ // capture calls from collect()
+ std::vector<std::string> collected;
+
+ /*------------------------- test functions -------------------------*/
+ void various(LLSD::Boolean b, LLSD::Integer i, LLSD::Real f, const LLSD::String& s,
+ const LLSD::UUID& uu, const LLSD::Date& dt,
+ const LLSD::URI& uri, const LLSD::Binary& bin)
+ {
+ called = true;
+ ensure_equals( "b mismatch", b, statics::b);
+ ensure_equals( "i mismatch", i, statics::i);
+ ensure_equals( "f mismatch", f, statics::f);
+ ensure_equals( "s mismatch", s, statics::s);
+ ensure_equals( "uu mismatch", uu, statics::uu);
+ ensure_equals( "dt mismatch", dt, statics::dt);
+ ensure_equals("uri mismatch", uri, statics::uri);
+ ensure_equals("bin mismatch", bin, statics::bin);
+ }
+
+ void strings(std::string s0, std::string s1, std::string s2, std::string s3, std::string s4)
+ {
+ called = true;
+ ensure_equals("s0 mismatch", s0, statics::quick[0]);
+ ensure_equals("s1 mismatch", s1, statics::quick[1]);
+ ensure_equals("s2 mismatch", s2, statics::quick[2]);
+ ensure_equals("s3 mismatch", s3, statics::quick[3]);
+ ensure_equals("s4 mismatch", s4, statics::quick[4]);
+ }
+
+ void ints(int i0, int i1, int i2, int i3, int i4)
+ {
+ called = true;
+ ensure_equals("i0 mismatch", i0, statics::fibs[0]);
+ ensure_equals("i1 mismatch", i1, statics::fibs[1]);
+ ensure_equals("i2 mismatch", i2, statics::fibs[2]);
+ ensure_equals("i3 mismatch", i3, statics::fibs[3]);
+ ensure_equals("i4 mismatch", i4, statics::fibs[4]);
+ }
+
+ void sdfunc(const LLSD& sd)
+ {
+ called = true;
+ ensure_equals("sd mismatch", sd.asInteger(), statics::i);
+ }
+
+ void intfunc(int i)
+ {
+ called = true;
+ ensure_equals("i mismatch", i, statics::i);
+ }
+
+ void voidfunc()
+ {
+ called = true;
+ }
+
+ // recursion tail
+ void collect()
+ {
+ called = true;
+ }
+
+ // collect(arbitrary)
+ template <typename... ARGS>
+ void collect(const std::string& first, ARGS&&... rest)
+ {
+ statics::collected.push_back(first);
+ collect(std::forward<ARGS>(rest)...);
+ }
+ } // namespace statics
+
+ struct apply_data
+ {
+ apply_data()
+ {
+ // reset called before each test
+ statics::called = false;
+ statics::collected.clear();
+ }
+ };
+ typedef test_group<apply_data> apply_group;
+ typedef apply_group::object object;
+ apply_group applygrp("apply");
+
+ template<> template<>
+ void object::test<1>()
+ {
+ set_test_name("apply(tuple)");
+ LL::apply(statics::various,
+ std::make_tuple(statics::b, statics::i, statics::f, statics::s,
+ statics::uu, statics::dt, statics::uri, statics::bin));
+ ensure("apply(tuple) failed", statics::called);
+ }
+
+ template<> template<>
+ void object::test<2>()
+ {
+ set_test_name("apply(array)");
+ LL::apply(statics::ints, statics::fibs);
+ ensure("apply(array) failed", statics::called);
+ }
+
+ template<> template<>
+ void object::test<3>()
+ {
+ set_test_name("apply(vector)");
+ LL::apply(statics::strings, statics::quick);
+ ensure("apply(vector) failed", statics::called);
+ }
+
+ // The various apply(LLSD) tests exercise only the success cases because
+ // the failure cases trigger assert() fail, which is hard to catch.
+ template<> template<>
+ void object::test<4>()
+ {
+ set_test_name("apply(LLSD())");
+ LL::apply(statics::voidfunc, LLSD());
+ ensure("apply(LLSD()) failed", statics::called);
+ }
+
+ template<> template<>
+ void object::test<5>()
+ {
+ set_test_name("apply(fn(int), LLSD scalar)");
+ LL::apply(statics::intfunc, LLSD(statics::i));
+ ensure("apply(fn(int), LLSD scalar) failed", statics::called);
+ }
+
+ template<> template<>
+ void object::test<6>()
+ {
+ set_test_name("apply(fn(LLSD), LLSD scalar)");
+ // This test verifies that LLSDParam<LLSD> doesn't send the compiler
+ // into infinite recursion when the target is itself LLSD.
+ LL::apply(statics::sdfunc, LLSD(statics::i));
+ ensure("apply(fn(LLSD), LLSD scalar) failed", statics::called);
+ }
+
+ template<> template<>
+ void object::test<7>()
+ {
+ set_test_name("apply(LLSD array)");
+ LL::apply(statics::various,
+ llsd::array(statics::b, statics::i, statics::f, statics::s,
+ statics::uu, statics::dt, statics::uri, statics::bin));
+ ensure("apply(LLSD array) failed", statics::called);
+ }
+
+ template<> template<>
+ void object::test<8>()
+ {
+ set_test_name("VAPPLY()");
+ // Make a std::array<std::string> from statics::quick. We can't call a
+ // variadic function with a data structure of dynamic length.
+ std::array<std::string, 5> strray;
+ for (size_t i = 0; i < strray.size(); ++i)
+ strray[i] = statics::quick[i];
+ // This doesn't work: the compiler doesn't know which overload of
+ // collect() to pass to LL::apply().
+ // LL::apply(statics::collect, strray);
+ // That's what VAPPLY() is for.
+ VAPPLY(statics::collect, strray);
+ ensure("VAPPLY() failed", statics::called);
+ ensure_equals("collected mismatch", statics::collected, statics::quick);
+ }
+} // namespace tut
diff --git a/indra/llcommon/tests/lazyeventapi_test.cpp b/indra/llcommon/tests/lazyeventapi_test.cpp
new file mode 100644
index 0000000000..31b2d6d17f
--- /dev/null
+++ b/indra/llcommon/tests/lazyeventapi_test.cpp
@@ -0,0 +1,136 @@
+/**
+ * @file lazyeventapi_test.cpp
+ * @author Nat Goodspeed
+ * @date 2022-06-18
+ * @brief Test for lazyeventapi.
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Copyright (c) 2022, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lazyeventapi.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+#include "llevents.h"
+#include "llsdutil.h"
+
+// observable side effect, solely for testing
+static LLSD data;
+
+// LLEventAPI listener subclass
+class MyListener: public LLEventAPI
+{
+public:
+ // need this trivial forwarding constructor
+ // (of course do any other initialization your subclass requires)
+ MyListener(const LL::LazyEventAPIParams& params):
+ LLEventAPI(params)
+ {}
+
+ // example operation, registered by LazyEventAPI subclass below
+ void set_data(const LLSD& event)
+ {
+ data = event["data"];
+ }
+};
+
+// LazyEventAPI registrar subclass
+class MyRegistrar: public LL::LazyEventAPI<MyListener>
+{
+ using super = LL::LazyEventAPI<MyListener>;
+ using super::listener;
+public:
+ // LazyEventAPI subclass initializes like a classic LLEventAPI subclass
+ // constructor, with API name and desc plus add() calls for the defined
+ // operations
+ MyRegistrar():
+ super("Test", "This is a test LLEventAPI")
+ {
+ add("set", "This is a set operation", &listener::set_data);
+ }
+};
+// Normally we'd declare a static instance of MyRegistrar -- but because we
+// want to test both with and without, defer declaration to individual test
+// methods.
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct lazyeventapi_data
+ {
+ lazyeventapi_data()
+ {
+ // before every test, reset 'data'
+ data.clear();
+ }
+ ~lazyeventapi_data()
+ {
+ // after every test, reset LLEventPumps
+ LLEventPumps::deleteSingleton();
+ }
+ };
+ typedef test_group<lazyeventapi_data> lazyeventapi_group;
+ typedef lazyeventapi_group::object object;
+ lazyeventapi_group lazyeventapigrp("lazyeventapi");
+
+ template<> template<>
+ void object::test<1>()
+ {
+ set_test_name("LazyEventAPI");
+ // this is where the magic (should) happen
+ // 'register' still a keyword until C++17
+ MyRegistrar regster;
+ LLEventPumps::instance().obtain("Test").post(llsd::map("op", "set", "data", "hey"));
+ ensure_equals("failed to set data", data.asString(), "hey");
+ }
+
+ template<> template<>
+ void object::test<2>()
+ {
+ set_test_name("No LazyEventAPI");
+ // Because the MyRegistrar declaration in test<1>() is local, because
+ // it has been destroyed, we fully expect NOT to reach a MyListener
+ // instance with this post.
+ LLEventPumps::instance().obtain("Test").post(llsd::map("op", "set", "data", "moot"));
+ ensure("accidentally set data", ! data.isDefined());
+ }
+
+ template<> template<>
+ void object::test<3>()
+ {
+ set_test_name("LazyEventAPI metadata");
+ MyRegistrar regster;
+ // Of course we have 'regster' in hand; we don't need to search for
+ // it. But this next test verifies that we can find (all) LazyEventAPI
+ // instances using LazyEventAPIBase::instance_snapshot. Normally we
+ // wouldn't search; normally we'd just look at each instance in the
+ // loop body.
+ const MyRegistrar* found = nullptr;
+ for (const auto& registrar : LL::LazyEventAPIBase::instance_snapshot())
+ if ((found = dynamic_cast<const MyRegistrar*>(&registrar)))
+ break;
+ ensure("Failed to find MyRegistrar via LLInstanceTracker", found);
+
+ ensure_equals("wrong API name", found->getName(), "Test");
+ ensure_contains("wrong API desc", found->getDesc(), "test LLEventAPI");
+ ensure_equals("wrong API field", found->getDispatchKey(), "op");
+ // Normally we'd just iterate over *found. But for test purposes,
+ // actually capture the range of NameDesc pairs in a vector.
+ std::vector<LL::LazyEventAPIBase::NameDesc> ops{ found->begin(), found->end() };
+ ensure_equals("failed to find operations", ops.size(), 1);
+ ensure_equals("wrong operation name", ops[0].first, "set");
+ ensure_contains("wrong operation desc", ops[0].second, "set operation");
+ LLSD metadata{ found->getMetadata(ops[0].first) };
+ ensure_equals("bad metadata name", metadata["name"].asString(), ops[0].first);
+ ensure_equals("bad metadata desc", metadata["desc"].asString(), ops[0].second);
+ }
+} // namespace tut
diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp
index 148c18aabe..b4cdbdc6bf 100644
--- a/indra/llcommon/tests/llerror_test.cpp
+++ b/indra/llcommon/tests/llerror_test.cpp
@@ -153,27 +153,27 @@ namespace tut
int countMessages()
{
- return boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->countMessages();
+ return std::dynamic_pointer_cast<TestRecorder>(mRecorder)->countMessages();
}
void clearMessages()
{
- boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->clearMessages();
+ std::dynamic_pointer_cast<TestRecorder>(mRecorder)->clearMessages();
}
void setWantsTime(bool t)
{
- boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->showTime(t);
+ std::dynamic_pointer_cast<TestRecorder>(mRecorder)->showTime(t);
}
void setWantsMultiline(bool t)
{
- boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->showMultiline(t);
+ std::dynamic_pointer_cast<TestRecorder>(mRecorder)->showMultiline(t);
}
std::string message(int n)
{
- return boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->message(n);
+ return std::dynamic_pointer_cast<TestRecorder>(mRecorder)->message(n);
}
void ensure_message_count(int expectedCount)
@@ -497,12 +497,12 @@ namespace
void testLogName(LLError::RecorderPtr recorder, LogFromFunction f,
const std::string& class_name = "")
{
- boost::dynamic_pointer_cast<tut::TestRecorder>(recorder)->clearMessages();
+ std::dynamic_pointer_cast<tut::TestRecorder>(recorder)->clearMessages();
std::string name = f(false);
f(true);
- std::string messageWithoutName = boost::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(0);
- std::string messageWithName = boost::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(1);
+ std::string messageWithoutName = std::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(0);
+ std::string messageWithName = std::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(1);
ensure_has(name + " logged without name",
messageWithoutName, name);
@@ -691,13 +691,13 @@ namespace tut
LL_INFOS() << "boo" << LL_ENDL;
ensure_message_field_equals(0, MSG_FIELD, "boo");
- ensure_equals("alt recorder count", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 1);
- ensure_contains("alt recorder message 0", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(0), "boo");
+ ensure_equals("alt recorder count", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 1);
+ ensure_contains("alt recorder message 0", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(0), "boo");
LLError::setTimeFunction(roswell);
LLError::RecorderPtr anotherRecorder(new TestRecorder());
- boost::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->showTime(true);
+ std::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->showTime(true);
LLError::addRecorder(anotherRecorder);
LL_INFOS() << "baz" << LL_ENDL;
@@ -705,10 +705,10 @@ namespace tut
std::string when = roswell();
ensure_message_does_not_contain(1, when);
- ensure_equals("alt recorder count", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 2);
- ensure_does_not_contain("alt recorder message 1", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(1), when);
- ensure_equals("another recorder count", boost::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->countMessages(), 1);
- ensure_contains("another recorder message 0", boost::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->message(0), when);
+ ensure_equals("alt recorder count", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 2);
+ ensure_does_not_contain("alt recorder message 1", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(1), when);
+ ensure_equals("another recorder count", std::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->countMessages(), 1);
+ ensure_contains("another recorder message 0", std::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->message(0), when);
LLError::removeRecorder(altRecorder);
LLError::removeRecorder(anotherRecorder);
diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp
index 032923a108..01104545c6 100644
--- a/indra/llcommon/tests/lleventcoro_test.cpp
+++ b/indra/llcommon/tests/lleventcoro_test.cpp
@@ -101,7 +101,7 @@ namespace tut
int which;
LLTestApp testApp;
- void explicit_wait(boost::shared_ptr<LLCoros::Promise<std::string>>& cbp);
+ void explicit_wait(std::shared_ptr<LLCoros::Promise<std::string>>& cbp);
void waitForEventOn1();
void coroPump();
void postAndWait1();
@@ -111,7 +111,7 @@ namespace tut
typedef coroutine_group::object object;
coroutine_group coroutinegrp("coroutine");
- void test_data::explicit_wait(boost::shared_ptr<LLCoros::Promise<std::string>>& cbp)
+ void test_data::explicit_wait(std::shared_ptr<LLCoros::Promise<std::string>>& cbp)
{
BEGIN
{
@@ -127,7 +127,7 @@ namespace tut
// For test purposes, instead of handing 'callback' (or an
// adapter) off to some I/O subsystem, we'll just pass it back to
// our caller.
- cbp = boost::make_shared<LLCoros::Promise<std::string>>();
+ cbp = std::make_shared<LLCoros::Promise<std::string>>();
LLCoros::Future<std::string> future = LLCoros::getFuture(*cbp);
// calling get() on the future causes us to suspend
@@ -146,7 +146,7 @@ namespace tut
DEBUG;
// Construct the coroutine instance that will run explicit_wait.
- boost::shared_ptr<LLCoros::Promise<std::string>> respond;
+ std::shared_ptr<LLCoros::Promise<std::string>> respond;
LLCoros::instance().launch("test<1>",
[this, &respond](){ explicit_wait(respond); });
mSync.bump();
diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp
index 466f11f52a..b0c532887c 100644
--- a/indra/llcommon/tests/lleventdispatcher_test.cpp
+++ b/indra/llcommon/tests/lleventdispatcher_test.cpp
@@ -18,9 +18,12 @@
// external library headers
// other Linden headers
#include "../test/lltut.h"
+#include "lleventfilter.h"
#include "llsd.h"
#include "llsdutil.h"
+#include "llevents.h"
#include "stringize.h"
+#include "StringVec.h"
#include "tests/wrapllerrs.h"
#include "../test/catch_and_store_what_in.h"
#include "../test/debug.h"
@@ -32,8 +35,6 @@
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/range.hpp>
-#include <boost/foreach.hpp>
-#define foreach BOOST_FOREACH
#include <boost/lambda/lambda.hpp>
@@ -177,6 +178,7 @@ struct Vars
/*-------- Arbitrary-params (non-const, const, static) methods ---------*/
void methodna(NPARAMSa)
{
+ DEBUG;
// Because our const char* param cp might be NULL, and because we
// intend to capture the value in a std::string, have to distinguish
// between the NULL value and any non-NULL value. Use a convention
@@ -188,7 +190,7 @@ struct Vars
else
vcp = std::string("'") + cp + "'";
- debug()("methodna(", b,
+ this->debug()("methodna(", b,
", ", i,
", ", f,
", ", d,
@@ -205,7 +207,7 @@ struct Vars
void methodnb(NPARAMSb)
{
std::ostringstream vbin;
- foreach(U8 byte, bin)
+ for (U8 byte: bin)
{
vbin << std::hex << std::setfill('0') << std::setw(2) << unsigned(byte);
}
@@ -226,7 +228,8 @@ struct Vars
void cmethodna(NPARAMSa) const
{
- debug()('c', NONL);
+ DEBUG;
+ this->debug()('c', NONL);
const_cast<Vars*>(this)->methodna(NARGSa);
}
@@ -315,6 +318,31 @@ void freenb(NPARAMSb)
*****************************************************************************/
namespace tut
{
+ void ensure_has(const std::string& outer, const std::string& inner)
+ {
+ ensure(stringize("'", outer, "' does not contain '", inner, "'"),
+ outer.find(inner) != std::string::npos);
+ }
+
+ template <typename CALLABLE>
+ std::string call_exc(CALLABLE&& func, const std::string& exc_frag)
+ {
+ std::string what =
+ catch_what<LLEventDispatcher::DispatchError>(std::forward<CALLABLE>(func));
+ ensure_has(what, exc_frag);
+ return what;
+ }
+
+ template <typename CALLABLE>
+ void call_logerr(CALLABLE&& func, const std::string& frag)
+ {
+ CaptureLog capture;
+ // the error should be logged; we just need to stop the exception
+ // propagating
+ catch_what<LLEventDispatcher::DispatchError>(std::forward<CALLABLE>(func));
+ capture.messageWith(frag);
+ }
+
struct lleventdispatcher_data
{
Debug debug{"test"};
@@ -397,9 +425,9 @@ namespace tut
work.add(name, desc, &Dispatcher::cmethod1, required);
// Non-subclass method with/out required params
addf("method1", "method1", &v);
- work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1));
+ work.add(name, desc, [this](const LLSD& args){ return v.method1(args); });
addf("method1_req", "method1", &v);
- work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1), required);
+ work.add(name, desc, [this](const LLSD& args){ return v.method1(args); }, required);
/*--------------- Arbitrary params, array style ----------------*/
@@ -461,7 +489,7 @@ namespace tut
debug("dft_array_full:\n",
dft_array_full);
// Partial defaults arrays.
- foreach(LLSD::String a, ab)
+ for (LLSD::String a: ab)
{
LLSD::Integer partition(std::min(partial_offset, dft_array_full[a].size()));
dft_array_partial[a] =
@@ -471,7 +499,7 @@ namespace tut
debug("dft_array_partial:\n",
dft_array_partial);
- foreach(LLSD::String a, ab)
+ for(LLSD::String a: ab)
{
// Generate full defaults maps by zipping (params, dft_array_full).
dft_map_full[a] = zipmap(params[a], dft_array_full[a]);
@@ -583,6 +611,7 @@ namespace tut
void addf(const std::string& n, const std::string& d, Vars* v)
{
+ debug("addf('", n, "', '", d, "')");
// This method is to capture in our own DescMap the name and
// description of every registered function, for metadata query
// testing.
@@ -598,19 +627,14 @@ namespace tut
{
// Copy descs to a temp map of same type.
DescMap forgotten(descs.begin(), descs.end());
- // LLEventDispatcher intentionally provides only const_iterator:
- // since dereferencing that iterator generates values on the fly,
- // it's meaningless to have a modifiable iterator. But since our
- // 'work' object isn't const, by default BOOST_FOREACH() wants to
- // use non-const iterators. Persuade it to use the const_iterator.
- foreach(LLEventDispatcher::NameDesc nd, const_cast<const Dispatcher&>(work))
+ for (LLEventDispatcher::NameDesc nd: work)
{
DescMap::iterator found = forgotten.find(nd.first);
- ensure(STRINGIZE("LLEventDispatcher records function '" << nd.first
- << "' we didn't enter"),
+ ensure(stringize("LLEventDispatcher records function '", nd.first,
+ "' we didn't enter"),
found != forgotten.end());
- ensure_equals(STRINGIZE("LLEventDispatcher desc '" << nd.second <<
- "' doesn't match what we entered: '" << found->second << "'"),
+ ensure_equals(stringize("LLEventDispatcher desc '", nd.second,
+ "' doesn't match what we entered: '", found->second, "'"),
nd.second, found->second);
// found in our map the name from LLEventDispatcher, good, erase
// our map entry
@@ -621,41 +645,49 @@ namespace tut
std::ostringstream out;
out << "LLEventDispatcher failed to report";
const char* delim = ": ";
- foreach(const DescMap::value_type& fme, forgotten)
+ for (const DescMap::value_type& fme: forgotten)
{
out << delim << fme.first;
delim = ", ";
}
- ensure(out.str(), false);
+ throw failure(out.str());
}
}
Vars* varsfor(const std::string& name)
{
VarsMap::const_iterator found = funcvars.find(name);
- ensure(STRINGIZE("No Vars* for " << name), found != funcvars.end());
- ensure(STRINGIZE("NULL Vars* for " << name), found->second);
+ ensure(stringize("No Vars* for ", name), found != funcvars.end());
+ ensure(stringize("NULL Vars* for ", name), found->second);
return found->second;
}
- void ensure_has(const std::string& outer, const std::string& inner)
+ std::string call_exc(const std::string& func, const LLSD& args, const std::string& exc_frag)
{
- ensure(STRINGIZE("'" << outer << "' does not contain '" << inner << "'").c_str(),
- outer.find(inner) != std::string::npos);
+ return tut::call_exc(
+ [this, func, args]()
+ {
+ if (func.empty())
+ {
+ work(args);
+ }
+ else
+ {
+ work(func, args);
+ }
+ },
+ exc_frag);
}
- void call_exc(const std::string& func, const LLSD& args, const std::string& exc_frag)
+ void call_logerr(const std::string& func, const LLSD& args, const std::string& frag)
{
- std::string threw = catch_what<std::runtime_error>([this, &func, &args](){
- work(func, args);
- });
- ensure_has(threw, exc_frag);
+ tut::call_logerr([this, func, args](){ work(func, args); }, frag);
}
LLSD getMetadata(const std::string& name)
{
LLSD meta(work.getMetadata(name));
- ensure(STRINGIZE("No metadata for " << name), meta.isDefined());
+ ensure(stringize("No metadata for ", name), meta.isDefined());
return meta;
}
@@ -724,7 +756,7 @@ namespace tut
set_test_name("map-style registration with non-array params");
// Pass "param names" as scalar or as map
LLSD attempts(llsd::array(17, LLSDMap("pi", 3.14)("two", 2)));
- foreach(LLSD ae, inArray(attempts))
+ for (LLSD ae: inArray(attempts))
{
std::string threw = catch_what<std::exception>([this, &ae](){
work.add("freena_err", "freena", freena, ae);
@@ -799,7 +831,7 @@ namespace tut
{
set_test_name("query Callables with/out required params");
LLSD names(llsd::array("free1", "Dmethod1", "Dcmethod1", "method1"));
- foreach(LLSD nm, inArray(names))
+ for (LLSD nm: inArray(names))
{
LLSD metadata(getMetadata(nm));
ensure_equals("name mismatch", metadata["name"], nm);
@@ -828,19 +860,19 @@ namespace tut
(5, llsd::array("freena_array", "smethodna_array", "methodna_array")),
llsd::array
(5, llsd::array("freenb_array", "smethodnb_array", "methodnb_array"))));
- foreach(LLSD ae, inArray(expected))
+ for (LLSD ae: inArray(expected))
{
LLSD::Integer arity(ae[0].asInteger());
LLSD names(ae[1]);
LLSD req(LLSD::emptyArray());
if (arity)
req[arity - 1] = LLSD();
- foreach(LLSD nm, inArray(names))
+ for (LLSD nm: inArray(names))
{
LLSD metadata(getMetadata(nm));
ensure_equals("name mismatch", metadata["name"], nm);
ensure_equals(metadata["desc"].asString(), descs[nm]);
- ensure_equals(STRINGIZE("mismatched required for " << nm.asString()),
+ ensure_equals(stringize("mismatched required for ", nm.asString()),
metadata["required"], req);
ensure("should not have optional", metadata["optional"].isUndefined());
}
@@ -854,7 +886,7 @@ namespace tut
// - (Free function | non-static method), map style, no params (ergo
// no defaults)
LLSD names(llsd::array("free0_map", "smethod0_map", "method0_map"));
- foreach(LLSD nm, inArray(names))
+ for (LLSD nm: inArray(names))
{
LLSD metadata(getMetadata(nm));
ensure_equals("name mismatch", metadata["name"], nm);
@@ -884,7 +916,7 @@ namespace tut
llsd::array("smethodnb_map_adft", "smethodnb_map_mdft"),
llsd::array("methodna_map_adft", "methodna_map_mdft"),
llsd::array("methodnb_map_adft", "methodnb_map_mdft")));
- foreach(LLSD eq, inArray(equivalences))
+ for (LLSD eq: inArray(equivalences))
{
LLSD adft(eq[0]);
LLSD mdft(eq[1]);
@@ -898,8 +930,8 @@ namespace tut
ensure_equals("mdft name", mdft, mmeta["name"]);
ameta.erase("name");
mmeta.erase("name");
- ensure_equals(STRINGIZE("metadata for " << adft.asString()
- << " vs. " << mdft.asString()),
+ ensure_equals(stringize("metadata for ", adft.asString(),
+ " vs. ", mdft.asString()),
ameta, mmeta);
}
}
@@ -915,7 +947,7 @@ namespace tut
// params are required. Also maps containing left requirements for
// partial defaults arrays. Also defaults maps from defaults arrays.
LLSD allreq, leftreq, rightdft;
- foreach(LLSD::String a, ab)
+ for (LLSD::String a: ab)
{
// The map in which all params are required uses params[a] as
// keys, with all isUndefined() as values. We can accomplish that
@@ -943,9 +975,9 @@ namespace tut
// Generate maps containing parameter names not provided by the
// dft_map_partial maps.
LLSD skipreq(allreq);
- foreach(LLSD::String a, ab)
+ for (LLSD::String a: ab)
{
- foreach(const MapEntry& me, inMap(dft_map_partial[a]))
+ for (const MapEntry& me: inMap(dft_map_partial[a]))
{
skipreq[a].erase(me.first);
}
@@ -990,7 +1022,7 @@ namespace tut
(llsd::array("freenb_map_mdft", "smethodnb_map_mdft", "methodnb_map_mdft"),
llsd::array(LLSD::emptyMap(), dft_map_full["b"])))); // required, optional
- foreach(LLSD grp, inArray(groups))
+ for (LLSD grp: inArray(groups))
{
// Internal structure of each group in 'groups':
LLSD names(grp[0]);
@@ -1003,14 +1035,14 @@ namespace tut
optional);
// Loop through 'names'
- foreach(LLSD nm, inArray(names))
+ for (LLSD nm: inArray(names))
{
LLSD metadata(getMetadata(nm));
ensure_equals("name mismatch", metadata["name"], nm);
ensure_equals(nm.asString(), metadata["desc"].asString(), descs[nm]);
- ensure_equals(STRINGIZE(nm << " required mismatch"),
+ ensure_equals(stringize(nm, " required mismatch"),
metadata["required"], required);
- ensure_equals(STRINGIZE(nm << " optional mismatch"),
+ ensure_equals(stringize(nm, " optional mismatch"),
metadata["optional"], optional);
}
}
@@ -1031,13 +1063,7 @@ namespace tut
{
set_test_name("call with bad name");
call_exc("freek", LLSD(), "not found");
- // We don't have a comparable helper function for the one-arg
- // operator() method, and it's not worth building one just for this
- // case. Write it out.
- std::string threw = catch_what<std::runtime_error>([this](){
- work(LLSDMap("op", "freek"));
- });
- ensure_has(threw, "bad");
+ std::string threw = call_exc("", LLSDMap("op", "freek"), "bad");
ensure_has(threw, "op");
ensure_has(threw, "freek");
}
@@ -1079,7 +1105,7 @@ namespace tut
// LLSD value matching 'required' according to llsd_matches() rules.
LLSD matching(LLSDMap("d", 3.14)("array", llsd::array("answer", true, answer)));
// Okay, walk through 'tests'.
- foreach(const CallablesTriple& tr, tests)
+ for (const CallablesTriple& tr: tests)
{
// Should be able to pass 'answer' to Callables registered
// without 'required'.
@@ -1087,7 +1113,7 @@ namespace tut
ensure_equals("answer mismatch", tr.llsd, answer);
// Should NOT be able to pass 'answer' to Callables registered
// with 'required'.
- call_exc(tr.name_req, answer, "bad request");
+ call_logerr(tr.name_req, answer, "bad request");
// But SHOULD be able to pass 'matching' to Callables registered
// with 'required'.
work(tr.name_req, matching);
@@ -1101,17 +1127,20 @@ namespace tut
set_test_name("passing wrong args to (map | array)-style registrations");
// Pass scalar/map to array-style functions, scalar/array to map-style
- // functions. As that validation happens well before we engage the
- // argument magic, it seems pointless to repeat this with every
- // variation: (free function | non-static method), (no | arbitrary)
- // args. We should only need to engage it for one map-style
- // registration and one array-style registration.
- std::string array_exc("needs an args array");
- call_exc("free0_array", 17, array_exc);
- call_exc("free0_array", LLSDMap("pi", 3.14), array_exc);
+ // functions. It seems pointless to repeat this with every variation:
+ // (free function | non-static method), (no | arbitrary) args. We
+ // should only need to engage it for one map-style registration and
+ // one array-style registration.
+ // Now that LLEventDispatcher has been extended to treat an LLSD
+ // scalar as a single-entry array, the error we expect in this case is
+ // that apply() is trying to pass that non-empty array to a nullary
+ // function.
+ call_logerr("free0_array", 17, "LL::apply");
+ // similarly, apply() doesn't accept an LLSD Map
+ call_logerr("free0_array", LLSDMap("pi", 3.14), "unsupported");
std::string map_exc("needs a map");
- call_exc("free0_map", 17, map_exc);
+ call_logerr("free0_map", 17, map_exc);
// Passing an array to a map-style function works now! No longer an
// error case!
// call_exc("free0_map", llsd::array("a", "b"), map_exc);
@@ -1125,7 +1154,7 @@ namespace tut
("free0_array", "free0_map",
"smethod0_array", "smethod0_map",
"method0_array", "method0_map"));
- foreach(LLSD name, inArray(names))
+ for (LLSD name: inArray(names))
{
// Look up the Vars instance for this function.
Vars* vars(varsfor(name));
@@ -1150,15 +1179,21 @@ namespace tut
template<> template<>
void object::test<19>()
{
- set_test_name("call array-style functions with too-short arrays");
- // Could have two different too-short arrays, one for *na and one for
- // *nb, but since they both take 5 params...
+ set_test_name("call array-style functions with wrong-length arrays");
+ // Could have different wrong-length arrays for *na and for *nb, but
+ // since they both take 5 params...
LLSD tooshort(llsd::array("this", "array", "too", "short"));
- foreach(const LLSD& funcsab, inArray(array_funcs))
+ LLSD toolong (llsd::array("this", "array", "is", "one", "too", "long"));
+ LLSD badargs (llsd::array(tooshort, toolong));
+ for (const LLSD& toosomething: inArray(badargs))
{
- foreach(const llsd::MapEntry& e, inMap(funcsab))
+ for (const LLSD& funcsab: inArray(array_funcs))
{
- call_exc(e.second, tooshort, "requires more arguments");
+ for (const llsd::MapEntry& e: inMap(funcsab))
+ {
+ // apply() complains about wrong number of array entries
+ call_logerr(e.second, toosomething, "LL::apply");
+ }
}
}
}
@@ -1166,7 +1201,7 @@ namespace tut
template<> template<>
void object::test<20>()
{
- set_test_name("call array-style functions with (just right | too long) arrays");
+ set_test_name("call array-style functions with right-size arrays");
std::vector<U8> binary;
for (size_t h(0x01), i(0); i < 5; h+= 0x22, ++i)
{
@@ -1178,40 +1213,25 @@ namespace tut
LLDate("2011-02-03T15:07:00Z"),
LLURI("http://secondlife.com"),
binary)));
- LLSD argsplus(args);
- argsplus["a"].append("bogus");
- argsplus["b"].append("bogus");
LLSD expect;
- foreach(LLSD::String a, ab)
+ for (LLSD::String a: ab)
{
expect[a] = zipmap(params[a], args[a]);
}
// Adjust expect["a"]["cp"] for special Vars::cp treatment.
- expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'";
+ expect["a"]["cp"] = stringize("'", expect["a"]["cp"].asString(), "'");
debug("expect: ", expect);
- // Use substantially the same logic for args and argsplus
- LLSD argsarrays(llsd::array(args, argsplus));
- // So i==0 selects 'args', i==1 selects argsplus
- for (LLSD::Integer i(0), iend(argsarrays.size()); i < iend; ++i)
+ for (const LLSD& funcsab: inArray(array_funcs))
{
- foreach(const LLSD& funcsab, inArray(array_funcs))
+ for (LLSD::String a: ab)
{
- foreach(LLSD::String a, ab)
- {
- // Reset the Vars instance before each call
- Vars* vars(varsfor(funcsab[a]));
- *vars = Vars();
- work(funcsab[a], argsarrays[i][a]);
- ensure_llsd(STRINGIZE(funcsab[a].asString() <<
- ": expect[\"" << a << "\"] mismatch"),
- vars->inspect(), expect[a], 7); // 7 bits ~= 2 decimal digits
-
- // TODO: in the i==1 or argsplus case, intercept LL_WARNS
- // output? Even without that, using argsplus verifies that
- // passing too many args isn't fatal; it works -- but
- // would be nice to notice the warning too.
- }
+ // Reset the Vars instance before each call
+ Vars* vars(varsfor(funcsab[a]));
+ *vars = Vars();
+ work(funcsab[a], args[a]);
+ ensure_llsd(stringize(funcsab[a].asString(), ": expect[\"", a, "\"] mismatch"),
+ vars->inspect(), expect[a], 7); // 7 bits ~= 2 decimal digits
}
}
}
@@ -1239,7 +1259,7 @@ namespace tut
("a", llsd::array(false, 255, 98.6, 1024.5, "pointer"))
("b", llsd::array("object", LLUUID::generateNewID(), LLDate::now(), LLURI("http://wiki.lindenlab.com/wiki"), LLSD::Binary(boost::begin(binary), boost::end(binary)))));
LLSD array_overfull(array_full);
- foreach(LLSD::String a, ab)
+ for (LLSD::String a: ab)
{
array_overfull[a].append("bogus");
}
@@ -1253,7 +1273,7 @@ namespace tut
ensure_not_equals("UUID collision",
array_full["b"][1].asUUID(), dft_array_full["b"][1].asUUID());
LLSD map_full, map_overfull;
- foreach(LLSD::String a, ab)
+ for (LLSD::String a: ab)
{
map_full[a] = zipmap(params[a], array_full[a]);
map_overfull[a] = map_full[a];
@@ -1294,21 +1314,360 @@ namespace tut
"freenb_map_mdft", "smethodnb_map_mdft", "methodnb_map_mdft")));
// Treat (full | overfull) (array | map) the same.
LLSD argssets(llsd::array(array_full, array_overfull, map_full, map_overfull));
- foreach(const LLSD& args, inArray(argssets))
+ for (const LLSD& args: inArray(argssets))
{
- foreach(LLSD::String a, ab)
+ for (LLSD::String a: ab)
{
- foreach(LLSD::String name, inArray(names[a]))
+ for (LLSD::String name: inArray(names[a]))
{
// Reset the Vars instance
Vars* vars(varsfor(name));
*vars = Vars();
work(name, args[a]);
- ensure_llsd(STRINGIZE(name << ": expect[\"" << a << "\"] mismatch"),
+ ensure_llsd(stringize(name, ": expect[\"", a, "\"] mismatch"),
vars->inspect(), expect[a], 7); // 7 bits, 2 decimal digits
// intercept LL_WARNS for the two overfull cases?
}
}
}
}
+
+ struct DispatchResult: public LLDispatchListener
+ {
+ using DR = DispatchResult;
+
+ DispatchResult(): LLDispatchListener("results", "op")
+ {
+ add("strfunc", "return string", &DR::strfunc);
+ add("voidfunc", "void function", &DR::voidfunc);
+ add("emptyfunc", "return empty LLSD", &DR::emptyfunc);
+ add("intfunc", "return Integer LLSD", &DR::intfunc);
+ add("llsdfunc", "return passed LLSD", &DR::llsdfunc);
+ add("mapfunc", "return map LLSD", &DR::mapfunc);
+ add("arrayfunc", "return array LLSD", &DR::arrayfunc);
+ }
+
+ std::string strfunc(const std::string& str) const { return "got " + str; }
+ void voidfunc() const {}
+ LLSD emptyfunc() const { return {}; }
+ int intfunc(int i) const { return -i; }
+ LLSD llsdfunc(const LLSD& event) const
+ {
+ LLSD result{ event };
+ result["with"] = "string";
+ return result;
+ }
+ LLSD mapfunc(int i, const std::string& str) const
+ {
+ return llsd::map("i", intfunc(i), "str", strfunc(str));
+ }
+ LLSD arrayfunc(int i, const std::string& str) const
+ {
+ return llsd::array(intfunc(i), strfunc(str));
+ }
+ };
+
+ template<> template<>
+ void object::test<23>()
+ {
+ set_test_name("string result");
+ DispatchResult service;
+ LLSD result{ service("strfunc", "a string") };
+ ensure_equals("strfunc() mismatch", result.asString(), "got a string");
+ }
+
+ template<> template<>
+ void object::test<24>()
+ {
+ set_test_name("void result");
+ DispatchResult service;
+ LLSD result{ service("voidfunc", LLSD()) };
+ ensure("voidfunc() returned defined", result.isUndefined());
+ }
+
+ template<> template<>
+ void object::test<25>()
+ {
+ set_test_name("Integer result");
+ DispatchResult service;
+ LLSD result{ service("intfunc", -17) };
+ ensure_equals("intfunc() mismatch", result.asInteger(), 17);
+ }
+
+ template<> template<>
+ void object::test<26>()
+ {
+ set_test_name("LLSD echo");
+ DispatchResult service;
+ LLSD result{ service("llsdfunc", llsd::map("op", "llsdfunc", "reqid", 17)) };
+ ensure_equals("llsdfunc() mismatch", result,
+ llsd::map("op", "llsdfunc", "reqid", 17, "with", "string"));
+ }
+
+ template<> template<>
+ void object::test<27>()
+ {
+ set_test_name("map LLSD result");
+ DispatchResult service;
+ LLSD result{ service("mapfunc", llsd::array(-12, "value")) };
+ ensure_equals("mapfunc() mismatch", result, llsd::map("i", 12, "str", "got value"));
+ }
+
+ template<> template<>
+ void object::test<28>()
+ {
+ set_test_name("array LLSD result");
+ DispatchResult service;
+ LLSD result{ service("arrayfunc", llsd::array(-8, "word")) };
+ ensure_equals("arrayfunc() mismatch", result, llsd::array(8, "got word"));
+ }
+
+ template<> template<>
+ void object::test<29>()
+ {
+ set_test_name("listener error, no reply");
+ DispatchResult service;
+ tut::call_exc(
+ [&service]()
+ { service.post(llsd::map("op", "nosuchfunc", "reqid", 17)); },
+ "nosuchfunc");
+ }
+
+ template<> template<>
+ void object::test<30>()
+ {
+ set_test_name("listener error with reply");
+ DispatchResult service;
+ LLCaptureListener<LLSD> result;
+ service.post(llsd::map("op", "nosuchfunc", "reqid", 17, "reply", result.getName()));
+ LLSD reply{ result.get() };
+ ensure("no reply", reply.isDefined());
+ ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17);
+ ensure_has(reply["error"].asString(), "nosuchfunc");
+ }
+
+ template<> template<>
+ void object::test<31>()
+ {
+ set_test_name("listener call to void function");
+ DispatchResult service;
+ LLCaptureListener<LLSD> result;
+ result.set("non-empty");
+ for (const auto& func: StringVec{ "voidfunc", "emptyfunc" })
+ {
+ service.post(llsd::map(
+ "op", func,
+ "reqid", 17,
+ "reply", result.getName()));
+ ensure_equals("reply from " + func, result.get().asString(), "non-empty");
+ }
+ }
+
+ template<> template<>
+ void object::test<32>()
+ {
+ set_test_name("listener call to string function");
+ DispatchResult service;
+ LLCaptureListener<LLSD> result;
+ service.post(llsd::map(
+ "op", "strfunc",
+ "args", llsd::array("a string"),
+ "reqid", 17,
+ "reply", result.getName()));
+ LLSD reply{ result.get() };
+ ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17);
+ ensure_equals("bad reply from strfunc", reply["data"].asString(), "got a string");
+ }
+
+ template<> template<>
+ void object::test<33>()
+ {
+ set_test_name("listener call to map function");
+ DispatchResult service;
+ LLCaptureListener<LLSD> result;
+ service.post(llsd::map(
+ "op", "mapfunc",
+ "args", llsd::array(-7, "value"),
+ "reqid", 17,
+ "reply", result.getName()));
+ LLSD reply{ result.get() };
+ ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17);
+ ensure_equals("bad i from mapfunc", reply["i"].asInteger(), 7);
+ ensure_equals("bad str from mapfunc", reply["str"], "got value");
+ }
+
+ template<> template<>
+ void object::test<34>()
+ {
+ set_test_name("batched map success");
+ DispatchResult service;
+ LLCaptureListener<LLSD> result;
+ service.post(llsd::map(
+ "op", llsd::map(
+ "strfunc", "some string",
+ "intfunc", 2,
+ "voidfunc", LLSD(),
+ "arrayfunc", llsd::array(-5, "other string")),
+ "reqid", 17,
+ "reply", result.getName()));
+ LLSD reply{ result.get() };
+ ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17);
+ reply.erase("reqid");
+ ensure_equals(
+ "bad map batch",
+ reply,
+ llsd::map(
+ "strfunc", "got some string",
+ "intfunc", -2,
+ "voidfunc", LLSD(),
+ "arrayfunc", llsd::array(5, "got other string")));
+ }
+
+ template<> template<>
+ void object::test<35>()
+ {
+ set_test_name("batched map error");
+ DispatchResult service;
+ LLCaptureListener<LLSD> result;
+ service.post(llsd::map(
+ "op", llsd::map(
+ "badfunc", 34, // !
+ "strfunc", "some string",
+ "intfunc", 2,
+ "missing", LLSD(), // !
+ "voidfunc", LLSD(),
+ "arrayfunc", llsd::array(-5, "other string")),
+ "reqid", 17,
+ "reply", result.getName()));
+ LLSD reply{ result.get() };
+ ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17);
+ reply.erase("reqid");
+ auto error{ reply["error"].asString() };
+ reply.erase("error");
+ ensure_has(error, "badfunc");
+ ensure_has(error, "missing");
+ ensure_equals(
+ "bad partial batch",
+ reply,
+ llsd::map(
+ "strfunc", "got some string",
+ "intfunc", -2,
+ "voidfunc", LLSD(),
+ "arrayfunc", llsd::array(5, "got other string")));
+ }
+
+ template<> template<>
+ void object::test<36>()
+ {
+ set_test_name("batched map exception");
+ DispatchResult service;
+ auto error = tut::call_exc(
+ [&service]()
+ {
+ service.post(llsd::map(
+ "op", llsd::map(
+ "badfunc", 34, // !
+ "strfunc", "some string",
+ "intfunc", 2,
+ "missing", LLSD(), // !
+ "voidfunc", LLSD(),
+ "arrayfunc", llsd::array(-5, "other string")),
+ "reqid", 17));
+ // no "reply"
+ },
+ "badfunc");
+ ensure_has(error, "missing");
+ }
+
+ template<> template<>
+ void object::test<37>()
+ {
+ set_test_name("batched array success");
+ DispatchResult service;
+ LLCaptureListener<LLSD> result;
+ service.post(llsd::map(
+ "op", llsd::array(
+ llsd::array("strfunc", "some string"),
+ llsd::array("intfunc", 2),
+ "arrayfunc",
+ "voidfunc"),
+ "args", llsd::array(
+ LLSD(),
+ LLSD(),
+ llsd::array(-5, "other string")),
+ // args array deliberately short, since the default
+ // [3] is undefined, which should work for voidfunc
+ "reqid", 17,
+ "reply", result.getName()));
+ LLSD reply{ result.get() };
+ ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17);
+ reply.erase("reqid");
+ ensure_equals(
+ "bad array batch",
+ reply,
+ llsd::map(
+ "data", llsd::array(
+ "got some string",
+ -2,
+ llsd::array(5, "got other string"),
+ LLSD())));
+ }
+
+ template<> template<>
+ void object::test<38>()
+ {
+ set_test_name("batched array error");
+ DispatchResult service;
+ LLCaptureListener<LLSD> result;
+ service.post(llsd::map(
+ "op", llsd::array(
+ llsd::array("strfunc", "some string"),
+ llsd::array("intfunc", 2, "whoops"), // bad form
+ "arrayfunc",
+ "voidfunc"),
+ "args", llsd::array(
+ LLSD(),
+ LLSD(),
+ llsd::array(-5, "other string")),
+ // args array deliberately short, since the default
+ // [3] is undefined, which should work for voidfunc
+ "reqid", 17,
+ "reply", result.getName()));
+ LLSD reply{ result.get() };
+ ensure_equals("reqid not echoed", reply["reqid"].asInteger(), 17);
+ reply.erase("reqid");
+ auto error{ reply["error"] };
+ reply.erase("error");
+ ensure_has(error, "[1]");
+ ensure_has(error, "unsupported");
+ ensure_equals("bad array batch", reply,
+ llsd::map("data", llsd::array("got some string")));
+ }
+
+ template<> template<>
+ void object::test<39>()
+ {
+ set_test_name("batched array exception");
+ DispatchResult service;
+ auto error = tut::call_exc(
+ [&service]()
+ {
+ service.post(llsd::map(
+ "op", llsd::array(
+ llsd::array("strfunc", "some string"),
+ llsd::array("intfunc", 2, "whoops"), // bad form
+ "arrayfunc",
+ "voidfunc"),
+ "args", llsd::array(
+ LLSD(),
+ LLSD(),
+ llsd::array(-5, "other string")),
+ // args array deliberately short, since the default
+ // [3] is undefined, which should work for voidfunc
+ "reqid", 17));
+ // no "reply"
+ },
+ "[1]");
+ ensure_has(error, "unsupported");
+ }
} // namespace tut
diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp
index 5daa29adf4..95af9c2a50 100644
--- a/indra/llcommon/tests/llinstancetracker_test.cpp
+++ b/indra/llcommon/tests/llinstancetracker_test.cpp
@@ -94,7 +94,7 @@ namespace tut
ensure("couldn't find stack Keyed", bool(found));
ensure_equals("found wrong Keyed instance", found.get(), &one);
{
- boost::scoped_ptr<Keyed> two(new Keyed("two"));
+ std::unique_ptr<Keyed> two(new Keyed("two"));
ensure_equals(Keyed::instanceCount(), 2);
auto found = Keyed::getInstance("two");
ensure("couldn't find heap Keyed", bool(found));
@@ -118,7 +118,7 @@ namespace tut
std::weak_ptr<Unkeyed> found = one.getWeak();
ensure(! found.expired());
{
- boost::scoped_ptr<Unkeyed> two(new Unkeyed);
+ std::unique_ptr<Unkeyed> two(new Unkeyed);
ensure_equals(Unkeyed::instanceCount(), 2);
}
ensure_equals(Unkeyed::instanceCount(), 1);
diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp
index 4f14ba3c81..001717d223 100644
--- a/indra/llcommon/tests/llleap_test.cpp
+++ b/indra/llcommon/tests/llleap_test.cpp
@@ -103,12 +103,7 @@ namespace tut
"import os\n"
"import sys\n"
"\n"
- "try:\n"
- // new freestanding llsd package
- " import llsd\n"
- "except ImportError:\n"
- // older llbase.llsd module
- " from llbase import llsd\n"
+ "import llsd\n"
"\n"
"class ProtocolError(Exception):\n"
" def __init__(self, msg, data):\n"
diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index ece567f40e..deef717e5c 100644
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -21,7 +21,6 @@
// external library headers
#include "llapr.h"
#include "apr_thread_proc.h"
-#include <boost/foreach.hpp>
#include <boost/function.hpp>
#include <boost/algorithm/string/find_iterator.hpp>
#include <boost/algorithm/string/finder.hpp>
@@ -221,7 +220,7 @@ struct PythonProcessLauncher
LLProcess::Params mParams;
LLProcessPtr mPy;
std::string mDesc;
- NamedTempFile mScript;
+ NamedExtTempFile mScript;
};
/// convenience function for PythonProcessLauncher::run()
@@ -324,7 +323,7 @@ namespace tut
{
/*==========================================================================*|
std::string reason_str;
- BOOST_FOREACH(const ReasonCode& rcp, reasons)
+ for (const ReasonCode& rcp : reasons)
{
if (reason == rcp.code)
{
@@ -382,7 +381,7 @@ namespace tut
set_test_name("raw APR nonblocking I/O");
// Create a script file in a temporary place.
- NamedTempFile script("py",
+ NamedExtTempFile script("py",
"from __future__ import print_function" EOL
"import sys" EOL
"import time" EOL
@@ -555,7 +554,7 @@ namespace tut
catch (const failure&)
{
std::cout << "History:\n";
- BOOST_FOREACH(const Item& item, history)
+ for (const Item& item : history)
{
std::string what(item.what);
if ((! what.empty()) && what[what.length() - 1] == '\n')
diff --git a/indra/llcommon/tests/llrand_test.cpp b/indra/llcommon/tests/llrand_test.cpp
index 383e6f9e0a..ac5a33d0ba 100644
--- a/indra/llcommon/tests/llrand_test.cpp
+++ b/indra/llcommon/tests/llrand_test.cpp
@@ -29,7 +29,23 @@
#include "../test/lltut.h"
#include "../llrand.h"
+#include "stringize.h"
+// In llrand.h, every function is documented to return less than the high end
+// -- specifically, because you can pass a negative extent, they're documented
+// never to return a value equal to the extent.
+// So that we don't need two different versions of ensure_in_range(), when
+// testing extent < 0, negate the return value and the extent before passing
+// into ensure_in_range().
+template <typename NUMBER>
+void ensure_in_range(const std::string_view& name,
+ NUMBER value, NUMBER low, NUMBER high)
+{
+ auto failmsg{ stringize(name, " >= ", low, " (", value, ')') };
+ tut::ensure(failmsg, (value >= low));
+ failmsg = stringize(name, " < ", high, " (", value, ')');
+ tut::ensure(failmsg, (value < high));
+}
namespace tut
{
@@ -44,84 +60,65 @@ namespace tut
template<> template<>
void random_object_t::test<1>()
{
- F32 number = 0.0f;
for(S32 ii = 0; ii < 100000; ++ii)
{
- number = ll_frand();
- ensure("frand >= 0", (number >= 0.0f));
- ensure("frand < 1", (number < 1.0f));
+ ensure_in_range("frand", ll_frand(), 0.0f, 1.0f);
}
}
template<> template<>
void random_object_t::test<2>()
{
- F64 number = 0.0f;
for(S32 ii = 0; ii < 100000; ++ii)
{
- number = ll_drand();
- ensure("drand >= 0", (number >= 0.0));
- ensure("drand < 1", (number < 1.0));
+ ensure_in_range("drand", ll_drand(), 0.0, 1.0);
}
}
template<> template<>
void random_object_t::test<3>()
{
- F32 number = 0.0f;
for(S32 ii = 0; ii < 100000; ++ii)
{
- number = ll_frand(2.0f) - 1.0f;
- ensure("frand >= 0", (number >= -1.0f));
- ensure("frand < 1", (number <= 1.0f));
+ ensure_in_range("frand(2.0f)", ll_frand(2.0f) - 1.0f, -1.0f, 1.0f);
}
}
template<> template<>
void random_object_t::test<4>()
{
- F32 number = 0.0f;
for(S32 ii = 0; ii < 100000; ++ii)
{
- number = ll_frand(-7.0);
- ensure("drand <= 0", (number <= 0.0));
- ensure("drand > -7", (number > -7.0));
+ // Negate the result so we don't have to allow a templated low-end
+ // comparison as well.
+ ensure_in_range("-frand(-7.0)", -ll_frand(-7.0), 0.0f, 7.0f);
}
}
template<> template<>
void random_object_t::test<5>()
{
- F64 number = 0.0f;
for(S32 ii = 0; ii < 100000; ++ii)
{
- number = ll_drand(-2.0);
- ensure("drand <= 0", (number <= 0.0));
- ensure("drand > -2", (number > -2.0));
+ ensure_in_range("-drand(-2.0)", -ll_drand(-2.0), 0.0, 2.0);
}
}
template<> template<>
void random_object_t::test<6>()
{
- S32 number = 0;
for(S32 ii = 0; ii < 100000; ++ii)
{
- number = ll_rand(100);
- ensure("rand >= 0", (number >= 0));
- ensure("rand < 100", (number < 100));
+ ensure_in_range("rand(100)", ll_rand(100), 0, 100);
}
}
template<> template<>
void random_object_t::test<7>()
{
- S32 number = 0;
for(S32 ii = 0; ii < 100000; ++ii)
{
- number = ll_rand(-127);
- ensure("rand <= 0", (number <= 0));
- ensure("rand > -127", (number > -127));
+ ensure_in_range("-rand(-127)", -ll_rand(-127), 0, 127);
}
}
}
diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
index 341b0d5609..5e6a518610 100644
--- a/indra/llcommon/tests/llsdserialize_test.cpp
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -50,9 +50,11 @@ typedef U32 uint32_t;
#include "llformat.h"
#include "llmemorystream.h"
+#include "../test/hexdump.h"
#include "../test/lltut.h"
#include "../test/namedtempfile.h"
#include "stringize.h"
+#include "StringVec.h"
#include <functional>
typedef std::function<void(const LLSD& data, std::ostream& str)> FormatterFunction;
@@ -1789,16 +1791,12 @@ namespace tut
// helper for TestPythonCompatible
static std::string import_llsd("import os.path\n"
"import sys\n"
- "try:\n"
- // new freestanding llsd package
- " import llsd\n"
- "except ImportError:\n"
- // older llbase.llsd module
- " from llbase import llsd\n");
+ "import llsd\n");
// helper for TestPythonCompatible
- template <typename CONTENT>
- void python(const std::string& desc, const CONTENT& script, int expect=0)
+ template <typename CONTENT, typename... ARGS>
+ void python_expect(const std::string& desc, const CONTENT& script, int expect=0,
+ ARGS&&... args)
{
auto PYTHON(LLStringUtil::getenv("PYTHON"));
ensure("Set $PYTHON to the Python interpreter", !PYTHON.empty());
@@ -1809,7 +1807,8 @@ namespace tut
std::string q("\"");
std::string qPYTHON(q + PYTHON + q);
std::string qscript(q + scriptfile.getName() + q);
- int rc = _spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(), NULL);
+ int rc = _spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(),
+ std::forward<ARGS>(args)..., NULL);
if (rc == -1)
{
char buffer[256];
@@ -1825,6 +1824,10 @@ namespace tut
LLProcess::Params params;
params.executable = PYTHON;
params.args.add(scriptfile.getName());
+ for (const std::string& arg : StringVec{ std::forward<ARGS>(args)... })
+ {
+ params.args.add(arg);
+ }
LLProcessPtr py(LLProcess::create(params));
ensure(STRINGIZE("Couldn't launch " << desc << " script"), bool(py));
// Implementing timeout would mean messing with alarm() and
@@ -1859,6 +1862,14 @@ namespace tut
#endif
}
+ // helper for TestPythonCompatible
+ template <typename CONTENT, typename... ARGS>
+ void python(const std::string& desc, const CONTENT& script, ARGS&&... args)
+ {
+ // plain python() expects rc 0
+ python_expect(desc, script, 0, std::forward<ARGS>(args)...);
+ }
+
struct TestPythonCompatible
{
TestPythonCompatible() {}
@@ -1873,10 +1884,10 @@ namespace tut
void TestPythonCompatibleObject::test<1>()
{
set_test_name("verify python()");
- python("hello",
- "import sys\n"
- "sys.exit(17)\n",
- 17); // expect nonzero rc
+ python_expect("hello",
+ "import sys\n"
+ "sys.exit(17)\n",
+ 17); // expect nonzero rc
}
template<> template<>
@@ -1892,7 +1903,7 @@ namespace tut
static void writeLLSDArray(const FormatterFunction& serialize,
std::ostream& out, const LLSD& array)
{
- for (const LLSD& item : llsd::inArray(array))
+ for (const LLSD& item: llsd::inArray(array))
{
// It's important to delimit the entries in this file somehow
// because, although Python's llsd.parse() can accept a file
@@ -1907,7 +1918,14 @@ namespace tut
auto buffstr{ buffer.str() };
int bufflen{ static_cast<int>(buffstr.length()) };
out.write(reinterpret_cast<const char*>(&bufflen), sizeof(bufflen));
+ LL_DEBUGS() << "Wrote length: "
+ << hexdump(reinterpret_cast<const char*>(&bufflen),
+ sizeof(bufflen))
+ << LL_ENDL;
out.write(buffstr.c_str(), buffstr.length());
+ LL_DEBUGS() << "Wrote data: "
+ << hexmix(buffstr.c_str(), buffstr.length())
+ << LL_ENDL;
}
}
@@ -1936,10 +1954,10 @@ namespace tut
" else:\n"
" raise AssertionError('Too many data items')\n";
- // Create an llsdXXXXXX file containing 'data' serialized to
- // notation.
+ // Create an llsdXXXXXX file containing 'data' serialized per
+ // FormatterFunction.
NamedTempFile file("llsd",
- // NamedTempFile's std::function constructor
+ // NamedTempFile's function constructor
// takes a callable. To this callable it passes the
// std::ostream with which it's writing the
// NamedTempFile.
@@ -1947,35 +1965,50 @@ namespace tut
(std::ostream& out)
{ writeLLSDArray(serialize, out, cdata); });
- python("read C++ " + desc,
- [pydata, &file](std::ostream& out) {
- out <<
- import_llsd <<
- "from functools import partial\n"
- "import io\n"
- "import struct\n"
- "lenformat = struct.Struct('i')\n"
- "def parse_each(inf):\n"
- " for rawlen in iter(partial(inf.read, lenformat.size), b''):\n"
- " len = lenformat.unpack(rawlen)[0]\n"
- // Since llsd.parse() has no max_bytes argument, instead of
- // passing the input stream directly to parse(), read the item
- // into a distinct bytes object and parse that.
- " data = inf.read(len)\n"
- " try:\n"
- " frombytes = llsd.parse(data)\n"
- " except llsd.LLSDParseError as err:\n"
- " print(f'*** {err}')\n"
- " print(f'Bad content:\\n{data!r}')\n"
- " raise\n"
- // Also try parsing from a distinct stream.
- " stream = io.BytesIO(data)\n"
- " fromstream = llsd.parse(stream)\n"
- " assert frombytes == fromstream\n"
- " yield frombytes\n"
- << pydata <<
- // Don't forget raw-string syntax for Windows pathnames.
- "verify(parse_each(open(r'" << file.getName() << "', 'rb')))\n"; });
+ // 'debug' starts empty because it's intended as an output file
+ NamedTempFile debug("debug", "");
+
+ try
+ {
+ python("read C++ " + desc,
+ [&](std::ostream& out){ out <<
+ import_llsd <<
+ "from functools import partial\n"
+ "import io\n"
+ "import struct\n"
+ "lenformat = struct.Struct('i')\n"
+ "def parse_each(inf):\n"
+ " for rawlen in iter(partial(inf.read, lenformat.size), b''):\n"
+ " print('Read length:', ''.join(('%02x' % b) for b in rawlen),\n"
+ " file=debug)\n"
+ " len = lenformat.unpack(rawlen)[0]\n"
+ // Since llsd.parse() has no max_bytes argument, instead of
+ // passing the input stream directly to parse(), read the item
+ // into a distinct bytes object and parse that.
+ " data = inf.read(len)\n"
+ " print('Read data: ', repr(data), file=debug)\n"
+ " try:\n"
+ " frombytes = llsd.parse(data)\n"
+ " except llsd.LLSDParseError as err:\n"
+ " print(f'*** {err}')\n"
+ " print(f'Bad content:\\n{data!r}')\n"
+ " raise\n"
+ // Also try parsing from a distinct stream.
+ " stream = io.BytesIO(data)\n"
+ " fromstream = llsd.parse(stream)\n"
+ " assert frombytes == fromstream\n"
+ " yield frombytes\n"
+ << pydata <<
+ // Don't forget raw-string syntax for Windows pathnames.
+ "debug = open(r'" << debug.getName() << "', 'w')\n"
+ "verify(parse_each(open(r'" << file.getName() << "', 'rb')))\n";});
+ }
+ catch (const failure&)
+ {
+ LL_DEBUGS() << "Script debug output:" << LL_ENDL;
+ debug.peep_log();
+ throw;
+ }
}
template<> template<>
diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp
index 15ffe68e67..6f8aaaa0cb 100644
--- a/indra/llcommon/tests/llsingleton_test.cpp
+++ b/indra/llcommon/tests/llsingleton_test.cpp
@@ -47,8 +47,8 @@ public: \
DEP_INIT /* dependency in initSingleton */ \
} sDepFlag; \
\
- void initSingleton(); \
- void cleanupSingleton(); \
+ void initSingleton() override; \
+ void cleanupSingleton() override; \
}; \
\
CLS::dep_flag CLS::sDepFlag = DEP_NONE
@@ -300,7 +300,7 @@ namespace tut
{
LLSINGLETON_EMPTY_CTOR(CircularPInit);
public:
- virtual void initSingleton()
+ virtual void initSingleton() override
{
// never mind indirection, just go straight for the circularity
CircularPInit *pt = getInstance();
diff --git a/indra/llcommon/tests/llstreamqueue_test.cpp b/indra/llcommon/tests/llstreamqueue_test.cpp
index 050ad5c5bf..8af057328b 100644
--- a/indra/llcommon/tests/llstreamqueue_test.cpp
+++ b/indra/llcommon/tests/llstreamqueue_test.cpp
@@ -15,9 +15,6 @@
#include "llstreamqueue.h"
// STL headers
#include <vector>
-// std headers
-// external library headers
-#include <boost/foreach.hpp>
// other Linden headers
#include "../test/lltut.h"
#include "stringize.h"
@@ -133,7 +130,7 @@ namespace tut
std::streamsize leave(5); // len("craft") above
std::streamsize skip(total - leave);
std::streamsize written(0);
- BOOST_FOREACH(const std::string& block, blocks)
+ for (const std::string& block : blocks)
{
written += strq.write(&block[0], block.length());
ensure_equals("size() after write()", strq.size(), written);
@@ -152,7 +149,7 @@ namespace tut
{
set_test_name("concatenate blocks");
std::string blocks[] = { "abcd", "efghij", "klmnopqrs" };
- BOOST_FOREACH(const std::string& block, blocks)
+ for (const std::string& block : blocks)
{
strq.write(&block[0], block.length());
}
@@ -170,7 +167,7 @@ namespace tut
{
set_test_name("split blocks");
std::string blocks[] = { "abcdefghijklm", "nopqrstuvwxyz" };
- BOOST_FOREACH(const std::string& block, blocks)
+ for (const std::string& block : blocks)
{
strq.write(&block[0], block.length());
}
diff --git a/indra/llcommon/tests/lltreeiterators_test.cpp b/indra/llcommon/tests/lltreeiterators_test.cpp
index 1d619867d4..b9c7a70c07 100644
--- a/indra/llcommon/tests/lltreeiterators_test.cpp
+++ b/indra/llcommon/tests/lltreeiterators_test.cpp
@@ -38,7 +38,6 @@
// external library headers
#include <boost/bind.hpp>
#include <boost/range/iterator_range.hpp>
-#include <boost/foreach.hpp>
// associated header
#include "../lltreeiterators.h"
@@ -402,7 +401,7 @@ private:
*
* Example:
* @code
- * BOOST_FOREACH(TreeNodePtr node, getRootRange<LLTreeIter::UP>(somenode))
+ * for (TreeNodePtr node : getRootRange<LLTreeIter::UP>(somenode))
* {
* std::cout << node->name() << '\n';
* }
@@ -424,7 +423,7 @@ getRootRange(const TreeNodePtr& node)
*
* Example:
* @code
- * BOOST_FOREACH(TreeNodePtr node, getWalkRange<LLTreeIter::DFS_PRE>(root))
+ * for (TreeNodePtr node : getWalkRange<LLTreeIter::DFS_PRE>(root))
* {
* std::cout << node->name() << '\n';
* }
@@ -520,7 +519,7 @@ public:
*
* Example usage:
* @code
- * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getRootRange<LLTreeIter::UP>())
+ * for (EnhancedTreeNodePtr node : somenode->getRootRange<LLTreeIter::UP>())
* {
* std::cout << node->name() << '\n';
* }
@@ -564,7 +563,7 @@ public:
*
* Example usage:
* @code
- * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getWalkRange<LLTreeIter::DFS_PRE>())
+ * for (EnhancedTreeNodePtr node : somenode->getWalkRange<LLTreeIter::DFS_PRE>())
* {
* std::cout << node->name() << '\n';
* }
@@ -644,7 +643,7 @@ LLLinkedIter<PlainTree> PlainTree_child_end(PlainTree* node)
*
* Example:
* @code
- * BOOST_FOREACH(PlainTree* node, getRootRange<LLTreeIter::UP>(somenode))
+ * for (PlainTree* node : getRootRange<LLTreeIter::UP>(somenode))
* {
* std::cout << node->name() << '\n';
* }
@@ -668,7 +667,7 @@ getRootRange(PlainTree* node)
*
* Example:
* @code
- * BOOST_FOREACH(PlainTree* node, getWalkRange<LLTreeIter::DFS_PRE>(root))
+ * for (PlainTree* node : getWalkRange<LLTreeIter::DFS_PRE>(root))
* {
* std::cout << node->name() << '\n';
* }
@@ -1103,18 +1102,18 @@ namespace tut
// This test function illustrates the looping techniques described in the
// comments for the getRootRange() free function, the
// EnhancedTreeNode::root_range template and the
- // EnhancedTreeNode::getRootRange() method. Obviously the BOOST_FOREACH()
+ // EnhancedTreeNode::getRootRange() method. Obviously the for()
// forms are more succinct.
TreeNodePtr tnroot(example_tree<TreeNode>());
TreeNodePtr tnB2b(get_B2b<TreeNode, TreeNode::child_iterator>
(tnroot, boost::bind(&TreeNode::child_begin, _1)));
- std::string desc1("BOOST_FOREACH(TreeNodePr, getRootRange<LLTreeIter::UP>(tnB2b))");
+ std::string desc1("for (TreeNodePr : getRootRange<LLTreeIter::UP>(tnB2b))");
// std::cout << desc1 << "\n";
// Although we've commented out the output statement, ensure that the
// loop construct is still valid, as promised by the getRootRange()
// documentation.
- BOOST_FOREACH(TreeNodePtr node, getRootRange<LLTreeIter::UP>(tnB2b))
+ for (TreeNodePtr node : getRootRange<LLTreeIter::UP>(tnB2b))
{
// std::cout << node->name() << '\n';
}
@@ -1137,9 +1136,9 @@ namespace tut
// std::cout << (*ri)->name() << '\n';
}
- std::string desc2("BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange<LLTreeIter::UP>())");
+ std::string desc2("for (EnhancedTreeNodePtr node : etnB2b->getRootRange<LLTreeIter::UP>())");
// std::cout << desc2 << '\n';
- BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange<LLTreeIter::UP>())
+ for (EnhancedTreeNodePtr node : etnB2b->getRootRange<LLTreeIter::UP>())
{
// std::cout << node->name() << '\n';
}
diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp
index c421cc7b1c..8851590189 100644
--- a/indra/llcommon/tests/threadsafeschedule_test.cpp
+++ b/indra/llcommon/tests/threadsafeschedule_test.cpp
@@ -46,11 +46,12 @@ namespace tut
// the real time required for each push() call. Explicitly increment
// the timestamp for each one -- but since we're passing explicit
// timestamps, make the queue reorder them.
- queue.push(Queue::TimeTuple(Queue::Clock::now() + 200ms, "ghi"));
+ auto now{ Queue::Clock::now() };
+ queue.push(Queue::TimeTuple(now + 200ms, "ghi"));
// Given the various push() overloads, you have to match the type
// exactly: conversions are ambiguous.
queue.push("abc"s);
- queue.push(Queue::Clock::now() + 100ms, "def");
+ queue.push(now + 100ms, "def");
queue.close();
auto entry = queue.pop();
ensure_equals("failed to pop first", std::get<0>(entry), "abc"s);
diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp
index 1d73f7aa0d..df16f4a46e 100644
--- a/indra/llcommon/tests/workqueue_test.cpp
+++ b/indra/llcommon/tests/workqueue_test.cpp
@@ -38,7 +38,7 @@ namespace tut
{
struct workqueue_data
{
- WorkQueue queue{"queue"};
+ WorkSchedule queue{"queue"};
};
typedef test_group<workqueue_data> workqueue_group;
typedef workqueue_group::object object;
@@ -49,8 +49,8 @@ namespace tut
{
set_test_name("name");
ensure_equals("didn't capture name", queue.getKey(), "queue");
- ensure("not findable", WorkQueue::getInstance("queue") == queue.getWeak().lock());
- WorkQueue q2;
+ ensure("not findable", WorkSchedule::getInstance("queue") == queue.getWeak().lock());
+ WorkSchedule q2;
ensure("has no name", LLStringUtil::startsWith(q2.getKey(), "WorkQueue"));
}
@@ -73,17 +73,21 @@ namespace tut
{
set_test_name("postEvery");
// record of runs
- using Shared = std::deque<WorkQueue::TimePoint>;
+ using Shared = std::deque<WorkSchedule::TimePoint>;
// This is an example of how to share data between the originator of
- // postEvery(work) and the work item itself, since usually a WorkQueue
+ // postEvery(work) and the work item itself, since usually a WorkSchedule
// is used to dispatch work to a different thread. Neither of them
// should call any of LLCond's wait methods: you don't want to stall
// either the worker thread or the originating thread (conventionally
// main). Use LLCond or a subclass even if all you want to do is
// signal the work item that it can quit; consider LLOneShotCond.
LLCond<Shared> data;
- auto start = WorkQueue::TimePoint::clock::now();
- auto interval = 100ms;
+ auto start = WorkSchedule::TimePoint::clock::now();
+ // 2s seems like a long time to wait, since it directly impacts the
+ // duration of this test program. Unfortunately GitHub's Mac runners
+ // are pretty wimpy, and we're getting spurious "too late" errors just
+ // because the thread doesn't wake up as soon as we want.
+ auto interval = 2s;
queue.postEvery(
interval,
[&data, count = 0]
@@ -93,7 +97,7 @@ namespace tut
data.update_one(
[](Shared& data)
{
- data.push_back(WorkQueue::TimePoint::clock::now());
+ data.push_back(WorkSchedule::TimePoint::clock::now());
});
// by the 3rd call, return false to stop
return (++count < 3);
@@ -102,7 +106,7 @@ namespace tut
// postEvery() running, so run until we have exhausted the iterations
// or we time out waiting
for (auto finish = start + 10*interval;
- WorkQueue::TimePoint::clock::now() < finish &&
+ WorkSchedule::TimePoint::clock::now() < finish &&
data.get([](const Shared& data){ return data.size(); }) < 3; )
{
queue.runPending();
@@ -139,8 +143,8 @@ namespace tut
void object::test<4>()
{
set_test_name("postTo");
- WorkQueue main("main");
- auto qptr = WorkQueue::getInstance("queue");
+ WorkSchedule main("main");
+ auto qptr = WorkSchedule::getInstance("queue");
int result = 0;
main.postTo(
qptr,
@@ -171,8 +175,8 @@ namespace tut
void object::test<5>()
{
set_test_name("postTo with void return");
- WorkQueue main("main");
- auto qptr = WorkQueue::getInstance("queue");
+ WorkSchedule main("main");
+ auto qptr = WorkSchedule::getInstance("queue");
std::string observe;
main.postTo(
qptr,
@@ -194,7 +198,7 @@ namespace tut
std::string stored;
// Try to call waitForResult() on this thread's main coroutine. It
// should throw because the main coroutine must service the queue.
- auto what{ catch_what<WorkQueue::Error>(
+ auto what{ catch_what<WorkSchedule::Error>(
[this, &stored](){ stored = queue.waitForResult(
[](){ return "should throw"; }); }) };
ensure("lambda should not have run", stored.empty());
diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h
index 3779fb41bc..6978c296b3 100644
--- a/indra/llcommon/tests/wrapllerrs.h
+++ b/indra/llcommon/tests/wrapllerrs.h
@@ -218,12 +218,17 @@ public:
/// for the sought string.
std::string messageWith(const std::string& search, bool required=true)
{
- return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required);
+ return std::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required);
}
std::ostream& streamto(std::ostream& out) const
{
- return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out);
+ return std::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out);
+ }
+
+ friend inline std::ostream& operator<<(std::ostream& out, const CaptureLog& self)
+ {
+ return self.streamto(out);
}
private: