diff options
Diffstat (limited to 'indra/test')
-rw-r--r-- | indra/test/CMakeLists.txt | 3 | ||||
-rw-r--r-- | indra/test/debug.h | 69 | ||||
-rw-r--r-- | indra/test/hexdump.h | 97 | ||||
-rw-r--r-- | indra/test/io.cpp | 78 | ||||
-rw-r--r-- | indra/test/llbuffer_tut.cpp | 32 | ||||
-rw-r--r-- | indra/test/llevents_tut.cpp | 59 | ||||
-rw-r--r-- | indra/test/llpermissions_tut.cpp | 6 | ||||
-rw-r--r-- | indra/test/llpipeutil.cpp | 2 | ||||
-rw-r--r-- | indra/test/llsaleinfo_tut.cpp | 12 | ||||
-rw-r--r-- | indra/test/llsdmessagebuilder_tut.cpp | 14 | ||||
-rw-r--r-- | indra/test/llsdmessagereader_tut.cpp | 16 | ||||
-rw-r--r-- | indra/test/llstreamtools_tut.cpp | 2 | ||||
-rw-r--r-- | indra/test/lltemplatemessagebuilder_tut.cpp | 14 | ||||
-rw-r--r-- | indra/test/lltut.h | 49 | ||||
-rw-r--r-- | indra/test/message_tut.cpp | 2 | ||||
-rw-r--r-- | indra/test/namedtempfile.h | 24 | ||||
-rw-r--r-- | indra/test/print.h | 4 | ||||
-rw-r--r-- | indra/test/test.cpp | 127 | ||||
-rwxr-xr-x | indra/test/writestr.h | 39 |
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) */ |