phoenix-firestorm/indra/llcommon/tests/apply_test.cpp

241 lines
7.8 KiB
C++

/**
* @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