summaryrefslogtreecommitdiff
path: root/indra/llcommon/tests/apply_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/tests/apply_test.cpp')
-rw-r--r--indra/llcommon/tests/apply_test.cpp237
1 files changed, 237 insertions, 0 deletions
diff --git a/indra/llcommon/tests/apply_test.cpp b/indra/llcommon/tests/apply_test.cpp
new file mode 100644
index 0000000000..9a17afc18c
--- /dev/null
+++ b/indra/llcommon/tests/apply_test.cpp
@@ -0,0 +1,237 @@
+/**
+ * @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"
+
+// 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