summaryrefslogtreecommitdiff
path: root/indra/test
diff options
context:
space:
mode:
Diffstat (limited to 'indra/test')
-rw-r--r--indra/test/CMakeLists.txt3
-rw-r--r--indra/test/debug.h69
-rw-r--r--indra/test/hexdump.h97
-rw-r--r--indra/test/io.cpp78
-rw-r--r--indra/test/llbuffer_tut.cpp32
-rw-r--r--indra/test/llevents_tut.cpp59
-rw-r--r--indra/test/llpermissions_tut.cpp6
-rw-r--r--indra/test/llpipeutil.cpp2
-rw-r--r--indra/test/llsaleinfo_tut.cpp12
-rw-r--r--indra/test/llsdmessagebuilder_tut.cpp14
-rw-r--r--indra/test/llsdmessagereader_tut.cpp16
-rw-r--r--indra/test/llstreamtools_tut.cpp2
-rw-r--r--indra/test/lltemplatemessagebuilder_tut.cpp14
-rw-r--r--indra/test/lltut.h49
-rw-r--r--indra/test/message_tut.cpp2
-rw-r--r--indra/test/namedtempfile.h24
-rw-r--r--indra/test/print.h4
-rw-r--r--indra/test/test.cpp127
-rwxr-xr-xindra/test/writestr.h39
19 files changed, 299 insertions, 350 deletions
diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt
index 4a0a8716c4..745c0eedf8 100644
--- a/indra/test/CMakeLists.txt
+++ b/indra/test/CMakeLists.txt
@@ -9,7 +9,6 @@ include(Linking)
include(Tut)
include(LLAddBuildTest)
include(bugsplat)
-include(GoogleMock)
set(test_SOURCE_FILES
io.cpp
@@ -65,7 +64,6 @@ target_link_libraries(lltest
llxml
llcommon
llcorehttp
- ll::googlemock
)
if (WINDOWS)
@@ -73,6 +71,7 @@ if (WINDOWS)
PROPERTIES
LINK_FLAGS "/NODEFAULTLIB:LIBCMT"
LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\""
+ RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}"
)
elseif (DARWIN)
# Support our "@executable_path/../Resources" load path for our test
diff --git a/indra/test/debug.h b/indra/test/debug.h
index 1579bb9c86..ea9c634cc7 100644
--- a/indra/test/debug.h
+++ b/indra/test/debug.h
@@ -30,43 +30,56 @@
#define LL_DEBUG_H
#include "print.h"
+#include "stringize.h"
+#include <exception> // std::uncaught_exceptions()
/*****************************************************************************
* Debugging stuff
*****************************************************************************/
/**
- * This class is intended to illuminate entry to a given block, exit from the
- * same block and checkpoints along the way. It also provides a convenient
- * place to turn std::cerr output on and off.
- *
- * If the environment variable LOGTEST is non-empty, each Debug instance will
- * announce its construction and destruction, presumably at entry and exit to
- * the block in which it's declared. Moreover, any arguments passed to its
- * operator()() will be streamed to std::cerr, prefixed by the block
- * description.
+ * Return true if the environment variable LOGTEST is non-empty.
*
* The variable LOGTEST is used because that's the environment variable
* checked by test.cpp, our TUT main() program, to turn on LLError logging. It
* is expected that Debug is solely for use in test programs.
*/
+inline
+bool LOGTEST_enabled()
+{
+ auto LOGTEST{ getenv("LOGTEST") };
+ // debug output enabled when LOGTEST is set AND non-empty
+ return LOGTEST && *LOGTEST;
+}
+
+/**
+ * This class is intended to illuminate entry to a given block, exit from the
+ * same block and checkpoints along the way. It also provides a convenient
+ * place to turn std::cerr output on and off.
+ *
+ * If enabled, each Debug instance will announce its construction and
+ * destruction, presumably at entry and exit to the block in which it's
+ * declared. Moreover, any arguments passed to its operator()() will be
+ * streamed to std::cerr, prefixed by the block description.
+ */
class Debug
{
public:
- Debug(const std::string& block):
- mBlock(block),
- mLOGTEST(getenv("LOGTEST")),
- // debug output enabled when LOGTEST is set AND non-empty
- mEnabled(mLOGTEST && *mLOGTEST)
+ template <typename... ARGS>
+ Debug(ARGS&&... args):
+ mBlock(stringize(std::forward<ARGS>(args)...)),
+ mEnabled(LOGTEST_enabled())
{
(*this)("entry");
}
// non-copyable
Debug(const Debug&) = delete;
+ Debug& operator=(const Debug&) = delete;
~Debug()
{
- (*this)("exit");
+ auto exceptional{ std::uncaught_exceptions()? "exceptional " : "" };
+ (*this)(exceptional, "exit");
}
template <typename... ARGS>
@@ -80,7 +93,6 @@ public:
private:
const std::string mBlock;
- const char* mLOGTEST;
bool mEnabled;
};
@@ -88,20 +100,19 @@ private:
// of the Debug block.
#define DEBUG Debug debug(LL_PRETTY_FUNCTION)
-// These BEGIN/END macros are specifically for debugging output -- please
-// don't assume you must use such for coroutines in general! They only help to
-// make control flow (as well as exception exits) explicit.
-#define BEGIN \
-{ \
- DEBUG; \
- try
+/// If enabled, debug_expr(expression) gives you output concerning an inline
+/// expression such as a class member initializer.
+#define debug_expr(expr) debug_expr_(#expr, [&](){ return expr; })
-#define END \
- catch (...) \
- { \
- debug("*** exceptional "); \
- throw; \
- } \
+template <typename EXPR>
+inline auto debug_expr_(const char* strexpr, EXPR&& lambda)
+{
+ if (! LOGTEST_enabled())
+ return std::forward<EXPR>(lambda)();
+ print("Before: ", strexpr);
+ auto result{ std::forward<EXPR>(lambda)() };
+ print(strexpr, " -> ", result);
+ return result;
}
#endif /* ! defined(LL_DEBUG_H) */
diff --git a/indra/test/hexdump.h b/indra/test/hexdump.h
deleted file mode 100644
index 95f1e297c3..0000000000
--- a/indra/test/hexdump.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * @file hexdump.h
- * @author Nat Goodspeed
- * @date 2023-09-08
- * @brief Provide hexdump() and hexmix() ostream formatters
- *
- * $LicenseInfo:firstyear=2023&license=viewerlgpl$
- * Copyright (c) 2023, Linden Research, Inc.
- * $/LicenseInfo$
- */
-
-#if ! defined(LL_HEXDUMP_H)
-#define LL_HEXDUMP_H
-
-#include <cctype>
-#include <iomanip>
-#include <iostream>
-#include <string_view>
-
-// Format a given byte string as 2-digit hex values, no separators
-// Usage: std::cout << hexdump(somestring) << ...
-class hexdump
-{
-public:
- hexdump(const std::string_view& data):
- hexdump(data.data(), data.length())
- {}
-
- hexdump(const char* data, size_t len):
- hexdump(reinterpret_cast<const unsigned char*>(data), len)
- {}
-
- hexdump(const unsigned char* data, size_t len):
- mData(data, data + len)
- {}
-
- friend std::ostream& operator<<(std::ostream& out, const hexdump& self)
- {
- auto oldfmt{ out.flags() };
- auto oldfill{ out.fill() };
- out.setf(std::ios_base::hex, std::ios_base::basefield);
- out.fill('0');
- for (auto c : self.mData)
- {
- out << std::setw(2) << unsigned(c);
- }
- out.setf(oldfmt, std::ios_base::basefield);
- out.fill(oldfill);
- return out;
- }
-
-private:
- std::vector<unsigned char> mData;
-};
-
-// Format a given byte string as a mix of printable characters and, for each
-// non-printable character, "\xnn"
-// Usage: std::cout << hexmix(somestring) << ...
-class hexmix
-{
-public:
- hexmix(const std::string_view& data):
- mData(data)
- {}
-
- hexmix(const char* data, size_t len):
- mData(data, len)
- {}
-
- friend std::ostream& operator<<(std::ostream& out, const hexmix& self)
- {
- auto oldfmt{ out.flags() };
- auto oldfill{ out.fill() };
- out.setf(std::ios_base::hex, std::ios_base::basefield);
- out.fill('0');
- for (auto c : self.mData)
- {
- // std::isprint() must be passed an unsigned char!
- if (std::isprint(static_cast<unsigned char>(c)))
- {
- out << c;
- }
- else
- {
- out << "\\x" << std::setw(2) << unsigned(c);
- }
- }
- out.setf(oldfmt, std::ios_base::basefield);
- out.fill(oldfill);
- return out;
- }
-
-private:
- std::string mData;
-};
-
-#endif /* ! defined(LL_HEXDUMP_H) */
diff --git a/indra/test/io.cpp b/indra/test/io.cpp
index 412f9ca1d2..24e1a782d3 100644
--- a/indra/test/io.cpp
+++ b/indra/test/io.cpp
@@ -45,6 +45,7 @@
#include "llcommon.h"
#include "lluuid.h"
#include "llinstantmessage.h"
+#include "stringize.h"
namespace tut
{
@@ -155,7 +156,7 @@ namespace tut
void buffer_object::test<1>()
{
const char HELLO_WORLD[] = "hello world";
- const S32 str_len = strlen(HELLO_WORLD);
+ const S32 str_len = static_cast<S32>(strlen(HELLO_WORLD));
LLChannelDescriptors ch = mBuffer.nextChannel();
mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len);
S32 count = mBuffer.countAfter(ch.in(), NULL);
@@ -170,7 +171,7 @@ namespace tut
void buffer_object::test<2>()
{
const char HELLO_WORLD[] = "hello world";
- const S32 str_len = strlen(HELLO_WORLD); /* Flawfinder: ignore */
+ const S32 str_len = static_cast<S32>(strlen(HELLO_WORLD)); /* Flawfinder: ignore */
LLChannelDescriptors ch = mBuffer.nextChannel();
mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len);
mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len);
@@ -249,15 +250,15 @@ namespace tut
expected << "ContentLength: " << response.length() << "\r\n\r\n"
<< response;
LLChannelDescriptors ch = mBuffer.nextChannel();
- mBuffer.append(ch.in(), (U8*)request.c_str(), request.length());
- mBuffer.append(ch.out(), (U8*)response.c_str(), response.length());
+ mBuffer.append(ch.in(), (U8*)request.c_str(), static_cast<S32>(request.length()));
+ mBuffer.append(ch.out(), (U8*)response.c_str(), static_cast<S32>(response.length()));
S32 count = mBuffer.countAfter(ch.out(), NULL);
std::ostringstream header;
header << "ContentLength: " << count << "\r\n\r\n";
std::string head(header.str());
- mBuffer.prepend(ch.out(), (U8*)head.c_str(), head.length());
+ mBuffer.prepend(ch.out(), (U8*)head.c_str(), static_cast<S32>(head.length()));
char buffer[1024]; /* Flawfinder: ignore */
- S32 len = response.size() + head.length();
+ S32 len = static_cast<S32>(response.size() + head.length());
ensure_equals("same length", len, (S32)expected.str().length());
mBuffer.readAfter(ch.out(), NULL, (U8*)buffer, len);
buffer[len] = '\0';
@@ -282,7 +283,7 @@ namespace tut
text.append(lines[i]);
}
LLChannelDescriptors ch = mBuffer.nextChannel();
- mBuffer.append(ch.in(), (U8*)text.c_str(), text.length());
+ mBuffer.append(ch.in(), (U8*)text.c_str(), static_cast<S32>(text.length()));
const S32 BUFFER_LEN = 1024;
char buf[BUFFER_LEN];
S32 len;
@@ -293,7 +294,7 @@ namespace tut
len = BUFFER_LEN;
last = mBuffer.readAfter(ch.in(), last, (U8*)buf, len);
char* newline = strchr((char*)buf, '\n');
- S32 offset = -((len - 1) - (newline - buf));
+ S32 offset = -((len - 1) - (S32)(newline - buf));
++newline;
*newline = '\0';
last_line.assign(buf);
@@ -411,7 +412,7 @@ namespace tut
void bas_object::test<1>()
{
const char HELLO_WORLD[] = "hello world";
- const S32 str_len = strlen(HELLO_WORLD); /* Flawfinder: ignore */
+ const S32 str_len = static_cast<S32>(strlen(HELLO_WORLD)); /* Flawfinder: ignore */
LLChannelDescriptors ch = mBuffer.nextChannel();
LLBufferStream str(ch, &mBuffer);
mBuffer.append(ch.in(), (U8*)HELLO_WORLD, str_len);
@@ -431,10 +432,10 @@ namespace tut
std::string ignore("ignore me");
LLChannelDescriptors ch = mBuffer.nextChannel();
LLBufferStream str(ch, &mBuffer);
- mBuffer.append(ch.in(), (U8*)part1.c_str(), part1.length());
- mBuffer.append(ch.in(), (U8*)part2.c_str(), part2.length());
- mBuffer.append(ch.out(), (U8*)ignore.c_str(), ignore.length());
- mBuffer.append(ch.in(), (U8*)part3.c_str(), part3.length());
+ mBuffer.append(ch.in(), (U8*)part1.c_str(), static_cast<S32>(part1.length()));
+ mBuffer.append(ch.in(), (U8*)part2.c_str(), static_cast<S32>(part2.length()));
+ mBuffer.append(ch.out(), (U8*)ignore.c_str(), static_cast<S32>(ignore.length()));
+ mBuffer.append(ch.in(), (U8*)part3.c_str(), static_cast<S32>(part3.length()));
std::string eat;
std::string my;
std::string shorts;
@@ -452,8 +453,8 @@ namespace tut
std::string part1("junk in ");
std::string part2("the trunk");
const S32 CHANNEL = 0;
- mBuffer.append(CHANNEL, (U8*)part1.c_str(), part1.length());
- mBuffer.append(CHANNEL, (U8*)part2.c_str(), part2.length());
+ mBuffer.append(CHANNEL, (U8*)part1.c_str(), static_cast<S32>(part1.length()));
+ mBuffer.append(CHANNEL, (U8*)part2.c_str(), static_cast<S32>(part2.length()));
U8* last = 0;
const S32 BUF_LEN = 128;
char buf[BUF_LEN];
@@ -475,7 +476,7 @@ namespace tut
{
std::string phrase("zippity do da!");
const S32 CHANNEL = 0;
- mBuffer.append(CHANNEL, (U8*)phrase.c_str(), phrase.length());
+ mBuffer.append(CHANNEL, (U8*)phrase.c_str(), static_cast<S32>(phrase.length()));
const S32 BUF_LEN = 128;
char buf[BUF_LEN];
S32 len = 7;
@@ -506,7 +507,7 @@ namespace tut
const S32 BUF_LEN = 128;
char buf[BUF_LEN];
S32 actual_len = BUF_LEN;
- S32 expected_len = h1.size() + h2.size();
+ S32 expected_len = static_cast<S32>(h1.size() + h2.size());
(void) mBuffer.readAfter(ch.out(), NULL, (U8*)buf, actual_len);
ensure_equals("streamed size", actual_len, expected_len);
buf[actual_len] = '\0';
@@ -728,7 +729,7 @@ namespace tut
"'circuit_code': i124,'group_id': '8615c885-9cf0-bf0a-6e40-0c11462aa652','limited_to_estate': i1,'look_at': [ i0, i0, i0],"
"'agent_id': '0e346d8b-4433-4d66-a6b0-fd37083abc4c','first_name': 'Kelly','start': 'url'}]}";
LLChannelDescriptors ch = mBuffer.nextChannel();
- mBuffer.append(ch.out(), (U8*)LOGIN_STREAM, strlen(LOGIN_STREAM)); /* Flawfinder: ignore */
+ mBuffer.append(ch.out(), (U8*)LOGIN_STREAM, static_cast<S32>(strlen(LOGIN_STREAM))); /* Flawfinder: ignore */
ch = mBuffer.nextChannel();
LLBufferStream istr(ch, &mBuffer);
LLSD data;
@@ -1116,6 +1117,9 @@ namespace tut
template<> template<>
void fitness_test_object::test<5>()
{
+ skip("Test is strongly timing dependent, "
+ "and on slow CI machines it fails way too often.");
+ const int retries = 100;
// Set up the server
LLPumpIO::chain_t chain;
typedef LLCloneIOFactory<LLIOSleeper> sleeper_t;
@@ -1129,9 +1133,12 @@ namespace tut
chain.push_back(LLIOPipe::ptr_t(server));
mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS);
// We need to tickle the pump a little to set up the listen()
- pump_loop(mPump, 0.1f);
- U32 count = mPump->runningChains();
- ensure_equals("server chain onboard", count, 1);
+ for (int retry = 0; mPump->runningChains() < 1 && retry < retries; ++retry)
+ {
+ pump_loop(mPump, 0.1f);
+ }
+ auto count = mPump->runningChains();
+ ensure_equals("server chain 1 onboard", count, 1);
LL_DEBUGS() << "** Server is up." << LL_ENDL;
// Set up the client
@@ -1140,9 +1147,12 @@ namespace tut
bool connected = client->blockingConnect(server_host);
ensure("Connected to server", connected);
LL_DEBUGS() << "connected" << LL_ENDL;
- pump_loop(mPump,0.1f);
+ for (int retry = 0; mPump->runningChains() < 2 && retry < retries; ++retry)
+ {
+ pump_loop(mPump,0.1f);
+ }
count = mPump->runningChains();
- ensure_equals("server chain onboard", count, 2);
+ ensure_equals("server chain 2 onboard", count, 2);
LL_DEBUGS() << "** Client is connected." << LL_ENDL;
// We have connected, since the socket reader does not block,
@@ -1156,20 +1166,32 @@ namespace tut
chain.clear();
// pump for a bit and make sure all 3 chains are running
- pump_loop(mPump,0.1f);
+ for (int retry = 0; mPump->runningChains() < 3 && retry < retries; ++retry)
+ {
+ pump_loop(mPump, 0.1f);
+ }
count = mPump->runningChains();
- // ensure_equals("client chain onboard", count, 3); commented out because it fails frequently - appears to be timing sensitive
+ ensure_equals("client chain onboard", count, 3);
LL_DEBUGS() << "** request should have been sent." << LL_ENDL;
// pump for long enough the the client socket closes, and the
// server socket should not be closed yet.
- pump_loop(mPump,0.2f);
+ for (int retry = 0; mPump->runningChains() == 3 && retry < retries; ++retry)
+ {
+ pump_loop(mPump, 0.1f);
+ }
+ // We used to test for count == 2 here, but on a slow test machine it
+ // can happen that not just one but two chains close before we reach
+ // this point.
count = mPump->runningChains();
- ensure_equals("client chain timed out ", count, 2);
+ ensure(stringize("client chain timed out: count ", count), count < 3);
LL_DEBUGS() << "** client chain should be closed." << LL_ENDL;
// At this point, the socket should be closed by the timeout
- pump_loop(mPump,1.0f);
+ for (int retry = 0; mPump->runningChains() > 1 && retry < retries; ++retry)
+ {
+ pump_loop(mPump, 0.1f);
+ }
count = mPump->runningChains();
ensure_equals("accepted socked close", count, 1);
LL_DEBUGS() << "** Sleeper should have timed out.." << LL_ENDL;
diff --git a/indra/test/llbuffer_tut.cpp b/indra/test/llbuffer_tut.cpp
index a31870241c..330a4f288f 100644
--- a/indra/test/llbuffer_tut.cpp
+++ b/indra/test/llbuffer_tut.cpp
@@ -62,7 +62,7 @@ namespace tut
ensure("LLSegment get functions failed", (0 == segment.getChannel() && NULL == segment.data() && 0 == segment.size()));
segment.setChannel(50);
ensure_equals("LLSegment setChannel() function failed", segment.getChannel(), 50);
- ensure("LLSegment isOnChannel() function failed", (TRUE == segment.isOnChannel(50)));
+ ensure("LLSegment isOnChannel() function failed", (true == segment.isOnChannel(50)));
}
template<> template<>
@@ -74,7 +74,7 @@ namespace tut
LLSegment segment(channel, (U8*)str, len);
ensure("LLSegment get functions failed", (30 == segment.getChannel() && len == segment.size() && (U8*)str == segment.data()));
ensure_memory_matches("LLSegment::data() failed", segment.data(), segment.size(), (U8*)str, len);
- ensure("LLSegment isOnChannel() function failed", (TRUE == segment.isOnChannel(channel)));
+ ensure("LLSegment isOnChannel() function failed", (true == segment.isOnChannel(channel)));
}
template<> template<>
@@ -91,27 +91,27 @@ namespace tut
S32 requestSize;
requestSize = 16384-1;
- ensure("1. LLHeapBuffer createSegment failed", (TRUE == buf.createSegment(channel, requestSize, segment)) && segment.size() == requestSize);
+ ensure("1. LLHeapBuffer createSegment failed", (true == buf.createSegment(channel, requestSize, segment)) && segment.size() == requestSize);
// second request for remainign 1 byte
requestSize = 1;
- ensure("2. LLHeapBuffer createSegment failed", (TRUE == buf.createSegment(channel, requestSize, segment)) && segment.size() == requestSize);
+ ensure("2. LLHeapBuffer createSegment failed", (true == buf.createSegment(channel, requestSize, segment)) && segment.size() == requestSize);
// it should fail now.
requestSize = 1;
- ensure("3. LLHeapBuffer createSegment failed", (FALSE == buf.createSegment(channel, requestSize, segment)));
+ ensure("3. LLHeapBuffer createSegment failed", (false == buf.createSegment(channel, requestSize, segment)));
LLHeapBuffer buf1(bigSize);
// requst for more than default size but less than total sizeit should fail now.
requestSize = 16384 + 1;
- ensure("4. LLHeapBuffer createSegment failed", (TRUE == buf1.createSegment(channel, requestSize, segment)) && segment.size() == requestSize);
+ ensure("4. LLHeapBuffer createSegment failed", (true == buf1.createSegment(channel, requestSize, segment)) && segment.size() == requestSize);
LLHeapBuffer buf2((U8*) str, smallSize);
requestSize = smallSize;
- ensure("5. LLHeapBuffer createSegment failed", (TRUE == buf2.createSegment(channel, requestSize, segment)) && segment.size() == requestSize && memcmp(segment.data(), (U8*) str, requestSize) == 0);
+ ensure("5. LLHeapBuffer createSegment failed", (true == buf2.createSegment(channel, requestSize, segment)) && segment.size() == requestSize && memcmp(segment.data(), (U8*) str, requestSize) == 0);
requestSize = smallSize+1;
- ensure("6. LLHeapBuffer createSegment failed", (FALSE == buf2.createSegment(channel, requestSize, segment)));
+ ensure("6. LLHeapBuffer createSegment failed", (false == buf2.createSegment(channel, requestSize, segment)));
}
//makeChannelConsumer()
@@ -128,7 +128,7 @@ namespace tut
{
LLBufferArray bufferArray;
const char array[] = "SecondLife";
- S32 len = strlen(array);
+ S32 len = static_cast<S32>(strlen(array));
LLChannelDescriptors channelDescriptors = bufferArray.nextChannel();
bufferArray.append(channelDescriptors.in(), (U8*)array, len);
S32 count = bufferArray.countAfter(channelDescriptors.in(), NULL);
@@ -141,9 +141,9 @@ namespace tut
{
LLBufferArray bufferArray;
const char array[] = "SecondLife";
- S32 len = strlen(array);
+ S32 len = static_cast<S32>(strlen(array));
const char array1[] = "LindenLabs";
- S32 len1 = strlen(array1);
+ S32 len1 = static_cast<S32>(strlen(array1));
std::string str(array1);
str.append(array);
@@ -166,9 +166,9 @@ namespace tut
{
LLBufferArray bufferArray;
const char array[] = "SecondLife";
- S32 len = strlen(array);
+ S32 len = static_cast<S32>(strlen(array));
const char array1[] = "LindenLabs";
- S32 len1 = strlen(array1);
+ S32 len1 = static_cast<S32>(strlen(array1));
std::string str(array);
str.append(array1);
@@ -190,7 +190,7 @@ namespace tut
{
LLBufferArray bufferArray;
const char array[] = "SecondLife";
- S32 len = strlen(array) + 1;
+ S32 len = static_cast<S32>(strlen(array)) + 1;
std::string str(array);
LLChannelDescriptors channelDescriptors = bufferArray.nextChannel();
bufferArray.append(channelDescriptors.in(), (U8*)array, len);
@@ -208,7 +208,7 @@ namespace tut
void buffer_object_t::test<10>()
{
const char array[] = "SecondLife is a Virtual World";
- S32 len = strlen(array);
+ S32 len = static_cast<S32>(strlen(array));
LLBufferArray bufferArray;
bufferArray.append(0, (U8*)array, len);
@@ -229,7 +229,7 @@ namespace tut
void buffer_object_t::test<11>()
{
const char array[] = "SecondLife is a Virtual World";
- S32 len = strlen(array);
+ S32 len = static_cast<S32>(strlen(array));
LLBufferArray bufferArray;
bufferArray.append(0, (U8*)array, len);
diff --git a/indra/test/llevents_tut.cpp b/indra/test/llevents_tut.cpp
index 875ca9ad89..1f723c84b6 100644
--- a/indra/test/llevents_tut.cpp
+++ b/indra/test/llevents_tut.cpp
@@ -44,7 +44,6 @@
#include <typeinfo>
// external library headers
#include <boost/bind.hpp>
-#include <boost/shared_ptr.hpp>
#include <boost/assign/list_of.hpp>
// other Linden headers
#include "tests/listener.h" // must PRECEDE lltut.h
@@ -429,7 +428,7 @@ void events_object::test<9>()
{
set_test_name("listen(boost::bind(...TempListener...))");
// listen() can't do anything about a plain TempListener instance:
- // it's not managed with shared_ptr, nor is it an LLEventTrackable subclass
+ // it's not managed with shared_ptr
bool live = false;
LLEventPump& heaptest(pumps.obtain("heaptest"));
LLBoundListener connection;
@@ -453,60 +452,4 @@ void events_object::test<9>()
heaptest.stopListening("temp");
}
-class TempTrackableListener: public TempListener, public LLEventTrackable
-{
-public:
- TempTrackableListener(const std::string& name, bool& liveFlag):
- TempListener(name, liveFlag)
- {}
-};
-
-template<> template<>
-void events_object::test<10>()
-{
- set_test_name("listen(boost::bind(...TempTrackableListener ref...))");
- bool live = false;
- LLEventPump& heaptest(pumps.obtain("heaptest"));
- LLBoundListener connection;
- {
- TempTrackableListener tempListener("temp", live);
- ensure("TempTrackableListener constructed", live);
- connection = heaptest.listen(tempListener.getName(),
- boost::bind(&TempTrackableListener::call,
- boost::ref(tempListener), _1));
- heaptest.post(1);
- check_listener("received", tempListener, 1);
- } // presumably this will make tempListener go away?
- // verify that
- ensure("TempTrackableListener destroyed", ! live);
- ensure("implicit disconnect", ! connection.connected());
- // now just make sure we don't blow up trying to access a freed object!
- heaptest.post(2);
-}
-
-template<> template<>
-void events_object::test<11>()
-{
- set_test_name("listen(boost::bind(...TempTrackableListener pointer...))");
- bool live = false;
- LLEventPump& heaptest(pumps.obtain("heaptest"));
- LLBoundListener connection;
- {
- TempTrackableListener* newListener(new TempTrackableListener("temp", live));
- ensure("TempTrackableListener constructed", live);
- connection = heaptest.listen(newListener->getName(),
- boost::bind(&TempTrackableListener::call,
- newListener, _1));
- heaptest.post(1);
- check_listener("received", *newListener, 1);
- // explicitly destroy newListener
- delete newListener;
- }
- // verify that
- ensure("TempTrackableListener destroyed", ! live);
- ensure("implicit disconnect", ! connection.connected());
- // now just make sure we don't blow up trying to access a freed object!
- heaptest.post(2);
-}
-
} // namespace tut
diff --git a/indra/test/llpermissions_tut.cpp b/indra/test/llpermissions_tut.cpp
index ebee89f9fa..1328939004 100644
--- a/indra/test/llpermissions_tut.cpp
+++ b/indra/test/llpermissions_tut.cpp
@@ -199,7 +199,7 @@ namespace tut
{
LLPermissions perm1;
LLUUID uuid;
- BOOL is_group_owned = FALSE;
+ bool is_group_owned = false;
ensure("1:getOwnership:failed ", ! perm1.getOwnership(uuid,is_group_owned));
LLPermissions perm;
@@ -262,7 +262,7 @@ namespace tut
{
LLPermissions perm;
LLUUID agent;
- BOOL set = 1;
+ bool set = true;
U32 bits = PERM_TRANSFER | PERM_MODIFY;
ensure("setBaseBits():failed ", perm.setBaseBits(agent, set, bits));
ensure("setOwnerBits():failed ", perm.setOwnerBits(agent, set, bits));
@@ -278,7 +278,7 @@ namespace tut
LLPermissions perm;
LLUUID agent;
LLUUID group("9c8eca51-53d5-42a7-bb58-cef070395db8");
- BOOL set = 1;
+ bool set = true;
U32 bits = 10;
ensure("setGroupBits():failed ", perm.setGroupBits(agent,group, set, bits));
ensure("setEveryoneBits():failed ", perm.setEveryoneBits(agent,group, set, bits));
diff --git a/indra/test/llpipeutil.cpp b/indra/test/llpipeutil.cpp
index c64cf21326..1dd4bdfa3c 100644
--- a/indra/test/llpipeutil.cpp
+++ b/indra/test/llpipeutil.cpp
@@ -60,7 +60,7 @@ LLIOPipe::EStatus LLPipeStringInjector::process_impl(
LLSD& context,
LLPumpIO* pump)
{
- buffer->append(channels.out(), (U8*) mString.data(), mString.size());
+ buffer->append(channels.out(), (U8*) mString.data(), static_cast<S32>(mString.size()));
eos = true;
return STATUS_DONE;
}
diff --git a/indra/test/llsaleinfo_tut.cpp b/indra/test/llsaleinfo_tut.cpp
index 1a4ead00b6..1da7101aa3 100644
--- a/indra/test/llsaleinfo_tut.cpp
+++ b/indra/test/llsaleinfo_tut.cpp
@@ -54,7 +54,7 @@ namespace tut
LLSaleInfo saleinfo1 = ll_sale_info_from_sd(llsd_obj1);
ensure("1. The getSaleType() fn failed", LLSaleInfo::FS_COPY == llsaleinfo.getSaleType());
- ensure("2. LLSaleInfo::isForSale() fn failed", TRUE == llsaleinfo.isForSale());
+ ensure("2. LLSaleInfo::isForSale() fn failed", true == llsaleinfo.isForSale());
ensure("3. The getSalePrice() fn failed", sale_price == llsaleinfo.getSalePrice());
ensure("4. The getCRC32() fn failed", 235833404 == llsaleinfo.getCRC32());
ensure("5. LLSaleInfo::lookup(const char* name) fn failed", LLSaleInfo::FS_COPY == llsaleinfo.lookup(sale));
@@ -68,7 +68,7 @@ namespace tut
saleinfo1 = ll_sale_info_from_sd(llsd_obj1);
ensure("8. The getSaleType() and setSaleType() fn failed", LLSaleInfo::FS_ORIGINAL == llsaleinfo.getSaleType());
- ensure("9. LLSaleInfo::isForSale() fn failed", TRUE == llsaleinfo.isForSale());
+ ensure("9. LLSaleInfo::isForSale() fn failed", true == llsaleinfo.isForSale());
ensure("10. The getSalePrice() fn failed", 10000000 == llsaleinfo.getSalePrice());
ensure("11. The getCRC32() fn failed", 127911702 == llsaleinfo.getCRC32());
ensure("12. LLSaleInfo::lookup(const char* name) fn failed", LLSaleInfo::FS_CONTENTS == llsaleinfo.lookup(sale));
@@ -82,7 +82,7 @@ namespace tut
saleinfo1 = ll_sale_info_from_sd(llsd_obj1);
ensure("15. The getSaleType() and setSaleType() fn failed", LLSaleInfo::FS_CONTENTS == llsaleinfo.getSaleType());
- ensure("16. LLSaleInfo::isForSale() fn failed", TRUE == llsaleinfo.isForSale());
+ ensure("16. LLSaleInfo::isForSale() fn failed", true == llsaleinfo.isForSale());
ensure("17. The getSalePrice() fn failed", 55000550 == llsaleinfo.getSalePrice());
ensure("18. The getCRC32() fn failed", 408735656 == llsaleinfo.getCRC32());
ensure("19. LLSaleInfo::lookup(const char* name) fn failed", LLSaleInfo::FS_ORIGINAL == llsaleinfo.lookup(sale));
@@ -96,7 +96,7 @@ namespace tut
saleinfo1 = ll_sale_info_from_sd(llsd_obj1);
ensure("22. The getSaleType() and setSaleType() fn failed", LLSaleInfo::FS_NOT == llsaleinfo.getSaleType());
- ensure("23. LLSaleInfo::isForSale() fn failed", FALSE == llsaleinfo.isForSale());
+ ensure("23. LLSaleInfo::isForSale() fn failed", false == llsaleinfo.isForSale());
ensure("24. The getSalePrice() fn failed", 0 == llsaleinfo.getSalePrice());
ensure("25. The getCRC32() fn failed", 0 == llsaleinfo.getCRC32());
ensure("26. LLSaleInfo::lookup(const char* name) fn failed", LLSaleInfo::FS_NOT == llsaleinfo.lookup(sale));
@@ -116,7 +116,7 @@ namespace tut
std::istringstream istream(ostream.str());
LLSaleInfo llsaleinfo1;
U32 perm_mask = 0;
- BOOL has_perm_mask = FALSE;
+ bool has_perm_mask = false;
llsaleinfo1.importLegacyStream(istream, has_perm_mask, perm_mask);
ensure("importStream() fn failed ",
@@ -133,7 +133,7 @@ namespace tut
LLSD sd_result = saleinfo.asLLSD();
U32 perm_mask = 0 ;
- BOOL has_perm_mask = FALSE;
+ bool has_perm_mask = false;
LLSaleInfo saleinfo1;
saleinfo1.fromLLSD( sd_result, has_perm_mask, perm_mask);
diff --git a/indra/test/llsdmessagebuilder_tut.cpp b/indra/test/llsdmessagebuilder_tut.cpp
index d85d460198..6804c3e29e 100644
--- a/indra/test/llsdmessagebuilder_tut.cpp
+++ b/indra/test/llsdmessagebuilder_tut.cpp
@@ -126,14 +126,14 @@ namespace tut
template<> template<>
void LLSDMessageBuilderTestObject::test<2>()
- // BOOL
+ // bool
{
- BOOL outValue, inValue = TRUE;
+ bool outValue, inValue = true;
LLSDMessageBuilder builder = defaultBuilder();
builder.addBOOL("var", inValue);
LLSDMessageReader reader = setReader(builder);
reader.getBOOL("block", "var", outValue);
- ensure_equals("Ensure BOOL", inValue, outValue);
+ ensure_equals("Ensure bool", inValue, outValue);
}
template<> template<>
@@ -688,13 +688,13 @@ namespace tut
template<> template<>
void LLSDMessageBuilderTestObject::test<39>()
{
- BOOL valueTrue = true;
- BOOL valueFalse = false;
+ bool valueTrue = true;
+ bool valueFalse = false;
LLMsgData* md = new LLMsgData("testMessage");
LLMsgBlkData* mbd = new LLMsgBlkData("testBlock", 0);
- addValue(mbd, (char *)"testBoolFalse", &valueFalse, MVT_BOOL, sizeof(BOOL));
- addValue(mbd, (char *)"testBoolTrue", &valueTrue, MVT_BOOL, sizeof(BOOL));
+ addValue(mbd, (char *)"testBoolFalse", &valueFalse, MVT_BOOL, sizeof(bool));
+ addValue(mbd, (char *)"testBoolTrue", &valueTrue, MVT_BOOL, sizeof(bool));
md->addBlock(mbd);
LLSDMessageBuilder builder = defaultBuilder();
diff --git a/indra/test/llsdmessagereader_tut.cpp b/indra/test/llsdmessagereader_tut.cpp
index 1d39fed0cb..dd6520ea33 100644
--- a/indra/test/llsdmessagereader_tut.cpp
+++ b/indra/test/llsdmessagereader_tut.cpp
@@ -73,11 +73,11 @@ namespace tut
const std::string& block,
const std::string& var,
S32 blocknum,
- BOOL expected)
+ bool expected)
{
LLSDMessageReader msg;
msg.setMessage("fakename", msg_data);
- BOOL test_data;
+ bool test_data;
msg.getBOOL(block.c_str(), var.c_str(), test_data, blocknum);
ensure_equals( "Ensure bool field", test_data, expected);
}
@@ -118,8 +118,8 @@ namespace tut
{
LLSD message = LLSD::emptyMap();
message["block1"] = LLSD::emptyArray();
- BOOL bool_true = TRUE;
- BOOL bool_false = FALSE;
+ bool bool_true = true;
+ bool bool_false = false;
message["block1"][0] = LLSD::emptyMap();
message["block1"][0]["BoolField1"] = bool_true;
message["block1"][1] = LLSD::emptyMap();
@@ -127,9 +127,9 @@ namespace tut
message["block1"][1]["BoolField2"] = bool_true;
ensureMessageName("name3", message, "name3");
- ensureBool(message, "block1", "BoolField1", 0, TRUE);
- ensureBool(message, "block1", "BoolField1", 1, FALSE);
- ensureBool(message, "block1", "BoolField2", 1, TRUE);
+ ensureBool(message, "block1", "BoolField1", 0, true);
+ ensureBool(message, "block1", "BoolField1", 1, false);
+ ensureBool(message, "block1", "BoolField2", 1, true);
ensureNumberOfBlocks(message, "block1", 2);
ensureMessageSize(message, 0);
}
@@ -318,7 +318,7 @@ namespace tut
inValue[1] = 1;
LLSDMessageReader msg = testType(inValue);
- msg.getBinaryData("block", "var", &(outValue[0]), inValue.size());
+ msg.getBinaryData("block", "var", &(outValue[0]), static_cast<S32>(inValue.size()));
ensure_equals("Ensure Binary", outValue, inValue);
}
}
diff --git a/indra/test/llstreamtools_tut.cpp b/indra/test/llstreamtools_tut.cpp
index 68bd5e0ec9..970afb3b02 100644
--- a/indra/test/llstreamtools_tut.cpp
+++ b/indra/test/llstreamtools_tut.cpp
@@ -846,7 +846,7 @@ namespace tut
char buf[255] = {0};
fullread(is, buf, 255);
- ensure_memory_matches("fullread: read with newlines", (void*) buf, str.size()-1, (void*) str.c_str(), str.size()-1);
+ ensure_memory_matches("fullread: read with newlines", (void*) buf, static_cast<U32>(str.size())-1, (void*) str.c_str(), static_cast<U32>(str.size())-1);
is.clear();
is.str(str = "First Line.\nSecond Line\n");
diff --git a/indra/test/lltemplatemessagebuilder_tut.cpp b/indra/test/lltemplatemessagebuilder_tut.cpp
index 67bdbb09b3..ddf1c3dbcc 100644
--- a/indra/test/lltemplatemessagebuilder_tut.cpp
+++ b/indra/test/lltemplatemessagebuilder_tut.cpp
@@ -61,7 +61,7 @@ namespace tut
1,
0,
0,
- FALSE,
+ false,
"notasharedsecret",
NULL,
false,
@@ -135,16 +135,16 @@ namespace tut
template<> template<>
void LLTemplateMessageBuilderTestObject::test<2>()
- // BOOL
+ // bool
{
LLMessageTemplate messageTemplate = defaultTemplate();
messageTemplate.addBlock(defaultBlock(MVT_BOOL, 1));
- BOOL outValue, inValue = TRUE;
+ bool outValue, inValue = true;
LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
builder->addBOOL(_PREHASH_Test0, inValue);
LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
reader->getBOOL(_PREHASH_Test0, _PREHASH_Test0, outValue);
- ensure_equals("Ensure BOOL", inValue, outValue);
+ ensure_equals("Ensure bool", inValue, outValue);
delete reader;
}
@@ -591,17 +591,17 @@ namespace tut
template<> template<>
void LLTemplateMessageBuilderTestObject::test<26>()
- // non-zero offset with BOOL
+ // non-zero offset with bool
{
LLMessageTemplate messageTemplate = defaultTemplate();
messageTemplate.addBlock(defaultBlock(MVT_BOOL, 1));
- BOOL outValue, inValue = TRUE;
+ bool outValue, inValue = true;
LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
builder->addBOOL(_PREHASH_Test0, inValue);
LLTemplateMessageReader* reader = setReader(
messageTemplate, builder, 1);
reader->getBOOL(_PREHASH_Test0, _PREHASH_Test0, outValue);
- ensure_equals("Ensure BOOL", inValue, outValue);
+ ensure_equals("Ensure bool", inValue, outValue);
delete reader;
}
diff --git a/indra/test/lltut.h b/indra/test/lltut.h
index e56b4e8d1c..986bdd0619 100644
--- a/indra/test/lltut.h
+++ b/indra/test/lltut.h
@@ -30,7 +30,11 @@
#define LL_LLTUT_H
#include "is_approx_equal_fraction.h" // instead of llmath.h
+#include "stringize.h"
#include <cstring>
+#include <string>
+#include <string_view>
+#include <vector>
class LLDate;
class LLSD;
@@ -87,49 +91,38 @@ namespace tut
// The functions BELOW this point actually consume tut.hpp functionality.
namespace tut
{
- inline void ensure_approximately_equals(const char* msg, F64 actual, F64 expected, U32 frac_bits)
+ template <typename F> // replace with C++20 floating-point concept
+ inline void ensure_approximately_equals(std::string_view msg, F actual, F expected, U32 frac_bits)
{
if(!is_approx_equal_fraction(actual, expected, frac_bits))
{
- std::stringstream ss;
- ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected;
- throw tut::failure(ss.str().c_str());
+ throw tut::failure(stringize(msg, (msg.empty()?"":": "), "not equal actual: ",
+ actual, " expected: ", expected));
}
}
- inline void ensure_approximately_equals(const char* msg, F32 actual, F32 expected, U32 frac_bits)
+ template <typename F> // replace with C++20 floating-point concept
+ inline void ensure_approximately_equals(F actual, F expected, U32 frac_bits)
{
- if(!is_approx_equal_fraction(actual, expected, frac_bits))
- {
- std::stringstream ss;
- ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected;
- throw tut::failure(ss.str().c_str());
- }
- }
-
- inline void ensure_approximately_equals(F32 actual, F32 expected, U32 frac_bits)
- {
- ensure_approximately_equals(NULL, actual, expected, frac_bits);
+ ensure_approximately_equals("", actual, expected, frac_bits);
}
- inline void ensure_approximately_equals_range(const char *msg, F32 actual, F32 expected, F32 delta)
+ template <typename F> // replace with C++20 floating-point concept
+ inline void ensure_approximately_equals_range(std::string_view msg, F actual, F expected, F delta)
{
if (fabs(actual-expected)>delta)
{
- std::stringstream ss;
- ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected << " tolerance: " << delta;
- throw tut::failure(ss.str().c_str());
+ throw tut::failure(stringize(msg, (msg.empty()?"":": "), "not equal actual: ",
+ actual, " expected: ", expected, " tolerance: ", delta));
}
}
- inline void ensure_memory_matches(const char* msg,const void* actual, U32 actual_len, const void* expected,U32 expected_len)
+ inline void ensure_memory_matches(std::string_view msg,const void* actual, U32 actual_len, const void* expected,U32 expected_len)
{
if((expected_len != actual_len) ||
(std::memcmp(actual, expected, actual_len) != 0))
{
- std::stringstream ss;
- ss << (msg?msg:"") << (msg?": ":"") << "not equal";
- throw tut::failure(ss.str().c_str());
+ throw tut::failure(stringize(msg, (msg.empty()?"":": "), "not equal"));
}
}
@@ -139,20 +132,18 @@ namespace tut
}
template <class T,class Q>
- void ensure_not_equals(const char* msg,const Q& actual,const T& expected)
+ void ensure_not_equals(std::string_view msg,const Q& actual,const T& expected)
{
if( expected == actual )
{
- std::stringstream ss;
- ss << (msg?msg:"") << (msg?": ":"") << "both equal " << expected;
- throw tut::failure(ss.str().c_str());
+ throw tut::failure(stringize(msg, (msg.empty()?"":": "), "both equal ", expected));
}
}
template <class T,class Q>
void ensure_not_equals(const Q& actual,const T& expected)
{
- ensure_not_equals(NULL, actual, expected);
+ ensure_not_equals("", actual, expected);
}
}
diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp
index 96308b54af..11cd710ef6 100644
--- a/indra/test/message_tut.cpp
+++ b/indra/test/message_tut.cpp
@@ -75,7 +75,7 @@ namespace tut
1,
0,
0,
- FALSE,
+ false,
"notasharedsecret",
NULL,
false,
diff --git a/indra/test/namedtempfile.h b/indra/test/namedtempfile.h
index 8027f95728..96b19523ab 100644
--- a/indra/test/namedtempfile.h
+++ b/indra/test/namedtempfile.h
@@ -32,18 +32,18 @@ class NamedTempFile: public boost::noncopyable
{
LOG_CLASS(NamedTempFile);
public:
- NamedTempFile(const std::string_view& pfx,
- const std::string_view& content,
- const std::string_view& sfx=std::string_view(""))
+ NamedTempFile(std::string_view pfx,
+ std::string_view content,
+ std::string_view sfx=std::string_view(""))
{
createFile(pfx, [&content](std::ostream& out){ out << content; }, sfx);
}
// Disambiguate when passing string literal -- unclear why a string
// literal should be ambiguous wrt std::string_view and Streamer
- NamedTempFile(const std::string_view& pfx,
+ NamedTempFile(std::string_view pfx,
const char* content,
- const std::string_view& sfx=std::string_view(""))
+ std::string_view sfx=std::string_view(""))
{
createFile(pfx, [&content](std::ostream& out){ out << content; }, sfx);
}
@@ -53,9 +53,9 @@ public:
// (boost::phoenix::placeholders::arg1 << "the value is " << 17 << '\n')
typedef std::function<void(std::ostream&)> Streamer;
- NamedTempFile(const std::string_view& pfx,
+ NamedTempFile(std::string_view pfx,
const Streamer& func,
- const std::string_view& sfx=std::string_view(""))
+ std::string_view sfx=std::string_view(""))
{
createFile(pfx, func, sfx);
}
@@ -94,8 +94,8 @@ public:
return out;
}
- static boost::filesystem::path temp_path(const std::string_view& pfx="",
- const std::string_view& sfx="")
+ static boost::filesystem::path temp_path(std::string_view pfx="",
+ std::string_view sfx="")
{
// This variable is set by GitHub actions and is the recommended place
// to put temp files belonging to an actions job.
@@ -114,9 +114,9 @@ public:
}
protected:
- void createFile(const std::string_view& pfx,
+ void createFile(std::string_view pfx,
const Streamer& func,
- const std::string_view& sfx)
+ std::string_view sfx)
{
// Create file in a temporary place.
mPath = temp_path(pfx, sfx);
@@ -137,7 +137,7 @@ class NamedExtTempFile: public NamedTempFile
{
LOG_CLASS(NamedExtTempFile);
public:
- NamedExtTempFile(const std::string& ext, const std::string_view& content):
+ NamedExtTempFile(const std::string& ext, std::string_view content):
NamedTempFile(remove_dot(ext), content, ensure_dot(ext))
{}
diff --git a/indra/test/print.h b/indra/test/print.h
index 7577698cc8..6906eae581 100644
--- a/indra/test/print.h
+++ b/indra/test/print.h
@@ -23,7 +23,9 @@ struct NONL_t {};
inline
void print()
{
+#ifdef LL_TEST
std::cerr << std::endl;
+#endif
}
// print(NONL) is a no-op
@@ -35,8 +37,10 @@ void print(NONL_t)
template <typename T, typename... ARGS>
void print(T&& first, ARGS&&... rest)
{
+#ifdef LL_TEST
std::cerr << first;
print(std::forward<ARGS>(rest)...);
+#endif
}
#endif /* ! defined(LL_PRINT_H) */
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index 61a4eb07c5..c002edd94c 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -35,13 +35,15 @@
*/
#include "linden_common.h"
-#include "llerrorcontrol.h"
-#include "lltut.h"
+#include "llexception.h"
#include "chained_callback.h"
-#include "stringize.h"
-#include "namedtempfile.h"
+#include "fsyspath.h"
+#include "llerrorcontrol.h"
#include "lltrace.h"
#include "lltracethreadrecorder.h"
+#include "lltut.h"
+#include "namedtempfile.h"
+#include "stringize.h"
#include "apr_pools.h"
#include "apr_getopt.h"
@@ -53,25 +55,8 @@
# include "ctype_workaround.h"
#endif
-#ifndef LL_WINDOWS
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#endif
-
-#if LL_MSVC
-#pragma warning (push)
-#pragma warning (disable : 4702) // warning C4702: unreachable code
-#endif
#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/stream.hpp>
-#if LL_MSVC
-#pragma warning (pop)
-#endif
-
-#include <boost/scoped_ptr.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/foreach.hpp>
#include <fstream>
@@ -112,7 +97,7 @@ public:
virtual void recordMessage(LLError::ELevel level, const std::string& message)
{
- LL_PROFILE_ZONE_SCOPED
+ LL_PROFILE_ZONE_SCOPED;
mFile << message << std::endl;
}
@@ -181,10 +166,6 @@ public:
LLTestCallback(bool verbose_mode, std::ostream *stream,
std::shared_ptr<LLReplayLog> replayer) :
mVerboseMode(verbose_mode),
- mTotalTests(0),
- mPassedTests(0),
- mFailedTests(0),
- mSkippedTests(0),
// By default, capture a shared_ptr to std::cout, with a no-op "deleter"
// so that destroying the shared_ptr makes no attempt to delete std::cout.
mStream(std::shared_ptr<std::ostream>(&std::cout, [](std::ostream*){})),
@@ -220,6 +201,8 @@ public:
virtual void group_started(const std::string& name) {
LL_INFOS("TestRunner")<<"Unit test group_started name=" << name << LL_ENDL;
*mStream << "Unit test group_started name=" << name << std::endl;
+ mGroup = name;
+ mGroupTests = 0;
super::group_started(name);
}
@@ -232,6 +215,7 @@ public:
virtual void test_completed(const tut::test_result& tr)
{
++mTotalTests;
+ ++mGroupTests;
// If this test failed, dump requested log messages BEFORE stating the
// test result.
@@ -319,12 +303,15 @@ public:
super::run_completed();
}
+ std::string mGroup;
+ int mGroupTests{ 0 };
+
protected:
- bool mVerboseMode;
- int mTotalTests;
- int mPassedTests;
- int mFailedTests;
- int mSkippedTests;
+ bool mVerboseMode{ false };
+ int mTotalTests{ 0 };
+ int mPassedTests{ 0 };
+ int mFailedTests{ 0 };
+ int mSkippedTests{ 0 };
std::shared_ptr<std::ostream> mStream;
std::shared_ptr<LLReplayLog> mReplayer;
};
@@ -522,12 +509,6 @@ static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL;
int main(int argc, char **argv)
{
- // The following line must be executed to initialize Google Mock
- // (and Google Test) before running the tests.
-#ifndef LL_WINDOWS
- ::testing::InitGoogleMock(&argc, argv);
-#endif
-
ll_init_apr();
apr_getopt_t* os = NULL;
if(APR_SUCCESS != apr_getopt_init(&os, gAPRPoolp, argc, argv))
@@ -545,6 +526,29 @@ int main(int argc, char **argv)
// LOGTEST overrides default, but can be overridden by --debug.
const char* LOGTEST = getenv("LOGTEST");
+ // Sometimes we must rebuild much of the viewer before we get to the
+ // specific test we want to monitor, and some viewer integration tests are
+ // quite verbose. In addition to noticing plain LOGTEST= (for all tests),
+ // also notice LOGTEST_progname= (for a specific test).
+ // (Why doesn't MSVC notice fsyspath::operator std::string()?
+ // Why must we explicitly call fsyspath::string()?)
+ std::string basename(fsyspath(argv[0]).stem().string());
+ // don't make user set LOGTEST_INTEGRATION_TEST_progname or (worse)
+ // LOGTEST_PROJECT_foo_TEST_bar -- only LOGTEST_progname or LOGTEST_bar
+ auto _TEST_ = basename.find("_TEST_");
+ if (_TEST_ != std::string::npos)
+ {
+ basename.erase(0, _TEST_+6);
+ }
+ std::string LOGTEST_prog_key("LOGTEST_" + basename);
+ const char* LOGTEST_prog = getenv(LOGTEST_prog_key.c_str());
+// std::cout << LOGTEST_prog_key << "='" << (LOGTEST_prog? LOGTEST_prog : "") << "'" << std::endl;
+ if (LOGTEST_prog && *LOGTEST_prog)
+ {
+ LOGTEST = LOGTEST_prog;
+ std::cout << "LOGTEST='" << LOGTEST << "' from " << LOGTEST_prog_key << std::endl;
+ }
+
// values used for options parsing
apr_status_t apr_err;
const char* opt_arg = NULL;
@@ -658,14 +662,47 @@ int main(int argc, char **argv)
// a chained_callback subclass must be linked with previous
mycallback->link();
- if(test_group.empty())
- {
- tut::runner.get().run_tests();
- }
- else
- {
- tut::runner.get().run_tests(test_group);
- }
+ LL::seh::catcher(
+ // __try
+ [test_group]
+ {
+ if(test_group.empty())
+ {
+ tut::runner.get().run_tests();
+ }
+ else
+ {
+ tut::runner.get().run_tests(test_group);
+ }
+ },
+ // __except
+ [mycallback](U32 code, const std::string& /*stacktrace*/)
+ {
+ static std::map<U32, const char*> codes = {
+ { 0xC0000005, "Access Violation" },
+ { 0xC00000FD, "Stack Overflow" },
+ // ... continue filling in as desired
+ };
+
+ auto found{ codes.find(code) };
+ const char* name = ((found == codes.end())? "unknown" : found->second);
+ auto msg{ stringize("test threw ", std::hex, code, " (", name, ")") };
+
+ // Instead of bombing the whole test run, report this as a test
+ // failure. Arguably, catching structured exceptions should be
+ // hacked into TUT itself.
+ mycallback->test_completed(tut::test_result(
+ mycallback->mGroup,
+ mycallback->mGroupTests+1, // test within group
+ "unknown", // test name
+ tut::test_result::ex, // result: exception
+ // we don't have to throw this exception subclass to use it to
+ // populate the test_result struct
+ Windows_SEH_exception(msg)));
+ // we've left the TUT framework -- finish up by hand
+ mycallback->group_completed(mycallback->mGroup);
+ mycallback->run_completed();
+ });
bool success = (mycallback->getFailedTests() == 0);
diff --git a/indra/test/writestr.h b/indra/test/writestr.h
new file mode 100755
index 0000000000..af8be5a3aa
--- /dev/null
+++ b/indra/test/writestr.h
@@ -0,0 +1,39 @@
+/**
+ * @file writestr.h
+ * @author Nat Goodspeed
+ * @date 2024-05-21
+ * @brief writestr() function for when iostream isn't set up
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Copyright (c) 2024, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_WRITESTR_H)
+#define LL_WRITESTR_H
+
+#include "stringize.h"
+
+#ifndef LL_WINDOWS
+
+#include <unistd.h>
+
+#else // LL_WINDOWS
+
+#include <io.h>
+inline
+int write(int fd, const void* buffer, unsigned int count)
+{
+ return _write(fd, buffer, count);
+}
+
+#endif // LL_WINDOWS
+
+template <typename... ARGS>
+auto writestr(int fd, ARGS&&... args)
+{
+ std::string str{ stringize(std::forward<ARGS>(args)..., '\n') };
+ return write(fd, str.data(), str.length());
+}
+
+#endif /* ! defined(LL_WRITESTR_H) */