From 1228b10845f5723726c3e4d78459ff8872ac066b Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 14 Oct 2026 00:09:03 -0400 Subject: [PATCH 1/4] Work handed back to the main loop asks one place which queue that is Code that works off the main thread hands what it found back through the queue the main loop services; where there is none, in a test, it does the work in place. Nine places asked for that queue by its name, so in one test process a queue one test made under that name chose the way for every test after it: alscriptlookup's walks went to a thread for the cases that rely on their being done in place. They ask ALMainLoop::queue() now. It answers as they did, unless a test holds an ALMainLoop::Choice, which says which queue it answers, or none, for as long as it lives. newview's test queue no longer has the main loop's name, so making it chooses nothing; alscriptlookup's threaded case and alscriptstudiomasters' fixture choose it for themselves. Ahead of TM24, where newview's tests share one process. Co-Authored-By: Claude Opus 5.5 --- indra/alscript/masters/almasterwatch.cpp | 3 +- indra/llcommon/CMakeLists.txt | 2 + indra/llcommon/almainloop.cpp | 57 ++++++++++++++++++ indra/llcommon/almainloop.h | 58 +++++++++++++++++++ indra/llcommon/alwatchedfile.cpp | 3 +- indra/newview/alscriptlinkbadges.cpp | 3 +- indra/newview/alscriptlinkscripts.cpp | 3 +- indra/newview/alscriptlookup.cpp | 3 +- indra/newview/alscriptmasterupload.cpp | 5 +- indra/newview/alscriptstudiomasters.cpp | 5 +- indra/newview/tests/alscriptlookup_test.cpp | 9 ++- .../tests/alscriptstudiomasters_test.cpp | 7 ++- indra/newview/tests/newview_test_fakes.cpp | 2 +- indra/newview/tests/newview_test_fakes.h | 10 ++-- 14 files changed, 151 insertions(+), 19 deletions(-) create mode 100644 indra/llcommon/almainloop.cpp create mode 100644 indra/llcommon/almainloop.h diff --git a/indra/alscript/masters/almasterwatch.cpp b/indra/alscript/masters/almasterwatch.cpp index 0f97654b79..7dd295ac76 100644 --- a/indra/alscript/masters/almasterwatch.cpp +++ b/indra/alscript/masters/almasterwatch.cpp @@ -26,6 +26,7 @@ #include "almasterwatch.h" +#include "almainloop.h" #include "alserialworker.h" #include "alwatchedfile.h" #include "llsingleton.h" @@ -74,7 +75,7 @@ namespace ALMasterWatch::look_t ALMasterWatch::offThread() { return [](std::vector paths, stamped_t found) { - const LL::WorkQueue::ptr_t main_loop = LL::WorkQueue::getInstance("mainloop"); + const LL::WorkQueue::ptr_t main_loop = ALMainLoop::queue(); if (!main_loop) { // No main loop to hand them back to -- a test -- so looked at diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 24ddb265ad..3584c24bbe 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -18,6 +18,7 @@ target_sources( llcommon PRIVATE alfilewrite.cpp + almainloop.cpp alserialworker.cpp alparamtype.cpp alrecoverystore.cpp @@ -122,6 +123,7 @@ target_sources( FILES alfilewrite.h allinebreaks.h + almainloop.h alserialworker.h alparamtype.h alrandmap.h diff --git a/indra/llcommon/almainloop.cpp b/indra/llcommon/almainloop.cpp new file mode 100644 index 0000000000..e0b6bef012 --- /dev/null +++ b/indra/llcommon/almainloop.cpp @@ -0,0 +1,57 @@ +/** + * @file almainloop.cpp + * @brief The queue the main loop services, and a test's say over it. + * + * $LicenseInfo:firstyear=2026&license=viewerlgpl$ + * Alchemy Viewer Source Code + * Copyright (C) 2026, Rye + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "almainloop.h" + +#include + +namespace +{ + // Read from the threads that ask whether to hand back, so a choice made + // on the main thread is seen whole. + std::atomic sChoice{ nullptr }; +} + +LL::WorkQueue::ptr_t ALMainLoop::queue() +{ + if (const Choice* choice = sChoice.load(std::memory_order_acquire)) + { + return choice->mChosen; + } + return LL::WorkQueue::getInstance("mainloop"); +} + +ALMainLoop::Choice::Choice(LL::WorkQueue* chosen) + : mChosen(chosen ? LL::WorkQueue::getInstance(chosen->getKey()) : nullptr) + , mOuter(sChoice.load(std::memory_order_relaxed)) +{ + sChoice.store(this, std::memory_order_release); +} + +ALMainLoop::Choice::~Choice() +{ + sChoice.store(mOuter, std::memory_order_release); +} diff --git a/indra/llcommon/almainloop.h b/indra/llcommon/almainloop.h new file mode 100644 index 0000000000..cdaa437f56 --- /dev/null +++ b/indra/llcommon/almainloop.h @@ -0,0 +1,58 @@ +/** + * @file almainloop.h + * @brief The queue the main loop services, and a test's say over it. + * + * $LicenseInfo:firstyear=2026&license=viewerlgpl$ + * Alchemy Viewer Source Code + * Copyright (C) 2026, Rye + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * $/LicenseInfo$ + */ + +#pragma once + +#include "workqueue.h" + +// The queue the viewer's main loop services: what work done on another +// thread hands its result back through. Code that works off the main +// thread asks here rather than for the queue by its name, so that a test +// can say which way that code goes. +namespace ALMainLoop +{ + // The main loop's queue, or null where nothing services one -- a test + // that has not chosen one -- and the work is done in place instead. + LL_COMMON_API LL::WorkQueue::ptr_t queue(); + + // While one lives, queue() answers the queue it was given, or null for + // none, whatever queue of the main loop's name there is. Without it a + // queue one test made would choose the way for every test after it in + // the process. The newest living one wins. Main thread only. + class LL_COMMON_API Choice + { + public: + explicit Choice(LL::WorkQueue* chosen); + ~Choice(); + + Choice(const Choice&) = delete; + Choice& operator=(const Choice&) = delete; + + private: + friend LL::WorkQueue::ptr_t queue(); + + LL::WorkQueue::ptr_t mChosen; + const Choice* mOuter; + }; +} diff --git a/indra/llcommon/alwatchedfile.cpp b/indra/llcommon/alwatchedfile.cpp index 3ff4bd0bae..e5628d972e 100644 --- a/indra/llcommon/alwatchedfile.cpp +++ b/indra/llcommon/alwatchedfile.cpp @@ -26,6 +26,7 @@ #include "alwatchedfile.h" +#include "almainloop.h" #include "alserialworker.h" #include "fsyspath.h" #include "llerror.h" @@ -188,7 +189,7 @@ class ALWatchedFile::Watcher : public std::enable_shared_from_this { return; } - const LL::WorkQueue::ptr_t main = LL::WorkQueue::getInstance("mainloop"); + const LL::WorkQueue::ptr_t main = ALMainLoop::queue(); if (!mWorker) { mWorker = std::make_unique("WatchedFiles"); diff --git a/indra/newview/alscriptlinkbadges.cpp b/indra/newview/alscriptlinkbadges.cpp index c25473a18a..141d2902a1 100644 --- a/indra/newview/alscriptlinkbadges.cpp +++ b/indra/newview/alscriptlinkbadges.cpp @@ -26,6 +26,7 @@ #include "alscriptlinkbadges.h" +#include "almainloop.h" #include "alscriptdiskmasters.h" #include "alserialworker.h" #include "workqueue.h" @@ -173,7 +174,7 @@ void ALScriptLinkBadges::look() } // Where there is no main loop to hand what was found back to -- a test // -- looked at here. - const LL::WorkQueue::ptr_t main_loop = LL::WorkQueue::getInstance("mainloop"); + const LL::WorkQueue::ptr_t main_loop = ALMainLoop::queue(); if (!main_loop) { Stamps stamps; diff --git a/indra/newview/alscriptlinkscripts.cpp b/indra/newview/alscriptlinkscripts.cpp index e5f6c88faa..094404f91d 100644 --- a/indra/newview/alscriptlinkscripts.cpp +++ b/indra/newview/alscriptlinkscripts.cpp @@ -26,6 +26,7 @@ #include "alscriptlinkscripts.h" +#include "almainloop.h" #include "almastermatch.h" #include "alscriptcontentsindex.h" #include "alscriptdiskmasters.h" @@ -394,7 +395,7 @@ void ALScriptLinkScripts::findFiles() // a drive that may be slow. Where there is no main loop to hand what it // found back to -- a test -- looked at here. const U32 generation = mGeneration; - const LL::WorkQueue::ptr_t main_loop = LL::WorkQueue::getInstance("mainloop"); + const LL::WorkQueue::ptr_t main_loop = ALMainLoop::queue(); if (!main_loop) { found(generation, match(asks, lsl, lua, {})); diff --git a/indra/newview/alscriptlookup.cpp b/indra/newview/alscriptlookup.cpp index b687d3a3ca..e5c78527b5 100644 --- a/indra/newview/alscriptlookup.cpp +++ b/indra/newview/alscriptlookup.cpp @@ -28,6 +28,7 @@ #include "aldiskincludes.h" #include "alincludeidentity.h" +#include "almainloop.h" #include "alscriptlexicon.h" #include "alscriptnavigation.h" #include "alscriptstudioanalysis.h" @@ -352,7 +353,7 @@ void ALScriptLookup::walkDisk(const std::string& id, U32 generation, std::vector // Off the main thread: a walk may look at thousands of entries and // read hundreds of files, on a drive that may be slow. Where there is // no main loop to hand what it read back to -- a test -- walked here. - const LL::WorkQueue::ptr_t main_loop = LL::WorkQueue::getInstance("mainloop"); + const LL::WorkQueue::ptr_t main_loop = ALMainLoop::queue(); if (!main_loop) { walked(id, generation, readDisk(folders, lua, name, listed, {}), nullptr); diff --git a/indra/newview/alscriptmasterupload.cpp b/indra/newview/alscriptmasterupload.cpp index b28f1393a8..a79039cac6 100644 --- a/indra/newview/alscriptmasterupload.cpp +++ b/indra/newview/alscriptmasterupload.cpp @@ -27,6 +27,7 @@ #include "alscriptmasterupload.h" #include "alfilewrite.h" +#include "almainloop.h" #include "alrecovery.h" #include "alrecoverystore.h" #include "alsavehistory.h" @@ -169,7 +170,7 @@ void ALScriptMasterUpload::read() // to this send on the main thread, which alone goes on with it. With no // main loop to hand it back to -- a test -- or the thread closed as the // viewer goes, read here. - if (const LL::WorkQueue::ptr_t main_loop = LL::WorkQueue::getInstance("mainloop")) + if (const LL::WorkQueue::ptr_t main_loop = ALMainLoop::queue()) { std::shared_ptr self = shared_from_this(); const std::string master = mLink.master; @@ -408,7 +409,7 @@ void ALScriptMasterUpload::askHistory() // given to keep before this; what it found handed back to the main // thread. With no main loop to hand it back to -- a test -- read here; // with the thread stopped, as the viewer quits, not read at all. - const LL::WorkQueue::ptr_t main_loop = LL::WorkQueue::getInstance("mainloop"); + const LL::WorkQueue::ptr_t main_loop = ALMainLoop::queue(); if (!main_loop) { historyHas(history->holds(key, asset, *text, HISTORY_NEWEST)); diff --git a/indra/newview/alscriptstudiomasters.cpp b/indra/newview/alscriptstudiomasters.cpp index 7fef5bb221..c7816fa74e 100644 --- a/indra/newview/alscriptstudiomasters.cpp +++ b/indra/newview/alscriptstudiomasters.cpp @@ -28,6 +28,7 @@ #include "alcodeeditor.h" #include "alfilewrite.h" +#include "almainloop.h" #include "almastermatch.h" #include "alnotecardembedded.h" #include "alscriptenvelope.h" @@ -382,7 +383,7 @@ void ALScriptStudioMasters::loaded(Doc& doc) std::vector> aliases = mDiskMasters.aliasesFor(std::string(), lua); const U32 look = ++doc.master->hintLook; const std::string id = doc.id; - const LL::WorkQueue::ptr_t main_loop = LL::WorkQueue::getInstance("mainloop"); + const LL::WorkQueue::ptr_t main_loop = ALMainLoop::queue(); if (!main_loop) { // No main loop to hand it back to -- a test -- so looked for here. @@ -621,7 +622,7 @@ void ALScriptStudioMasters::lookAgain() { return; } - const LL::WorkQueue::ptr_t main_loop = LL::WorkQueue::getInstance("mainloop"); + const LL::WorkQueue::ptr_t main_loop = ALMainLoop::queue(); if (!main_loop) { return; diff --git a/indra/newview/tests/alscriptlookup_test.cpp b/indra/newview/tests/alscriptlookup_test.cpp index 1997e4ac15..9f4ca1c5fc 100644 --- a/indra/newview/tests/alscriptlookup_test.cpp +++ b/indra/newview/tests/alscriptlookup_test.cpp @@ -30,6 +30,7 @@ #include "../alscriptlookup.h" #include "alincludeidentity.h" +#include "almainloop.h" #include "llfile.h" #include "workqueue.h" @@ -1075,9 +1076,11 @@ namespace tut const std::string B_LUA = "local lib = require(\"./lib\")\nprint(lib.twice(4))\n"; llofstream((root / "b.luau").string(), std::ios::binary) << B_LUA; studio.disk = { root.string() }; - // The main loop's queue, as the viewer's is: kept, since a walk - // let go of may hand back to it after the test. - LL::WorkQueue& main_loop = newview_test::mainLoop(); + // A main loop's queue, as the viewer's is, chosen for this test + // alone: the queue kept, since a walk let go of may hand back to it + // after the test. + LL::WorkQueue& main_loop = newview_test::mainLoop(); + const ALMainLoop::Choice chosen(&main_loop); const auto pumped = [&main_loop](const std::function& until, std::chrono::milliseconds within) { const auto deadline = std::chrono::steady_clock::now() + within; while (std::chrono::steady_clock::now() < deadline) diff --git a/indra/newview/tests/alscriptstudiomasters_test.cpp b/indra/newview/tests/alscriptstudiomasters_test.cpp index 8c163bbcf2..6422a36d2b 100644 --- a/indra/newview/tests/alscriptstudiomasters_test.cpp +++ b/indra/newview/tests/alscriptstudiomasters_test.cpp @@ -28,6 +28,7 @@ #include "../alnotecardembedded.h" #include "alfilewrite.h" +#include "almainloop.h" #include "alscriptstudio_fixture.h" #include "alwatchedfile.h" #include "fsyspath.h" @@ -226,6 +227,9 @@ namespace tut NoWorld world; std::string folder; std::vector wired; + // A look at the tabs waits for the main loop, so every case here + // has one: this file's choice, not whatever a test before it made. + const ALMainLoop::Choice main_loop{ &mainLoop() }; ~alscriptstudiomasters_data() { @@ -242,7 +246,7 @@ namespace tut } } - // The main loop's queue, as the viewer's is, which a look at the + // The queue standing in for the main loop's, which a look at the // tabs waits for: the process's, kept for the rest of the run. static LL::WorkQueue& mainLoop() { return newview_test::mainLoop(); } // Whatever was waiting for the main loop, done. @@ -254,7 +258,6 @@ namespace tut { skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } - mainLoop(); const fsyspath made = std::filesystem::temp_directory_path() / fsyspath("alscriptstudiomasters_" + LLUUID::generateNewID().asString()); std::filesystem::create_directories(made); folder = made.string(); diff --git a/indra/newview/tests/newview_test_fakes.cpp b/indra/newview/tests/newview_test_fakes.cpp index 517c4b7b71..067e080de4 100644 --- a/indra/newview/tests/newview_test_fakes.cpp +++ b/indra/newview/tests/newview_test_fakes.cpp @@ -46,6 +46,6 @@ const std::string& rlvGetAnonym(const LLAvatarName&) LL::WorkQueue& newview_test::mainLoop() { - static LL::WorkQueue queue("mainloop", 1024); + static LL::WorkQueue queue("newview_test main loop", 1024); return queue; } diff --git a/indra/newview/tests/newview_test_fakes.h b/indra/newview/tests/newview_test_fakes.h index 3c0fd0ddfb..8a6a268813 100644 --- a/indra/newview/tests/newview_test_fakes.h +++ b/indra/newview/tests/newview_test_fakes.h @@ -32,10 +32,12 @@ namespace LL namespace newview_test { - // The main loop's queue, as the viewer's is: made the first time a test - // asks for it, never while the process starts, and kept for the rest of - // the run, since what was posted to it for a test gone finds nobody. A - // queue's name is its key in a process, so every test shares this one. + // A queue for a test to stand in for the main loop's, chosen through + // ALMainLoop::Choice for as long as the test wants work handed back to + // it: made the first time a test asks for it, never while the process + // starts, and kept for the rest of the run, since what was posted to it + // for a test gone finds nobody. Not under the main loop's name, so that + // its being made chooses nothing for the tests after. LL::WorkQueue& mainLoop(); } From e27d9a211e15cbd31d36565ea56df5d54cc77ec7 Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 14 Oct 2026 02:00:27 -0400 Subject: [PATCH 2/4] newview's tests are Catch2 binaries, converted by tut2catch.py TM24, the last wave of stage 3: newview's 85 TUT files, 832 tests, become thirteen Catch2 binaries, each file still run in a process of its own: - newview_tests, 72 files: the models, and Script Studio's units, many built over one headless UI on the source tree's skins and fonts. The viewer has no library, so the 74 files of it they need are compiled into the binary once each, where each test compiled its own copies; al_studio_test_common, the archive the Script Studio tests shared, goes. llvocache.cpp, which leaves out what reads the viewer's settings under LL_TEST, is an object library of its own with that define, since the viewer compiles the same file without it; - newview_gl_tests, the two that draw on llrender's shared hidden window: the selection outline and the depth under the HUD; - a binary each for the eleven Linden-era tests whose hand stubs of llui, llxml and the viewer differ from one another: lldateutil, lllogininstance, llremoteparcelrequest, llsecapi, llsechandler_basic, llslurl, lltextureinfo, llviewerhelputil, llviewernetwork, llworldmap and llworldmipmap. They take llui's headers, which the viewer's precompiled header names, without its library. The fakes, the studio's stand-ins and the settings group are SUPPORT objects. The files are tut2catch.py's output, with the names the idiom pass that follows chose. It marked one site TM-CHECK, in code this Mac does not compile, resolved by hand: noise's comparison with MSVC's rand() (an ensure_equals() over its draws). tut_parity.py, against the TUT executables' recorded results (832 tests, 830 ok and 2 skipped), holds plain for 84 files and under --recounted for noise, with one assertion site reviewed as never running in a passing case: alselectionoutline_gl's check of the unreversed depth, which runs only under reverse-Z, where the context has clip control, as this Mac's GL 4.1 context does not. All 98 entries pass, and newview_tests passes whole, in declared order and in random ones. Co-Authored-By: Claude Opus 5.5 --- indra/newview/CMakeLists.txt | 857 +++------- .../tests/alagentlocationformat_test.cpp | 137 +- indra/newview/tests/alchattimestamp_test.cpp | 59 +- .../newview/tests/alcolorwheelmodel_test.cpp | 254 +-- indra/newview/tests/alcrashreporter_test.cpp | 234 +-- indra/newview/tests/alcurvemodel_test.cpp | 708 +++++--- .../tests/aldaycyclelandmarks_test.cpp | 136 +- indra/newview/tests/alfarplane_test.cpp | 367 ++-- indra/newview/tests/alfeedback_test.cpp | 635 ++++--- indra/newview/tests/alfeedbackoutbox_test.cpp | 190 ++- indra/newview/tests/algradehistory_test.cpp | 397 +++-- indra/newview/tests/alhuddepth_gl_test.cpp | 158 +- .../newview/tests/almotionpredictor_test.cpp | 212 ++- .../newview/tests/alnotecardembedded_test.cpp | 217 ++- indra/newview/tests/alrecoverykeeper_test.cpp | 132 +- .../tests/alsceneexplorerpredicate_test.cpp | 292 ++-- indra/newview/tests/alscopedata_test.cpp | 405 +++-- .../tests/alscriptanalysislane_test.cpp | 171 +- .../newview/tests/alscriptanalyzers_test.cpp | 52 +- .../tests/alscriptcontentsindex_test.cpp | 198 ++- .../newview/tests/alscriptcrumbsbar_test.cpp | 400 +++-- .../tests/alscriptexplorermodel_test.cpp | 521 ++++-- .../tests/alscriptexplorertree_test.cpp | 205 ++- .../tests/alscriptexternaleditor_test.cpp | 243 ++- .../tests/alscriptinspectorpane_test.cpp | 148 +- indra/newview/tests/alscriptitemdrop_test.cpp | 57 +- indra/newview/tests/alscriptjobqueue_test.cpp | 178 +- indra/newview/tests/alscriptkeymap_test.cpp | 325 ++-- indra/newview/tests/alscriptlookup_test.cpp | 941 ++++++++--- .../newview/tests/alscriptnavigation_test.cpp | 145 +- .../tests/alscriptobjectcheck_test.cpp | 159 +- .../tests/alscriptoutlinepane_test.cpp | 272 +-- .../newview/tests/alscriptoutputpane_test.cpp | 368 ++-- .../tests/alscriptproblemspane_test.cpp | 607 ++++--- .../newview/tests/alscriptrecompile_test.cpp | 232 ++- .../tests/alscriptreferencespane_test.cpp | 279 +-- .../tests/alscriptregionusage_test.cpp | 196 ++- indra/newview/tests/alscriptsaveflow_test.cpp | 280 +-- .../newview/tests/alscriptsearchpane_test.cpp | 364 ++-- indra/newview/tests/alscriptsnippets_test.cpp | 264 ++- .../tests/alscriptstudioaccount_test.cpp | 57 +- .../tests/alscriptstudiocaret_test.cpp | 334 ++-- .../tests/alscriptstudiochecking_test.cpp | 1052 ++++++++---- .../tests/alscriptstudiocommands_test.cpp | 128 +- .../tests/alscriptstudiocomparepairs_test.cpp | 98 +- .../tests/alscriptstudiocomparewith_test.cpp | 254 +-- .../newview/tests/alscriptstudiodoc_test.cpp | 330 ++-- .../alscriptstudioexpandedcompare_test.cpp | 180 +- .../tests/alscriptstudiofiles_test.cpp | 389 +++-- .../tests/alscriptstudiohistory_test.cpp | 267 +-- .../tests/alscriptstudiomasters_test.cpp | 544 ++++-- .../tests/alscriptstudiomerging_test.cpp | 272 ++- .../tests/alscriptstudioorphans_test.cpp | 521 ++++-- .../tests/alscriptstudiorecovery_test.cpp | 518 ++++-- .../tests/alscriptstudiosaving_test.cpp | 629 ++++--- .../tests/alscriptstudioselections_test.cpp | 152 +- .../newview/tests/alscriptstudiovim_test.cpp | 833 ++++++--- .../tests/alscriptstudioweighing_test.cpp | 294 ++-- .../tests/alscriptstudiowords_test.cpp | 512 ++++-- indra/newview/tests/alscripttheme_test.cpp | 156 +- indra/newview/tests/alscripttypes_test.cpp | 73 +- .../tests/alscriptweightspane_test.cpp | 340 ++-- .../tests/alselectionoutline_gl_test.cpp | 1502 +++++++++++------ .../tests/alterrainsurfacemaps_test.cpp | 208 ++- indra/newview/tests/altexturetable_test.cpp | 404 +++-- .../tests/alwhitebalancesolver_test.cpp | 143 +- indra/newview/tests/cppfeatures_test.cpp | 116 +- indra/newview/tests/llagentaccess_test.cpp | 216 ++- indra/newview/tests/lldateutil_test.cpp | 124 +- .../newview/tests/llhttpretrypolicy_test.cpp | 206 ++- indra/newview/tests/lllogininstance_test.cpp | 87 +- .../tests/llremoteparcelrequest_test.cpp | 21 +- indra/newview/tests/llsecapi_test.cpp | 33 +- .../newview/tests/llsechandler_basic_test.cpp | 565 ++++--- indra/newview/tests/llslurl_test.cpp | 213 ++- indra/newview/tests/lltextureinfo_test.cpp | 91 +- indra/newview/tests/llversioninfo_test.cpp | 51 +- .../newview/tests/llviewerassetstats_test.cpp | 253 +-- .../tests/llviewercontrollistener_test.cpp | 100 +- indra/newview/tests/llviewerhelputil_test.cpp | 42 +- indra/newview/tests/llviewernetwork_test.cpp | 292 ++-- indra/newview/tests/llvocache_test.cpp | 434 ++--- indra/newview/tests/llworldmap_test.cpp | 321 ++-- indra/newview/tests/llworldmipmap_test.cpp | 54 +- indra/newview/tests/lutcube_test.cpp | 150 +- indra/newview/tests/noise_test.cpp | 57 +- 86 files changed, 15996 insertions(+), 9615 deletions(-) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 009fcb1520..a80d3dff3f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2217,8 +2217,7 @@ if(AL_BUILD_VIEWER) # The bundle's localised strings carry the version. file(READ "${CMAKE_CURRENT_SOURCE_DIR}/English.lproj/InfoPlist.strings" infoplist_strings) string( - REPLACE - "%%VERSION%%" + REPLACE "%%VERSION%%" "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}" infoplist_strings "${infoplist_strings}" @@ -2450,47 +2449,7 @@ if(AL_BUILD_TESTS) lllogin ) set(test_project ${AL_VIEWER_BINARY_NAME}) - - # What Script Studio's tests have in common -- a tab, its save's flow, a - # notecard's items, the places and words, the account's recovery, and - # the units a unit under test is given -- - # built once for all of them, rather than once in each. Static: a test - # takes only the objects it uses, so one that fakes part of them keeps - # its fakes. - add_library( - al_studio_test_common - STATIC - alnotecardembedded.cpp - alrecovery.cpp - alscriptexternaleditor.cpp - alscriptlookup.cpp - alscriptnavigation.cpp - alscriptnoticebar.cpp - alscriptsaveflow.cpp - alscriptstudiodoc.cpp - alscriptstudiofileio.cpp - alscriptstudiofiles.cpp - alscriptstudioorphans.cpp - alscriptstudioplaces.cpp - alscriptstudiorecovery.cpp - alscriptstudioviewer.cpp - alscriptstudioweighing.cpp - alscriptstudiowords.cpp - alscripttypes.cpp - alscriptweightspane.cpp - tests/alscriptstudio_stubs.cpp - ) - get_property(studio_test_includes TARGET ${test_project} PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - target_include_directories( - al_studio_test_common - PRIVATE - ${studio_test_includes} - ${INDRA_SOURCE_DIR}/test - ${INDRA_SOURCE_DIR}/llmath - ${INDRA_SOURCE_DIR}/llui - ) - target_link_libraries(al_studio_test_common PRIVATE al::flags PUBLIC llui alscript ${test_libs}) - set_target_properties(al_studio_test_common PROPERTIES FOLDER "Tests/${test_project}") + get_property(newview_includes TARGET ${test_project} PROPERTY INTERFACE_INCLUDE_DIRECTORIES) # What the tests take of the rest of the viewer, faked once. Objects, which # a test links whole, since what reaches for them is a library the linker @@ -2503,587 +2462,311 @@ if(AL_BUILD_TESTS) add_library(newview_test_settings OBJECT tests/newview_test_settings.cpp) target_link_libraries(newview_test_settings PRIVATE al::flags llxml) set_target_properties(newview_test_settings PROPERTIES FOLDER "Tests/${test_project}") - - # A unit test compiles one viewer source file on its own. Each line is one - # such file and its test under tests/. - foreach( - test - alagentlocationformat - alchattimestamp - alcolorwheelmodel - alcrashreporter - alcurvemodel - aldaycyclelandmarks - alfarplane - alfeedback - algradehistory - almotionpredictor - alsceneexplorerpredicate - alwhitebalancesolver - lldateutil - llviewerhelputil - llversioninfo - llvocache - lutcube - noise - ) - al_add_test(${test} UNIT PROJECT ${test_project} LIBRARIES ${test_libs}) - endforeach() - # A parcel's information handed to its observers and to the URL entries - # that name it: llui's own, rather than stubs of them. - al_add_test( - llremoteparcelrequest - UNIT + # What Script Studio's units call of the rest of the viewer, which no test + # builds: one stand-in each. + add_library(newview_studio_test_stubs OBJECT tests/alscriptstudio_stubs.cpp) + target_include_directories( + newview_studio_test_stubs + PRIVATE ${newview_includes} ${INDRA_SOURCE_DIR}/test ${INDRA_SOURCE_DIR}/llmath + ) + target_link_libraries(newview_studio_test_stubs PRIVATE al::flags llui alscript ${test_libs}) + set_target_properties(newview_studio_test_stubs PROPERTIES FOLDER "Tests/${test_project}") + # The object cache as its test has it: with LL_TEST, which leaves out what + # reads the viewer's settings and the cull. On this object alone, since + # the viewer compiles the same file without it. + add_library(newview_test_llvocache OBJECT llvocache.cpp) + target_include_directories( + newview_test_llvocache + PRIVATE ${newview_includes} ${INDRA_SOURCE_DIR}/llmath + ) + target_compile_definitions(newview_test_llvocache PRIVATE "LL_TEST=llvocache" "LL_TEST_llvocache") + target_link_libraries(newview_test_llvocache PRIVATE al::flags llui ${test_libs}) + set_target_properties(newview_test_llvocache PROPERTIES FOLDER "Tests/${test_project}") + # A viewer texture's boost level, which the world map's tests reach. + add_library(newview_test_viewertexture OBJECT tests/llviewertexture_stub.cpp) + target_include_directories( + newview_test_viewertexture + PRIVATE ${newview_includes} ${INDRA_SOURCE_DIR}/llmath + ) + target_link_libraries(newview_test_viewertexture PRIVATE al::flags llui ${test_libs}) + set_target_properties(newview_test_viewertexture PROPERTIES FOLDER "Tests/${test_project}") + + # The viewer's own code, in one binary, each test file run in a process of + # its own. There is no library of the viewer to link, so each file of it a + # test needs is compiled here, once. The UI is up before the first case, + # as llui's tests have it, from the source tree's skins and fonts. + al_add_test_binary( + newview_tests PROJECT ${test_project} - LIBRARIES newview_test_fakes llui ${test_libs} - ) - # The agent's maturity, read and written through a settings group of each - # test's own. - al_add_test(llagentaccess UNIT PROJECT ${test_project} LIBRARIES llxml ${test_libs}) - # The vectorscope bins on the colour wheels' own chroma plane, so the scope - # data test links the model that defines it rather than keeping a second copy - # of the basis that could drift from it. - al_add_test( - alscopedata + SOURCES + tests/alagentlocationformat_test.cpp + tests/alchattimestamp_test.cpp + tests/alcolorwheelmodel_test.cpp + tests/alcrashreporter_test.cpp + tests/alcurvemodel_test.cpp + tests/aldaycyclelandmarks_test.cpp + tests/alfarplane_test.cpp + tests/alfeedback_test.cpp + tests/alfeedbackoutbox_test.cpp + tests/algradehistory_test.cpp + tests/almotionpredictor_test.cpp + tests/alnotecardembedded_test.cpp + tests/alrecoverykeeper_test.cpp + tests/alsceneexplorerpredicate_test.cpp + tests/alscopedata_test.cpp + tests/alscriptanalysislane_test.cpp + tests/alscriptanalyzers_test.cpp + tests/alscriptcontentsindex_test.cpp + tests/alscriptcrumbsbar_test.cpp + tests/alscriptexplorermodel_test.cpp + tests/alscriptexplorertree_test.cpp + tests/alscriptexternaleditor_test.cpp + tests/alscriptinspectorpane_test.cpp + tests/alscriptitemdrop_test.cpp + tests/alscriptjobqueue_test.cpp + tests/alscriptkeymap_test.cpp + tests/alscriptlookup_test.cpp + tests/alscriptnavigation_test.cpp + tests/alscriptobjectcheck_test.cpp + tests/alscriptoutlinepane_test.cpp + tests/alscriptoutputpane_test.cpp + tests/alscriptproblemspane_test.cpp + tests/alscriptrecompile_test.cpp + tests/alscriptreferencespane_test.cpp + tests/alscriptregionusage_test.cpp + tests/alscriptsaveflow_test.cpp + tests/alscriptsearchpane_test.cpp + tests/alscriptsnippets_test.cpp + tests/alscriptstudioaccount_test.cpp + tests/alscriptstudiocaret_test.cpp + tests/alscriptstudiochecking_test.cpp + tests/alscriptstudiocommands_test.cpp + tests/alscriptstudiocomparepairs_test.cpp + tests/alscriptstudiocomparewith_test.cpp + tests/alscriptstudiodoc_test.cpp + tests/alscriptstudioexpandedcompare_test.cpp + tests/alscriptstudiofiles_test.cpp + tests/alscriptstudiohistory_test.cpp + tests/alscriptstudiomasters_test.cpp + tests/alscriptstudiomerging_test.cpp + tests/alscriptstudioorphans_test.cpp + tests/alscriptstudiorecovery_test.cpp + tests/alscriptstudiosaving_test.cpp + tests/alscriptstudioselections_test.cpp + tests/alscriptstudiovim_test.cpp + tests/alscriptstudioweighing_test.cpp + tests/alscriptstudiowords_test.cpp + tests/alscripttheme_test.cpp + tests/alscripttypes_test.cpp + tests/alscriptweightspane_test.cpp + tests/alterrainsurfacemaps_test.cpp + tests/altexturetable_test.cpp + tests/alwhitebalancesolver_test.cpp + tests/cppfeatures_test.cpp + tests/llagentaccess_test.cpp + tests/llhttpretrypolicy_test.cpp + tests/llversioninfo_test.cpp + tests/llviewerassetstats_test.cpp + tests/llviewercontrollistener_test.cpp + tests/llvocache_test.cpp + tests/lutcube_test.cpp + tests/noise_test.cpp UNIT + alagentlocationformat.cpp + alchattimestamp.cpp + alcolorwheelmodel.cpp + alcrashreporter.cpp + alcurvemodel.cpp + aldaycyclelandmarks.cpp + alfarplane.cpp + alfeedback.cpp + alfeedbackoutbox.cpp + algradehistory.cpp + almotionpredictor.cpp + alnotecardembedded.cpp + alrecovery.cpp + alrecoverykeeper.cpp + alsceneexplorerpredicate.cpp + alscopedata.cpp + alscriptanalysislane.cpp + alscriptanalyzers.cpp + alscriptcontentsindex.cpp + alscriptcrumbsbar.cpp + alscriptexplorermodel.cpp + alscriptexplorertree.cpp + alscriptexternaleditor.cpp + alscriptinspectorpane.cpp + alscriptitemdrop.cpp + alscriptkeymap.cpp + alscriptkeypresets.cpp + alscriptlookup.cpp + alscriptnavigation.cpp + alscriptnoticebar.cpp + alscriptobjectcheck.cpp + alscriptoutlinepane.cpp + alscriptoutputpane.cpp + alscriptproblemspane.cpp + alscriptrecompile.cpp + alscriptreferencespane.cpp + alscriptregionusage.cpp + alscriptsaveflow.cpp + alscriptsearch.cpp + alscriptsearchpane.cpp + alscriptsnippets.cpp + alscriptstudioaccount.cpp + alscriptstudiocaret.cpp + alscriptstudiochecking.cpp + alscriptstudiocommands.cpp + alscriptstudiocomparepairs.cpp + alscriptstudiocomparewith.cpp + alscriptstudiodoc.cpp + alscriptstudioexpandedcompare.cpp + alscriptstudiofileio.cpp + alscriptstudiofiles.cpp + alscriptstudiohistory.cpp + alscriptstudiomasters.cpp + alscriptstudiomerging.cpp + alscriptstudioorphans.cpp + alscriptstudioplaces.cpp + alscriptstudiorecovery.cpp + alscriptstudiosaving.cpp + alscriptstudioselections.cpp + alscriptstudioviewer.cpp + alscriptstudiovim.cpp + alscriptstudioweighing.cpp + alscriptstudiowords.cpp + alscripttheme.cpp + alscripttypes.cpp + alscriptweightspane.cpp + alwhitebalancesolver.cpp + llagentaccess.cpp + llhttpretrypolicy.cpp + llversioninfo.cpp + llviewerassetstats.cpp + llviewercontrollistener.cpp + lutcube.cpp + noise.cpp + LIBRARIES llui alscript ll::slua llxml ${test_libs} + SUPPORT + newview_test_fakes + newview_test_settings + newview_studio_test_stubs + newview_test_llvocache + DEFINES + "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" + "AL_LSL_DEFINITIONS_DIR=\"${LSL_DEFINITIONS_DIR}\"" + ) + + # The selection outline's id and edge passes, and the window's depth under + # the HUD, the viewer's own shader files read from the source tree, on + # llrender's shared hidden window. + al_add_test_binary( + newview_gl_tests PROJECT ${test_project} - LIBRARIES ${test_libs} - SOURCES alcolorwheelmodel.cpp - ) - # The selection outline's id and edge passes, the viewer's own shader files - # read from the source tree, on LLWindowManager's hidden window. - al_add_test( - alselectionoutline_gl - GL - PROJECT ${test_project} + SOURCES tests/alhuddepth_gl_test.cpp tests/alselectionoutline_gl_test.cpp LIBRARIES llrender INCLUDES ${INDRA_SOURCE_DIR}/llprimitive DEFINES "AL_TEST_SHADER_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/app_settings/shaders\"" - ) - # The window's depth under the HUD: cleared in the HUD's rects, then the - # scene's written back with the viewer's own copy shader. - al_add_test( - alhuddepth_gl GL - PROJECT ${test_project} - LIBRARIES llrender - DEFINES "AL_TEST_SHADER_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/app_settings/shaders\"" ) - # The outbox keeps what the pure feedback code makes. - al_add_test( - alfeedbackoutbox - UNIT - PROJECT ${test_project} - LIBRARIES ${test_libs} - SOURCES alfeedback.cpp - ) - al_add_test( - lllogininstance - UNIT - PROJECT ${test_project} - LIBRARIES ${test_libs} - SOURCES llversioninfo.cpp - ) - al_add_test( - llworldmap - UNIT + + # Linden's tests that stand in for parts of the viewer, llui and llxml by + # hand, each in its own way, so that no two could share a binary: a + # binary each, until one set of fakes replaces their stubs. Most take + # llui's headers, which the viewer's precompiled header names, without its + # library, whose code they stub. + set(llui_headers $) + al_add_test_binary( + lldateutil_test PROJECT ${test_project} + SOURCES tests/lldateutil_test.cpp + UNIT lldateutil.cpp LIBRARIES ${test_libs} - SOURCES tests/llviewertexture_stub.cpp + INCLUDES ${llui_headers} ) - al_add_test( - llworldmipmap - UNIT + al_add_test_binary( + lllogininstance_test PROJECT ${test_project} + SOURCES tests/lllogininstance_test.cpp + UNIT lllogininstance.cpp llversioninfo.cpp LIBRARIES ${test_libs} - SOURCES tests/llviewertexture_stub.cpp - ) - - # An inventory item dropped on a script: its name or its key, over the - # studio's own window. - al_add_test( - alscriptitemdrop - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # A notecard's items in its text, over a fake of the viewer's side. - al_add_test( - alnotecardembedded - UNIT - PROJECT ${test_project} - LIBRARIES newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # What each prim holds, as one index for every studio window, over a - # fake of the world. - al_add_test( - alscriptcontentsindex - UNIT - PROJECT ${test_project} - LIBRARIES llui alscript ${test_libs} - ) - - # What the region reserves for the objects in hand, the world faked: the - # answers read, each object asked once a minute, the attachments at once. - al_add_test(alscriptregionusage UNIT PROJECT ${test_project} LIBRARIES llui alscript ${test_libs}) - - # What the Script Studio's explorer lists, and the rows it makes of them, - # with nothing of the world. - al_add_test( - alscriptexplorermodel - UNIT - PROJECT ${test_project} - LIBRARIES newview_test_fakes llui alscript ${test_libs} - SOURCES alscriptcontentsindex.cpp - ) - - # The explorer's rows shown as the inventory's folder view, from the source - # tree's skins and fonts. - al_add_test( - alscriptexplorertree - UNIT - PROJECT ${test_project} - LIBRARIES newview_test_fakes llui alscript ${test_libs} - SOURCES alscriptexplorermodel.cpp alscriptcontentsindex.cpp - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # The Script Studio's Output tab over the studio's own window, the - # window's side faked. - al_add_test( - alscriptoutputpane - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # The Script Studio's Problems tab over the studio's own window, the - # window's side faked, and a tab's problems gathered for it. - al_add_test( - alscriptproblemspane - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # The Script Studio's Search tab over the studio's own window, the - # window's side faked; and what Replace All does with a script found. - al_add_test( - alscriptsearchpane - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - SOURCES alscriptsearch.cpp - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # A window's unsaved text kept in a recovery store of the test's. - al_add_test( - alrecoverykeeper - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - ) - - # A Script Studio window's saves kept in a history of the test's, listed, - # compared and put back over tabs of their own editors. - al_add_test( - alscriptstudiohistory - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # A Script Studio window's Compare With over tabs of their own editors: - # what a tab is offered, and each kind of thing chosen set beside it. - al_add_test( - alscriptstudiocomparewith - UNIT - PROJECT ${test_project} - SOURCES alscriptstudiohistory.cpp - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # A Script Studio window's comparison lined up by its texts' functions, - # over tabs of their own editors: each text's outline asked for as it is - # another, and the two paired. - al_add_test( - alscriptstudiocomparepairs - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # A Script Studio window's source beside what a save sends of it, lined - # up by the preprocessor's map, over tabs of their own editors. - al_add_test( - alscriptstudioexpandedcompare - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # A Script Studio window's merges over tabs of their own editors and - # comparisons: begun, settled, and compared where they cannot be. - al_add_test( - alscriptstudiomerging - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # A Script Studio window's selections held and compared, over tabs of - # their own editors and comparisons. - al_add_test( - alscriptstudioselections - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" + INCLUDES ${llui_headers} ) - - # A Script Studio window's unsaved texts kept in a recovery store of the - # test's, and taken up again over tabs of their own editors. - al_add_test( - alscriptstudiorecovery - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # The scripter's snippets: the shipped and their own, read, written and - # kept whole on disk. - al_add_test( - alscriptsnippets - UNIT + # A parcel's information handed to its observers and to the URL entries + # that name it: llui's own, rather than stubs of them. + al_add_test_binary( + llremoteparcelrequest_test PROJECT ${test_project} + SOURCES tests/llremoteparcelrequest_test.cpp + UNIT llremoteparcelrequest.cpp LIBRARIES llui ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's themes: their colours, the shipped ones legible, and - # every skin's script colours read against what they are drawn on. - al_add_test( - alscripttheme - UNIT - PROJECT ${test_project} - LIBRARIES newview_test_fakes llui ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # The Script Studio's commands by name, with nothing of the window. - al_add_test(alscriptstudiocommands UNIT PROJECT ${test_project} LIBRARIES ${test_libs}) - - # Script Studio's keys: the editors' keymap and the menus' keys, with a - # person's changes over them in a setting of the test's. - al_add_test( - alscriptkeymap - UNIT - PROJECT ${test_project} - SOURCES alscriptkeypresets.cpp - LIBRARIES newview_test_fakes newview_test_settings llui ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Whole saves of a Script Studio tab through where they stand and where - # they go, with nothing of the viewer. - al_add_test(alscriptsaveflow UNIT PROJECT ${test_project} LIBRARIES llui alscript ${test_libs}) - - # Whole saves of Script Studio tabs done -- tidied, checked, preprocessed, - # sent, answered -- over the window's side faked. - al_add_test( - alscriptstudiosaving - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's files on disk, over the window's side faked: languages, - # the recent lists, writing, changes outside, loading, Save As. - al_add_test( - alscriptstudiofiles - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # A Script Studio window's side of scripts mastered by files on disk, over - # the window's side faked and the account's links held in memory: what may - # be linked, a tab linked and what was typed in it, and a tab giving way - # to its file. - al_add_test( - alscriptstudiomasters - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # What of Script Studio's state is an account's own, kept apart from the - # shared and put back over it. - al_add_test(alscriptstudioaccount UNIT PROJECT ${test_project} LIBRARIES ${test_libs}) - - # Script Studio's navigation: the history of places, back and forward, - # and previews opened as a list is walked. - al_add_test( - alscriptnavigation - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's lookups across scripts, the window's side and the - # preprocessor's names faked: the fan-out, answers dropped, renames. - al_add_test( - alscriptlookup - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # The Script Studio's References tab over the studio's own window, the - # window's side faked: listed, slid with edits, chosen, sorted. - al_add_test( - alscriptreferencespane - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's outline over the studio's own window, the window's - # side faked: the tree, folds, the filter, sorting, the caret followed. - al_add_test( - alscriptoutlinepane - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's bar under the editor over the studio's own window, the - # window's side faked: the path of symbols, the trailer's parts, a step. - al_add_test( - alscriptcrumbsbar - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's inspector over the studio's own window, the window's - # side faked: a name's declaration, words and page, and the problems. - al_add_test( - alscriptinspectorpane - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's name at the caret, the window's side faked: definitions - # gone to, references read back and asked for, the caret watched. - al_add_test( - alscriptstudiocaret - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # What waits for the script analysis thread: the latest of each kind - # about each script, by rank, a stale text passed over. - al_add_test(alscriptjobqueue PROJECT ${test_project} LIBRARIES llcommon) - - # One engine's analysis thread, over analyzers made to wait: a long - # check on one lane holding nothing of the other's, and another tab's - # check giving way to a question of the tab in front. - al_add_test( - alscriptanalysislane - UNIT - PROJECT ${test_project} - LIBRARIES alscript llui ll::slua ${test_libs} - ) - - # Each language's analyzer, asked as the analysis thread asks it, over - # the grid's own definitions. - al_add_test( - alscriptanalyzers - UNIT - PROJECT ${test_project} - LIBRARIES newview_test_fakes alscript llui ${test_libs} - DEFINES "AL_LSL_DEFINITIONS_DIR=\"${LSL_DEFINITIONS_DIR}\"" - ) - - # Script Studio's checking, the window's side and the viewer's sources - # faked: checks due and answered, expansions, imports, lints, fixes. - al_add_test( - alscriptstudiochecking - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # A check of every script of an object, the window and the world faked: - # the open ones left to their tabs, the rest read, expanded and asked. - al_add_test( - alscriptobjectcheck - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - SOURCES alscriptstudiochecking.cpp - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # A compile's result read back to the source it was of: under the - # envelope's lines, through the expansion's map. - al_add_test(alscripttypes UNIT PROJECT ${test_project} LIBRARIES alscript ${test_libs}) - - # A recompile from the Explorer, the window and the world faked: scripts - # and prims walked a few at a time, each said, a closed one's problems - # read back through its expansion. - al_add_test( - alscriptrecompile - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's orphans, the world's reach faked: what a tab has become, - # the check, reattaching, and the notice over the editor with its bar. - al_add_test( - alscriptstudioorphans - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's words: the vocabulary from definitions a test gives, - # editors taught it, hovers, completions, the Insert menu, the reference. - al_add_test( - alscriptstudiowords - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's weighing, over the window's side and the analyzers - # faked: targets, answers, what a save sends, notes and heat, fixes. - al_add_test( - alscriptstudioweighing - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's tabs held open in an editor outside, over the window's - # side faked: the copy, its saves taken or held, the log, letting go. - al_add_test( - alscriptexternaleditor - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # Script Studio's side of vim over the window's commands and its side - # faked: the : commands, :set, :history, q:, = and the banner. - al_add_test( - alscriptstudiovim - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - SOURCES alscriptstudiocommands.cpp - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" - ) - - # A Script Studio tab's own logic, and the fake of the window's services - # the units split out of the window are tested with. - al_add_test( - alscriptstudiodoc - UNIT - PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" + SUPPORT newview_test_fakes ) - - # The Script Studio's Weights tab over the studio's own window, from the - # source tree's skins and fonts as llui's widget tests have them. - al_add_test( - alscriptweightspane - UNIT + al_add_test_binary( + llsecapi_test PROJECT ${test_project} - LIBRARIES al_studio_test_common newview_test_fakes llui alscript ${test_libs} - DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" + SOURCES tests/llsecapi_test.cpp + UNIT llsecapi.cpp + LIBRARIES ${test_libs} + INCLUDES ${llui_headers} ) - - al_add_test(cppfeatures PROJECT ${test_project} LIBRARIES ${test_libs}) - al_add_test(altexturetable PROJECT ${test_project} LIBRARIES ${test_libs}) - # The map layout and the neighbour walk are inline in the header; the GL - # and surface side stays out of the test. - al_add_test(alterrainsurfacemaps PROJECT ${test_project} LIBRARIES ${test_libs}) - al_add_test( - llsechandler_basic + al_add_test_binary( + llsechandler_basic_test PROJECT ${test_project} + SOURCES tests/llsechandler_basic_test.cpp + UNIT llsechandler_basic.cpp LIBRARIES ${test_libs} - SOURCES llsechandler_basic.cpp + INCLUDES ${llui_headers} ) - al_add_test(llsecapi PROJECT ${test_project} LIBRARIES ${test_libs} SOURCES llsecapi.cpp) - al_add_test( - llslurl + al_add_test_binary( + llslurl_test PROJECT ${test_project} + SOURCES tests/llslurl_test.cpp + UNIT llslurl.cpp llviewernetwork.cpp LIBRARIES ${test_libs} - SOURCES llslurl.cpp llviewernetwork.cpp + INCLUDES ${llui_headers} ) - al_add_test( - llviewercontrollistener + al_add_test_binary( + lltextureinfo_test PROJECT ${test_project} + SOURCES tests/lltextureinfo_test.cpp + UNIT lltextureinfo.cpp LIBRARIES llxml ${test_libs} - SOURCES llviewercontrollistener.cpp + SUPPORT newview_test_settings + INCLUDES ${llui_headers} ) - al_add_test( - llviewernetwork + al_add_test_binary( + llviewerhelputil_test PROJECT ${test_project} + SOURCES tests/llviewerhelputil_test.cpp + UNIT llviewerhelputil.cpp LIBRARIES ${test_libs} - SOURCES llviewernetwork.cpp + INCLUDES ${llui_headers} ) - al_add_test( - llviewerassetstats + al_add_test_binary( + llviewernetwork_test PROJECT ${test_project} + SOURCES tests/llviewernetwork_test.cpp + UNIT llviewernetwork.cpp LIBRARIES ${test_libs} - SOURCES llviewerassetstats.cpp + INCLUDES ${llui_headers} ) - al_add_test( - llhttpretrypolicy + al_add_test_binary( + llworldmap_test PROJECT ${test_project} + SOURCES tests/llworldmap_test.cpp + UNIT llworldmap.cpp LIBRARIES ${test_libs} - SOURCES llhttpretrypolicy.cpp + SUPPORT newview_test_viewertexture + INCLUDES ${llui_headers} ) - al_add_test( - lltextureinfo + al_add_test_binary( + llworldmipmap_test PROJECT ${test_project} - LIBRARIES newview_test_settings llxml ${test_libs} - SOURCES lltextureinfo.cpp + SOURCES tests/llworldmipmap_test.cpp + UNIT llworldmipmap.cpp + LIBRARIES ${test_libs} + SUPPORT newview_test_viewertexture + INCLUDES ${llui_headers} ) endif() diff --git a/indra/newview/tests/alagentlocationformat_test.cpp b/indra/newview/tests/alagentlocationformat_test.cpp index e932ac6bda..1121e50b63 100644 --- a/indra/newview/tests/alagentlocationformat_test.cpp +++ b/indra/newview/tests/alagentlocationformat_test.cpp @@ -26,9 +26,9 @@ #include "../alagentlocationformat.h" -#include "../test/lltut.h" +#include -namespace tut +namespace { struct alagentlocationformat_data { @@ -52,135 +52,122 @@ namespace tut return out; } }; - typedef test_group factory; - typedef factory::object object; } namespace -{ - tut::factory tf("ALAgentLocationFormat"); -} - -namespace tut { // A parcel with a name is what most of these show. - template<> template<> - void object::test<1>() + TEST_CASE_METHOD(alagentlocationformat_data, "ALAgentLocationFormat: what each format shows of a named parcel", "[ALAgentLocationFormat]") { - ensure_equals("NORMAL is the parcel and the region", - named(LLAgentUI::LOCATION_FORMAT_NORMAL), + UNSCOPED_INFO("NORMAL is the parcel and the region"); + CHECK(named(LLAgentUI::LOCATION_FORMAT_NORMAL) == std::string("Ye Olde Parcel, Hippotropolis")); - ensure_equals("NORMAL_COORDS is the parcel and the position, no region", - named(LLAgentUI::LOCATION_FORMAT_NORMAL_COORDS), + UNSCOPED_INFO("NORMAL_COORDS is the parcel and the position, no region"); + CHECK(named(LLAgentUI::LOCATION_FORMAT_NORMAL_COORDS) == std::string("Ye Olde Parcel (128, 64, 22)")); - ensure_equals("LANDMARK is the parcel alone", - named(LLAgentUI::LOCATION_FORMAT_LANDMARK), + UNSCOPED_INFO("LANDMARK is the parcel alone"); + CHECK(named(LLAgentUI::LOCATION_FORMAT_LANDMARK) == std::string("Ye Olde Parcel")); - ensure_equals("NO_MATURITY is everything but the rating", - named(LLAgentUI::LOCATION_FORMAT_NO_MATURITY), + UNSCOPED_INFO("NO_MATURITY is everything but the rating"); + CHECK(named(LLAgentUI::LOCATION_FORMAT_NO_MATURITY) == std::string("Ye Olde Parcel, Hippotropolis (128, 64, 22)")); - ensure_equals("NO_COORDS is everything but the position", - named(LLAgentUI::LOCATION_FORMAT_NO_COORDS), + UNSCOPED_INFO("NO_COORDS is everything but the position"); + CHECK(named(LLAgentUI::LOCATION_FORMAT_NO_COORDS) == std::string("Ye Olde Parcel, Hippotropolis - Adult")); - ensure_equals("FULL is everything", - named(LLAgentUI::LOCATION_FORMAT_FULL), + UNSCOPED_INFO("FULL is everything"); + CHECK(named(LLAgentUI::LOCATION_FORMAT_FULL) == std::string("Ye Olde Parcel, Hippotropolis (128, 64, 22) - Adult")); } // An unnamed parcel drops out entirely rather than leaving its comma // behind, and the region takes its place. - template<> template<> - void object::test<2>() + TEST_CASE_METHOD(alagentlocationformat_data, "ALAgentLocationFormat: an unnamed parcel drops out and the region takes its place", "[ALAgentLocationFormat]") { - ensure_equals("NORMAL falls back to the region", - unnamed(LLAgentUI::LOCATION_FORMAT_NORMAL), + UNSCOPED_INFO("NORMAL falls back to the region"); + CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_NORMAL) == std::string("Hippotropolis")); - ensure_equals("NORMAL_COORDS falls back to the region", - unnamed(LLAgentUI::LOCATION_FORMAT_NORMAL_COORDS), + UNSCOPED_INFO("NORMAL_COORDS falls back to the region"); + CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_NORMAL_COORDS) == std::string("Hippotropolis (128, 64, 22)")); - ensure_equals("LANDMARK falls back to the region", - unnamed(LLAgentUI::LOCATION_FORMAT_LANDMARK), + UNSCOPED_INFO("LANDMARK falls back to the region"); + CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_LANDMARK) == std::string("Hippotropolis")); // The one place the two branches agree on the answer but reach it // differently: with no parcel to name, NO_MATURITY has nothing left to // distinguish it from NORMAL_COORDS. - ensure_equals("NO_MATURITY falls back to the region", - unnamed(LLAgentUI::LOCATION_FORMAT_NO_MATURITY), + UNSCOPED_INFO("NO_MATURITY falls back to the region"); + CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_NO_MATURITY) == std::string("Hippotropolis (128, 64, 22)")); - ensure_equals("NO_COORDS falls back to the region", - unnamed(LLAgentUI::LOCATION_FORMAT_NO_COORDS), + UNSCOPED_INFO("NO_COORDS falls back to the region"); + CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_NO_COORDS) == std::string("Hippotropolis - Adult")); - ensure_equals("FULL falls back to the region", - unnamed(LLAgentUI::LOCATION_FORMAT_FULL), + UNSCOPED_INFO("FULL falls back to the region"); + CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_FULL) == std::string("Hippotropolis (128, 64, 22) - Adult")); } // No rating means no separator either, in both branches. A trailing " - " // is what forgetting this looks like. - template<> template<> - void object::test<3>() + TEST_CASE_METHOD(alagentlocationformat_data, "ALAgentLocationFormat: no rating leaves no separator for named or unnamed parcels", "[ALAgentLocationFormat]") { - ensure_equals("a named parcel with no rating has no separator", - named(LLAgentUI::LOCATION_FORMAT_NO_COORDS, ""), + UNSCOPED_INFO("a named parcel with no rating has no separator"); + CHECK(named(LLAgentUI::LOCATION_FORMAT_NO_COORDS, "") == std::string("Ye Olde Parcel, Hippotropolis")); - ensure_equals("nor does FULL", - named(LLAgentUI::LOCATION_FORMAT_FULL, ""), + UNSCOPED_INFO("nor does FULL"); + CHECK(named(LLAgentUI::LOCATION_FORMAT_FULL, "") == std::string("Ye Olde Parcel, Hippotropolis (128, 64, 22)")); - ensure_equals("nor does an unnamed parcel", - unnamed(LLAgentUI::LOCATION_FORMAT_NO_COORDS, ""), + UNSCOPED_INFO("nor does an unnamed parcel"); + CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_NO_COORDS, "") == std::string("Hippotropolis")); - ensure_equals("nor unnamed FULL", - unnamed(LLAgentUI::LOCATION_FORMAT_FULL, ""), + UNSCOPED_INFO("nor unnamed FULL"); + CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_FULL, "") == std::string("Hippotropolis (128, 64, 22)")); } // Negative and multi-digit coordinates reach the string intact. The // position is signed, and a region's Z runs well past three digits. - template<> template<> - void object::test<4>() + TEST_CASE_METHOD(alagentlocationformat_data, "ALAgentLocationFormat: negative and multi-digit coordinates reach the string intact", "[ALAgentLocationFormat]") { ALAgentLocationFormat::format(out, LLAgentUI::LOCATION_FORMAT_FULL, "Parcel", "Region", "General", -4, 0, 4096); - ensure_equals("negative and large coordinates survive", - out, std::string("Parcel, Region (-4, 0, 4096) - General")); + UNSCOPED_INFO("negative and large coordinates survive"); + CHECK(out == std::string("Parcel, Region (-4, 0, 4096) - General")); } // The buffer is cleared, not appended to. Callers keep it between rebuilds // for its capacity, and a formatter that appended would grow it forever. - template<> template<> - void object::test<5>() + TEST_CASE_METHOD(alagentlocationformat_data, "ALAgentLocationFormat: the buffer is cleared rather than appended to", "[ALAgentLocationFormat]") { out = "left over from last time"; - ensure_equals("the previous answer is gone", - named(LLAgentUI::LOCATION_FORMAT_NORMAL), + UNSCOPED_INFO("the previous answer is gone"); + CHECK(named(LLAgentUI::LOCATION_FORMAT_NORMAL) == std::string("Ye Olde Parcel, Hippotropolis")); // Including on the assigning branches, which do not go through the // formatter's sink at all. out = "left over from last time"; - ensure_equals("including where the name is assigned whole", - named(LLAgentUI::LOCATION_FORMAT_LANDMARK), + UNSCOPED_INFO("including where the name is assigned whole"); + CHECK(named(LLAgentUI::LOCATION_FORMAT_LANDMARK) == std::string("Ye Olde Parcel")); } // A landmark name is cut at LANDMARK_NAME_MAX_BYTES, and on a character // boundary. The printf this replaced used "%.100s", which counts bytes and // will cut a multi-byte character in half. - template<> template<> - void object::test<6>() + TEST_CASE_METHOD(alagentlocationformat_data, "ALAgentLocationFormat: LANDMARK cuts a long name on a character boundary", "[ALAgentLocationFormat]") { // 33 three-byte characters is 99 bytes; a 34th would straddle the // hundredth. A byte-counting truncation keeps one byte of it. @@ -189,48 +176,48 @@ namespace tut { wide += "\xe6\x97\xa5"; // U+65E5 } - ensure_equals("the fixture is three bytes per character", - wide.size(), std::size_t(120)); + UNSCOPED_INFO("the fixture is three bytes per character"); + REQUIRE(wide.size() == std::size_t(120)); ALAgentLocationFormat::format(out, LLAgentUI::LOCATION_FORMAT_LANDMARK, wide, "Region", "", 0, 0, 0); - ensure_equals("cut on the character before the limit, not across it", - out.size(), std::size_t(99)); - ensure_equals("and it is whole characters", - out, wide.substr(0, 99)); + UNSCOPED_INFO("cut on the character before the limit, not across it"); + REQUIRE(out.size() == std::size_t(99)); + UNSCOPED_INFO("and it is whole characters"); + CHECK(out == wide.substr(0, 99)); // The region branch takes the same rule. ALAgentLocationFormat::format(out, LLAgentUI::LOCATION_FORMAT_LANDMARK, "", wide, "", 0, 0, 0); - ensure_equals("the unnamed-parcel branch truncates too", - out.size(), std::size_t(99)); + UNSCOPED_INFO("the unnamed-parcel branch truncates too"); + REQUIRE(out.size() == std::size_t(99)); } // A name shorter than the limit is not touched, and a name whose bytes // land exactly on it keeps all of them. - template<> template<> - void object::test<7>() + TEST_CASE_METHOD(alagentlocationformat_data, "ALAgentLocationFormat: a name at or under the byte limit is kept whole", "[ALAgentLocationFormat]") { ALAgentLocationFormat::format(out, LLAgentUI::LOCATION_FORMAT_LANDMARK, "Short", "Region", "", 0, 0, 0); - ensure_equals("a short name is left alone", out, std::string("Short")); + UNSCOPED_INFO("a short name is left alone"); + CHECK(out == std::string("Short")); const std::string exact(ALAgentLocationFormat::LANDMARK_NAME_MAX_BYTES, 'x'); ALAgentLocationFormat::format(out, LLAgentUI::LOCATION_FORMAT_LANDMARK, exact, "Region", "", 0, 0, 0); - ensure_equals("a name exactly at the limit keeps every byte", out, exact); + UNSCOPED_INFO("a name exactly at the limit keeps every byte"); + CHECK(out == exact); } // Only LANDMARK truncates. A long parcel name is shown in full everywhere // else, because everywhere else is a readout rather than an asset name. - template<> template<> - void object::test<8>() + TEST_CASE_METHOD(alagentlocationformat_data, "ALAgentLocationFormat: only LANDMARK truncates a long parcel name", "[ALAgentLocationFormat]") { const std::string long_name(200, 'y'); ALAgentLocationFormat::format(out, LLAgentUI::LOCATION_FORMAT_NORMAL, long_name, "Region", "", 0, 0, 0); - ensure_equals("NORMAL does not truncate", - out, long_name + ", Region"); + UNSCOPED_INFO("NORMAL does not truncate"); + CHECK(out == long_name + ", Region"); } } diff --git a/indra/newview/tests/alchattimestamp_test.cpp b/indra/newview/tests/alchattimestamp_test.cpp index 29a428df76..5863b56e65 100644 --- a/indra/newview/tests/alchattimestamp_test.cpp +++ b/indra/newview/tests/alchattimestamp_test.cpp @@ -25,20 +25,11 @@ #include "linden_common.h" #include "../alchattimestamp.h" -#include "../test/lltut.h" +#include -namespace tut +namespace { -struct alchattimestamp_data -{ -}; -typedef test_group alchattimestamp_group; -typedef alchattimestamp_group::object alchattimestamp_object; -alchattimestamp_group alchattimestamp_test("alchattimestamp"); - -template<> -template<> -void alchattimestamp_object::test<1>() +TEST_CASE("alchattimestamp: each date and time form is cut with its spacing as the prefix", "[alchattimestamp]") { for (const std::string date : { "", "2026/09/25 ", "2026/9/5 " }) { @@ -50,27 +41,27 @@ void alchattimestamp_object::test<1>() const std::string message = "Example Resident: text with a colon: and [14:05:09]"; const std::string line = prefix + message; const size_t length = ALChatTimestamp::prefixLength(line); - ensure_equals("timestamp recognized: " + prefix, length, prefix.size()); - ensure_equals("message preserved", line.substr(length), message); + UNSCOPED_INFO("timestamp recognized: " + prefix); + REQUIRE(length == prefix.size()); + UNSCOPED_INFO("message preserved"); + REQUIRE(line.substr(length) == message); } } } } -template<> -template<> -void alchattimestamp_object::test<2>() +TEST_CASE("alchattimestamp: a timestamp without seconds is left as it is", "[alchattimestamp]") { for (const std::string timestamp : { "14:05", "2:05 PM", "2026/09/25 14:05", "2026/09/25 2:05 pm", "" }) { - ensure_equals("missing seconds stay missing", ALChatTimestamp::format(timestamp, true), timestamp); - ensure_equals("minute display stays unchanged", ALChatTimestamp::format(timestamp, false), timestamp); + UNSCOPED_INFO("missing seconds stay missing"); + REQUIRE(ALChatTimestamp::format(timestamp, true) == timestamp); + UNSCOPED_INFO("minute display stays unchanged"); + REQUIRE(ALChatTimestamp::format(timestamp, false) == timestamp); } } -template<> -template<> -void alchattimestamp_object::test<3>() +TEST_CASE("alchattimestamp: recorded seconds are shown or hidden without moving the minute", "[alchattimestamp]") { for (const std::string date : { "", "2026/09/25 " }) { @@ -81,25 +72,29 @@ void alchattimestamp_object::test<3>() { const std::string minutes = date + "2:05" + suffix; const std::string timestamp = date + "2:05" + seconds + suffix; - ensure_equals("recorded seconds retained", ALChatTimestamp::format(timestamp, true), timestamp); - ensure_equals("seconds hidden", ALChatTimestamp::format(timestamp, false), minutes); - ensure_equals("mixed logs share a merge minute", ALChatTimestamp::format(timestamp, false), + UNSCOPED_INFO("recorded seconds retained"); + REQUIRE(ALChatTimestamp::format(timestamp, true) == timestamp); + UNSCOPED_INFO("seconds hidden"); + REQUIRE(ALChatTimestamp::format(timestamp, false) == minutes); + UNSCOPED_INFO("mixed logs share a merge minute"); + REQUIRE(ALChatTimestamp::format(timestamp, false) == ALChatTimestamp::format(minutes, false)); } } } } -template<> -template<> -void alchattimestamp_object::test<4>() +TEST_CASE("alchattimestamp: a malformed timestamp is neither cut nor rewritten", "[alchattimestamp]") { for (const std::string line : { "", "Example Resident: hello", "text [14:05:09]", "[14:05:9] hello", "[14:05:091] hello", "[14:05:09 hello" }) { - ensure_equals("not a timestamp prefix: " + line, ALChatTimestamp::prefixLength(line), size_t(0)); + UNSCOPED_INFO("not a timestamp prefix: " + line); + REQUIRE(ALChatTimestamp::prefixLength(line) == size_t(0)); } - ensure_equals("unknown time is not rewritten", ALChatTimestamp::format("unknown:time:00", false), "unknown:time:00"); - ensure_equals("overlong seconds are not rewritten", ALChatTimestamp::format("14:05:091", false), "14:05:091"); + UNSCOPED_INFO("unknown time is not rewritten"); + CHECK(ALChatTimestamp::format("unknown:time:00", false) == "unknown:time:00"); + UNSCOPED_INFO("overlong seconds are not rewritten"); + CHECK(ALChatTimestamp::format("14:05:091", false) == "14:05:091"); } -} // namespace tut +} // anonymous namespace diff --git a/indra/newview/tests/alcolorwheelmodel_test.cpp b/indra/newview/tests/alcolorwheelmodel_test.cpp index a024af121d..ce64454d74 100644 --- a/indra/newview/tests/alcolorwheelmodel_test.cpp +++ b/indra/newview/tests/alcolorwheelmodel_test.cpp @@ -14,13 +14,14 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include +#include "altestmatchers.h" #include "../alcolorwheelmodel.h" #include -namespace tut +namespace { struct wheel_data { @@ -44,55 +45,58 @@ namespace tut } }; - typedef test_group wheel_group; - typedef wheel_group::object wheel_object; - tut::wheel_group wg("ALColorWheelModel"); - // --- the basis itself ---------------------------------------------------- // The whole design rests on {(1,1,1)/sqrt3, u, v} being orthonormal -- that // is what makes the decomposition lossless. A typo in the constants would // show up here and nowhere else obvious. - template<> template<> - void wheel_object::test<1>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: the chroma basis is orthonormal and has no grey in it", "[ALColorWheelModel]") { const LLVector3 u = ALColorWheelModel::chromaDirection(0.f); const LLVector3 v = ALColorWheelModel::chromaDirection(F_PI_BY_TWO); const LLVector3 grey(1.f, 1.f, 1.f); - ensure_approximately_equals("u is unit", u.magVec(), 1.f, 5); - ensure_approximately_equals("v is unit", v.magVec(), 1.f, 5); - ensure_approximately_equals("u and v are perpendicular", u * v, 0.f, 5); - ensure_approximately_equals("u has no achromatic part", u * grey, 0.f, 5); - ensure_approximately_equals("v has no achromatic part", v * grey, 0.f, 5); + UNSCOPED_INFO("u is unit"); + CHECK_THAT(u.magVec(), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("v is unit"); + CHECK_THAT(v.magVec(), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("u and v are perpendicular"); + CHECK_THAT(u * v, ll_test::WithinBits(0.f, 5)); + UNSCOPED_INFO("u has no achromatic part"); + CHECK_THAT(u * grey, ll_test::WithinBits(0.f, 5)); + UNSCOPED_INFO("v has no achromatic part"); + CHECK_THAT(v * grey, ll_test::WithinBits(0.f, 5)); } // Angle lands on the usual colour circle: red at 0, green at 120, blue at 240. - template<> template<> - void wheel_object::test<2>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: toPolar puts the primaries at their usual hues", "[ALColorWheelModel]") { F32 hue, sat; ALColorWheelModel::toPolar(LLVector3(1.f, 0.f, 0.f), hue, sat); - ensure_approximately_equals("pure red is hue 0", angleDelta(hue, deg(0.f)), 0.f, 4); + UNSCOPED_INFO("pure red is hue 0"); + CHECK_THAT(angleDelta(hue, deg(0.f)), ll_test::WithinBits(0.f, 4)); ALColorWheelModel::toPolar(LLVector3(0.f, 1.f, 0.f), hue, sat); - ensure_approximately_equals("pure green is 120", angleDelta(hue, deg(120.f)), 0.f, 4); + UNSCOPED_INFO("pure green is 120"); + CHECK_THAT(angleDelta(hue, deg(120.f)), ll_test::WithinBits(0.f, 4)); ALColorWheelModel::toPolar(LLVector3(0.f, 0.f, 1.f), hue, sat); - ensure_approximately_equals("pure blue is 240", angleDelta(hue, deg(240.f)), 0.f, 4); + UNSCOPED_INFO("pure blue is 240"); + CHECK_THAT(angleDelta(hue, deg(240.f)), ll_test::WithinBits(0.f, 4)); } // A neutral triplet has no chroma, and asking its hue must not produce a // NaN from atan2(0,0) -- the puck would jump the moment it crossed centre. - template<> template<> - void wheel_object::test<3>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: a grey has no saturation and a finite hue", "[ALColorWheelModel]") { F32 hue, sat; for (F32 grey : { -0.4f, 0.f, 0.5f, 1.f }) { ALColorWheelModel::toPolar(LLVector3(grey, grey, grey), hue, sat); - ensure_approximately_equals("no saturation", sat, 0.f, 5); - ensure("hue is finite", std::isfinite(hue)); + UNSCOPED_INFO("no saturation"); + REQUIRE_THAT(sat, ll_test::WithinBits(0.f, 5)); + UNSCOPED_INFO("hue is finite"); + REQUIRE(std::isfinite(hue)); } } @@ -101,8 +105,7 @@ namespace tut // The property everything else depends on: decompose and rebuild returns // the same triplet. If this fails, typing a number and dragging the puck // disagree about the value. - template<> template<> - void wheel_object::test<4>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: decomposing a triplet and rebuilding it returns the same triplet", "[ALColorWheelModel]") { const F32 samples[] = { -0.5f, -0.31f, -0.07f, 0.f, 0.12f, 0.29f, 0.5f }; for (F32 r : samples) @@ -117,17 +120,19 @@ namespace tut const LLVector3 out = ALColorWheelModel::toRGB( ALColorWheelModel::masterOf(in), hue, sat); - ensure_approximately_equals("r round trips", out.mV[VX], in.mV[VX], 5); - ensure_approximately_equals("g round trips", out.mV[VY], in.mV[VY], 5); - ensure_approximately_equals("b round trips", out.mV[VZ], in.mV[VZ], 5); + UNSCOPED_INFO("r round trips"); + REQUIRE_THAT(out.mV[VX], ll_test::WithinBits(in.mV[VX], 5)); + UNSCOPED_INFO("g round trips"); + REQUIRE_THAT(out.mV[VY], ll_test::WithinBits(in.mV[VY], 5)); + UNSCOPED_INFO("b round trips"); + REQUIRE_THAT(out.mV[VZ], ll_test::WithinBits(in.mV[VZ], 5)); } } } } // Round trip through the stored value, which is the path the widget takes. - template<> template<> - void wheel_object::test<5>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: setPolar round trips hue and saturation through the stored value", "[ALColorWheelModel]") { asLift(); for (S32 i = 0; i < 24; ++i) @@ -136,9 +141,12 @@ namespace tut const F32 sat = mWheel.getMaxSat() * 0.6f; mWheel.setPolar(hue, sat); - ensure_approximately_equals("hue survives", angleDelta(mWheel.getHue(), hue), 0.f, 4); - ensure_approximately_equals("saturation survives", mWheel.getSat(), sat, 4); - ensure_approximately_equals("master untouched", mWheel.getMaster(), 0.f, 5); + UNSCOPED_INFO("hue survives"); + REQUIRE_THAT(angleDelta(mWheel.getHue(), hue), ll_test::WithinBits(0.f, 4)); + UNSCOPED_INFO("saturation survives"); + REQUIRE_THAT(mWheel.getSat(), ll_test::WithinBits(sat, 4)); + UNSCOPED_INFO("master untouched"); + REQUIRE_THAT(mWheel.getMaster(), ll_test::WithinBits(0.f, 5)); } } @@ -146,8 +154,7 @@ namespace tut // getMaxSat is the inradius, so a puck on the rim is reachable at EVERY // hue with the master centred -- nothing gets clamped. - template<> template<> - void wheel_object::test<6>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: a puck on the rim is reachable at every hue with the master centred", "[ALColorWheelModel]") { asLift(); const F32 rim = mWheel.getMaxSat(); @@ -155,25 +162,28 @@ namespace tut { const F32 hue = deg((F32)i * 5.f); mWheel.setPolar(hue, rim); - ensure_approximately_equals("rim is reachable at every hue", mWheel.getSat(), rim, 3); - ensure_approximately_equals("and the hue is the one asked for", - angleDelta(mWheel.getHue(), hue), 0.f, 3); + UNSCOPED_INFO("rim is reachable at every hue"); + REQUIRE_THAT(mWheel.getSat(), ll_test::WithinBits(rim, 3)); + UNSCOPED_INFO("and the hue is the one asked for"); + REQUIRE_THAT(angleDelta(mWheel.getHue(), hue), ll_test::WithinBits(0.f, 3)); } } // The inradius is sqrt(1.5) * halfRange, and the tightest directions are // the primaries, where one channel lands exactly on its limit. - template<> template<> - void wheel_object::test<7>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: getMaxSat is the inradius and red on the rim sits on its limit", "[ALColorWheelModel]") { asLift(); - ensure_approximately_equals("inradius", mWheel.getMaxSat(), sqrtf(1.5f) * 0.5f, 4); + UNSCOPED_INFO("inradius"); + CHECK_THAT(mWheel.getMaxSat(), ll_test::WithinBits(sqrtf(1.5f) * 0.5f, 4)); mWheel.setPolar(0.f, mWheel.getMaxSat()); - ensure_approximately_equals("red sits on its limit", mWheel.getRGB().mV[VX], 0.5f, 3); + UNSCOPED_INFO("red sits on its limit"); + CHECK_THAT(mWheel.getRGB().mV[VX], ll_test::WithinBits(0.5f, 3)); asGain(); - ensure_approximately_equals("gain inradius", mWheel.getMaxSat(), sqrtf(1.5f) * 0.5f, 4); + UNSCOPED_INFO("gain inradius"); + CHECK_THAT(mWheel.getMaxSat(), ll_test::WithinBits(sqrtf(1.5f) * 0.5f, 4)); } // Past the rim the channel clamp bites: the value stays legal, and the @@ -194,8 +204,7 @@ namespace tut // Clamping moves the mean, so the result leaves the master-pinned hexagon // and lands on the projection of the whole cube -- the third figure. A // bound of the second is too tight and fails here. - template<> template<> - void wheel_object::test<8>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: past the rim the channel clamp keeps the value legal", "[ALColorWheelModel]") { asLift(); const F32 rim = mWheel.getMaxSat(); @@ -209,32 +218,40 @@ namespace tut const LLVector3& rgb = mWheel.getRGB(); for (S32 c = 0; c < 3; ++c) { - ensure("channel stayed in range", rgb.mV[c] >= -0.5f - 1e-5f && rgb.mV[c] <= 0.5f + 1e-5f); + { + INFO("channel stayed in range"); + REQUIRE(rgb.mV[c] >= -0.5f - 1e-5f); + REQUIRE(rgb.mV[c] <= 0.5f + 1e-5f); + } } - ensure("saturation did not run away", mWheel.getSat() <= widest + 1e-4f); - ensure("but it did move out to the boundary", mWheel.getSat() > rim * 0.9f); + UNSCOPED_INFO("saturation did not run away"); + REQUIRE(mWheel.getSat() <= widest + 1e-4f); + UNSCOPED_INFO("but it did move out to the boundary"); + REQUIRE(mWheel.getSat() > rim * 0.9f); } // Far enough past the rim in a primary direction and the triplet is // pinned to a cube corner, which is exactly the widest case. mWheel.setPolar(0.f, rim * 4.f); - ensure_approximately_equals("corner-pinned saturation", mWheel.getSat(), widest, 4); - ensure_approximately_equals("r on its ceiling", mWheel.getRGB().mV[VX], 0.5f, 5); - ensure_approximately_equals("g on its floor", mWheel.getRGB().mV[VY], -0.5f, 5); + UNSCOPED_INFO("corner-pinned saturation"); + CHECK_THAT(mWheel.getSat(), ll_test::WithinBits(widest, 4)); + UNSCOPED_INFO("r on its ceiling"); + CHECK_THAT(mWheel.getRGB().mV[VX], ll_test::WithinBits(0.5f, 5)); + UNSCOPED_INFO("g on its floor"); + CHECK_THAT(mWheel.getRGB().mV[VY], ll_test::WithinBits(-0.5f, 5)); } // Clamping must not silently rotate the hue -- the puck would slide around // the ring while the user dragged straight outward. - template<> template<> - void wheel_object::test<9>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: clamping past the rim does not rotate the hue", "[ALColorWheelModel]") { asLift(); for (S32 i = 0; i < 12; ++i) { const F32 hue = deg((F32)i * 30.f); mWheel.setPolar(hue, mWheel.getMaxSat() * 3.f); - ensure_approximately_equals("hue held through the clamp", - angleDelta(mWheel.getHue(), hue), 0.f, 3); + UNSCOPED_INFO("hue held through the clamp"); + REQUIRE_THAT(angleDelta(mWheel.getHue(), hue), ll_test::WithinBits(0.f, 3)); } } @@ -242,8 +259,7 @@ namespace tut // Moving the master keeps the chroma, which is what makes the wheel and // its slider feel independent. - template<> template<> - void wheel_object::test<10>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: moving the master keeps the hue and saturation", "[ALColorWheelModel]") { asGain(); mWheel.setPolar(deg(200.f), mWheel.getMaxSat() * 0.4f); @@ -251,40 +267,45 @@ namespace tut const F32 sat = mWheel.getSat(); mWheel.setMaster(1.2f); - ensure_approximately_equals("master moved", mWheel.getMaster(), 1.2f, 4); - ensure_approximately_equals("hue kept", angleDelta(mWheel.getHue(), hue), 0.f, 3); - ensure_approximately_equals("saturation kept", mWheel.getSat(), sat, 3); + UNSCOPED_INFO("master moved"); + CHECK_THAT(mWheel.getMaster(), ll_test::WithinBits(1.2f, 4)); + UNSCOPED_INFO("hue kept"); + CHECK_THAT(angleDelta(mWheel.getHue(), hue), ll_test::WithinBits(0.f, 3)); + UNSCOPED_INFO("saturation kept"); + CHECK_THAT(mWheel.getSat(), ll_test::WithinBits(sat, 3)); } // A master pushed past its range clamps, and the triplet stays legal. - template<> template<> - void wheel_object::test<11>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: a master pushed past its range clamps and the triplet stays legal", "[ALColorWheelModel]") { asGain(); mWheel.setMaster(9.f); - ensure("master clamped", mWheel.getMaster() <= 1.5f + 1e-5f); + UNSCOPED_INFO("master clamped"); + CHECK(mWheel.getMaster() <= 1.5f + 1e-5f); for (S32 c = 0; c < 3; ++c) { - ensure("channel in range", mWheel.getRGB().mV[c] <= 1.5f + 1e-5f); + UNSCOPED_INFO("channel in range"); + REQUIRE(mWheel.getRGB().mV[c] <= 1.5f + 1e-5f); } } // Tint wheels lock the master, because the renderer divides each tint by // dot(tint, LUMA) -- magnitude cancels, so a master there would be a // control that visibly does nothing. - template<> template<> - void wheel_object::test<12>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: a tint wheel ignores the master and re-centres it on a puck move", "[ALColorWheelModel]") { asTint(); mWheel.setPolar(deg(90.f), mWheel.getMaxSat() * 0.5f); const F32 master = mWheel.getMaster(); mWheel.setMaster(0.9f); - ensure_approximately_equals("master ignored", mWheel.getMaster(), master, 5); + UNSCOPED_INFO("master ignored"); + CHECK_THAT(mWheel.getMaster(), ll_test::WithinBits(master, 5)); // ... and a fresh puck move re-centres on the configured neutral. mWheel.setPolar(deg(30.f), mWheel.getMaxSat() * 0.5f); - ensure_approximately_equals("re-centred on neutral", mWheel.getMaster(), 0.5f, 4); + UNSCOPED_INFO("re-centred on neutral"); + CHECK_THAT(mWheel.getMaster(), ll_test::WithinBits(0.5f, 4)); } // --- ring / puck agreement ---------------------------------------------- @@ -292,8 +313,7 @@ namespace tut // The ring is generated from the same basis as the puck, so the colour // shown at an angle is the colour dragging to that angle produces. Drawing // a generic HSV ring instead is where these two drift apart. - template<> template<> - void wheel_object::test<13>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: the ring's colour at a hue is coloured and has that hue", "[ALColorWheelModel]") { for (S32 i = 0; i < 36; ++i) { @@ -302,24 +322,27 @@ namespace tut F32 ring_hue, ring_sat; ALColorWheelModel::toPolar(ring, ring_hue, ring_sat); - ensure_approximately_equals("ring hue matches the puck's", - angleDelta(ring_hue, hue), 0.f, 3); - ensure("ring is actually coloured", ring_sat > 0.f); + UNSCOPED_INFO("ring hue matches the puck's"); + REQUIRE_THAT(angleDelta(ring_hue, hue), ll_test::WithinBits(0.f, 3)); + UNSCOPED_INFO("ring is actually coloured"); + REQUIRE(ring_sat > 0.f); } } // The ring's reference chroma is chosen to stay inside 0..1, so no channel // is ever clipped -- clipping would bend the hue it is advertising. - template<> template<> - void wheel_object::test<14>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: every ring channel stays strictly inside 0..1", "[ALColorWheelModel]") { for (S32 i = 0; i < 72; ++i) { const LLVector3 ring = ALColorWheelModel::ringColor(deg((F32)i * 5.f)); for (S32 c = 0; c < 3; ++c) { - ensure("ring channel is strictly inside the gamut", - ring.mV[c] > 0.001f && ring.mV[c] < 0.999f); + { + INFO("ring channel is strictly inside the gamut"); + REQUIRE(ring.mV[c] > 0.001f); + REQUIRE(ring.mV[c] < 0.999f); + } } } } @@ -327,83 +350,98 @@ namespace tut // --- numeric entry and reset -------------------------------------------- // Typing into one field leaves the other two alone and moves the puck. - template<> template<> - void wheel_object::test<15>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: setChannel writes one channel alone and moves the puck", "[ALColorWheelModel]") { asLift(); mWheel.setChannel(0, 0.2f); - ensure_approximately_equals("channel written", mWheel.getRGB().mV[VX], 0.2f, 5); - ensure_approximately_equals("g untouched", mWheel.getRGB().mV[VY], 0.f, 5); - ensure_approximately_equals("b untouched", mWheel.getRGB().mV[VZ], 0.f, 5); - ensure("puck moved off centre", mWheel.getSat() > 0.f); - ensure_approximately_equals("towards red", angleDelta(mWheel.getHue(), 0.f), 0.f, 3); + UNSCOPED_INFO("channel written"); + CHECK_THAT(mWheel.getRGB().mV[VX], ll_test::WithinBits(0.2f, 5)); + UNSCOPED_INFO("g untouched"); + CHECK_THAT(mWheel.getRGB().mV[VY], ll_test::WithinBits(0.f, 5)); + UNSCOPED_INFO("b untouched"); + CHECK_THAT(mWheel.getRGB().mV[VZ], ll_test::WithinBits(0.f, 5)); + UNSCOPED_INFO("puck moved off centre"); + CHECK(mWheel.getSat() > 0.f); + UNSCOPED_INFO("towards red"); + CHECK_THAT(angleDelta(mWheel.getHue(), 0.f), ll_test::WithinBits(0.f, 3)); mWheel.setChannel(0, 9.f); - ensure_approximately_equals("typed value clamped", mWheel.getRGB().mV[VX], 0.5f, 5); + UNSCOPED_INFO("typed value clamped"); + CHECK_THAT(mWheel.getRGB().mV[VX], ll_test::WithinBits(0.5f, 5)); mWheel.setChannel(7, 1.f); // out of range, ignored - ensure_approximately_equals("bad index ignored", mWheel.getRGB().mV[VX], 0.5f, 5); + UNSCOPED_INFO("bad index ignored"); + CHECK_THAT(mWheel.getRGB().mV[VX], ll_test::WithinBits(0.5f, 5)); } // Reset returns the configured neutral for each flavour. - template<> template<> - void wheel_object::test<16>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: reset returns the configured neutral for each flavour", "[ALColorWheelModel]") { asLift(); mWheel.setPolar(deg(45.f), mWheel.getMaxSat()); mWheel.reset(); - ensure_approximately_equals("lift neutral is 0", mWheel.getMaster(), 0.f, 5); - ensure_approximately_equals("and colourless", mWheel.getSat(), 0.f, 5); + UNSCOPED_INFO("lift neutral is 0"); + CHECK_THAT(mWheel.getMaster(), ll_test::WithinBits(0.f, 5)); + UNSCOPED_INFO("and colourless"); + CHECK_THAT(mWheel.getSat(), ll_test::WithinBits(0.f, 5)); asGain(); mWheel.reset(); - ensure_approximately_equals("gain neutral is 1", mWheel.getMaster(), 1.f, 5); + UNSCOPED_INFO("gain neutral is 1"); + CHECK_THAT(mWheel.getMaster(), ll_test::WithinBits(1.f, 5)); asTint(); mWheel.reset(); - ensure_approximately_equals("tint neutral is 0.5", mWheel.getMaster(), 0.5f, 5); - ensure_approximately_equals("tint neutral r", mWheel.getRGB().mV[VX], 0.5f, 5); + UNSCOPED_INFO("tint neutral is 0.5"); + CHECK_THAT(mWheel.getMaster(), ll_test::WithinBits(0.5f, 5)); + UNSCOPED_INFO("tint neutral r"); + CHECK_THAT(mWheel.getRGB().mV[VX], ll_test::WithinBits(0.5f, 5)); } // Re-configuring re-clamps whatever was already held, so switching a wheel // from lift to gain cannot leave an out-of-range value behind. - template<> template<> - void wheel_object::test<17>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: configure re-clamps the value already held", "[ALColorWheelModel]") { asLift(); mWheel.setRGB(LLVector3(-0.4f, 0.f, 0.3f)); asGain(); for (S32 c = 0; c < 3; ++c) { - ensure("re-clamped on configure", - mWheel.getRGB().mV[c] >= 0.5f - 1e-5f && mWheel.getRGB().mV[c] <= 1.5f + 1e-5f); + { + INFO("re-clamped on configure"); + REQUIRE(mWheel.getRGB().mV[c] >= 0.5f - 1e-5f); + REQUIRE(mWheel.getRGB().mV[c] <= 1.5f + 1e-5f); + } } } // A reversed range is accepted rather than producing a negative width. - template<> template<> - void wheel_object::test<18>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: a reversed range is accepted rather than producing a negative width", "[ALColorWheelModel]") { mWheel.configure(0.f, 0.5f, -0.5f, false); - ensure_approximately_equals("min is the low one", mWheel.getMin(), -0.5f, 5); - ensure_approximately_equals("max is the high one", mWheel.getMax(), 0.5f, 5); - ensure("max saturation is positive", mWheel.getMaxSat() > 0.f); + UNSCOPED_INFO("min is the low one"); + CHECK_THAT(mWheel.getMin(), ll_test::WithinBits(-0.5f, 5)); + UNSCOPED_INFO("max is the high one"); + CHECK_THAT(mWheel.getMax(), ll_test::WithinBits(0.5f, 5)); + UNSCOPED_INFO("max saturation is positive"); + CHECK(mWheel.getMaxSat() > 0.f); } // Exactly zero, not approximately: the vectorscope bins chroma with floorf, // so an epsilon of either sign puts one grey in a different cell from the // next. Compared bit for bit because that is the property callers rely on, // and because an epsilon is exactly what a tolerance would hide. - template<> template<> - void wheel_object::test<19>() + TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: toChroma gives a grey exactly zero chroma", "[ALColorWheelModel]") { for (S32 level = 0; level < 256; ++level) { const F32 grey = (F32)level / 255.f; F32 u = 1.f, v = 1.f; ALColorWheelModel::toChroma(LLVector3(grey, grey, grey), u, v); - ensure("grey has no u", u == 0.f); - ensure("grey has no v", v == 0.f); + UNSCOPED_INFO("grey has no u"); + REQUIRE(u == 0.f); + UNSCOPED_INFO("grey has no v"); + REQUIRE(v == 0.f); } // Outside 0..1 as well: wheels carry lift and gain, which sit either @@ -412,8 +450,10 @@ namespace tut { F32 u = 1.f, v = 1.f; ALColorWheelModel::toChroma(LLVector3(grey, grey, grey), u, v); - ensure("grey has no u", u == 0.f); - ensure("grey has no v", v == 0.f); + UNSCOPED_INFO("grey has no u"); + REQUIRE(u == 0.f); + UNSCOPED_INFO("grey has no v"); + REQUIRE(v == 0.f); } } } diff --git a/indra/newview/tests/alcrashreporter_test.cpp b/indra/newview/tests/alcrashreporter_test.cpp index 0c06ff7690..93fc705722 100644 --- a/indra/newview/tests/alcrashreporter_test.cpp +++ b/indra/newview/tests/alcrashreporter_test.cpp @@ -30,56 +30,40 @@ #include "lluuid.h" #include "v3math.h" -#include "../test/lltut.h" +#include #include -namespace tut +namespace { - struct alcrashreporter_data + TEST_CASE("alcrashreporter: the release is the package at a version plus a build", "[alcrashreporter]") { - }; - - typedef test_group alcrashreporter_group; - typedef alcrashreporter_group::object object; - alcrashreporter_group alcrashreportergrp("alcrashreporter"); - - template<> template<> - void object::test<1>() - { - set_test_name("the release is the package at a version plus a build"); - ensure_equals(ALCrashReporter::releaseName(26, 4, 0, 64033), "alchemy@26.4.0+64033"); + CHECK(ALCrashReporter::releaseName(26, 4, 0, 64033) == "alchemy@26.4.0+64033"); } - template<> template<> - void object::test<2>() + TEST_CASE("alcrashreporter: a location is the region and whole metres", "[alcrashreporter]") { - set_test_name("a location is the region and whole metres"); - ensure_equals(ALCrashReporter::locationTag("Hippotropolis", LLVector3(128.4f, 63.6f, 22.5f)), + CHECK(ALCrashReporter::locationTag("Hippotropolis", LLVector3(128.4f, 63.6f, 22.5f)) == "Hippotropolis/128/64/23"); } - template<> template<> - void object::test<3>() + TEST_CASE("alcrashreporter: a location keeps the region's own spelling", "[alcrashreporter]") { - set_test_name("a location keeps the region's own spelling"); - ensure_equals(ALCrashReporter::locationTag("Ye Olde Region", LLVector3(0.f, 0.f, 0.f)), + CHECK(ALCrashReporter::locationTag("Ye Olde Region", LLVector3(0.f, 0.f, 0.f)) == "Ye Olde Region/0/0/0"); } - template<> template<> - void object::test<4>() + TEST_CASE("alcrashreporter: the run id is one string for the whole run", "[alcrashreporter]") { - set_test_name("the run id is one string for the whole run"); const std::string& first = ALCrashReporter::runId(); - ensure_equals("a UUID", first.size(), 36u); - ensure_equals("stable", ALCrashReporter::runId(), first); + UNSCOPED_INFO("a UUID"); + REQUIRE(first.size() == 36u); + UNSCOPED_INFO("stable"); + CHECK(ALCrashReporter::runId() == first); } - template<> template<> - void object::test<5>() + TEST_CASE("alcrashreporter: the previous run is read from its static debug file", "[alcrashreporter]") { - set_test_name("the previous run is read from its static debug file"); LLSD info; info["RunId"] = "6f4b1b2e-9d8c-4d0f-a5b7-2c3e4f5a6b7c"; info["SLLog"] = "/logs/Alchemy.crash"; @@ -90,147 +74,168 @@ namespace tut info["FatalMessage"] = "LL_ERRS: something"; ALCrashReporter::PreviousRun run = ALCrashReporter::previousRun(info); - ensure_equals(run.runId, "6f4b1b2e-9d8c-4d0f-a5b7-2c3e4f5a6b7c"); - ensure_equals(run.logFile, "/logs/Alchemy.crash"); - ensure_equals(run.userSettingsFile, "/settings/settings.xml"); - ensure_equals(run.accountSettingsFile, "/settings/ye_olde/settings_per_account.xml"); - ensure_equals("underscores become spaces", run.agentName, "Ye Olde Avatar"); - ensure_equals(run.region, "Hippotropolis"); - ensure_equals(run.fatalMessage, "LL_ERRS: something"); + CHECK(run.runId == "6f4b1b2e-9d8c-4d0f-a5b7-2c3e4f5a6b7c"); + CHECK(run.logFile == "/logs/Alchemy.crash"); + CHECK(run.userSettingsFile == "/settings/settings.xml"); + CHECK(run.accountSettingsFile == "/settings/ye_olde/settings_per_account.xml"); + UNSCOPED_INFO("underscores become spaces"); + CHECK(run.agentName == "Ye Olde Avatar"); + CHECK(run.region == "Hippotropolis"); + CHECK(run.fatalMessage == "LL_ERRS: something"); } - template<> template<> - void object::test<6>() + TEST_CASE("alcrashreporter: a file from before run ids reads as empty fields", "[alcrashreporter]") { - set_test_name("a file from before run ids reads as empty fields"); ALCrashReporter::PreviousRun run = ALCrashReporter::previousRun(LLSD()); - ensure("no run id", run.runId.empty()); - ensure("no log", run.logFile.empty()); - ensure("no name", run.agentName.empty()); + UNSCOPED_INFO("no run id"); + REQUIRE(run.runId.empty()); + UNSCOPED_INFO("no log"); + REQUIRE(run.logFile.empty()); + UNSCOPED_INFO("no name"); + REQUIRE(run.agentName.empty()); } - template<> template<> - void object::test<7>() + TEST_CASE("alcrashreporter: consent is a sentinel file that allowing makes and withdrawing removes", "[alcrashreporter]") { - set_test_name("consent is a sentinel file: recorded, seen, withdrawn"); // A name of this run's own: another run of the tests may be at it. const std::string sentinel = (std::filesystem::temp_directory_path() / ("alcrashreporter_test_consent_" + LLUUID::generateNewID().asString())).string(); ALCrashReporter::recordConsent(sentinel, false); - ensure("absent to begin with", !ALCrashReporter::consentRecorded(sentinel)); + UNSCOPED_INFO("absent to begin with"); + CHECK_FALSE(ALCrashReporter::consentRecorded(sentinel)); ALCrashReporter::recordConsent(sentinel, true); - ensure("present once allowed", ALCrashReporter::consentRecorded(sentinel)); + UNSCOPED_INFO("present once allowed"); + CHECK(ALCrashReporter::consentRecorded(sentinel)); ALCrashReporter::recordConsent(sentinel, true); - ensure("allowing twice keeps it", ALCrashReporter::consentRecorded(sentinel)); + UNSCOPED_INFO("allowing twice keeps it"); + CHECK(ALCrashReporter::consentRecorded(sentinel)); ALCrashReporter::recordConsent(sentinel, false); - ensure("gone once withdrawn", !ALCrashReporter::consentRecorded(sentinel)); + UNSCOPED_INFO("gone once withdrawn"); + CHECK_FALSE(ALCrashReporter::consentRecorded(sentinel)); ALCrashReporter::recordConsent(sentinel, false); - ensure("withdrawing twice is quiet", !ALCrashReporter::consentRecorded(sentinel)); + UNSCOPED_INFO("withdrawing twice is quiet"); + CHECK_FALSE(ALCrashReporter::consentRecorded(sentinel)); } - template<> template<> - void object::test<8>() + TEST_CASE("alcrashreporter: a location written into a buffer is the same or cut to fit", "[alcrashreporter]") { - set_test_name("a location written into a buffer is the same, or cut to fit"); const LLVector3 position(128.4f, -63.6f, 22.5f); char buffer[64]; size_t length = ALCrashReporter::locationTag(buffer, sizeof(buffer), "Hippotropolis", position); - ensure_equals("whole", std::string(buffer, length), "Hippotropolis/128/-64/23"); - ensure_equals("terminated", buffer[length], '\0'); + UNSCOPED_INFO("whole"); + CHECK(std::string(buffer, length) == "Hippotropolis/128/-64/23"); + UNSCOPED_INFO("terminated"); + CHECK(buffer[length] == '\0'); char small[12]; length = ALCrashReporter::locationTag(small, sizeof(small), "Hippotropolis", position); - ensure_equals("cut", std::string(small, length), "Hippotropol"); - ensure_equals("cut and terminated", small[length], '\0'); + UNSCOPED_INFO("cut"); + CHECK(std::string(small, length) == "Hippotropol"); + UNSCOPED_INFO("cut and terminated"); + CHECK(small[length] == '\0'); length = ALCrashReporter::locationTag(small, sizeof(small), "Ahern", position); - ensure_equals("cut in the numbers", std::string(small, length), "Ahern/128/-"); + UNSCOPED_INFO("cut in the numbers"); + CHECK(std::string(small, length) == "Ahern/128/-"); } - template<> template<> - void object::test<9>() + TEST_CASE("alcrashreporter: an event id is its 32 hex digits however it is spelled", "[alcrashreporter]") { - set_test_name("an event id is its 32 hex digits however it is spelled"); - ensure_equals("dashed", ALCrashReporter::compactEventId("0123ABCD-89ab-cdef-0123-456789ABCDEF"), + UNSCOPED_INFO("dashed"); + CHECK(ALCrashReporter::compactEventId("0123ABCD-89ab-cdef-0123-456789ABCDEF") == "0123abcd89abcdef0123456789abcdef"); - ensure_equals("braced", ALCrashReporter::compactEventId("{0123abcd-89ab-cdef-0123-456789abcdef}"), + UNSCOPED_INFO("braced"); + CHECK(ALCrashReporter::compactEventId("{0123abcd-89ab-cdef-0123-456789abcdef}") == "0123abcd89abcdef0123456789abcdef"); - ensure_equals("already compact", ALCrashReporter::compactEventId("0123abcd89abcdef0123456789abcdef"), + UNSCOPED_INFO("already compact"); + CHECK(ALCrashReporter::compactEventId("0123abcd89abcdef0123456789abcdef") == "0123abcd89abcdef0123456789abcdef"); - ensure("too short", ALCrashReporter::compactEventId("0123abcd").empty()); - ensure("not hex", ALCrashReporter::compactEventId("0123abcd89abcdef0123456789abcdeg").empty()); - ensure("empty", ALCrashReporter::compactEventId("").empty()); + UNSCOPED_INFO("too short"); + REQUIRE(ALCrashReporter::compactEventId("0123abcd").empty()); + UNSCOPED_INFO("not hex"); + REQUIRE(ALCrashReporter::compactEventId("0123abcd89abcdef0123456789abcdeg").empty()); + UNSCOPED_INFO("empty"); + REQUIRE(ALCrashReporter::compactEventId("").empty()); } - template<> template<> - void object::test<10>() + TEST_CASE("alcrashreporter: a freeze's report is recorded for the next run to take once", "[alcrashreporter]") { - set_test_name("a freeze's report is recorded for the next run, which takes it once"); // Names of this run's own, here and below: another run of the tests may be at it. const std::string record = (std::filesystem::temp_directory_path() / ("alcrashreporter_test_last_report_" + LLUUID::generateNewID().asString())).string(); ALCrashReporter::takeRecordedReport(record); - ensure("nothing to begin with", !ALCrashReporter::takeRecordedReport(record)); + UNSCOPED_INFO("nothing to begin with"); + REQUIRE_FALSE(ALCrashReporter::takeRecordedReport(record)); ALCrashReporter::recordReport(record, { "freeze", "0123abcd89abcdef0123456789abcdef" }); const auto taken = ALCrashReporter::takeRecordedReport(record); - ensure("taken", taken.has_value()); - ensure_equals("kind", taken->kind, "freeze"); - ensure_equals("id", taken->eventId, "0123abcd89abcdef0123456789abcdef"); - ensure("once", !ALCrashReporter::takeRecordedReport(record)); + UNSCOPED_INFO("taken"); + REQUIRE(taken.has_value()); + UNSCOPED_INFO("kind"); + CHECK(taken->kind == "freeze"); + UNSCOPED_INFO("id"); + CHECK(taken->eventId == "0123abcd89abcdef0123456789abcdef"); + UNSCOPED_INFO("once"); + REQUIRE_FALSE(ALCrashReporter::takeRecordedReport(record)); ALCrashReporter::recordReport(record, { "lunch", "0123abcd89abcdef0123456789abcdef" }); - ensure("an unknown kind is not a report", !ALCrashReporter::takeRecordedReport(record)); + UNSCOPED_INFO("an unknown kind is not a report"); + REQUIRE_FALSE(ALCrashReporter::takeRecordedReport(record)); ALCrashReporter::recordReport(record, { "crash", "nonsense" }); - ensure("nor is a broken id", !ALCrashReporter::takeRecordedReport(record)); + UNSCOPED_INFO("nor is a broken id"); + REQUIRE_FALSE(ALCrashReporter::takeRecordedReport(record)); } - template<> template<> - void object::test<11>() + TEST_CASE("alcrashreporter: the nil UUID is no event however it is spelled", "[alcrashreporter]") { - set_test_name("the nil UUID is no event, however it is spelled"); - ensure("dashed", ALCrashReporter::compactEventId("00000000-0000-0000-0000-000000000000").empty()); - ensure("braced", ALCrashReporter::compactEventId("{00000000-0000-0000-0000-000000000000}").empty()); - ensure("compact", ALCrashReporter::compactEventId("00000000000000000000000000000000").empty()); - ensure_equals("one digit set is an event", - ALCrashReporter::compactEventId("00000000-0000-0000-0000-000000000001"), + UNSCOPED_INFO("dashed"); + REQUIRE(ALCrashReporter::compactEventId("00000000-0000-0000-0000-000000000000").empty()); + UNSCOPED_INFO("braced"); + REQUIRE(ALCrashReporter::compactEventId("{00000000-0000-0000-0000-000000000000}").empty()); + UNSCOPED_INFO("compact"); + REQUIRE(ALCrashReporter::compactEventId("00000000000000000000000000000000").empty()); + UNSCOPED_INFO("one digit set is an event"); + CHECK(ALCrashReporter::compactEventId("00000000-0000-0000-0000-000000000001") == "00000000000000000000000000000001"); const std::string record = (std::filesystem::temp_directory_path() / ("alcrashreporter_test_nil_report_" + LLUUID::generateNewID().asString())).string(); ALCrashReporter::recordReport(record, { "freeze", "00000000000000000000000000000000" }); - ensure("a nil report is not taken", !ALCrashReporter::takeRecordedReport(record)); + UNSCOPED_INFO("a nil report is not taken"); + REQUIRE_FALSE(ALCrashReporter::takeRecordedReport(record)); } - template<> template<> - void object::test<12>() + TEST_CASE("alcrashreporter: a crash found at start is the previous run's only if it carries its id", "[alcrashreporter]") { - set_test_name("a crash found at start is the previous run's only when it carries that run's id"); const std::string_view event = "0123abcd-89ab-cdef-0123-456789abcdef"; const std::string_view previous = "6f4b1b2e-9d8c-4d0f-a5b7-2c3e4f5a6b7c"; const auto crash = ALCrashReporter::previousRunCrash(event, previous, previous); - ensure("the previous run's", crash.has_value()); - ensure_equals("a crash", crash->kind, "crash"); - ensure_equals("its id", crash->eventId, "0123abcd89abcdef0123456789abcdef"); - ensure("the run id however it is spelled", - ALCrashReporter::previousRunCrash(event, "6F4B1B2E9D8C4D0FA5B72C3E4F5A6B7C", previous).has_value()); - - ensure("another run's", !ALCrashReporter::previousRunCrash(event, "7f4b1b2e-9d8c-4d0f-a5b7-2c3e4f5a6b7c", + UNSCOPED_INFO("the previous run's"); + REQUIRE(crash.has_value()); + UNSCOPED_INFO("a crash"); + CHECK(crash->kind == "crash"); + UNSCOPED_INFO("its id"); + CHECK(crash->eventId == "0123abcd89abcdef0123456789abcdef"); + UNSCOPED_INFO("the run id however it is spelled"); + REQUIRE(ALCrashReporter::previousRunCrash(event, "6F4B1B2E9D8C4D0FA5B72C3E4F5A6B7C", previous).has_value()); + + UNSCOPED_INFO("another run's"); + REQUIRE_FALSE(ALCrashReporter::previousRunCrash(event, "7f4b1b2e-9d8c-4d0f-a5b7-2c3e4f5a6b7c", previous)); - ensure("one that carries no run id", !ALCrashReporter::previousRunCrash(event, "", previous)); - ensure("any, when the previous run is not known", !ALCrashReporter::previousRunCrash(event, previous, "")); - ensure("one filed as nothing", - !ALCrashReporter::previousRunCrash("00000000-0000-0000-0000-000000000000", previous, previous)); + UNSCOPED_INFO("one that carries no run id"); + REQUIRE_FALSE(ALCrashReporter::previousRunCrash(event, "", previous)); + UNSCOPED_INFO("any, when the previous run is not known"); + REQUIRE_FALSE(ALCrashReporter::previousRunCrash(event, previous, "")); + UNSCOPED_INFO("one filed as nothing"); + REQUIRE_FALSE(ALCrashReporter::previousRunCrash("00000000-0000-0000-0000-000000000000", previous, previous)); } - template<> template<> - void object::test<13>() + TEST_CASE("alcrashreporter: a record replaces the last whole and leaves nothing beside it", "[alcrashreporter]") { - set_test_name("a record is written whole over the last, and nothing is left beside it"); const std::filesystem::path dir = std::filesystem::temp_directory_path() / ("alcrashreporter_test_records_" + LLUUID::generateNewID().asString()); std::filesystem::create_directories(dir); @@ -242,19 +247,26 @@ namespace tut ALCrashReporter::recordReport(record, { "freeze", "0123abcd89abcdef0123456789abcdef" }); ALCrashReporter::recordReport(record, { "crash", "fedcba9876543210fedcba9876543210" }); - ensure_equals("the record alone", entries(), 1); + UNSCOPED_INFO("the record alone"); + CHECK(entries() == 1); const auto taken = ALCrashReporter::takeRecordedReport(record); - ensure("taken", taken.has_value()); - ensure_equals("the later kind", taken->kind, "crash"); - ensure_equals("the later id", taken->eventId, "fedcba9876543210fedcba9876543210"); - ensure_equals("nothing once taken", entries(), 0); + UNSCOPED_INFO("taken"); + REQUIRE(taken.has_value()); + UNSCOPED_INFO("the later kind"); + CHECK(taken->kind == "crash"); + UNSCOPED_INFO("the later id"); + CHECK(taken->eventId == "fedcba9876543210fedcba9876543210"); + UNSCOPED_INFO("nothing once taken"); + CHECK(entries() == 0); // A record that cannot be put in place leaves nothing written. const std::filesystem::path blocked = dir / "blocked"; std::filesystem::create_directories(blocked / "inside"); ALCrashReporter::recordReport(blocked.string(), { "freeze", "0123abcd89abcdef0123456789abcdef" }); - ensure_equals("only what was there", entries(), 1); - ensure("still a directory", std::filesystem::is_directory(blocked)); + UNSCOPED_INFO("only what was there"); + CHECK(entries() == 1); + UNSCOPED_INFO("still a directory"); + CHECK(std::filesystem::is_directory(blocked)); std::filesystem::remove_all(dir); } diff --git a/indra/newview/tests/alcurvemodel_test.cpp b/indra/newview/tests/alcurvemodel_test.cpp index 558c76c7c3..2b0ea107f9 100644 --- a/indra/newview/tests/alcurvemodel_test.cpp +++ b/indra/newview/tests/alcurvemodel_test.cpp @@ -14,7 +14,8 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include +#include "altestmatchers.h" #include "../alcurvemodel.h" @@ -22,7 +23,7 @@ #include #include -namespace tut +namespace { struct curve_data { @@ -100,119 +101,132 @@ namespace tut } }; - typedef test_group curve_group; - typedef curve_group::object curve_object; - tut::curve_group cg("ALCurveModel"); - // --- spline: ordering and point management ------------------------------- // A fresh model is the identity ramp. - template<> template<> - void curve_object::test<1>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: a fresh model is the identity ramp", "[ALCurveModel]") { - ensure_equals("two points by default", mCurve.getPointCount(), 2); + UNSCOPED_INFO("two points by default"); + CHECK(mCurve.getPointCount() == 2); for (S32 i = 0; i <= 10; ++i) { const F32 x = i * 0.1f; - ensure_approximately_equals("identity ramp", mCurve.evaluate(x), x, 5); + UNSCOPED_INFO("identity ramp"); + REQUIRE_THAT(mCurve.evaluate(x), ll_test::WithinBits(x, 5)); } } // Points added out of order come back sorted by x, and the reported index // is where the point actually landed. - template<> template<> - void curve_object::test<2>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: points added out of order come back sorted by x", "[ALCurveModel]") { const S32 idx_hi = mCurve.addPoint(0.8f, 0.9f); const S32 idx_lo = mCurve.addPoint(0.2f, 0.1f); - ensure_equals("high point went before the last", idx_hi, 1); - ensure_equals("low point went before the high one", idx_lo, 1); - ensure_equals("four points", mCurve.getPointCount(), 4); + UNSCOPED_INFO("high point went before the last"); + CHECK(idx_hi == 1); + UNSCOPED_INFO("low point went before the high one"); + CHECK(idx_lo == 1); + UNSCOPED_INFO("four points"); + CHECK(mCurve.getPointCount() == 4); const auto& p = mCurve.getPoints(); for (size_t i = 1; i < p.size(); ++i) { - ensure("x is ascending", p[i].mX > p[i - 1].mX); + UNSCOPED_INFO("x is ascending"); + REQUIRE(p[i].mX > p[i - 1].mX); } - ensure_approximately_equals("second point is the low one", p[1].mX, 0.2f, 5); - ensure_approximately_equals("third point is the high one", p[2].mX, 0.8f, 5); + UNSCOPED_INFO("second point is the low one"); + CHECK_THAT(p[1].mX, ll_test::WithinBits(0.2f, 5)); + UNSCOPED_INFO("third point is the high one"); + CHECK_THAT(p[2].mX, ll_test::WithinBits(0.8f, 5)); } // Coincident points are pushed apart rather than sharing an x, so no // segment can have zero width. - template<> template<> - void curve_object::test<3>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: coincident points are pushed apart by at least the minimum gap", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.f }, { 0.5f, 0.3f }, { 0.5f, 0.7f }, { 1.f, 1.f } })); const auto& p = mCurve.getPoints(); - ensure_equals("kept all four", (S32)p.size(), 4); + UNSCOPED_INFO("kept all four"); + REQUIRE((S32)p.size() == 4); for (size_t i = 1; i < p.size(); ++i) { - ensure("gap is at least MIN_POINT_GAP", - p[i].mX - p[i - 1].mX >= ALCurveModel::MIN_POINT_GAP - 1e-6f); + UNSCOPED_INFO("gap is at least MIN_POINT_GAP"); + REQUIRE(p[i].mX - p[i - 1].mX >= ALCurveModel::MIN_POINT_GAP - 1e-6f); } - ensure("evaluation is finite", std::isfinite(mCurve.evaluate(0.5f))); + UNSCOPED_INFO("evaluation is finite"); + CHECK(std::isfinite(mCurve.evaluate(0.5f))); } // A drag cannot push a point past its neighbours, and locked endpoints // keep their x while still accepting a new height. - template<> template<> - void curve_object::test<4>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: a drag stops at the neighbours and locked ends keep their x", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.f }, { 0.3f, 0.3f }, { 0.6f, 0.6f }, { 1.f, 1.f } })); mCurve.movePoint(1, 0.95f, 0.5f); const auto& p = mCurve.getPoints(); - ensure("clamped below its right neighbour", p[1].mX < p[2].mX); - ensure_approximately_equals("clamped to exactly the gap", - p[1].mX, 0.6f - ALCurveModel::MIN_POINT_GAP, 5); - ensure("still ordered", p[0].mX < p[1].mX && p[2].mX < p[3].mX); + UNSCOPED_INFO("clamped below its right neighbour"); + CHECK(p[1].mX < p[2].mX); + UNSCOPED_INFO("clamped to exactly the gap"); + CHECK_THAT(p[1].mX, ll_test::WithinBits(0.6f - ALCurveModel::MIN_POINT_GAP, 5)); + { + INFO("still ordered"); + CHECK(p[0].mX < p[1].mX); + CHECK(p[2].mX < p[3].mX); + } mCurve.movePoint(0, 0.4f, 0.25f); - ensure_approximately_equals("first point x stays pinned", mCurve.getPoints()[0].mX, 0.f, 6); - ensure_approximately_equals("first point y moved", mCurve.getPoints()[0].mY, 0.25f, 5); + UNSCOPED_INFO("first point x stays pinned"); + CHECK_THAT(mCurve.getPoints()[0].mX, ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("first point y moved"); + CHECK_THAT(mCurve.getPoints()[0].mY, ll_test::WithinBits(0.25f, 5)); mCurve.movePoint(3, 0.4f, 0.8f); - ensure_approximately_equals("last point x stays pinned", mCurve.getPoints()[3].mX, 1.f, 6); + UNSCOPED_INFO("last point x stays pinned"); + CHECK_THAT(mCurve.getPoints()[3].mX, ll_test::WithinBits(1.f, 6)); } // Removal refuses to break the curve: never below two points, and never an // endpoint while the endpoints are locked. - template<> template<> - void curve_object::test<5>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: removal never leaves fewer than two points or drops a locked end", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.f }, { 0.5f, 0.4f }, { 1.f, 1.f } })); - ensure("cannot remove the first", !mCurve.removePoint(0)); - ensure("cannot remove the last", !mCurve.removePoint(2)); - ensure("out of range refused", !mCurve.removePoint(7)); - ensure("interior removed", mCurve.removePoint(1)); - ensure_equals("two left", mCurve.getPointCount(), 2); - ensure("cannot go below two", !mCurve.removePoint(0)); + UNSCOPED_INFO("cannot remove the first"); + CHECK_FALSE(mCurve.removePoint(0)); + UNSCOPED_INFO("cannot remove the last"); + CHECK_FALSE(mCurve.removePoint(2)); + UNSCOPED_INFO("out of range refused"); + CHECK_FALSE(mCurve.removePoint(7)); + UNSCOPED_INFO("interior removed"); + CHECK(mCurve.removePoint(1)); + UNSCOPED_INFO("two left"); + CHECK(mCurve.getPointCount() == 2); + UNSCOPED_INFO("cannot go below two"); + CHECK_FALSE(mCurve.removePoint(0)); } // --- spline: shape ------------------------------------------------------- // The curve passes through every control point. - template<> template<> - void curve_object::test<6>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: the curve passes through every control point", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.05f }, { 0.25f, 0.5f }, { 0.7f, 0.6f }, { 1.f, 0.95f } })); for (const auto& p : mCurve.getPoints()) { - ensure_approximately_equals("interpolates its points", - mCurve.evaluate(p.mX), p.mY, 4); + UNSCOPED_INFO("interpolates its points"); + REQUIRE_THAT(mCurve.evaluate(p.mX), ll_test::WithinBits(p.mY, 4)); } } // Monotone data yields a monotone curve. A natural or Catmull-Rom spline // fails this on exactly this shape -- a long flat run into a sharp rise // makes it dip below the flat before climbing. - template<> template<> - void curve_object::test<7>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: monotone data yields a monotone curve", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.f }, { 0.4f, 0.02f }, { 0.6f, 0.05f }, { 0.7f, 0.9f }, { 1.f, 1.f } })); @@ -220,39 +234,40 @@ namespace tut mCurve.sample(s, 257); for (size_t i = 1; i < s.size(); ++i) { - ensure("never decreases", s[i] >= s[i - 1] - 1e-5f); + UNSCOPED_INFO("never decreases"); + REQUIRE(s[i] >= s[i - 1] - 1e-5f); } } // A flat run stays exactly flat -- no ringing between equal-valued points. - template<> template<> - void curve_object::test<8>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: a flat run stays exactly flat with no ringing between equal points", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.f }, { 0.3f, 0.5f }, { 0.7f, 0.5f }, { 1.f, 1.f } })); for (S32 i = 0; i <= 8; ++i) { const F32 x = 0.3f + i * 0.05f; - ensure_approximately_equals("flat between equal points", mCurve.evaluate(x), 0.5f, 4); + UNSCOPED_INFO("flat between equal points"); + REQUIRE_THAT(mCurve.evaluate(x), ll_test::WithinBits(0.5f, 4)); } } // Outside the point range the curve holds its end values rather than // extrapolating off the graph. - template<> template<> - void curve_object::test<9>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: outside its points the curve holds its end values", "[ALCurveModel]") { mCurve.setEndpointsLocked(false); mCurve.setPoints(pts({ { 0.2f, 0.3f }, { 0.8f, 0.7f } })); - ensure_approximately_equals("holds the left value", mCurve.evaluate(0.f), 0.3f, 5); - ensure_approximately_equals("holds the right value", mCurve.evaluate(1.f), 0.7f, 5); + UNSCOPED_INFO("holds the left value"); + CHECK_THAT(mCurve.evaluate(0.f), ll_test::WithinBits(0.3f, 5)); + UNSCOPED_INFO("holds the right value"); + CHECK_THAT(mCurve.evaluate(1.f), ll_test::WithinBits(0.7f, 5)); } // Output never leaves 0..1, so a curve can never ask the caller to write an // out-of-gamut value. - template<> template<> - void curve_object::test<10>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: output never leaves 0..1 even for a wild curve", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.f }, { 0.05f, 0.99f }, { 0.1f, 0.01f }, { 1.f, 1.f } })); @@ -260,70 +275,86 @@ namespace tut mCurve.sample(s, 129); for (F32 y : s) { - ensure("in range", y >= 0.f && y <= 1.f); - ensure("finite", std::isfinite(y)); + { + INFO("in range"); + REQUIRE(y >= 0.f); + REQUIRE(y <= 1.f); + } + UNSCOPED_INFO("finite"); + REQUIRE(std::isfinite(y)); } } // --- sampling ------------------------------------------------------------ // sample() spans 0..1 inclusive and honours its count. - template<> template<> - void curve_object::test<11>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: sample() spans 0..1 inclusive and honours its count", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.1f }, { 0.5f, 0.4f }, { 1.f, 0.9f } })); std::vector s; mCurve.sample(s, 65); - ensure_equals("count honoured", (S32)s.size(), 65); - ensure_approximately_equals("starts at evaluate(0)", s.front(), mCurve.evaluate(0.f), 6); - ensure_approximately_equals("ends at evaluate(1)", s.back(), mCurve.evaluate(1.f), 6); - ensure_approximately_equals("the last sample is the value at exactly 1", s.back(), 0.9f, 6); + UNSCOPED_INFO("count honoured"); + REQUIRE((S32)s.size() == 65); + UNSCOPED_INFO("starts at evaluate(0)"); + CHECK_THAT(s.front(), ll_test::WithinBits(mCurve.evaluate(0.f), 6)); + UNSCOPED_INFO("ends at evaluate(1)"); + CHECK_THAT(s.back(), ll_test::WithinBits(mCurve.evaluate(1.f), 6)); + UNSCOPED_INFO("the last sample is the value at exactly 1"); + CHECK_THAT(s.back(), ll_test::WithinBits(0.9f, 6)); mCurve.sample(s, 1); - ensure("a single sample is not a curve", s.empty()); + UNSCOPED_INFO("a single sample is not a curve"); + REQUIRE(s.empty()); mCurve.sample(s, 0); - ensure("zero samples", s.empty()); + UNSCOPED_INFO("zero samples"); + REQUIRE(s.empty()); } // Unlocking the endpoints lets the first and last points move horizontally; // re-locking snaps them back to the full domain. - template<> template<> - void curve_object::test<12>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: unlocked ends move horizontally and relocking snaps them back", "[ALCurveModel]") { mCurve.setEndpointsLocked(false); mCurve.setPoints(pts({ { 0.f, 0.f }, { 0.5f, 0.5f }, { 1.f, 1.f } })); mCurve.movePoint(0, 0.2f, 0.1f); - ensure_approximately_equals("unlocked end moved", mCurve.getPoints()[0].mX, 0.2f, 5); + UNSCOPED_INFO("unlocked end moved"); + CHECK_THAT(mCurve.getPoints()[0].mX, ll_test::WithinBits(0.2f, 5)); mCurve.setEndpointsLocked(true); - ensure_approximately_equals("relock snaps to 0", mCurve.getPoints()[0].mX, 0.f, 6); - ensure_approximately_equals("relock snaps to 1", mCurve.getPoints().back().mX, 1.f, 6); + UNSCOPED_INFO("relock snaps to 0"); + CHECK_THAT(mCurve.getPoints()[0].mX, ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("relock snaps to 1"); + CHECK_THAT(mCurve.getPoints().back().mX, ll_test::WithinBits(1.f, 6)); } // setPoints refuses to leave the model unusable. - template<> template<> - void curve_object::test<13>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: setPoints resets a single point to the identity ramp", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.3f, 0.3f } })); - ensure_equals("degenerate input resets to a ramp", mCurve.getPointCount(), 2); - ensure_approximately_equals("and it is the identity", mCurve.evaluate(0.5f), 0.5f, 5); + UNSCOPED_INFO("degenerate input resets to a ramp"); + CHECK(mCurve.getPointCount() == 2); + UNSCOPED_INFO("and it is the identity"); + CHECK_THAT(mCurve.evaluate(0.5f), ll_test::WithinBits(0.5f, 5)); } // The point cap: addPoint refuses at MAX_POINTS, and setPoints truncates // while keeping both ends, so a locked curve still spans the domain. - template<> template<> - void curve_object::test<14>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: addPoint stops at MAX_POINTS and setPoints keeps both ends", "[ALCurveModel]") { for (S32 i = 1; i <= ALCurveModel::MAX_POINTS - 2; ++i) { const F32 x = (F32)i / (F32)(ALCurveModel::MAX_POINTS - 1); - ensure("added while under the cap", mCurve.addPoint(x, x) >= 0); + UNSCOPED_INFO("added while under the cap"); + REQUIRE(mCurve.addPoint(x, x) >= 0); } - ensure_equals("at the cap", mCurve.getPointCount(), ALCurveModel::MAX_POINTS); - ensure_equals("refused past the cap", mCurve.addPoint(0.123f, 0.5f), -1); - ensure_equals("count unchanged", mCurve.getPointCount(), ALCurveModel::MAX_POINTS); + UNSCOPED_INFO("at the cap"); + CHECK(mCurve.getPointCount() == ALCurveModel::MAX_POINTS); + UNSCOPED_INFO("refused past the cap"); + CHECK(mCurve.addPoint(0.123f, 0.5f) == -1); + UNSCOPED_INFO("count unchanged"); + CHECK(mCurve.getPointCount() == ALCurveModel::MAX_POINTS); // A stored curve may carry more than the editor adds, and keeps every // point: truncating a file would render a shape the file does not @@ -335,9 +366,12 @@ namespace tut many.push_back(ALCurveModel::Point{ x, x * 0.5f }); } mCurve.setPoints(many); - ensure_equals("twenty stored points survive", mCurve.getPointCount(), 20); - ensure_approximately_equals("interior point kept", mCurve.getPoints()[15].mX, 15.f / 19.f, 5); - ensure_equals("but no further adds", mCurve.addPoint(0.123f, 0.5f), -1); + UNSCOPED_INFO("twenty stored points survive"); + CHECK(mCurve.getPointCount() == 20); + UNSCOPED_INFO("interior point kept"); + CHECK_THAT(mCurve.getPoints()[15].mX, ll_test::WithinBits(15.f / 19.f, 5)); + UNSCOPED_INFO("but no further adds"); + CHECK(mCurve.addPoint(0.123f, 0.5f) == -1); std::vector absurd; for (S32 i = 0; i < 100; ++i) @@ -346,10 +380,14 @@ namespace tut absurd.push_back(ALCurveModel::Point{ x, x * 0.5f }); } mCurve.setPoints(absurd); - ensure_equals("setPoints capped at the stored limit", mCurve.getPointCount(), ALCurveModel::MAX_STORED_POINTS); - ensure_approximately_equals("first point kept at 0", mCurve.getPoints().front().mX, 0.f, 6); - ensure_approximately_equals("last point kept at 1", mCurve.getPoints().back().mX, 1.f, 6); - ensure_approximately_equals("and it is the original last point", mCurve.getPoints().back().mY, 0.5f, 5); + UNSCOPED_INFO("setPoints capped at the stored limit"); + CHECK(mCurve.getPointCount() == ALCurveModel::MAX_STORED_POINTS); + UNSCOPED_INFO("first point kept at 0"); + CHECK_THAT(mCurve.getPoints().front().mX, ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("last point kept at 1"); + CHECK_THAT(mCurve.getPoints().back().mX, ll_test::WithinBits(1.f, 6)); + UNSCOPED_INFO("and it is the original last point"); + CHECK_THAT(mCurve.getPoints().back().mY, ll_test::WithinBits(0.5f, 5)); } // --- split-tone bands ---------------------------------------------------- @@ -358,8 +396,7 @@ namespace tut // computed before the widths existed, across the whole range of split // points the Balance slider can ask for. This is the promise that every // Look saved before then renders unchanged. - template<> template<> - void curve_object::test<15>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: default widths give the bands the shader computed before widths existed", "[ALCurveModel]") { for (F32 mid : { 0.1f, 0.3f, 0.5f, 0.7f, 0.9f }) { @@ -369,13 +406,16 @@ namespace tut F32 lo, md, hi; shaderSplitWeights(l, mid, lo, md, hi); const auto w = ALCurveModel::splitToneWeights(l, mid); - ensure_approximately_equals("shadow matches the old shader", w.mShadow, lo, 5); - ensure_approximately_equals("midtone matches the old shader", w.mMidtone, md, 5); - ensure_approximately_equals("highlight matches the old shader", w.mHighlight, hi, 5); + UNSCOPED_INFO("shadow matches the old shader"); + REQUIRE_THAT(w.mShadow, ll_test::WithinBits(lo, 5)); + UNSCOPED_INFO("midtone matches the old shader"); + REQUIRE_THAT(w.mMidtone, ll_test::WithinBits(md, 5)); + UNSCOPED_INFO("highlight matches the old shader"); + REQUIRE_THAT(w.mHighlight, ll_test::WithinBits(hi, 5)); } } - ensure_approximately_equals("the default width is the old constant", - ALCurveModel::SPLIT_TONE_DEFAULT_WIDTH, 0.35f, 6); + UNSCOPED_INFO("the default width is the old constant"); + CHECK_THAT(ALCurveModel::SPLIT_TONE_DEFAULT_WIDTH, ll_test::WithinBits(0.35f, 6)); } // The three weights partition the luma range: they sum to one everywhere. @@ -383,32 +423,48 @@ namespace tut // untinted, only ever shared between neighbouring bands -- and it holds // because the two ramps meet at the split without overlapping, so the // midtone remainder is never clamped away. - template<> template<> - void curve_object::test<16>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: the three split-tone weights sum to one everywhere", "[ALCurveModel]") { for (F32 mid : { 0.1f, 0.35f, 0.5f, 0.65f, 0.9f }) { for (S32 i = 0; i <= 64; ++i) { const auto w = ALCurveModel::splitToneWeights((F32)i / 64.f, mid); - ensure_approximately_equals("weights sum to one", - w.mShadow + w.mMidtone + w.mHighlight, 1.f, 5); - ensure("shadow in range", w.mShadow >= 0.f && w.mShadow <= 1.f); - ensure("midtone in range", w.mMidtone >= 0.f && w.mMidtone <= 1.f); - ensure("highlight in range", w.mHighlight >= 0.f && w.mHighlight <= 1.f); + UNSCOPED_INFO("weights sum to one"); + REQUIRE_THAT(w.mShadow + w.mMidtone + w.mHighlight, ll_test::WithinBits(1.f, 5)); + { + INFO("shadow in range"); + REQUIRE(w.mShadow >= 0.f); + REQUIRE(w.mShadow <= 1.f); + } + { + INFO("midtone in range"); + REQUIRE(w.mMidtone >= 0.f); + REQUIRE(w.mMidtone <= 1.f); + } + { + INFO("highlight in range"); + REQUIRE(w.mHighlight >= 0.f); + REQUIRE(w.mHighlight <= 1.f); + } } } const F32 mid = 0.55f; const auto at_mid = ALCurveModel::splitToneWeights(mid, mid); - ensure_approximately_equals("midtone peaks at the split", at_mid.mMidtone, 1.f, 5); - ensure_approximately_equals("shadow is spent there", at_mid.mShadow, 0.f, 5); - ensure_approximately_equals("highlight has not started", at_mid.mHighlight, 0.f, 5); + UNSCOPED_INFO("midtone peaks at the split"); + CHECK_THAT(at_mid.mMidtone, ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("shadow is spent there"); + CHECK_THAT(at_mid.mShadow, ll_test::WithinBits(0.f, 5)); + UNSCOPED_INFO("highlight has not started"); + CHECK_THAT(at_mid.mHighlight, ll_test::WithinBits(0.f, 5)); const auto black = ALCurveModel::splitToneWeights(0.f, mid); const auto white = ALCurveModel::splitToneWeights(1.f, mid); - ensure_approximately_equals("black is all shadow", black.mShadow, 1.f, 5); - ensure_approximately_equals("white is all highlight", white.mHighlight, 1.f, 5); + UNSCOPED_INFO("black is all shadow"); + CHECK_THAT(black.mShadow, ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("white is all highlight"); + CHECK_THAT(white.mHighlight, ll_test::WithinBits(1.f, 5)); // Monotone, so the bands cannot cross back over themselves. If the // shader's ramp edges were ever swapped, this is what notices. @@ -416,8 +472,10 @@ namespace tut for (S32 i = 0; i <= 64; ++i) { const auto w = ALCurveModel::splitToneWeights((F32)i / 64.f, mid); - ensure("highlight never falls", w.mHighlight >= prev_hi - 1e-5f); - ensure("shadow never rises", w.mShadow <= prev_lo + 1e-5f); + UNSCOPED_INFO("highlight never falls"); + REQUIRE(w.mHighlight >= prev_hi - 1e-5f); + UNSCOPED_INFO("shadow never rises"); + REQUIRE(w.mShadow <= prev_lo + 1e-5f); prev_hi = w.mHighlight; prev_lo = w.mShadow; } @@ -426,33 +484,35 @@ namespace tut // Balance and split point invert each other across the whole slider range, // which is what lets the graph's handle be read back into the setting // without the value creeping a little on every drag. - template<> template<> - void curve_object::test<17>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: balance and split point invert each other across the slider range", "[ALCurveModel]") { for (S32 i = -10; i <= 10; ++i) { const F32 balance = (F32)i / 10.f; const F32 mid = ALCurveModel::splitToneMid(balance); - ensure("split point stays in range", mid >= 0.1f - 1e-5f && mid <= 0.9f + 1e-5f); - ensure_approximately_equals("balance round-trips", - ALCurveModel::splitToneBalance(mid), balance, 5); + { + INFO("split point stays in range"); + REQUIRE(mid >= 0.1f - 1e-5f); + REQUIRE(mid <= 0.9f + 1e-5f); + } + UNSCOPED_INFO("balance round-trips"); + REQUIRE_THAT(ALCurveModel::splitToneBalance(mid), ll_test::WithinBits(balance, 5)); } - ensure_approximately_equals("neutral balance splits at mid grey", - ALCurveModel::splitToneMid(0.f), 0.5f, 6); + UNSCOPED_INFO("neutral balance splits at mid grey"); + CHECK_THAT(ALCurveModel::splitToneMid(0.f), ll_test::WithinBits(0.5f, 6)); // Clamped, not wrapped: pipeline.cpp clamps the balance before it // uploads the ramps, so the graph must agree rather than plot a split // the renderer will never use. - ensure_approximately_equals("out-of-range balance clamps", - ALCurveModel::splitToneMid(3.f), 0.9f, 6); - ensure_approximately_equals("and so does the inverse", - ALCurveModel::splitToneBalance(2.f), 1.f, 6); + UNSCOPED_INFO("out-of-range balance clamps"); + CHECK_THAT(ALCurveModel::splitToneMid(3.f), ll_test::WithinBits(0.9f, 6)); + UNSCOPED_INFO("and so does the inverse"); + CHECK_THAT(ALCurveModel::splitToneBalance(2.f), ll_test::WithinBits(1.f, 6)); } // With independent widths the model still agrees with the shader, which // now takes each ramp as the {scale, bias} pair the CPU derives. - template<> template<> - void curve_object::test<18>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: independent widths agree with the shader's scale and bias ramps", "[ALCurveModel]") { const std::pair widths[] = { { 0.05f, 0.5f }, { 0.35f, 0.35f }, { 0.5f, 0.02f }, { 0.2f, 0.1f } }; for (F32 mid : { 0.1f, 0.5f, 0.9f }) @@ -465,9 +525,12 @@ namespace tut F32 lo, md, hi; shaderSplitWeightsRamped(l, mid, wsh.first, wsh.second, lo, md, hi); const auto w = ALCurveModel::splitToneWeights(l, mid, wsh.first, wsh.second); - ensure_approximately_equals("shadow matches the shader", w.mShadow, lo, 5); - ensure_approximately_equals("midtone matches the shader", w.mMidtone, md, 5); - ensure_approximately_equals("highlight matches the shader", w.mHighlight, hi, 5); + UNSCOPED_INFO("shadow matches the shader"); + REQUIRE_THAT(w.mShadow, ll_test::WithinBits(lo, 5)); + UNSCOPED_INFO("midtone matches the shader"); + REQUIRE_THAT(w.mMidtone, ll_test::WithinBits(md, 5)); + UNSCOPED_INFO("highlight matches the shader"); + REQUIRE_THAT(w.mHighlight, ll_test::WithinBits(hi, 5)); } } } @@ -475,8 +538,7 @@ namespace tut // Partition of unity survives asymmetric widths: the ramps still meet at // the split and only at the split. - template<> template<> - void curve_object::test<19>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: partition of unity survives asymmetric widths", "[ALCurveModel]") { const std::pair widths[] = { { 0.05f, 0.5f }, { 0.5f, 0.02f }, { 0.2f, 0.1f } }; for (F32 mid : { 0.1f, 0.5f, 0.9f }) @@ -488,18 +550,33 @@ namespace tut { const F32 l = (F32)i / 64.f; const auto w = ALCurveModel::splitToneWeights(l, mid, wsh.first, wsh.second); - ensure_approximately_equals("weights sum to one", - w.mShadow + w.mMidtone + w.mHighlight, 1.f, 5); - ensure("shadow in range", w.mShadow >= 0.f && w.mShadow <= 1.f); - ensure("midtone in range", w.mMidtone >= 0.f && w.mMidtone <= 1.f); - ensure("highlight in range", w.mHighlight >= 0.f && w.mHighlight <= 1.f); - ensure("highlight never falls", w.mHighlight >= prev_hi - 1e-5f); - ensure("shadow never rises", w.mShadow <= prev_lo + 1e-5f); + UNSCOPED_INFO("weights sum to one"); + REQUIRE_THAT(w.mShadow + w.mMidtone + w.mHighlight, ll_test::WithinBits(1.f, 5)); + { + INFO("shadow in range"); + REQUIRE(w.mShadow >= 0.f); + REQUIRE(w.mShadow <= 1.f); + } + { + INFO("midtone in range"); + REQUIRE(w.mMidtone >= 0.f); + REQUIRE(w.mMidtone <= 1.f); + } + { + INFO("highlight in range"); + REQUIRE(w.mHighlight >= 0.f); + REQUIRE(w.mHighlight <= 1.f); + } + UNSCOPED_INFO("highlight never falls"); + REQUIRE(w.mHighlight >= prev_hi - 1e-5f); + UNSCOPED_INFO("shadow never rises"); + REQUIRE(w.mShadow <= prev_lo + 1e-5f); prev_hi = w.mHighlight; prev_lo = w.mShadow; } const auto at_mid = ALCurveModel::splitToneWeights(mid, mid, wsh.first, wsh.second); - ensure_approximately_equals("midtone peaks at the split", at_mid.mMidtone, 1.f, 5); + UNSCOPED_INFO("midtone peaks at the split"); + REQUIRE_THAT(at_mid.mMidtone, ll_test::WithinBits(1.f, 5)); // The ends are fully tinted only when the ramp fits on the // plot. A wide ramp under a low split runs off below zero and // black is then only partly shadow -- as it was with the old @@ -507,13 +584,13 @@ namespace tut // shows. if (mid - wsh.first >= 0.f) { - ensure_approximately_equals("black is all shadow", - ALCurveModel::splitToneWeights(0.f, mid, wsh.first, wsh.second).mShadow, 1.f, 5); + UNSCOPED_INFO("black is all shadow"); + REQUIRE_THAT(ALCurveModel::splitToneWeights(0.f, mid, wsh.first, wsh.second).mShadow, ll_test::WithinBits(1.f, 5)); } if (mid + wsh.second <= 1.f) { - ensure_approximately_equals("white is all highlight", - ALCurveModel::splitToneWeights(1.f, mid, wsh.first, wsh.second).mHighlight, 1.f, 5); + UNSCOPED_INFO("white is all highlight"); + REQUIRE_THAT(ALCurveModel::splitToneWeights(1.f, mid, wsh.first, wsh.second).mHighlight, ll_test::WithinBits(1.f, 5)); } } } @@ -522,28 +599,31 @@ namespace tut // A zero width is a step at the split, finite on both sides, and still a // partition -- the floor is applied before the shadow ramp's left edge is // formed, so the ramp ends at the split rather than short of it. - template<> template<> - void curve_object::test<20>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: a zero width is a finite step at the split and still a partition", "[ALCurveModel]") { const auto ramp = ALCurveModel::splitToneRamp(0.5f, 0.f); - ensure("scale finite", std::isfinite(ramp.mScale)); - ensure("bias finite", std::isfinite(ramp.mBias)); + UNSCOPED_INFO("scale finite"); + CHECK(std::isfinite(ramp.mScale)); + UNSCOPED_INFO("bias finite"); + CHECK(std::isfinite(ramp.mBias)); const auto below = ALCurveModel::splitToneWeights(0.49f, 0.5f, 0.f, 0.f); const auto above = ALCurveModel::splitToneWeights(0.51f, 0.5f, 0.f, 0.f); - ensure_approximately_equals("all shadow just below the split", below.mShadow, 1.f, 5); - ensure_approximately_equals("all highlight just above the split", above.mHighlight, 1.f, 5); + UNSCOPED_INFO("all shadow just below the split"); + CHECK_THAT(below.mShadow, ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("all highlight just above the split"); + CHECK_THAT(above.mHighlight, ll_test::WithinBits(1.f, 5)); for (S32 i = 0; i <= 64; ++i) { const auto w = ALCurveModel::splitToneWeights((F32)i / 64.f, 0.5f, 0.f, 0.f); - ensure_approximately_equals("still sums to one", w.mShadow + w.mMidtone + w.mHighlight, 1.f, 5); + UNSCOPED_INFO("still sums to one"); + REQUIRE_THAT(w.mShadow + w.mMidtone + w.mHighlight, ll_test::WithinBits(1.f, 5)); } } // The scale/bias pair is the two-edge form folded: l*scale + bias is // (l - edge0) / width wherever the width is above the floor. - template<> template<> - void curve_object::test<21>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: the scale/bias pair is the two-edge ramp folded", "[ALCurveModel]") { const F32 edges[] = { 0.f, 0.15f, 0.5f, 0.9f }; const F32 widths[] = { 0.02f, 0.1f, 0.35f, 0.5f }; @@ -555,16 +635,15 @@ namespace tut for (S32 i = 0; i <= 20; ++i) { const F32 l = (F32)i / 20.f; - ensure_approximately_equals("folded form agrees", - l * ramp.mScale + ramp.mBias, (l - edge0) / width, 4); + UNSCOPED_INFO("folded form agrees"); + REQUIRE_THAT(l * ramp.mScale + ramp.mBias, ll_test::WithinBits((l - edge0) / width, 4)); } } } } // The two-argument overload is the four-argument call at the default. - template<> template<> - void curve_object::test<22>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: the two-argument overload is the four-argument call at the default", "[ALCurveModel]") { for (F32 mid : { 0.1f, 0.5f, 0.9f }) { @@ -573,9 +652,12 @@ namespace tut const F32 l = (F32)i / 32.f; const auto a = ALCurveModel::splitToneWeights(l, mid); const auto b = ALCurveModel::splitToneWeights(l, mid, 0.35f, 0.35f); - ensure_equals("shadow bit for bit", a.mShadow, b.mShadow); - ensure_equals("midtone bit for bit", a.mMidtone, b.mMidtone); - ensure_equals("highlight bit for bit", a.mHighlight, b.mHighlight); + UNSCOPED_INFO("shadow bit for bit"); + REQUIRE(a.mShadow == b.mShadow); + UNSCOPED_INFO("midtone bit for bit"); + REQUIRE(a.mMidtone == b.mMidtone); + UNSCOPED_INFO("highlight bit for bit"); + REQUIRE(a.mHighlight == b.mHighlight); } } } @@ -583,23 +665,25 @@ namespace tut // --- ALToneCurveSet ------------------------------------------------------ // A fresh set is identity in every channel, and bakes to the identity ramp. - template<> template<> - void curve_object::test<23>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: a fresh set is identity in every channel and bakes to the identity ramp", "[ALCurveModel]") { ALToneCurveSet set; - ensure("identity by default", set.isIdentity()); + UNSCOPED_INFO("identity by default"); + CHECK(set.isIdentity()); for (S32 c = 0; c < ALToneCurveSet::CH_COUNT; ++c) { for (S32 i = 0; i <= 20; ++i) { const F32 x = (F32)i / 20.f; - ensure_approximately_equals("evaluates to x", set.evaluate((ALToneCurveSet::EChannel)c, x), x, 6); + UNSCOPED_INFO("evaluates to x"); + REQUIRE_THAT(set.evaluate((ALToneCurveSet::EChannel)c, x), ll_test::WithinBits(x, 6)); } } std::vector texels; set.bake(texels, 512); - ensure_equals("four U16 per texel", (S32)texels.size(), 512 * 4); + UNSCOPED_INFO("four U16 per texel"); + REQUIRE((S32)texels.size() == 512 * 4); for (S32 i = 0; i < 512; ++i) { const S32 expected = (S32)std::floor(65535.0 * i / 511.0 + 0.5); @@ -608,58 +692,77 @@ namespace tut // Within one code: the spline runs in F32, and a few of the // ratios sit close enough to a rounding boundary for the last // bit to decide which side. - ensure("identity ramp texel", std::abs((S32)texels[i * 4 + c] - expected) <= 1); + UNSCOPED_INFO("identity ramp texel"); + REQUIRE(std::abs((S32)texels[i * 4 + c] - expected) <= 1); } - ensure_equals("alpha opaque", (S32)texels[i * 4 + 3], (S32)ALToneCurveSet::ALPHA_OPAQUE); + UNSCOPED_INFO("alpha opaque"); + REQUIRE((S32)texels[i * 4 + 3] == (S32)ALToneCurveSet::ALPHA_OPAQUE); } } // Points survive an LLSD round trip, in the array-of-pairs shape the // settings and Looks carry. - template<> template<> - void curve_object::test<24>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: points survive an LLSD round trip as an array of pairs", "[ALCurveModel]") { const auto in = pts({ { 0.f, 0.05f }, { 0.25f, 0.2f }, { 0.75f, 0.8f }, { 1.f, 0.95f } }); const LLSD sd = ALToneCurveSet::pointsToLLSD(in); - ensure("array", sd.isArray()); - ensure_equals("one entry per point", (S32)sd.size(), 4); + UNSCOPED_INFO("array"); + REQUIRE(sd.isArray()); + UNSCOPED_INFO("one entry per point"); + REQUIRE((S32)sd.size() == 4); for (S32 i = 0; i < 4; ++i) { - ensure("entry is an array", sd[i].isArray()); - ensure_equals("entry is a pair", (S32)sd[i].size(), 2); - ensure("x is a real", sd[i][0].isReal()); - ensure("y is a real", sd[i][1].isReal()); + UNSCOPED_INFO("entry is an array"); + REQUIRE(sd[i].isArray()); + UNSCOPED_INFO("entry is a pair"); + REQUIRE((S32)sd[i].size() == 2); + UNSCOPED_INFO("x is a real"); + REQUIRE(sd[i][0].isReal()); + UNSCOPED_INFO("y is a real"); + REQUIRE(sd[i][1].isReal()); } std::vector out; - ensure("parsed", ALToneCurveSet::pointsFromLLSD(sd, out)); - ensure_equals("all points back", (S32)out.size(), 4); + UNSCOPED_INFO("parsed"); + REQUIRE(ALToneCurveSet::pointsFromLLSD(sd, out)); + UNSCOPED_INFO("all points back"); + REQUIRE((S32)out.size() == 4); for (S32 i = 0; i < 4; ++i) { - ensure_approximately_equals("x survives", out[i].mX, in[i].mX, 6); - ensure_approximately_equals("y survives", out[i].mY, in[i].mY, 6); + UNSCOPED_INFO("x survives"); + REQUIRE_THAT(out[i].mX, ll_test::WithinBits(in[i].mX, 6)); + UNSCOPED_INFO("y survives"); + REQUIRE_THAT(out[i].mY, ll_test::WithinBits(in[i].mY, 6)); } ALToneCurveSet set; - ensure("set from LLSD", set.setCurveFromLLSD(ALToneCurveSet::CH_GREEN, sd)); - ensure("no longer identity", !set.isIdentity()); + UNSCOPED_INFO("set from LLSD"); + REQUIRE(set.setCurveFromLLSD(ALToneCurveSet::CH_GREEN, sd)); + UNSCOPED_INFO("no longer identity"); + CHECK_FALSE(set.isIdentity()); const LLSD back = set.getCurveAsLLSD(ALToneCurveSet::CH_GREEN); - ensure_equals("same count after the model", (S32)back.size(), 4); - ensure_approximately_equals("same value after the model", (F32)back[1][1].asReal(), 0.2f, 6); + UNSCOPED_INFO("same count after the model"); + REQUIRE((S32)back.size() == 4); + UNSCOPED_INFO("same value after the model"); + CHECK_THAT((F32)back[1][1].asReal(), ll_test::WithinBits(0.2f, 6)); } // Garbage in is identity out, and never a crash or a point at the origin: // a corrupt setting renders as "no curve". - template<> template<> - void curve_object::test<25>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: garbage LLSD is refused or skipped and leaves an identity curve", "[ALCurveModel]") { std::vector out; - ensure("undefined refused", !ALToneCurveSet::pointsFromLLSD(LLSD(), out)); - ensure_equals("identity on refusal", (S32)out.size(), 2); - ensure("string refused", !ALToneCurveSet::pointsFromLLSD(LLSD("[[0,0],[1,1]]"), out)); - ensure("map refused", !ALToneCurveSet::pointsFromLLSD(LLSD::emptyMap(), out)); - ensure("empty array refused", !ALToneCurveSet::pointsFromLLSD(LLSD::emptyArray(), out)); + UNSCOPED_INFO("undefined refused"); + REQUIRE_FALSE(ALToneCurveSet::pointsFromLLSD(LLSD(), out)); + UNSCOPED_INFO("identity on refusal"); + REQUIRE((S32)out.size() == 2); + UNSCOPED_INFO("string refused"); + CHECK_FALSE(ALToneCurveSet::pointsFromLLSD(LLSD("[[0,0],[1,1]]"), out)); + UNSCOPED_INFO("map refused"); + CHECK_FALSE(ALToneCurveSet::pointsFromLLSD(LLSD::emptyMap(), out)); + UNSCOPED_INFO("empty array refused"); + CHECK_FALSE(ALToneCurveSet::pointsFromLLSD(LLSD::emptyArray(), out)); // Malformed entries are skipped, not fatal; the survivors are used. LLSD mixed = LLSD::emptyArray(); @@ -676,25 +779,38 @@ namespace tut mixed.append(pair(LLSD::Real(0.0), LLSD::Real(0.0))); mixed.append(pair(LLSD::Integer(1), LLSD::Integer(1))); // integers are numbers too mixed.append(pair(LLSD::Real(0.5), LLSD::Real(0.3))); - ensure("survivors accepted", ALToneCurveSet::pointsFromLLSD(mixed, out)); - ensure_equals("exactly the three well-formed pairs", (S32)out.size(), 3); + UNSCOPED_INFO("survivors accepted"); + CHECK(ALToneCurveSet::pointsFromLLSD(mixed, out)); + UNSCOPED_INFO("exactly the three well-formed pairs"); + REQUIRE((S32)out.size() == 3); // One well-formed pair is not a curve. LLSD one = LLSD::emptyArray(); one.append(pair(LLSD::Real(0.5), LLSD::Real(0.5))); - ensure("a lone pair refused", !ALToneCurveSet::pointsFromLLSD(one, out)); - ensure_equals("identity again", (S32)out.size(), 2); + UNSCOPED_INFO("a lone pair refused"); + CHECK_FALSE(ALToneCurveSet::pointsFromLLSD(one, out)); + UNSCOPED_INFO("identity again"); + REQUIRE((S32)out.size() == 2); // Out of range is clamped by the model, not rejected. LLSD wild = LLSD::emptyArray(); wild.append(pair(LLSD::Real(-1.0), LLSD::Real(-1.0))); wild.append(pair(LLSD::Real(2.0), LLSD::Real(2.0))); ALToneCurveSet set; - ensure("parsed", set.setCurveFromLLSD(ALToneCurveSet::CH_RED, wild)); + UNSCOPED_INFO("parsed"); + REQUIRE(set.setCurveFromLLSD(ALToneCurveSet::CH_RED, wild)); for (const auto& p : set.curve(ALToneCurveSet::CH_RED).getPoints()) { - ensure("x clamped", p.mX >= 0.f && p.mX <= 1.f); - ensure("y clamped", p.mY >= 0.f && p.mY <= 1.f); + { + INFO("x clamped"); + REQUIRE(p.mX >= 0.f); + REQUIRE(p.mX <= 1.f); + } + { + INFO("y clamped"); + REQUIRE(p.mY >= 0.f); + REQUIRE(p.mY <= 1.f); + } } // More points than the editor adds are kept as long as a file could @@ -705,12 +821,17 @@ namespace tut const F64 x = i / 39.0; many.append(pair(LLSD::Real(x), LLSD::Real(x * x))); } - ensure("parsed", set.setCurveFromLLSD(ALToneCurveSet::CH_BLUE, many)); + UNSCOPED_INFO("parsed"); + CHECK(set.setCurveFromLLSD(ALToneCurveSet::CH_BLUE, many)); const auto& kept = set.curve(ALToneCurveSet::CH_BLUE).getPoints(); - ensure_equals("all forty kept", (S32)kept.size(), 40); - ensure_approximately_equals("first at 0", kept.front().mX, 0.f, 6); - ensure_approximately_equals("last at 1", kept.back().mX, 1.f, 6); - ensure_approximately_equals("shape honoured", set.curve(ALToneCurveSet::CH_BLUE).evaluate(0.5f), 0.25f, 4); + UNSCOPED_INFO("all forty kept"); + REQUIRE((S32)kept.size() == 40); + UNSCOPED_INFO("first at 0"); + CHECK_THAT(kept.front().mX, ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("last at 1"); + CHECK_THAT(kept.back().mX, ll_test::WithinBits(1.f, 6)); + UNSCOPED_INFO("shape honoured"); + CHECK_THAT(set.curve(ALToneCurveSet::CH_BLUE).evaluate(0.5f), ll_test::WithinBits(0.25f, 4)); LLSD absurd = LLSD::emptyArray(); for (S32 i = 0; i <= ALCurveModel::MAX_STORED_POINTS; ++i) @@ -718,62 +839,66 @@ namespace tut const F64 x = (F64)i / ALCurveModel::MAX_STORED_POINTS; absurd.append(pair(LLSD::Real(x), LLSD::Real(x))); } - ensure("past the stored limit is refused", !set.setCurveFromLLSD(ALToneCurveSet::CH_BLUE, absurd)); - ensure_equals("and renders as no curve", set.curve(ALToneCurveSet::CH_BLUE).getPointCount(), 2); + UNSCOPED_INFO("past the stored limit is refused"); + CHECK_FALSE(set.setCurveFromLLSD(ALToneCurveSet::CH_BLUE, absurd)); + UNSCOPED_INFO("and renders as no curve"); + CHECK(set.curve(ALToneCurveSet::CH_BLUE).getPointCount() == 2); } // Composite order: the channel curve first, then master on its output. - template<> template<> - void curve_object::test<26>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: a channel's curve applies first and master on its output", "[ALCurveModel]") { ALToneCurveSet set; set.curve(ALToneCurveSet::CH_RED).setPoints(pts({ { 0.f, 0.f }, { 0.5f, 0.25f }, { 1.f, 1.f } })); set.curve(ALToneCurveSet::CH_MASTER).setPoints(pts({ { 0.f, 0.f }, { 0.25f, 0.75f }, { 1.f, 1.f } })); - ensure_approximately_equals("red then master", set.evaluate(ALToneCurveSet::CH_RED, 0.5f), 0.75f, 4); - ensure_approximately_equals("is master(red(x))", - set.evaluate(ALToneCurveSet::CH_RED, 0.5f), - set.curve(ALToneCurveSet::CH_MASTER).evaluate(set.curve(ALToneCurveSet::CH_RED).evaluate(0.5f)), 6); - ensure_approximately_equals("an identity channel is just master", - set.evaluate(ALToneCurveSet::CH_GREEN, 0.5f), - set.curve(ALToneCurveSet::CH_MASTER).evaluate(0.5f), 6); - ensure_approximately_equals("master alone is master", - set.evaluate(ALToneCurveSet::CH_MASTER, 0.5f), - set.curve(ALToneCurveSet::CH_MASTER).evaluate(0.5f), 6); + UNSCOPED_INFO("red then master"); + CHECK_THAT(set.evaluate(ALToneCurveSet::CH_RED, 0.5f), ll_test::WithinBits(0.75f, 4)); + UNSCOPED_INFO("is master(red(x))"); + CHECK_THAT(set.evaluate(ALToneCurveSet::CH_RED, 0.5f), + ll_test::WithinBits(set.curve(ALToneCurveSet::CH_MASTER).evaluate(set.curve(ALToneCurveSet::CH_RED).evaluate(0.5f)), 6)); + UNSCOPED_INFO("an identity channel is just master"); + CHECK_THAT(set.evaluate(ALToneCurveSet::CH_GREEN, 0.5f), + ll_test::WithinBits(set.curve(ALToneCurveSet::CH_MASTER).evaluate(0.5f), 6)); + UNSCOPED_INFO("master alone is master"); + CHECK_THAT(set.evaluate(ALToneCurveSet::CH_MASTER, 0.5f), + ll_test::WithinBits(set.curve(ALToneCurveSet::CH_MASTER).evaluate(0.5f), 6)); // A master edit moves every channel. ALToneCurveSet master_only; master_only.curve(ALToneCurveSet::CH_MASTER).setPoints(pts({ { 0.f, 0.1f }, { 1.f, 0.9f } })); for (S32 c = ALToneCurveSet::CH_RED; c <= ALToneCurveSet::CH_BLUE; ++c) { - ensure_approximately_equals("every channel follows master", - master_only.evaluate((ALToneCurveSet::EChannel)c, 0.f), 0.1f, 5); + UNSCOPED_INFO("every channel follows master"); + REQUIRE_THAT(master_only.evaluate((ALToneCurveSet::EChannel)c, 0.f), ll_test::WithinBits(0.1f, 5)); } } // Identity detection is exact on the points, with a tolerance far below // anything visible, and it is per set: one non-identity channel is enough. - template<> template<> - void curve_object::test<27>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: identity is detected within a tiny tolerance and per set", "[ALCurveModel]") { ALCurveModel close_curve; close_curve.setPoints(pts({ { 0.f, 0.f }, { 0.5f, 0.5f + 0.5f * ALToneCurveSet::IDENTITY_EPS }, { 1.f, 1.f } })); - ensure("within eps is identity", ALToneCurveSet::isIdentityCurve(close_curve)); + UNSCOPED_INFO("within eps is identity"); + CHECK(ALToneCurveSet::isIdentityCurve(close_curve)); ALCurveModel far_curve; far_curve.setPoints(pts({ { 0.f, 0.f }, { 0.5f, 0.5f + 10.f * ALToneCurveSet::IDENTITY_EPS }, { 1.f, 1.f } })); - ensure("beyond eps is not", !ALToneCurveSet::isIdentityCurve(far_curve)); + UNSCOPED_INFO("beyond eps is not"); + CHECK_FALSE(ALToneCurveSet::isIdentityCurve(far_curve)); ALToneCurveSet set; - ensure("all identity", set.isIdentity()); + UNSCOPED_INFO("all identity"); + CHECK(set.isIdentity()); set.curve(ALToneCurveSet::CH_BLUE).setPoints(pts({ { 0.f, 0.f }, { 0.5f, 0.6f }, { 1.f, 1.f } })); - ensure("one channel is enough", !set.isIdentity()); + UNSCOPED_INFO("one channel is enough"); + CHECK_FALSE(set.isIdentity()); } // The baked row: one RGBA16 texel per sample, the curve's ends at the // row's ends, and a monotone curve gives a monotone row. - template<> template<> - void curve_object::test<28>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: the baked row holds the curve's ends and is monotone and opaque", "[ALCurveModel]") { ALToneCurveSet set; set.curve(ALToneCurveSet::CH_MASTER).setPoints( @@ -783,28 +908,34 @@ namespace tut const S32 n = ALToneCurveSet::LUT_SIZE; std::vector texels; set.bake(texels, n); - ensure_equals("size", (S32)texels.size(), n * 4); + UNSCOPED_INFO("size"); + REQUIRE((S32)texels.size() == n * 4); for (S32 c = 0; c < 3; ++c) { const ALToneCurveSet::EChannel channel = (ALToneCurveSet::EChannel)(ALToneCurveSet::CH_RED + c); const F32 lo = set.evaluate(channel, 0.f) * 65535.f; const F32 hi = set.evaluate(channel, 1.f) * 65535.f; - ensure("first texel is the curve at 0", fabsf((F32)texels[c] - lo) <= 1.f); - ensure("last texel is the curve at 1", fabsf((F32)texels[(n - 1) * 4 + c] - hi) <= 1.f); + UNSCOPED_INFO("first texel is the curve at 0"); + REQUIRE(fabsf((F32)texels[c] - lo) <= 1.f); + UNSCOPED_INFO("last texel is the curve at 1"); + REQUIRE(fabsf((F32)texels[(n - 1) * 4 + c] - hi) <= 1.f); for (S32 i = 1; i < n; ++i) { - ensure("monotone row", texels[i * 4 + c] >= texels[(i - 1) * 4 + c]); + UNSCOPED_INFO("monotone row"); + REQUIRE(texels[i * 4 + c] >= texels[(i - 1) * 4 + c]); } } for (S32 i = 0; i < n; ++i) { - ensure_equals("alpha opaque", (S32)texels[i * 4 + 3], (S32)ALToneCurveSet::ALPHA_OPAQUE); + UNSCOPED_INFO("alpha opaque"); + REQUIRE((S32)texels[i * 4 + 3] == (S32)ALToneCurveSet::ALPHA_OPAQUE); } std::vector tiny; set.bake(tiny, 1); - ensure_equals("a size below 2 is raised to 2", (S32)tiny.size(), 2 * 4); + UNSCOPED_INFO("a size below 2 is raised to 2"); + REQUIRE((S32)tiny.size() == 2 * 4); } // What the shader will read back agrees with the analytic curve to well @@ -814,8 +945,7 @@ namespace tut // curves at 512 samples with 8-bit filter weights, and 0.50/1024 even with // the 4-bit weights old hardware is allowed; at 256 samples the 4-bit case // reaches 0.97/1024, which is why 512 is the size that ships. - template<> template<> - void curve_object::test<29>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: the shader's LUT fetch agrees with the curve to under 1/1024", "[ALCurveModel]") { ALToneCurveSet set; set.curve(ALToneCurveSet::CH_MASTER).setPoints( @@ -844,18 +974,18 @@ namespace tut { worst = std::max(worst, fabsf(shaderLutFetch(texels, n, c, x) - set.evaluate(channel, x))); } - ensure("endpoint 0 exact to the U16", - fabsf(shaderLutFetch(texels, n, c, 0.f) - set.evaluate(channel, 0.f)) <= 1.f / 65535.f + 1e-6f); - ensure("endpoint 1 exact to the U16", - fabsf(shaderLutFetch(texels, n, c, 1.f) - set.evaluate(channel, 1.f)) <= 1.f / 65535.f + 1e-6f); + UNSCOPED_INFO("endpoint 0 exact to the U16"); + REQUIRE(fabsf(shaderLutFetch(texels, n, c, 0.f) - set.evaluate(channel, 0.f)) <= 1.f / 65535.f + 1e-6f); + UNSCOPED_INFO("endpoint 1 exact to the U16"); + REQUIRE(fabsf(shaderLutFetch(texels, n, c, 1.f) - set.evaluate(channel, 1.f)) <= 1.f / 65535.f + 1e-6f); } - ensure("reconstruction error below 1/1024", worst < 1.f / 1024.f); + UNSCOPED_INFO("reconstruction error below 1/1024"); + CHECK(worst < 1.f / 1024.f); } // The half-texel mapping puts x = 0 on the centre of the first texel and // x = 1 on the centre of the last, for any row width. - template<> template<> - void curve_object::test<30>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: the half-texel mapping puts 0 and 1 on the end texels' centres", "[ALCurveModel]") { for (S32 n : { 2, 256, 512 }) { @@ -863,85 +993,111 @@ namespace tut ALToneCurveSet::lutScaleBias(n, scale, bias); const F32 u0 = 0.f * scale + bias; const F32 u1 = 1.f * scale + bias; - ensure_approximately_equals("x = 0 is texel 0's centre", u0 * (F32)n - 0.5f, 0.f, 6); - ensure_approximately_equals("x = 1 is the last texel's centre", u1 * (F32)n - 0.5f, (F32)(n - 1), 6); + UNSCOPED_INFO("x = 0 is texel 0's centre"); + REQUIRE_THAT(u0 * (F32)n - 0.5f, ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("x = 1 is the last texel's centre"); + REQUIRE_THAT(u1 * (F32)n - 0.5f, ll_test::WithinBits((F32)(n - 1), 6)); } } // The channel combo's values map onto the set, with anything unexpected // landing on Master rather than on a channel. - template<> template<> - void curve_object::test<31>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: combo values map onto channels and anything else onto master", "[ALCurveModel]") { - ensure_equals("-1 is master", (S32)ALToneCurveSet::channelFromCombo(-1), (S32)ALToneCurveSet::CH_MASTER); - ensure_equals("0 is red", (S32)ALToneCurveSet::channelFromCombo(0), (S32)ALToneCurveSet::CH_RED); - ensure_equals("1 is green", (S32)ALToneCurveSet::channelFromCombo(1), (S32)ALToneCurveSet::CH_GREEN); - ensure_equals("2 is blue", (S32)ALToneCurveSet::channelFromCombo(2), (S32)ALToneCurveSet::CH_BLUE); - ensure_equals("anything else is master", (S32)ALToneCurveSet::channelFromCombo(7), (S32)ALToneCurveSet::CH_MASTER); + UNSCOPED_INFO("-1 is master"); + CHECK((S32)ALToneCurveSet::channelFromCombo(-1) == (S32)ALToneCurveSet::CH_MASTER); + UNSCOPED_INFO("0 is red"); + CHECK((S32)ALToneCurveSet::channelFromCombo(0) == (S32)ALToneCurveSet::CH_RED); + UNSCOPED_INFO("1 is green"); + CHECK((S32)ALToneCurveSet::channelFromCombo(1) == (S32)ALToneCurveSet::CH_GREEN); + UNSCOPED_INFO("2 is blue"); + CHECK((S32)ALToneCurveSet::channelFromCombo(2) == (S32)ALToneCurveSet::CH_BLUE); + UNSCOPED_INFO("anything else is master"); + CHECK((S32)ALToneCurveSet::channelFromCombo(7) == (S32)ALToneCurveSet::CH_MASTER); const LLSD ident = ALToneCurveSet::identityLLSD(); - ensure_equals("identity is two points", (S32)ident.size(), 2); - ensure_approximately_equals("from the origin", (F32)ident[0][0].asReal(), 0.f, 6); - ensure_approximately_equals("to the corner", (F32)ident[1][1].asReal(), 1.f, 6); + UNSCOPED_INFO("identity is two points"); + REQUIRE((S32)ident.size() == 2); + UNSCOPED_INFO("from the origin"); + CHECK_THAT((F32)ident[0][0].asReal(), ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("to the corner"); + CHECK_THAT((F32)ident[1][1].asReal(), ll_test::WithinBits(1.f, 6)); } // An add at either edge lands one gap inside the pinned end, never on it, // so the curve still ends where the end says and the end stays the end. - template<> template<> - void curve_object::test<32>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: an add at either edge lands one gap inside the pinned end", "[ALCurveModel]") { - ensure("added at the right edge", mCurve.addPoint(1.f, 0.03f) >= 0); - ensure_equals("three points", mCurve.getPointCount(), 3); - ensure_approximately_equals("interior, one gap inside", mCurve.getPoints()[1].mX, 1.f - ALCurveModel::MIN_POINT_GAP, 5); - ensure_approximately_equals("the end is still the end", mCurve.getPoints().back().mX, 1.f, 6); - ensure_approximately_equals("and still at its height", mCurve.getPoints().back().mY, 1.f, 6); - ensure_approximately_equals("evaluate(1) is the end", mCurve.evaluate(1.f), 1.f, 6); - - ensure("added at the left edge", mCurve.addPoint(0.f, 0.9f) >= 0); - ensure_approximately_equals("the start is still the start", mCurve.getPoints().front().mX, 0.f, 6); - ensure_approximately_equals("and at its height", mCurve.getPoints().front().mY, 0.f, 6); - ensure_approximately_equals("interior, one gap inside", mCurve.getPoints()[1].mX, ALCurveModel::MIN_POINT_GAP, 5); - ensure_approximately_equals("evaluate(0) is the start", mCurve.evaluate(0.f), 0.f, 6); + UNSCOPED_INFO("added at the right edge"); + CHECK(mCurve.addPoint(1.f, 0.03f) >= 0); + UNSCOPED_INFO("three points"); + CHECK(mCurve.getPointCount() == 3); + UNSCOPED_INFO("interior, one gap inside"); + CHECK_THAT(mCurve.getPoints()[1].mX, ll_test::WithinBits(1.f - ALCurveModel::MIN_POINT_GAP, 5)); + UNSCOPED_INFO("the end is still the end"); + CHECK_THAT(mCurve.getPoints().back().mX, ll_test::WithinBits(1.f, 6)); + UNSCOPED_INFO("and still at its height"); + CHECK_THAT(mCurve.getPoints().back().mY, ll_test::WithinBits(1.f, 6)); + UNSCOPED_INFO("evaluate(1) is the end"); + CHECK_THAT(mCurve.evaluate(1.f), ll_test::WithinBits(1.f, 6)); + + UNSCOPED_INFO("added at the left edge"); + CHECK(mCurve.addPoint(0.f, 0.9f) >= 0); + UNSCOPED_INFO("the start is still the start"); + CHECK_THAT(mCurve.getPoints().front().mX, ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("and at its height"); + CHECK_THAT(mCurve.getPoints().front().mY, ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("interior, one gap inside"); + CHECK_THAT(mCurve.getPoints()[1].mX, ll_test::WithinBits(ALCurveModel::MIN_POINT_GAP, 5)); + UNSCOPED_INFO("evaluate(0) is the start"); + CHECK_THAT(mCurve.evaluate(0.f), ll_test::WithinBits(0.f, 6)); } // Points piled up on the top edge are pushed down, not left coincident: // the separation pass works from both ends. - template<> template<> - void curve_object::test<33>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: points piled up on the top edge are pushed apart below it", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.f }, { 1.f, 0.2f }, { 1.f, 0.4f }, { 1.f, 0.6f }, { 1.f, 1.f } })); const auto& p = mCurve.getPoints(); - ensure_equals("all kept", (S32)p.size(), 5); + UNSCOPED_INFO("all kept"); + REQUIRE((S32)p.size() == 5); for (size_t i = 1; i < p.size(); ++i) { - ensure("separated", p[i].mX - p[i - 1].mX >= ALCurveModel::MIN_POINT_GAP - 1e-6f); + UNSCOPED_INFO("separated"); + REQUIRE(p[i].mX - p[i - 1].mX >= ALCurveModel::MIN_POINT_GAP - 1e-6f); } - ensure_approximately_equals("the end is still at 1", p.back().mX, 1.f, 6); - ensure_approximately_equals("evaluate(1) is the end", mCurve.evaluate(1.f), 1.f, 6); + UNSCOPED_INFO("the end is still at 1"); + CHECK_THAT(p.back().mX, ll_test::WithinBits(1.f, 6)); + UNSCOPED_INFO("evaluate(1) is the end"); + CHECK_THAT(mCurve.evaluate(1.f), ll_test::WithinBits(1.f, 6)); std::vector s; mCurve.sample(s, 1025); for (size_t i = 1; i < s.size(); ++i) { - ensure("finite", std::isfinite(s[i])); - ensure("monotone", s[i] >= s[i - 1] - 1e-5f); + UNSCOPED_INFO("finite"); + REQUIRE(std::isfinite(s[i])); + UNSCOPED_INFO("monotone"); + REQUIRE(s[i] >= s[i - 1] - 1e-5f); } } // The setting names are one list: distinct, and channel-shaped. - template<> template<> - void curve_object::test<34>() + TEST_CASE_METHOD(curve_data, "ALCurveModel: the setting names are distinct and named for the curve", "[ALCurveModel]") { for (S32 c = 0; c < ALToneCurveSet::CH_COUNT; ++c) { const std::string name = ALToneCurveSet::settingName((ALToneCurveSet::EChannel)c); - ensure("named for the curve", name.rfind("RenderColorGradeCurve", 0) == 0); + UNSCOPED_INFO("named for the curve"); + REQUIRE(name.rfind("RenderColorGradeCurve", 0) == 0); for (S32 d = 0; d < c; ++d) { - ensure("distinct", name != ALToneCurveSet::settingName((ALToneCurveSet::EChannel)d)); + UNSCOPED_INFO("distinct"); + REQUIRE(name != ALToneCurveSet::settingName((ALToneCurveSet::EChannel)d)); } } - ensure_equals("master", std::string(ALToneCurveSet::settingName(ALToneCurveSet::CH_MASTER)), + UNSCOPED_INFO("master"); + CHECK(std::string(ALToneCurveSet::settingName(ALToneCurveSet::CH_MASTER)) == std::string("RenderColorGradeCurveMaster")); } } diff --git a/indra/newview/tests/aldaycyclelandmarks_test.cpp b/indra/newview/tests/aldaycyclelandmarks_test.cpp index 28852cb9e4..b317c98cab 100644 --- a/indra/newview/tests/aldaycyclelandmarks_test.cpp +++ b/indra/newview/tests/aldaycyclelandmarks_test.cpp @@ -14,7 +14,7 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include #include "../aldaycyclelandmarks.h" @@ -28,7 +28,7 @@ namespace constexpr F32 TWO_PI = 6.28318530718f; } -namespace tut +namespace { struct daycycle_landmarks { @@ -49,115 +49,145 @@ namespace tut } }; - typedef test_group landmark_group; - typedef landmark_group::object landmark_object; - tut::landmark_group lg("ALDayCycleLandmarks"); - // A plain sine puts sunrise at 0, noon at a quarter, sunset at a half and // midnight at three quarters. - template<> template<> - void landmark_object::test<1>() + TEST_CASE_METHOD(daycycle_landmarks, "ALDayCycleLandmarks: a plain sine has its four landmarks a quarter apart from 0", "[ALDayCycleLandmarks]") { const auto marks = ALDayCycleLandmarks::find(sine()); - ensure("has sunrise", marks.has_sunrise); - ensure("has noon", marks.has_noon); - ensure("has sunset", marks.has_sunset); - ensure("has midnight", marks.has_midnight); - - ensure("sunrise at 0", apart(marks.sunrise, 0.f) < 0.02f); - ensure("noon at 0.25", apart(marks.noon, 0.25f) < 0.02f); - ensure("sunset at 0.5", apart(marks.sunset, 0.5f) < 0.02f); - ensure("midnight at 0.75", apart(marks.midnight, 0.75f) < 0.02f); + UNSCOPED_INFO("has sunrise"); + CHECK(marks.has_sunrise); + UNSCOPED_INFO("has noon"); + CHECK(marks.has_noon); + UNSCOPED_INFO("has sunset"); + CHECK(marks.has_sunset); + UNSCOPED_INFO("has midnight"); + CHECK(marks.has_midnight); + + UNSCOPED_INFO("sunrise at 0"); + CHECK(apart(marks.sunrise, 0.f) < 0.02f); + UNSCOPED_INFO("noon at 0.25"); + CHECK(apart(marks.noon, 0.25f) < 0.02f); + UNSCOPED_INFO("sunset at 0.5"); + CHECK(apart(marks.sunset, 0.5f) < 0.02f); + UNSCOPED_INFO("midnight at 0.75"); + CHECK(apart(marks.midnight, 0.75f) < 0.02f); } // Every landmark moves with the cycle. This is the case that a hardcoded // "noon is 0.5" gets wrong, and the reason this code exists. - template<> template<> - void landmark_object::test<2>() + TEST_CASE_METHOD(daycycle_landmarks, "ALDayCycleLandmarks: every landmark moves with the phase of the cycle", "[ALDayCycleLandmarks]") { const F32 phase = 0.3f; const auto marks = ALDayCycleLandmarks::find(sine(phase)); - ensure("sunrise moved", apart(marks.sunrise, phase) < 0.02f); - ensure("noon moved", apart(marks.noon, phase + 0.25f) < 0.02f); - ensure("sunset moved", apart(marks.sunset, std::fmod(phase + 0.5f, 1.f)) < 0.02f); - ensure("midnight moved", apart(marks.midnight, std::fmod(phase + 0.75f, 1.f)) < 0.02f); + UNSCOPED_INFO("sunrise moved"); + CHECK(apart(marks.sunrise, phase) < 0.02f); + UNSCOPED_INFO("noon moved"); + CHECK(apart(marks.noon, phase + 0.25f) < 0.02f); + UNSCOPED_INFO("sunset moved"); + CHECK(apart(marks.sunset, std::fmod(phase + 0.5f, 1.f)) < 0.02f); + UNSCOPED_INFO("midnight moved"); + CHECK(apart(marks.midnight, std::fmod(phase + 0.75f, 1.f)) < 0.02f); } // A crossing that falls between two samples is interpolated, so the answer // is better than the sample grid rather than snapped to it. - template<> template<> - void landmark_object::test<3>() + TEST_CASE_METHOD(daycycle_landmarks, "ALDayCycleLandmarks: a crossing between two samples is found finer than the grid", "[ALDayCycleLandmarks]") { // Sunrise sits at 0.1, which no 16-sample grid position lands on. const auto marks = ALDayCycleLandmarks::find(sine(0.1f), 16); const F32 grid = 1.f / 16.f; - ensure("has sunrise", marks.has_sunrise); - ensure("beats the grid", apart(marks.sunrise, 0.1f) < grid * 0.5f); + UNSCOPED_INFO("has sunrise"); + CHECK(marks.has_sunrise); + UNSCOPED_INFO("beats the grid"); + CHECK(apart(marks.sunrise, 0.1f) < grid * 0.5f); } // A sun that never sets has a brightest moment and nothing else: naming a // sunrise there would be inventing one. - template<> template<> - void landmark_object::test<4>() + TEST_CASE_METHOD(daycycle_landmarks, "ALDayCycleLandmarks: a sun that never sets has a noon and nothing else", "[ALDayCycleLandmarks]") { const auto marks = ALDayCycleLandmarks::find( [](F32 p) { return 0.5f + 0.25f * std::sin(TWO_PI * p); }); - ensure("has noon", marks.has_noon); - ensure("no sunrise", !marks.has_sunrise); - ensure("no sunset", !marks.has_sunset); - ensure("no midnight", !marks.has_midnight); - ensure("noon at the peak", apart(marks.noon, 0.25f) < 0.02f); + UNSCOPED_INFO("has noon"); + CHECK(marks.has_noon); + UNSCOPED_INFO("no sunrise"); + CHECK_FALSE(marks.has_sunrise); + UNSCOPED_INFO("no sunset"); + CHECK_FALSE(marks.has_sunset); + UNSCOPED_INFO("no midnight"); + CHECK_FALSE(marks.has_midnight); + UNSCOPED_INFO("noon at the peak"); + CHECK(apart(marks.noon, 0.25f) < 0.02f); } // A sun that never rises is the same argument the other way up. - template<> template<> - void landmark_object::test<5>() + TEST_CASE_METHOD(daycycle_landmarks, "ALDayCycleLandmarks: a sun that never rises has a midnight and nothing else", "[ALDayCycleLandmarks]") { const auto marks = ALDayCycleLandmarks::find( [](F32 p) { return -0.5f + 0.25f * std::sin(TWO_PI * p); }); - ensure("has midnight", marks.has_midnight); - ensure("no noon", !marks.has_noon); - ensure("no sunrise", !marks.has_sunrise); - ensure("no sunset", !marks.has_sunset); + UNSCOPED_INFO("has midnight"); + CHECK(marks.has_midnight); + UNSCOPED_INFO("no noon"); + CHECK_FALSE(marks.has_noon); + UNSCOPED_INFO("no sunrise"); + CHECK_FALSE(marks.has_sunrise); + UNSCOPED_INFO("no sunset"); + CHECK_FALSE(marks.has_sunset); } // A cycle built from one repeated frame -- which is what the viewer's own // default day cycle actually is -- has no moment to single out. - template<> template<> - void landmark_object::test<6>() + TEST_CASE_METHOD(daycycle_landmarks, "ALDayCycleLandmarks: a cycle of one repeated frame has no landmarks", "[ALDayCycleLandmarks]") { const auto marks = ALDayCycleLandmarks::find([](F32) { return 0.5f; }); - ensure("nothing to find", !marks.any()); + UNSCOPED_INFO("nothing to find"); + CHECK_FALSE(marks.any()); } // Landmarks are cycle positions, so they stay inside [0, 1) even when the // crossing they came from sits across the seam. - template<> template<> - void landmark_object::test<7>() + TEST_CASE_METHOD(daycycle_landmarks, "ALDayCycleLandmarks: landmarks stay inside the cycle when a crossing is across the seam", "[ALDayCycleLandmarks]") { for (S32 i = 0; i < 20; ++i) { const F32 phase = (F32)i / 20.f; const auto marks = ALDayCycleLandmarks::find(sine(phase)); - ensure("sunrise in range", marks.sunrise >= 0.f && marks.sunrise < 1.f); - ensure("noon in range", marks.noon >= 0.f && marks.noon < 1.f); - ensure("sunset in range", marks.sunset >= 0.f && marks.sunset < 1.f); - ensure("midnight in range", marks.midnight >= 0.f && marks.midnight < 1.f); + { + INFO("sunrise in range"); + REQUIRE(marks.sunrise >= 0.f); + REQUIRE(marks.sunrise < 1.f); + } + { + INFO("noon in range"); + REQUIRE(marks.noon >= 0.f); + REQUIRE(marks.noon < 1.f); + } + { + INFO("sunset in range"); + REQUIRE(marks.sunset >= 0.f); + REQUIRE(marks.sunset < 1.f); + } + { + INFO("midnight in range"); + REQUIRE(marks.midnight >= 0.f); + REQUIRE(marks.midnight < 1.f); + } } } // Nothing to sample with, nothing to say. - template<> template<> - void landmark_object::test<8>() + TEST_CASE_METHOD(daycycle_landmarks, "ALDayCycleLandmarks: no sampler or too few samples finds nothing", "[ALDayCycleLandmarks]") { - ensure("no sampler", !ALDayCycleLandmarks::find(nullptr).any()); - ensure("too few samples", !ALDayCycleLandmarks::find(sine(), 1).any()); + UNSCOPED_INFO("no sampler"); + CHECK_FALSE(ALDayCycleLandmarks::find(nullptr).any()); + UNSCOPED_INFO("too few samples"); + CHECK_FALSE(ALDayCycleLandmarks::find(sine(), 1).any()); } } diff --git a/indra/newview/tests/alfarplane_test.cpp b/indra/newview/tests/alfarplane_test.cpp index ada69cd076..e04e41e5dd 100644 --- a/indra/newview/tests/alfarplane_test.cpp +++ b/indra/newview/tests/alfarplane_test.cpp @@ -25,7 +25,7 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include #include "../alfarplane.h" @@ -37,12 +37,8 @@ #include #include -namespace tut +namespace { - struct alfarplane_data - { - }; - // A shader's source, found from this file so the test reads what the viewer compiles. static std::string shader_source(const std::string& rel) { @@ -60,173 +56,275 @@ namespace tut return at == std::string::npos ? -1.f : std::stof(text.substr(at + key.size())); } - typedef test_group alfarplane_group; - typedef alfarplane_group::object alfarplane_object; - tut::alfarplane_group alfarplane_g("alfarplane"); - // The draw distance consumers see: forward-Z keeps 512 m, reverse-Z reaches MAX_FAR_CLIP. - template<> template<> - void alfarplane_object::test<1>() + TEST_CASE("alfarplane: draw distance caps at 512 m forward-Z and MAX_FAR_CLIP reversed", "[alfarplane]") { - set_test_name("draw distance ceiling"); - ensure_equals("forward ceiling", ALFarPlane::drawDistanceCeiling(false), 512.f); - ensure_equals("reverse ceiling", ALFarPlane::drawDistanceCeiling(true), 2048.f); - ensure_equals("forward caps", ALFarPlane::clampDrawDistance(2048.f, false), 512.f); - ensure_equals("forward keeps lower", ALFarPlane::clampDrawDistance(256.f, false), 256.f); - ensure_equals("reverse keeps 2048", ALFarPlane::clampDrawDistance(2048.f, true), 2048.f); - ensure_equals("reverse caps past MAX_FAR_CLIP", ALFarPlane::clampDrawDistance(4096.f, true), MAX_FAR_CLIP); + UNSCOPED_INFO("forward ceiling"); + CHECK(ALFarPlane::drawDistanceCeiling(false) == 512.f); + UNSCOPED_INFO("reverse ceiling"); + CHECK(ALFarPlane::drawDistanceCeiling(true) == 2048.f); + UNSCOPED_INFO("forward caps"); + CHECK(ALFarPlane::clampDrawDistance(2048.f, false) == 512.f); + UNSCOPED_INFO("forward keeps lower"); + CHECK(ALFarPlane::clampDrawDistance(256.f, false) == 256.f); + UNSCOPED_INFO("reverse keeps 2048"); + CHECK(ALFarPlane::clampDrawDistance(2048.f, true) == 2048.f); + UNSCOPED_INFO("reverse caps past MAX_FAR_CLIP"); + CHECK(ALFarPlane::clampDrawDistance(4096.f, true) == MAX_FAR_CLIP); } // Reverse-Z is infinite; forward-Z and probe captures keep the finite plane, and the debug force moves only the // main view under reverse-Z. - template<> template<> - void alfarplane_object::test<2>() + TEST_CASE("alfarplane: only the reverse-Z main view gets an infinite or forced far plane", "[alfarplane]") { - set_test_name("projection far plane"); using namespace ALFarPlane; - ensure("reverse infinite", isInfinite(projectionFar(true, false))); - ensure_equals("forward", projectionFar(false, false), FINITE_PROJECTION_FAR); - ensure_equals("reverse cube snapshot", projectionFar(true, true), FINITE_PROJECTION_FAR); - ensure_equals("forward cube snapshot", projectionFar(false, true), FINITE_PROJECTION_FAR); - ensure_equals("finite plane is 1024 m", FINITE_PROJECTION_FAR, 1024.f); - ensure("1024 is finite", !isInfinite(1024.f)); - ensure("infinite constant", isInfinite(INFINITE_FAR) && INFINITE_FAR > 0.f); + UNSCOPED_INFO("reverse infinite"); + CHECK(isInfinite(projectionFar(true, false))); + UNSCOPED_INFO("forward"); + CHECK(projectionFar(false, false) == FINITE_PROJECTION_FAR); + UNSCOPED_INFO("reverse cube snapshot"); + CHECK(projectionFar(true, true) == FINITE_PROJECTION_FAR); + UNSCOPED_INFO("forward cube snapshot"); + CHECK(projectionFar(false, true) == FINITE_PROJECTION_FAR); + UNSCOPED_INFO("finite plane is 1024 m"); + CHECK(FINITE_PROJECTION_FAR == 1024.f); + UNSCOPED_INFO("1024 is finite"); + CHECK_FALSE(isInfinite(1024.f)); + { + INFO("infinite constant"); + CHECK(isInfinite(INFINITE_FAR)); + CHECK(INFINITE_FAR > 0.f); + } - ensure("auto", isInfinite(projectionFar(true, false, FORCE_AUTOMATIC, 2048.f))); - ensure_equals("finite", projectionFar(true, false, FORCE_FINITE, 2048.f), 4096.f); - ensure_equals("finite never under the finite plane", projectionFar(true, false, FORCE_FINITE, 256.f), FINITE_PROJECTION_FAR); - ensure("infinite", isInfinite(projectionFar(true, false, FORCE_INFINITE, 2048.f))); - ensure("unknown mode", isInfinite(projectionFar(true, false, 7, 2048.f))); - ensure_equals("cube snapshot never forced infinite", projectionFar(true, true, FORCE_INFINITE, 2048.f), FINITE_PROJECTION_FAR); - ensure_equals("cube snapshot never forced finite", projectionFar(true, true, FORCE_FINITE, 2048.f), FINITE_PROJECTION_FAR); - ensure_equals("forward ignores infinite", projectionFar(false, false, FORCE_INFINITE, 2048.f), FINITE_PROJECTION_FAR); - ensure_equals("forward ignores finite", projectionFar(false, false, FORCE_FINITE, 2048.f), FINITE_PROJECTION_FAR); + UNSCOPED_INFO("auto"); + CHECK(isInfinite(projectionFar(true, false, FORCE_AUTOMATIC, 2048.f))); + UNSCOPED_INFO("finite"); + CHECK(projectionFar(true, false, FORCE_FINITE, 2048.f) == 4096.f); + UNSCOPED_INFO("finite never under the finite plane"); + CHECK(projectionFar(true, false, FORCE_FINITE, 256.f) == FINITE_PROJECTION_FAR); + UNSCOPED_INFO("infinite"); + CHECK(isInfinite(projectionFar(true, false, FORCE_INFINITE, 2048.f))); + UNSCOPED_INFO("unknown mode"); + CHECK(isInfinite(projectionFar(true, false, 7, 2048.f))); + UNSCOPED_INFO("cube snapshot never forced infinite"); + CHECK(projectionFar(true, true, FORCE_INFINITE, 2048.f) == FINITE_PROJECTION_FAR); + UNSCOPED_INFO("cube snapshot never forced finite"); + CHECK(projectionFar(true, true, FORCE_FINITE, 2048.f) == FINITE_PROJECTION_FAR); + UNSCOPED_INFO("forward ignores infinite"); + CHECK(projectionFar(false, false, FORCE_INFINITE, 2048.f) == FINITE_PROJECTION_FAR); + UNSCOPED_INFO("forward ignores finite"); + CHECK(projectionFar(false, false, FORCE_FINITE, 2048.f) == FINITE_PROJECTION_FAR); } // How far terrain and water reach, and from how high water is drawn. - template<> template<> - void alfarplane_object::test<3>() + TEST_CASE("alfarplane: how far terrain and water reach and from how high water shows", "[alfarplane]") { - set_test_name("terrain and water reach"); using namespace ALFarPlane; - ensure_equals("terrain reach under the infinite projection", terrainReach(INFINITE_FAR), 8192.f); - ensure_equals("terrain unbounded on forward-Z", terrainReach(projectionFar(false, false)), 0.f); - ensure_equals("terrain unbounded in cube snapshots", terrainReach(projectionFar(true, true)), 0.f); - ensure_equals("edge water, infinite", edgeWaterStretch(true), 256000.f); - ensure_equals("edge water, finite keeps 2048", edgeWaterStretch(false), 2048.f); - ensure("edge water covers the terrain reach", edgeWaterStretch(true) >= TERRAIN_REACH); + UNSCOPED_INFO("terrain reach under the infinite projection"); + CHECK(terrainReach(INFINITE_FAR) == 8192.f); + UNSCOPED_INFO("terrain unbounded on forward-Z"); + CHECK(terrainReach(projectionFar(false, false)) == 0.f); + UNSCOPED_INFO("terrain unbounded in cube snapshots"); + CHECK(terrainReach(projectionFar(true, true)) == 0.f); + UNSCOPED_INFO("edge water, infinite"); + CHECK(edgeWaterStretch(true) == 256000.f); + UNSCOPED_INFO("edge water, finite keeps 2048"); + CHECK(edgeWaterStretch(false) == 2048.f); + UNSCOPED_INFO("edge water covers the terrain reach"); + CHECK(edgeWaterStretch(true) >= TERRAIN_REACH); - ensure("finite: below 1024 m", waterVisibleFrom(1000.f, 20.f, FINITE_PROJECTION_FAR)); - ensure("finite: from 1024 m it stops", !waterVisibleFrom(1024.f, 20.f, FINITE_PROJECTION_FAR)); - ensure("finite: a farther plane shows it from higher", waterVisibleFrom(2000.f, 20.f, 4096.f)); - ensure("finite: up to that plane", !waterVisibleFrom(4096.f, 20.f, 4096.f)); - ensure("infinite: 2 km up still shows", waterVisibleFrom(2000.f, 20.f, INFINITE_FAR)); - ensure("infinite: within reach above the water", waterVisibleFrom(20.f + EDGE_WATER_STRETCH - 1.f, 20.f, INFINITE_FAR)); - ensure("infinite: past reach above the water", !waterVisibleFrom(20.f + EDGE_WATER_STRETCH, 20.f, INFINITE_FAR)); + UNSCOPED_INFO("finite: below 1024 m"); + CHECK(waterVisibleFrom(1000.f, 20.f, FINITE_PROJECTION_FAR)); + UNSCOPED_INFO("finite: from 1024 m it stops"); + CHECK_FALSE(waterVisibleFrom(1024.f, 20.f, FINITE_PROJECTION_FAR)); + UNSCOPED_INFO("finite: a farther plane shows it from higher"); + CHECK(waterVisibleFrom(2000.f, 20.f, 4096.f)); + UNSCOPED_INFO("finite: up to that plane"); + CHECK_FALSE(waterVisibleFrom(4096.f, 20.f, 4096.f)); + UNSCOPED_INFO("infinite: 2 km up still shows"); + CHECK(waterVisibleFrom(2000.f, 20.f, INFINITE_FAR)); + UNSCOPED_INFO("infinite: within reach above the water"); + CHECK(waterVisibleFrom(20.f + EDGE_WATER_STRETCH - 1.f, 20.f, INFINITE_FAR)); + UNSCOPED_INFO("infinite: past reach above the water"); + CHECK_FALSE(waterVisibleFrom(20.f + EDGE_WATER_STRETCH, 20.f, INFINITE_FAR)); } // Depth reconstruction: the far corners an infinite projection unprojects, and the floors the shaders carry. - template<> template<> - void alfarplane_object::test<4>() + TEST_CASE("alfarplane: the far window depth and the reconstruction floor in the shaders", "[alfarplane]") { - set_test_name("depth reconstruction"); using namespace ALFarPlane; - ensure_equals("infinite", frustumFarWindowDepth(true, 0.1f, 0.f), 0.1f / MAX_RECONSTRUCT_DISTANCE); - ensure("infinite depth unprojects to MAX_RECONSTRUCT_DISTANCE", fabsf(0.1f / frustumFarWindowDepth(true, 0.1f, 0.f) - MAX_RECONSTRUCT_DISTANCE) < 1.f); - ensure_equals("finite, reverse", frustumFarWindowDepth(false, 0.1f, 0.f), 0.f); - ensure_equals("finite, forward", frustumFarWindowDepth(false, 0.1f, 1.f), 1.f); + UNSCOPED_INFO("infinite"); + CHECK(frustumFarWindowDepth(true, 0.1f, 0.f) == 0.1f / MAX_RECONSTRUCT_DISTANCE); + UNSCOPED_INFO("infinite depth unprojects to MAX_RECONSTRUCT_DISTANCE"); + CHECK(fabsf(0.1f / frustumFarWindowDepth(true, 0.1f, 0.f) - MAX_RECONSTRUCT_DISTANCE) < 1.f); + UNSCOPED_INFO("finite, reverse"); + CHECK(frustumFarWindowDepth(false, 0.1f, 0.f) == 0.f); + UNSCOPED_INFO("finite, forward"); + CHECK(frustumFarWindowDepth(false, 0.1f, 1.f) == 1.f); // The sky keeps the cleared depth, 0 under reverse-Z. Anything drawn stores near / distance, which must stay // a normal float out to the reconstruction floor so no geometry rounds onto the sky. - ensure("reconstruction floor past the reach", MAX_RECONSTRUCT_DISTANCE > TERRAIN_REACH); - ensure("geometry at the floor stores a normal depth", MIN_NEAR_PLANE / MAX_RECONSTRUCT_DISTANCE >= std::numeric_limits::min()); + UNSCOPED_INFO("reconstruction floor past the reach"); + CHECK(MAX_RECONSTRUCT_DISTANCE > TERRAIN_REACH); + UNSCOPED_INFO("geometry at the floor stores a normal depth"); + CHECK(MIN_NEAR_PLANE / MAX_RECONSTRUCT_DISTANCE >= std::numeric_limits::min()); // The floors the shaders actually carry, read from their sources. const F32 floor = 1.f / MAX_RECONSTRUCT_DISTANCE; const std::string util = shader_source("class1/deferred/deferredUtil.glsl"); - ensure("deferredUtil read", !util.empty()); - ensure_equals("deferredUtil floor", literal_after(util, "#define RECONSTRUCT_W_FLOOR "), floor); - ensure_equals("aoUtil floor", literal_after(shader_source("class1/deferred/aoUtil.glsl"), "pos.w = max(pos.w, "), floor); - ensure_equals("cofF floor", literal_after(shader_source("class1/deferred/cofF.glsl"), "p.z/max(p.w, "), floor); + UNSCOPED_INFO("deferredUtil read"); + REQUIRE_FALSE(util.empty()); + UNSCOPED_INFO("deferredUtil floor"); + CHECK(literal_after(util, "#define RECONSTRUCT_W_FLOOR ") == floor); + UNSCOPED_INFO("aoUtil floor"); + CHECK(literal_after(shader_source("class1/deferred/aoUtil.glsl"), "pos.w = max(pos.w, ") == floor); + UNSCOPED_INFO("cofF floor"); + CHECK(literal_after(shader_source("class1/deferred/cofF.glsl"), "p.z/max(p.w, ") == floor); } // The sky is the cleared far depth and nothing else: every pass that tells sky from geometry tests for exactly // that value, so no distance, projection or pin enters the test. - template<> template<> - void alfarplane_object::test<5>() + TEST_CASE("alfarplane: every pass tells sky from geometry by the cleared depth alone", "[alfarplane]") { - set_test_name("sky is the cleared depth"); const std::string haze = shader_source("class3/deferred/hazeF.glsl"); const std::string haze_v = shader_source("class1/deferred/hazeV.glsl"); - ensure("haze drawn on the far plane, reversed", haze_v.find("gl_Position = vec4(position.xy, 0.0, 1.0);") != std::string::npos); - ensure("haze drawn on the far plane, forward", haze_v.find("gl_Position = vec4(position.xy, 1.0, 1.0);") != std::string::npos); + UNSCOPED_INFO("haze drawn on the far plane, reversed"); + REQUIRE(haze_v.find("gl_Position = vec4(position.xy, 0.0, 1.0);") != std::string::npos); + UNSCOPED_INFO("haze drawn on the far plane, forward"); + REQUIRE(haze_v.find("gl_Position = vec4(position.xy, 1.0, 1.0);") != std::string::npos); // The lighting passes draw there too: the light map's passes, the lights and the soften pass's lit program in // front of it, the soften pass's sky program on it. for (const char* path : { "class2/deferred/softenLightV.glsl", "class3/deferred/multiPointLightV.glsl", "class2/deferred/sunLightV.glsl", "class1/deferred/blurLightV.glsl" }) { const std::string v = shader_source(path); - ensure(std::string(path) + " drawn on the far plane, reversed", v.find("gl_Position = vec4(position.xy, 0.0, 1.0);") != std::string::npos); - ensure(std::string(path) + " drawn on the far plane, forward", v.find("gl_Position = vec4(position.xy, 1.0, 1.0);") != std::string::npos); + UNSCOPED_INFO(std::string(path) + " drawn on the far plane, reversed"); + REQUIRE(v.find("gl_Position = vec4(position.xy, 0.0, 1.0);") != std::string::npos); + UNSCOPED_INFO(std::string(path) + " drawn on the far plane, forward"); + REQUIRE(v.find("gl_Position = vec4(position.xy, 1.0, 1.0);") != std::string::npos); } const std::string soften = shader_source("class3/deferred/softenLightF.glsl"); - ensure("the sky's soften program lights nothing", soften.find("writeColor(skyColor(getGBuffer(tc)));") != std::string::npos); - ensure("haze takes geometry where it is", haze.find("= getPositionWithDepth(tc, depth);") != std::string::npos); - ensure("void water fog keys on the far depth", shader_source("class3/deferred/waterHazeF.glsl").find("if (isFarDepth(depth))") != std::string::npos); + UNSCOPED_INFO("the sky's soften program lights nothing"); + REQUIRE(soften.find("writeColor(skyColor(getGBuffer(tc)));") != std::string::npos); + UNSCOPED_INFO("haze takes geometry where it is"); + REQUIRE(haze.find("= getPositionWithDepth(tc, depth);") != std::string::npos); + UNSCOPED_INFO("void water fog keys on the far depth"); + REQUIRE(shader_source("class3/deferred/waterHazeF.glsl").find("if (isFarDepth(depth))") != std::string::npos); const std::string flare = shader_source("class1/alchemy/lensFlareStateF.glsl"); - ensure("flare sky is the far plane, reversed", flare.find("return d <= 0.0 ? 1.0 : 0.0;") != std::string::npos); - ensure("flare sky is the far plane, forward", flare.find("return d >= 1.0 ? 1.0 : 0.0;") != std::string::npos); + UNSCOPED_INFO("flare sky is the far plane, reversed"); + REQUIRE(flare.find("return d <= 0.0 ? 1.0 : 0.0;") != std::string::npos); + UNSCOPED_INFO("flare sky is the far plane, forward"); + REQUIRE(flare.find("return d >= 1.0 ? 1.0 : 0.0;") != std::string::npos); // Opaque geometry in the haze pass takes the in-scatter blended geometry takes in its own shading, and the // water surface alone converges on the sky behind it. - ensure("the haze pass's in-scatter is alpha's", haze.find("atmosFragLighting(vec3(0), additive, atten)") != std::string::npos); - ensure("water converges on the sky behind", haze.find("if (on_water && skyBehindWeight > 0.0)") != std::string::npos); - ensure("the sky behind is sampled for water", haze.find("texture(skyBehindMap, tc)") != std::string::npos); + UNSCOPED_INFO("the haze pass's in-scatter is alpha's"); + REQUIRE(haze.find("atmosFragLighting(vec3(0), additive, atten)") != std::string::npos); + UNSCOPED_INFO("water converges on the sky behind"); + REQUIRE(haze.find("if (on_water && skyBehindWeight > 0.0)") != std::string::npos); + UNSCOPED_INFO("the sky behind is sampled for water"); + REQUIRE(haze.find("texture(skyBehindMap, tc)") != std::string::npos); // The farthest geometry: a top corner of the edge water's extent, from as high above it as the water shows. const F64 edge = (F64)ALFarPlane::edgeWaterStretch(true) + MAX_FAR_CLIP; const F64 farthest = sqrt(2.0 * edge * edge + (F64)ALFarPlane::EDGE_WATER_STRETCH * ALFarPlane::EDGE_WATER_STRETCH); - ensure("farthest water inside the floor", farthest < MAX_RECONSTRUCT_DISTANCE); - ensure("farthest water stores a normal depth", (F32)(MIN_NEAR_PLANE / farthest) >= std::numeric_limits::min()); + UNSCOPED_INFO("farthest water inside the floor"); + CHECK(farthest < MAX_RECONSTRUCT_DISTANCE); + UNSCOPED_INFO("farthest water stores a normal depth"); + CHECK((F32)(MIN_NEAR_PLANE / farthest) >= std::numeric_limits::min()); } // Water's far terms: the old ones under a finite projection; under an infinite one the waves follow the surface // to the rim's farthest corner and the water fades over the edge water stretch. - template<> template<> - void alfarplane_object::test<6>() + TEST_CASE("alfarplane: water's wave clamp and edge fade under each projection", "[alfarplane]") { - set_test_name("water far terms"); using namespace ALFarPlane; const LLVector2 lo(-1000.f, -2000.f); const LLVector2 hi(3000.f, 500.f); const WaterFar finite = waterFar(FINITE_PROJECTION_FAR, true, lo, hi); - ensure_equals("finite wave clamp", finite.mWaveClamp, 2560.f); - ensure_equals("finite no edge fade", finite.mEdgeFade, 0.f); + UNSCOPED_INFO("finite wave clamp"); + CHECK(finite.mWaveClamp == 2560.f); + UNSCOPED_INFO("finite no edge fade"); + CHECK(finite.mEdgeFade == 0.f); const WaterFar infinite = waterFar(INFINITE_FAR, true, lo, hi); - ensure("wave clamp at the farthest rim corner", fabsf(infinite.mWaveClamp - sqrtf(3000.f * 3000.f + 2000.f * 2000.f)) < 0.01f); - ensure_equals("edge fade over the stretch", infinite.mEdgeFade, EDGE_WATER_STRETCH); + UNSCOPED_INFO("wave clamp at the farthest rim corner"); + CHECK(fabsf(infinite.mWaveClamp - sqrtf(3000.f * 3000.f + 2000.f * 2000.f)) < 0.01f); + UNSCOPED_INFO("edge fade over the stretch"); + CHECK(infinite.mEdgeFade == EDGE_WATER_STRETCH); const WaterFar rimless = waterFar(INFINITE_FAR, false, LLVector2(), LLVector2()); - ensure_equals("no rim, no fade", rimless.mEdgeFade, 0.f); - ensure("no rim, waves past the regions", rimless.mWaveClamp >= EDGE_WATER_STRETCH); + UNSCOPED_INFO("no rim, no fade"); + CHECK(rimless.mEdgeFade == 0.f); + UNSCOPED_INFO("no rim, waves past the regions"); + CHECK(rimless.mWaveClamp >= EDGE_WATER_STRETCH); const std::string water_f = shader_source("class3/environment/waterF.glsl"); const std::string haze = shader_source("class3/deferred/waterHazeF.glsl"); - ensure("sky behind water is held past the surface", haze.find("entry + VOID_WATER_FOG_DEPTH") != std::string::npos); + UNSCOPED_INFO("sky behind water is held past the surface"); + REQUIRE(haze.find("entry + VOID_WATER_FOG_DEPTH") != std::string::npos); const std::string water_v = shader_source("class1/environment/waterV.glsl"); - ensure("wave clamp from the uniform", water_v.find("min(d, waterFar.x)") != std::string::npos); - ensure("no literal wave clamp", water_v.find("min(d, 2560.0)") == std::string::npos); + UNSCOPED_INFO("wave clamp from the uniform"); + REQUIRE(water_v.find("min(d, waterFar.x)") != std::string::npos); + UNSCOPED_INFO("no literal wave clamp"); + REQUIRE(water_v.find("min(d, 2560.0)") == std::string::npos); // The per-fragment rebuild scrolls by the offsets waterV takes from the CPU, which sets no wave direction or time. for (const char* scroll : { "+ bigWaveScroll;", "+ littleWaveScroll.xy;", "+ littleWaveScroll.zw;" }) { - ensure(std::string("waterV scrolls by ") + scroll, water_v.find(scroll) != std::string::npos); - ensure(std::string("rebuilt waves scroll by ") + scroll, water_f.find(scroll) != std::string::npos); + UNSCOPED_INFO(std::string("waterV scrolls by ") + scroll); + REQUIRE(water_v.find(scroll) != std::string::npos); + UNSCOPED_INFO(std::string("rebuilt waves scroll by ") + scroll); + REQUIRE(water_f.find(scroll) != std::string::npos); + } + } + + // The far plane overlay: nearer-first pairs out to 100 km on distinct bearings, each farther column behind its + // partner and overlapping it on screen, and every column the same angular size. + TEST_CASE("alfarplane: overlay columns pair up out to 100 km at one angular size", "[alfarplane]") + { + const std::vector& columns = ALFarPlane::overlayColumns(); + { + INFO("pairs"); + REQUIRE(columns.size() >= 2); + REQUIRE(columns.size() % 2 == 0); + } + UNSCOPED_INFO("reaches 100 km"); + REQUIRE(columns[columns.size() - 2].mDistance == 100000.f); + for (size_t i = 0; i < columns.size(); i += 2) + { + const ALFarPlane::OverlayColumn& n = columns[i]; + const ALFarPlane::OverlayColumn& f = columns[i + 1]; + const std::string at = std::to_string((S32)n.mDistance) + " m"; + { + INFO("nearer first at " + at); + REQUIRE(n.mNearer); + REQUIRE_FALSE(f.mNearer); + } + UNSCOPED_INFO("farther behind at " + at); + REQUIRE(f.mDistance > n.mDistance); + UNSCOPED_INFO("same bearing at " + at); + REQUIRE(f.mBearing == n.mBearing); + // On screen the farther column's near edge sits inside the nearer column. + const F32 f_left = (f.mOffset - f.mHalfWidth) / f.mDistance; + const F32 n_right = (n.mOffset + n.mHalfWidth) / n.mDistance; + const F32 n_left = (n.mOffset - n.mHalfWidth) / n.mDistance; + { + INFO("overlap at " + at); + REQUIRE(f_left > n_left); + REQUIRE(f_left < n_right); + } + UNSCOPED_INFO("same angle at " + at); + REQUIRE(fabsf(n.mHeight / n.mDistance - columns[0].mHeight / columns[0].mDistance) < 1e-6f); + if (i > 0) + { + UNSCOPED_INFO("own bearing at " + at); + REQUIRE(n.mBearing != columns[i - 2].mBearing); + UNSCOPED_INFO("receding at " + at); + REQUIRE(n.mDistance > columns[i - 2].mDistance); + } } } // The eye-to-sky rotation: a level camera's forward, up and right land on the sky's (north, up, east) for its heading, // and any view's eye directions come back as toLightNorm's swizzle of the agent directions it rotated. - template<> template<> - void alfarplane_object::test<8>() + TEST_CASE("alfarplane: eyeToSkyFrame turns eye directions into the sky's frame", "[alfarplane]") { - set_test_name("eye to sky frame"); const auto apply = [](const std::array& m, const LLVector3& v) { return LLVector3(m[0] * v.mV[0] + m[3] * v.mV[1] + m[6] * v.mV[2], @@ -241,17 +339,22 @@ namespace tut north.setIdentity(); north.setRows(LLVector4a(1.f, 0.f, 0.f), LLVector4a(0.f, 0.f, -1.f), LLVector4a(0.f, 1.f, 0.f)); const std::array n = ALFarPlane::eyeToSkyFrame(north); - ensure("facing north, forward is north", close_to(apply(n, LLVector3(0.f, 0.f, -1.f)), LLVector3(1.f, 0.f, 0.f))); - ensure("facing north, up is up", close_to(apply(n, LLVector3(0.f, 1.f, 0.f)), LLVector3(0.f, 1.f, 0.f))); - ensure("facing north, right is east", close_to(apply(n, LLVector3(1.f, 0.f, 0.f)), LLVector3(0.f, 0.f, 1.f))); + UNSCOPED_INFO("facing north, forward is north"); + CHECK(close_to(apply(n, LLVector3(0.f, 0.f, -1.f)), LLVector3(1.f, 0.f, 0.f))); + UNSCOPED_INFO("facing north, up is up"); + CHECK(close_to(apply(n, LLVector3(0.f, 1.f, 0.f)), LLVector3(0.f, 1.f, 0.f))); + UNSCOPED_INFO("facing north, right is east"); + CHECK(close_to(apply(n, LLVector3(1.f, 0.f, 0.f)), LLVector3(0.f, 0.f, 1.f))); // Facing east: eye right is south, eye -z is east. LLMatrix4a east; east.setIdentity(); east.setRows(LLVector4a(0.f, 0.f, -1.f), LLVector4a(-1.f, 0.f, 0.f), LLVector4a(0.f, 1.f, 0.f)); const std::array e = ALFarPlane::eyeToSkyFrame(east); - ensure("facing east, forward is east", close_to(apply(e, LLVector3(0.f, 0.f, -1.f)), LLVector3(0.f, 0.f, 1.f))); - ensure("facing east, right is south", close_to(apply(e, LLVector3(1.f, 0.f, 0.f)), LLVector3(-1.f, 0.f, 0.f))); + UNSCOPED_INFO("facing east, forward is east"); + CHECK(close_to(apply(e, LLVector3(0.f, 0.f, -1.f)), LLVector3(0.f, 0.f, 1.f))); + UNSCOPED_INFO("facing east, right is south"); + CHECK(close_to(apply(e, LLVector3(1.f, 0.f, 0.f)), LLVector3(-1.f, 0.f, 0.f))); // A pitched, rolled, yawed view: what the pipeline rotates into eye space (as it does the sun's direction) // comes back as the sky frame's swizzle of the agent direction. @@ -262,49 +365,25 @@ namespace tut LLVector4a eye; view.rotate(LLVector4a(agent.mV[0], agent.mV[1], agent.mV[2], 0.f), eye); const LLVector3 sky = apply(v, LLVector3(eye.getF32ptr())); - ensure("agent direction back as (north, up, east)", close_to(sky, LLVector3(agent.mV[1], agent.mV[2], agent.mV[0]))); + UNSCOPED_INFO("agent direction back as (north, up, east)"); + REQUIRE(close_to(sky, LLVector3(agent.mV[1], agent.mV[2], agent.mV[0]))); } // WindLight's haze takes the rotation from the Environment block, for every pass that hazes geometry, and its // callers hand it eye space. const std::string funcs = shader_source("class1/windlight/atmosphericsFuncs.glsl"); - ensure("haze position into the sky's frame", funcs.find("vec3 rel_pos = eyeToSky * inPositionEye;") != std::string::npos); - ensure("haze light into the sky's frame", funcs.find("light_dir = eyeToSky * light_dir;") != std::string::npos); + UNSCOPED_INFO("haze position into the sky's frame"); + REQUIRE(funcs.find("vec3 rel_pos = eyeToSky * inPositionEye;") != std::string::npos); + UNSCOPED_INFO("haze light into the sky's frame"); + REQUIRE(funcs.find("light_dir = eyeToSky * light_dir;") != std::string::npos); // Only rising rays leave the haze, as the dome's do; a falling ray keeps its whole length. - ensure("altitude limit on rising rays alone", funcs.find("float h = max(rel_pos.y, 0.0) / max(max_y, 1.0);") != std::string::npos); - ensure("no limit on falling rays", funcs.find("abs(rel_pos.y)") == std::string::npos); - ensure("the rotation is in the Environment block", shader_source("class1/deferred/environmentBlock.glsl").find("mat3 eyeToSky;") != std::string::npos); - ensure("the haze pass hands over eye space", shader_source("class3/deferred/hazeF.glsl").find("eyeToSky") == std::string::npos); - } - - // The far plane overlay: nearer-first pairs out to 100 km on distinct bearings, each farther column behind its - // partner and overlapping it on screen, and every column the same angular size. - template<> template<> - void alfarplane_object::test<7>() - { - set_test_name("overlay columns"); - const std::vector& columns = ALFarPlane::overlayColumns(); - ensure("pairs", columns.size() >= 2 && columns.size() % 2 == 0); - ensure_equals("reaches 100 km", columns[columns.size() - 2].mDistance, 100000.f); - for (size_t i = 0; i < columns.size(); i += 2) - { - const ALFarPlane::OverlayColumn& n = columns[i]; - const ALFarPlane::OverlayColumn& f = columns[i + 1]; - const std::string at = std::to_string((S32)n.mDistance) + " m"; - ensure("nearer first at " + at, n.mNearer && !f.mNearer); - ensure("farther behind at " + at, f.mDistance > n.mDistance); - ensure("same bearing at " + at, f.mBearing == n.mBearing); - // On screen the farther column's near edge sits inside the nearer column. - const F32 f_left = (f.mOffset - f.mHalfWidth) / f.mDistance; - const F32 n_right = (n.mOffset + n.mHalfWidth) / n.mDistance; - const F32 n_left = (n.mOffset - n.mHalfWidth) / n.mDistance; - ensure("overlap at " + at, f_left > n_left && f_left < n_right); - ensure("same angle at " + at, fabsf(n.mHeight / n.mDistance - columns[0].mHeight / columns[0].mDistance) < 1e-6f); - if (i > 0) - { - ensure("own bearing at " + at, n.mBearing != columns[i - 2].mBearing); - ensure("receding at " + at, n.mDistance > columns[i - 2].mDistance); - } - } + UNSCOPED_INFO("altitude limit on rising rays alone"); + REQUIRE(funcs.find("float h = max(rel_pos.y, 0.0) / max(max_y, 1.0);") != std::string::npos); + UNSCOPED_INFO("no limit on falling rays"); + REQUIRE(funcs.find("abs(rel_pos.y)") == std::string::npos); + UNSCOPED_INFO("the rotation is in the Environment block"); + REQUIRE(shader_source("class1/deferred/environmentBlock.glsl").find("mat3 eyeToSky;") != std::string::npos); + UNSCOPED_INFO("the haze pass hands over eye space"); + REQUIRE(shader_source("class3/deferred/hazeF.glsl").find("eyeToSky") == std::string::npos); } } diff --git a/indra/newview/tests/alfeedback_test.cpp b/indra/newview/tests/alfeedback_test.cpp index c29ccbe9c6..44136a5de0 100644 --- a/indra/newview/tests/alfeedback_test.cpp +++ b/indra/newview/tests/alfeedback_test.cpp @@ -29,7 +29,7 @@ #include "llsd.h" #include "llsdjson.h" -#include "../test/lltut.h" +#include #include @@ -59,128 +59,130 @@ namespace } } -namespace tut +namespace { - struct alfeedback_data - { - }; - - typedef test_group alfeedback_group; - typedef alfeedback_group::object object; - alfeedback_group alfeedbackgrp("alfeedback"); - - template<> template<> - void object::test<1>() + TEST_CASE("alfeedback: a sentry.io DSN sends to its project's envelope endpoint", "[alfeedback]") { - set_test_name("a sentry.io DSN sends to its project's envelope endpoint"); const auto endpoint = ALFeedback::endpointFromDsn("https://0123abcd@o42.ingest.sentry.io/4501"); - ensure("parsed", endpoint.has_value()); - ensure_equals(endpoint->url, "https://o42.ingest.sentry.io/api/4501/envelope/"); - ensure_equals(endpoint->publicKey, "0123abcd"); + UNSCOPED_INFO("parsed"); + REQUIRE(endpoint.has_value()); + CHECK(endpoint->url == "https://o42.ingest.sentry.io/api/4501/envelope/"); + CHECK(endpoint->publicKey == "0123abcd"); } - template<> template<> - void object::test<2>() + TEST_CASE("alfeedback: a self-hosted DSN keeps its port and path and drops an old secret", "[alfeedback]") { - set_test_name("a self-hosted DSN keeps its port and path, and drops an old secret"); const auto endpoint = ALFeedback::endpointFromDsn("https://key:secret@sentry.example.com:9000/prefix/7/"); - ensure("parsed", endpoint.has_value()); - ensure_equals(endpoint->url, "https://sentry.example.com:9000/prefix/api/7/envelope/"); - ensure_equals(endpoint->publicKey, "key"); + UNSCOPED_INFO("parsed"); + REQUIRE(endpoint.has_value()); + CHECK(endpoint->url == "https://sentry.example.com:9000/prefix/api/7/envelope/"); + CHECK(endpoint->publicKey == "key"); } - template<> template<> - void object::test<3>() + TEST_CASE("alfeedback: a DSN missing a part is refused", "[alfeedback]") { - set_test_name("a DSN missing a part is refused"); - ensure("no scheme", !ALFeedback::endpointFromDsn("key@host/1")); - ensure("another scheme", !ALFeedback::endpointFromDsn("ftp://key@host/1")); - ensure("no key", !ALFeedback::endpointFromDsn("https://host/1")); - ensure("empty key", !ALFeedback::endpointFromDsn("https://@host/1")); - ensure("no project", !ALFeedback::endpointFromDsn("https://key@host")); - ensure("empty host", !ALFeedback::endpointFromDsn("https://key@/1")); - ensure("empty", !ALFeedback::endpointFromDsn("")); + UNSCOPED_INFO("no scheme"); + REQUIRE_FALSE(ALFeedback::endpointFromDsn("key@host/1")); + UNSCOPED_INFO("another scheme"); + REQUIRE_FALSE(ALFeedback::endpointFromDsn("ftp://key@host/1")); + UNSCOPED_INFO("no key"); + REQUIRE_FALSE(ALFeedback::endpointFromDsn("https://host/1")); + UNSCOPED_INFO("empty key"); + REQUIRE_FALSE(ALFeedback::endpointFromDsn("https://@host/1")); + UNSCOPED_INFO("no project"); + REQUIRE_FALSE(ALFeedback::endpointFromDsn("https://key@host")); + UNSCOPED_INFO("empty host"); + REQUIRE_FALSE(ALFeedback::endpointFromDsn("https://key@/1")); + UNSCOPED_INFO("empty"); + REQUIRE_FALSE(ALFeedback::endpointFromDsn("")); } - template<> template<> - void object::test<4>() + TEST_CASE("alfeedback: the auth header names the protocol version and the client and key", "[alfeedback]") { - set_test_name("the auth header names the protocol, the client and the key"); - ensure_equals(ALFeedback::authHeader("0123abcd", "alchemy-feedback/26.4.0"), + CHECK(ALFeedback::authHeader("0123abcd", "alchemy-feedback/26.4.0") == "Sentry sentry_version=7, sentry_client=alchemy-feedback/26.4.0, sentry_key=0123abcd"); } - template<> template<> - void object::test<5>() + TEST_CASE("alfeedback: settings named for keys or passwords or secrets or emails stay private", "[alfeedback]") { - set_test_name("keys, passwords and tokens stay out of the settings sent"); - ensure("translation key", ALFeedback::privateSetting("DeepLTranslateAPIKey")); - ensure("any case", ALFeedback::privateSetting("someapikey")); - ensure("password", ALFeedback::privateSetting("RememberPassword")); - ensure("token", ALFeedback::privateSetting("ServiceToken")); - ensure("secret", ALFeedback::privateSetting("ClientSecret")); - ensure("an address", ALFeedback::privateSetting("AlchemyFeedbackEmail")); - ensure("an ordinary setting goes", !ALFeedback::privateSetting("RenderQualityPerformance")); - ensure("a key binding goes", !ALFeedback::privateSetting("ArrowKeysAlwaysMove")); + UNSCOPED_INFO("translation key"); + CHECK(ALFeedback::privateSetting("DeepLTranslateAPIKey")); + UNSCOPED_INFO("any case"); + CHECK(ALFeedback::privateSetting("someapikey")); + UNSCOPED_INFO("password"); + CHECK(ALFeedback::privateSetting("RememberPassword")); + UNSCOPED_INFO("token"); + CHECK(ALFeedback::privateSetting("ServiceToken")); + UNSCOPED_INFO("secret"); + CHECK(ALFeedback::privateSetting("ClientSecret")); + UNSCOPED_INFO("an address"); + CHECK(ALFeedback::privateSetting("AlchemyFeedbackEmail")); + UNSCOPED_INFO("an ordinary setting goes"); + CHECK_FALSE(ALFeedback::privateSetting("RenderQualityPerformance")); + UNSCOPED_INFO("a key binding goes"); + CHECK_FALSE(ALFeedback::privateSetting("ArrowKeysAlwaysMove")); } - template<> template<> - void object::test<6>() + TEST_CASE("alfeedback: an email is checked for its shape only", "[alfeedback]") { - set_test_name("an email is checked for its shape only"); - ensure("plain", ALFeedback::plausibleEmail("rye@alchemyviewer.org")); - ensure("subdomain", ALFeedback::plausibleEmail("a.b+c@mail.example.co.uk")); - ensure("no at", !ALFeedback::plausibleEmail("rye.alchemyviewer.org")); - ensure("two ats", !ALFeedback::plausibleEmail("a@b@c.d")); - ensure("no local part", !ALFeedback::plausibleEmail("@example.com")); - ensure("no dot", !ALFeedback::plausibleEmail("rye@localhost")); - ensure("dot last", !ALFeedback::plausibleEmail("rye@example.")); - ensure("dot first", !ALFeedback::plausibleEmail("rye@.com")); - ensure("space", !ALFeedback::plausibleEmail("r ye@example.com")); - ensure("empty", !ALFeedback::plausibleEmail("")); + UNSCOPED_INFO("plain"); + CHECK(ALFeedback::plausibleEmail("rye@alchemyviewer.org")); + UNSCOPED_INFO("subdomain"); + CHECK(ALFeedback::plausibleEmail("a.b+c@mail.example.co.uk")); + UNSCOPED_INFO("no at"); + CHECK_FALSE(ALFeedback::plausibleEmail("rye.alchemyviewer.org")); + UNSCOPED_INFO("two ats"); + CHECK_FALSE(ALFeedback::plausibleEmail("a@b@c.d")); + UNSCOPED_INFO("no local part"); + CHECK_FALSE(ALFeedback::plausibleEmail("@example.com")); + UNSCOPED_INFO("no dot"); + CHECK_FALSE(ALFeedback::plausibleEmail("rye@localhost")); + UNSCOPED_INFO("dot last"); + CHECK_FALSE(ALFeedback::plausibleEmail("rye@example.")); + UNSCOPED_INFO("dot first"); + CHECK_FALSE(ALFeedback::plausibleEmail("rye@.com")); + UNSCOPED_INFO("space"); + CHECK_FALSE(ALFeedback::plausibleEmail("r ye@example.com")); + UNSCOPED_INFO("empty"); + CHECK_FALSE(ALFeedback::plausibleEmail("")); } - template<> template<> - void object::test<7>() + TEST_CASE("alfeedback: a short log goes whole", "[alfeedback]") { - set_test_name("a short log goes whole"); - ensure_equals(std::string(ALFeedback::logTail("one\ntwo\n", 64)), "one\ntwo\n"); + CHECK(std::string(ALFeedback::logTail("one\ntwo\n", 64)) == "one\ntwo\n"); } - template<> template<> - void object::test<8>() + TEST_CASE("alfeedback: a long log's tail starts at a line", "[alfeedback]") { - set_test_name("a long log's tail starts at a line"); const std::string log = "first line\nsecond line\nthird\n"; - ensure_equals("mid-line cut moves to the next line", std::string(ALFeedback::logTail(log, 15)), "third\n"); - ensure_equals("a cut on a line start stays", std::string(ALFeedback::logTail(log, 18)), + UNSCOPED_INFO("mid-line cut moves to the next line"); + CHECK(std::string(ALFeedback::logTail(log, 15)) == "third\n"); + UNSCOPED_INFO("a cut on a line start stays"); + CHECK(std::string(ALFeedback::logTail(log, 18)) == "second line\nthird\n"); } - template<> template<> - void object::test<9>() + TEST_CASE("alfeedback: a tail inside one long line never starts inside a character", "[alfeedback]") { - set_test_name("a tail inside one long line never starts inside a character"); // Three two-byte characters; five bytes from the end cuts the first. const std::string log = "\xC3\xA9\xC3\xA9\xC3\xA9"; const std::string tail(ALFeedback::logTail(log, 5)); - ensure_equals(tail, "\xC3\xA9\xC3\xA9"); + CHECK(tail == "\xC3\xA9\xC3\xA9"); } - template<> template<> - void object::test<10>() + TEST_CASE("alfeedback: an event id is 32 lower-case hex digits and new each time", "[alfeedback]") { - set_test_name("an event id is 32 lower-case hex digits, new each time"); const std::string id = ALFeedback::newEventId(); - ensure_equals("length", id.size(), 32u); - ensure("hex", id.find_first_not_of("0123456789abcdef") == std::string::npos); - ensure("new", id != ALFeedback::newEventId()); + UNSCOPED_INFO("length"); + REQUIRE(id.size() == 32u); + UNSCOPED_INFO("hex"); + REQUIRE(id.find_first_not_of("0123456789abcdef") == std::string::npos); + UNSCOPED_INFO("new"); + CHECK(id != ALFeedback::newEventId()); } - template<> template<> - void object::test<11>() + TEST_CASE("alfeedback: the feedback event carries the message as its feedback context", "[alfeedback]") { - set_test_name("the feedback event carries the message as its feedback context"); ALFeedback::Message message; message.kind = ALFeedback::Kind::Idea; message.text = "More knobs"; @@ -200,62 +202,83 @@ namespace tut context.tags = { { "run_id", "run" }, { "empty", "" } }; const LLSD event = ALFeedback::feedbackEvent("feedc0de", "2026-10-09T12:00:00Z", message, context); - ensure_equals("id", event["event_id"].asString(), "feedc0de"); - ensure_equals("timestamp", event["timestamp"].asString(), "2026-10-09T12:00:00Z"); - ensure_equals("level", event["level"].asString(), "info"); - ensure_equals("release", event["release"].asString(), "alchemy@26.4.0+64033"); - ensure_equals("environment", event["environment"].asString(), "Alchemy Test"); - ensure_equals("dist", event["dist"].asString(), "64033"); - ensure_equals("user id", event["user"]["id"].asString(), context.userId); - ensure_equals("user name", event["user"]["username"].asString(), "rye.resident"); - ensure_equals("kind", event["tags"]["feedback_kind"].asString(), "idea"); - ensure_equals("tag", event["tags"]["run_id"].asString(), "run"); - ensure("an empty tag is left out", !event["tags"].has("empty")); + UNSCOPED_INFO("id"); + CHECK(event["event_id"].asString() == "feedc0de"); + UNSCOPED_INFO("timestamp"); + CHECK(event["timestamp"].asString() == "2026-10-09T12:00:00Z"); + UNSCOPED_INFO("level"); + CHECK(event["level"].asString() == "info"); + UNSCOPED_INFO("release"); + CHECK(event["release"].asString() == "alchemy@26.4.0+64033"); + UNSCOPED_INFO("environment"); + CHECK(event["environment"].asString() == "Alchemy Test"); + UNSCOPED_INFO("dist"); + CHECK(event["dist"].asString() == "64033"); + UNSCOPED_INFO("user id"); + CHECK(event["user"]["id"].asString() == context.userId); + UNSCOPED_INFO("user name"); + CHECK(event["user"]["username"].asString() == "rye.resident"); + UNSCOPED_INFO("kind"); + CHECK(event["tags"]["feedback_kind"].asString() == "idea"); + UNSCOPED_INFO("tag"); + CHECK(event["tags"]["run_id"].asString() == "run"); + UNSCOPED_INFO("an empty tag is left out"); + REQUIRE_FALSE(event["tags"].has("empty")); const LLSD& feedback = event["contexts"]["feedback"]; - ensure_equals("message", feedback["message"].asString(), "More knobs"); - ensure_equals("email", feedback["contact_email"].asString(), "rye@example.com"); - ensure_equals("name", feedback["name"].asString(), "Rye"); - ensure_equals("associated", feedback["associated_event_id"].asString(), message.associatedEventId); - ensure_equals("os", event["contexts"]["os"]["name"].asString(), context.osName); - ensure_equals("gpu", event["contexts"]["gpu"]["vendor_name"].asString(), "NVIDIA"); + UNSCOPED_INFO("message"); + CHECK(feedback["message"].asString() == "More knobs"); + UNSCOPED_INFO("email"); + CHECK(feedback["contact_email"].asString() == "rye@example.com"); + UNSCOPED_INFO("name"); + CHECK(feedback["name"].asString() == "Rye"); + UNSCOPED_INFO("associated"); + CHECK(feedback["associated_event_id"].asString() == message.associatedEventId); + UNSCOPED_INFO("os"); + CHECK(event["contexts"]["os"]["name"].asString() == context.osName); + UNSCOPED_INFO("gpu"); + CHECK(event["contexts"]["gpu"]["vendor_name"].asString() == "NVIDIA"); } - template<> template<> - void object::test<12>() + TEST_CASE("alfeedback: what the user left empty is not in the event", "[alfeedback]") { - set_test_name("what the user left empty is not in the event"); ALFeedback::Message message; message.text = "It broke"; const LLSD event = ALFeedback::feedbackEvent("feedc0de", "2026-10-09T12:00:00Z", message, ALFeedback::Context()); - ensure("no user", !event.has("user")); - ensure("no release", !event.has("release")); - ensure("no os", !event["contexts"].has("os")); - ensure("no gpu", !event["contexts"].has("gpu")); + UNSCOPED_INFO("no user"); + REQUIRE_FALSE(event.has("user")); + UNSCOPED_INFO("no release"); + REQUIRE_FALSE(event.has("release")); + UNSCOPED_INFO("no os"); + REQUIRE_FALSE(event["contexts"].has("os")); + UNSCOPED_INFO("no gpu"); + REQUIRE_FALSE(event["contexts"].has("gpu")); const LLSD& feedback = event["contexts"]["feedback"]; - ensure("no email", !feedback.has("contact_email")); - ensure("no name", !feedback.has("name")); - ensure("no association", !feedback.has("associated_event_id")); - ensure_equals("problem by default", event["tags"]["feedback_kind"].asString(), "problem"); + UNSCOPED_INFO("no email"); + REQUIRE_FALSE(feedback.has("contact_email")); + UNSCOPED_INFO("no name"); + REQUIRE_FALSE(feedback.has("name")); + UNSCOPED_INFO("no association"); + REQUIRE_FALSE(feedback.has("associated_event_id")); + UNSCOPED_INFO("problem by default"); + CHECK(event["tags"]["feedback_kind"].asString() == "problem"); } - template<> template<> - void object::test<13>() + TEST_CASE("alfeedback: a tag value is one line cut on a character within Sentry's limit", "[alfeedback]") { - set_test_name("a tag value is one line within Sentry's limit, cut on a character"); ALFeedback::Context context; std::string long_value(ALFeedback::TAG_VALUE_MAX_BYTES - 1, 'a'); long_value += "\xC3\xA9tail"; context.tags = { { "long", long_value }, { "lines", "one\ntwo\r\n" } }; const LLSD event = ALFeedback::feedbackEvent("id", "t", ALFeedback::Message(), context); - ensure_equals("cut before the character", event["tags"]["long"].asString(), + UNSCOPED_INFO("cut before the character"); + CHECK(event["tags"]["long"].asString() == std::string(ALFeedback::TAG_VALUE_MAX_BYTES - 1, 'a')); - ensure_equals("one line", event["tags"]["lines"].asString(), "one two "); + UNSCOPED_INFO("one line"); + CHECK(event["tags"]["lines"].asString() == "one two "); } - template<> template<> - void object::test<14>() + TEST_CASE("alfeedback: the envelope is a header then the feedback then attachments by byte length", "[alfeedback]") { - set_test_name("the envelope is a header, the feedback, then each attachment, lengths in bytes"); ALFeedback::Message message; message.text = "caf\xC3\xA9 \xF0\x9F\x99\x82\nsecond line"; const LLSD event = ALFeedback::feedbackEvent("feedc0de", "2026-10-09T12:00:00Z", message, ALFeedback::Context()); @@ -269,137 +292,179 @@ namespace tut size_t pos = 0; const LLSD header = json(take(bytes, pos)); - ensure_equals("header id", header["event_id"].asString(), "feedc0de"); - ensure_equals("header dsn", header["dsn"].asString(), "https://k@h/1"); + UNSCOPED_INFO("header id"); + CHECK(header["event_id"].asString() == "feedc0de"); + UNSCOPED_INFO("header dsn"); + CHECK(header["dsn"].asString() == "https://k@h/1"); // A kept envelope goes again as it is, days later maybe: a time it // was sent would be read as the client's clock being wrong. - ensure("no time sent", !header.has("sent_at")); - ensure_equals("header sdk", header["sdk"]["name"].asString(), "alchemy.feedback"); + UNSCOPED_INFO("no time sent"); + REQUIRE_FALSE(header.has("sent_at")); + UNSCOPED_INFO("header sdk"); + CHECK(header["sdk"]["name"].asString() == "alchemy.feedback"); const LLSD feedback_item = json(take(bytes, pos)); - ensure_equals("feedback type", feedback_item["type"].asString(), "feedback"); + UNSCOPED_INFO("feedback type"); + CHECK(feedback_item["type"].asString() == "feedback"); const LLSD payload = json(take(bytes, pos, feedback_item["length"].asInteger())); - ensure_equals("the message round-trips", payload["contexts"]["feedback"]["message"].asString(), message.text); + UNSCOPED_INFO("the message round-trips"); + CHECK(payload["contexts"]["feedback"]["message"].asString() == message.text); const LLSD screenshot_item = json(take(bytes, pos)); - ensure_equals("attachment type", screenshot_item["type"].asString(), "attachment"); - ensure_equals("filename", screenshot_item["filename"].asString(), "screenshot.png"); - ensure_equals("content type", screenshot_item["content_type"].asString(), "image/png"); - ensure_equals("binary bytes", std::string(take(bytes, pos, screenshot_item["length"].asInteger())), binary); + UNSCOPED_INFO("attachment type"); + CHECK(screenshot_item["type"].asString() == "attachment"); + UNSCOPED_INFO("filename"); + CHECK(screenshot_item["filename"].asString() == "screenshot.png"); + UNSCOPED_INFO("content type"); + CHECK(screenshot_item["content_type"].asString() == "image/png"); + UNSCOPED_INFO("binary bytes"); + CHECK(std::string(take(bytes, pos, screenshot_item["length"].asInteger())) == binary); const LLSD log_item = json(take(bytes, pos)); - ensure_equals("log bytes", std::string(take(bytes, pos, log_item["length"].asInteger())), "line\n"); - ensure_equals("nothing after", pos, bytes.size()); + UNSCOPED_INFO("log bytes"); + CHECK(std::string(take(bytes, pos, log_item["length"].asInteger())) == "line\n"); + UNSCOPED_INFO("nothing after"); + REQUIRE(pos == bytes.size()); } - template<> template<> - void object::test<15>() + TEST_CASE("alfeedback: gzip makes one member that inflates back to the data", "[alfeedback]") { - set_test_name("gzip makes one member that inflates back to the data"); std::string data; for (int i = 0; i < 2000; ++i) { data += "2026-10-09T12:00:00Z INFO: a log line that repeats\n"; } std::string zipped; - ensure("compressed", ALFeedback::gzip(data, zipped)); - ensure("gzip magic", zipped.size() > 2 && zipped[0] == '\x1f' && zipped[1] == '\x8b'); - ensure("smaller", zipped.size() < data.size() / 4); + UNSCOPED_INFO("compressed"); + REQUIRE(ALFeedback::gzip(data, zipped)); + { + INFO("gzip magic"); + REQUIRE(zipped.size() > 2); + CHECK(zipped[0] == '\x1f'); + CHECK(zipped[1] == '\x8b'); + } + UNSCOPED_INFO("smaller"); + REQUIRE(zipped.size() < data.size() / 4); std::string inflated(data.size(), '\0'); z_stream stream = {}; - ensure_equals("inflate init", inflateInit2(&stream, MAX_WBITS + 16), Z_OK); + UNSCOPED_INFO("inflate init"); + CHECK(inflateInit2(&stream, MAX_WBITS + 16) == Z_OK); stream.next_in = reinterpret_cast(zipped.data()); stream.avail_in = static_cast(zipped.size()); stream.next_out = reinterpret_cast(inflated.data()); stream.avail_out = static_cast(inflated.size()); - ensure_equals("inflated whole", inflate(&stream, Z_FINISH), Z_STREAM_END); + UNSCOPED_INFO("inflated whole"); + CHECK(inflate(&stream, Z_FINISH) == Z_STREAM_END); inflateEnd(&stream); - ensure("round trip", inflated == data); + UNSCOPED_INFO("round trip"); + CHECK(inflated == data); } - template<> template<> - void object::test<16>() + TEST_CASE("alfeedback: the server's answer reads as an outcome", "[alfeedback]") { - set_test_name("the server's answer reads as an outcome"); using ALFeedback::Outcome; - ensure("200", ALFeedback::classify(200) == Outcome::Sent); - ensure("429", ALFeedback::classify(429) == Outcome::RateLimited); - ensure("413", ALFeedback::classify(413) == Outcome::TooLarge); - ensure("400", ALFeedback::classify(400) == Outcome::Rejected); - ensure("403", ALFeedback::classify(403) == Outcome::Rejected); - ensure("408", ALFeedback::classify(408) == Outcome::Unreachable); - ensure("503", ALFeedback::classify(503) == Outcome::Unreachable); - ensure("no answer", ALFeedback::classify(0) == Outcome::Unreachable); - ensure("retry when limited", ALFeedback::retryable(Outcome::RateLimited)); - ensure("retry when unreachable", ALFeedback::retryable(Outcome::Unreachable)); - ensure("no retry when refused", !ALFeedback::retryable(Outcome::Rejected)); - ensure("no retry when too large", !ALFeedback::retryable(Outcome::TooLarge)); - ensure("no retry when sent", !ALFeedback::retryable(Outcome::Sent)); + UNSCOPED_INFO("200"); + CHECK(ALFeedback::classify(200) == Outcome::Sent); + UNSCOPED_INFO("429"); + CHECK(ALFeedback::classify(429) == Outcome::RateLimited); + UNSCOPED_INFO("413"); + CHECK(ALFeedback::classify(413) == Outcome::TooLarge); + UNSCOPED_INFO("400"); + CHECK(ALFeedback::classify(400) == Outcome::Rejected); + UNSCOPED_INFO("403"); + CHECK(ALFeedback::classify(403) == Outcome::Rejected); + UNSCOPED_INFO("408"); + CHECK(ALFeedback::classify(408) == Outcome::Unreachable); + UNSCOPED_INFO("503"); + CHECK(ALFeedback::classify(503) == Outcome::Unreachable); + UNSCOPED_INFO("no answer"); + CHECK(ALFeedback::classify(0) == Outcome::Unreachable); + UNSCOPED_INFO("retry when limited"); + CHECK(ALFeedback::retryable(Outcome::RateLimited)); + UNSCOPED_INFO("retry when unreachable"); + CHECK(ALFeedback::retryable(Outcome::Unreachable)); + UNSCOPED_INFO("no retry when refused"); + CHECK_FALSE(ALFeedback::retryable(Outcome::Rejected)); + UNSCOPED_INFO("no retry when too large"); + CHECK_FALSE(ALFeedback::retryable(Outcome::TooLarge)); + UNSCOPED_INFO("no retry when sent"); + CHECK_FALSE(ALFeedback::retryable(Outcome::Sent)); } - template<> template<> - void object::test<17>() + TEST_CASE("alfeedback: a kept report's wait doubles from 15 minutes to 6 hours or more if asked", "[alfeedback]") { - set_test_name("a kept report waits a quarter hour, doubling to six hours, never less than asked"); const S64 now = 1000000; - ensure_equals("first", ALFeedback::nextAttempt(now, 1, 0.f), now + 15 * 60); - ensure_equals("second", ALFeedback::nextAttempt(now, 2, 0.f), now + 30 * 60); - ensure_equals("third", ALFeedback::nextAttempt(now, 3, 0.f), now + 60 * 60); - ensure_equals("capped", ALFeedback::nextAttempt(now, 20, 0.f), now + 6 * 60 * 60); - ensure_equals("the server's word", ALFeedback::nextAttempt(now, 1, 3600.5f), now + 3601); + UNSCOPED_INFO("first"); + CHECK(ALFeedback::nextAttempt(now, 1, 0.f) == now + 15 * 60); + UNSCOPED_INFO("second"); + CHECK(ALFeedback::nextAttempt(now, 2, 0.f) == now + 30 * 60); + UNSCOPED_INFO("third"); + CHECK(ALFeedback::nextAttempt(now, 3, 0.f) == now + 60 * 60); + UNSCOPED_INFO("capped"); + CHECK(ALFeedback::nextAttempt(now, 20, 0.f) == now + 6 * 60 * 60); + UNSCOPED_INFO("the server's word"); + CHECK(ALFeedback::nextAttempt(now, 1, 3600.5f) == now + 3601); } - template<> template<> - void object::test<18>() + TEST_CASE("alfeedback: a kept report is given up after a week or five tries", "[alfeedback]") { - set_test_name("a kept report is given up after a week or five tries"); ALFeedback::Queued queued; queued.created = 0; queued.attempts = 4; - ensure("young and tried four times", !ALFeedback::expired(queued, ALFeedback::QUEUE_MAX_AGE_SECONDS)); - ensure("over a week", ALFeedback::expired(queued, ALFeedback::QUEUE_MAX_AGE_SECONDS + 1)); + UNSCOPED_INFO("young and tried four times"); + CHECK_FALSE(ALFeedback::expired(queued, ALFeedback::QUEUE_MAX_AGE_SECONDS)); + UNSCOPED_INFO("over a week"); + CHECK(ALFeedback::expired(queued, ALFeedback::QUEUE_MAX_AGE_SECONDS + 1)); queued.attempts = 5; - ensure("five tries", ALFeedback::expired(queued, 0)); + UNSCOPED_INFO("five tries"); + CHECK(ALFeedback::expired(queued, 0)); } - template<> template<> - void object::test<19>() + TEST_CASE("alfeedback: a kept report's record round-trips past 2038 too", "[alfeedback]") { - set_test_name("a kept report's record round-trips, past 2038 too"); ALFeedback::Queued queued; queued.eventId = "0123abcd89abcdef0123456789abcdef"; queued.created = 4102444800; // 2100 queued.attempts = 3; queued.nextAt = 4102448400; const auto back = ALFeedback::queuedFromJson(ALFeedback::queuedToJson(queued)); - ensure("parsed", back.has_value()); - ensure_equals("id", back->eventId, queued.eventId); - ensure_equals("created", back->created, queued.created); - ensure_equals("attempts", back->attempts, queued.attempts); - ensure_equals("next", back->nextAt, queued.nextAt); - ensure("not a record", !ALFeedback::queuedFromJson("{\"nothing\":1}")); - ensure("not json", !ALFeedback::queuedFromJson("garbage")); + UNSCOPED_INFO("parsed"); + REQUIRE(back.has_value()); + UNSCOPED_INFO("id"); + CHECK(back->eventId == queued.eventId); + UNSCOPED_INFO("created"); + CHECK(back->created == queued.created); + UNSCOPED_INFO("attempts"); + CHECK(back->attempts == queued.attempts); + UNSCOPED_INFO("next"); + CHECK(back->nextAt == queued.nextAt); + UNSCOPED_INFO("not a record"); + REQUIRE_FALSE(ALFeedback::queuedFromJson("{\"nothing\":1}")); + UNSCOPED_INFO("not json"); + REQUIRE_FALSE(ALFeedback::queuedFromJson("garbage")); } - template<> template<> - void object::test<20>() + TEST_CASE("alfeedback: a DSN sends in the clear only to this machine", "[alfeedback]") { - set_test_name("a DSN sends in the clear only to this machine"); const auto local = ALFeedback::endpointFromDsn("http://0123abcd@127.0.0.1:8765/1"); - ensure("loopback", local.has_value()); - ensure_equals(local->url, "http://127.0.0.1:8765/api/1/envelope/"); - ensure("localhost", ALFeedback::endpointFromDsn("http://k@localhost/1").has_value()); - ensure("IPv6 loopback", ALFeedback::endpointFromDsn("http://k@[::1]:9000/1").has_value()); - ensure("another host", !ALFeedback::endpointFromDsn("http://k@o42.ingest.sentry.io/4501")); - ensure("a host that starts like loopback", !ALFeedback::endpointFromDsn("http://k@127.0.0.1.example.com/1")); - ensure("loopback as a user name", !ALFeedback::endpointFromDsn("http://k@evil.example.com/127.0.0.1/1")); + UNSCOPED_INFO("loopback"); + REQUIRE(local.has_value()); + CHECK(local->url == "http://127.0.0.1:8765/api/1/envelope/"); + UNSCOPED_INFO("localhost"); + REQUIRE(ALFeedback::endpointFromDsn("http://k@localhost/1").has_value()); + UNSCOPED_INFO("IPv6 loopback"); + REQUIRE(ALFeedback::endpointFromDsn("http://k@[::1]:9000/1").has_value()); + UNSCOPED_INFO("another host"); + REQUIRE_FALSE(ALFeedback::endpointFromDsn("http://k@o42.ingest.sentry.io/4501")); + UNSCOPED_INFO("a host that starts like loopback"); + REQUIRE_FALSE(ALFeedback::endpointFromDsn("http://k@127.0.0.1.example.com/1")); + UNSCOPED_INFO("loopback as a user name"); + REQUIRE_FALSE(ALFeedback::endpointFromDsn("http://k@evil.example.com/127.0.0.1/1")); } - template<> template<> - void object::test<21>() + TEST_CASE("alfeedback: a report's logs hide capability addresses and the given words", "[alfeedback]") { - set_test_name("a report's logs hide capability addresses and the given words"); const std::string log = "INFO: Requesting seed from https://simhost-0a1b.agni.lindenlab.com:12043/cap/" "0f1e2d3c-4b5a-6978-8796-a5b4c3d2e1f0 region name Ahern\n" @@ -408,88 +473,114 @@ namespace tut "INFO: Logging out as agent: a2e76fcd-9360-4f6d-a924-000000000003\n"; const std::string scrubbed = ALFeedback::scrubLog(log, { "rye resident", "rye.resident", "a2e76fcd-9360-4f6d-a924-000000000003", "" }); - ensure("a Second Life capability", scrubbed.find("0f1e2d3c") == std::string::npos); - ensure("an OpenSim capability, any case", scrubbed.find("0F1E2D3C") == std::string::npos); - ensure("what is not secret stays", scrubbed.find("simhost-0a1b.agni.lindenlab.com:12043/cap/[hidden] region name Ahern") + UNSCOPED_INFO("a Second Life capability"); + REQUIRE(scrubbed.find("0f1e2d3c") == std::string::npos); + UNSCOPED_INFO("an OpenSim capability, any case"); + REQUIRE(scrubbed.find("0F1E2D3C") == std::string::npos); + UNSCOPED_INFO("what is not secret stays"); + REQUIRE(scrubbed.find("simhost-0a1b.agni.lindenlab.com:12043/cap/[hidden] region name Ahern") != std::string::npos); - ensure("the path after it stays", scrubbed.find("/CAPS/[hidden]/'") != std::string::npos); - ensure("a name, any case", scrubbed.find("Attempting login as: [hidden]\n") != std::string::npos); - ensure("an id", scrubbed.find("agent: [hidden]\n") != std::string::npos); - ensure_equals("nothing to hide is the log", ALFeedback::scrubLog("plain line\n", {}), "plain line\n"); + UNSCOPED_INFO("the path after it stays"); + REQUIRE(scrubbed.find("/CAPS/[hidden]/'") != std::string::npos); + UNSCOPED_INFO("a name, any case"); + REQUIRE(scrubbed.find("Attempting login as: [hidden]\n") != std::string::npos); + UNSCOPED_INFO("an id"); + REQUIRE(scrubbed.find("agent: [hidden]\n") != std::string::npos); + UNSCOPED_INFO("nothing to hide is the log"); + CHECK(ALFeedback::scrubLog("plain line\n", {}) == "plain line\n"); } - template<> template<> - void object::test<22>() + TEST_CASE("alfeedback: only an id can name a file", "[alfeedback]") { - set_test_name("only an id can name a file"); - ensure("an id", ALFeedback::validEventId(ALFeedback::newEventId())); - ensure("upper case", !ALFeedback::validEventId("0123456789ABCDEF0123456789abcdef")); - ensure("short", !ALFeedback::validEventId("0123456789abcdef")); - ensure("a path", !ALFeedback::validEventId("../../../../../../../../../../x")); - ensure("dashed", !ALFeedback::validEventId("01234567-89ab-cdef-0123-456789abcdef")); - ensure("nil", !ALFeedback::validEventId("00000000000000000000000000000000")); - ensure_equals("a reference is its start", ALFeedback::reference("0123456789abcdef0123456789abcdef"), "01234567"); + UNSCOPED_INFO("an id"); + CHECK(ALFeedback::validEventId(ALFeedback::newEventId())); + UNSCOPED_INFO("upper case"); + CHECK_FALSE(ALFeedback::validEventId("0123456789ABCDEF0123456789abcdef")); + UNSCOPED_INFO("short"); + CHECK_FALSE(ALFeedback::validEventId("0123456789abcdef")); + UNSCOPED_INFO("a path"); + CHECK_FALSE(ALFeedback::validEventId("../../../../../../../../../../x")); + UNSCOPED_INFO("dashed"); + CHECK_FALSE(ALFeedback::validEventId("01234567-89ab-cdef-0123-456789abcdef")); + UNSCOPED_INFO("nil"); + CHECK_FALSE(ALFeedback::validEventId("00000000000000000000000000000000")); + UNSCOPED_INFO("a reference is its start"); + CHECK(ALFeedback::reference("0123456789abcdef0123456789abcdef") == "01234567"); } - template<> template<> - void object::test<23>() + TEST_CASE("alfeedback: a changed setting's text shows only when it is plain", "[alfeedback]") { - set_test_name("a changed setting's text shows only when it is plain"); - ensure_equals("a number", ALFeedback::settingText("RenderQualityPerformance", LLSD(3)), "i3"); - ensure_equals("a word", ALFeedback::settingText("SkinCurrent", LLSD("alchemy")), "'alchemy'"); - ensure_equals("a path", ALFeedback::settingText("InstantMessageLogPath", LLSD("C:\\Users\\rye\\chat")), + UNSCOPED_INFO("a number"); + CHECK(ALFeedback::settingText("RenderQualityPerformance", LLSD(3)) == "i3"); + UNSCOPED_INFO("a word"); + CHECK(ALFeedback::settingText("SkinCurrent", LLSD("alchemy")) == "'alchemy'"); + UNSCOPED_INFO("a path"); + CHECK(ALFeedback::settingText("InstantMessageLogPath", LLSD("C:\\Users\\rye\\chat")) == "(hidden)"); - ensure_equals("a sentence", ALFeedback::settingText("DoNotDisturbModeResponse", LLSD("Away right now")), + UNSCOPED_INFO("a sentence"); + CHECK(ALFeedback::settingText("DoNotDisturbModeResponse", LLSD("Away right now")) == "(hidden)"); - ensure_equals("an address", ALFeedback::settingText("StreamURL", LLSD("http://radio.example.com/?k=1")), + UNSCOPED_INFO("an address"); + CHECK(ALFeedback::settingText("StreamURL", LLSD("http://radio.example.com/?k=1")) == "(hidden)"); - ensure_equals("a name", ALFeedback::settingText("LastName", LLSD("Resident")), "(hidden)"); - ensure_equals("a list", ALFeedback::settingText("StreamList", LLSD::emptyArray()), "(hidden)"); + UNSCOPED_INFO("a name"); + CHECK(ALFeedback::settingText("LastName", LLSD("Resident")) == "(hidden)"); + UNSCOPED_INFO("a list"); + CHECK(ALFeedback::settingText("StreamList", LLSD::emptyArray()) == "(hidden)"); } - template<> template<> - void object::test<24>() + TEST_CASE("alfeedback: a wait the server asks for is a sane number of seconds", "[alfeedback]") { - set_test_name("a wait the server asks for is a sane number of seconds"); - ensure_equals("none", ALFeedback::serverWait(0.f), 0); - ensure_equals("negative", ALFeedback::serverWait(-5.f), 0); - ensure_equals("not a number", ALFeedback::serverWait(std::numeric_limits::quiet_NaN()), 0); - ensure_equals("rounded up", ALFeedback::serverWait(90.2f), 91); - ensure_equals("forever is a week", ALFeedback::serverWait(std::numeric_limits::infinity()), + UNSCOPED_INFO("none"); + CHECK(ALFeedback::serverWait(0.f) == 0); + UNSCOPED_INFO("negative"); + CHECK(ALFeedback::serverWait(-5.f) == 0); + UNSCOPED_INFO("not a number"); + CHECK(ALFeedback::serverWait(std::numeric_limits::quiet_NaN()) == 0); + UNSCOPED_INFO("rounded up"); + CHECK(ALFeedback::serverWait(90.2f) == 91); + UNSCOPED_INFO("forever is a week"); + CHECK(ALFeedback::serverWait(std::numeric_limits::infinity()) == ALFeedback::QUEUE_MAX_AGE_SECONDS); - ensure_equals("too long is a week", ALFeedback::serverWait(1e30f), ALFeedback::QUEUE_MAX_AGE_SECONDS); + UNSCOPED_INFO("too long is a week"); + CHECK(ALFeedback::serverWait(1e30f) == ALFeedback::QUEUE_MAX_AGE_SECONDS); const S64 now = 1000000; - ensure("never before now", ALFeedback::nextAttempt(now, 1, std::numeric_limits::infinity()) > now); + UNSCOPED_INFO("never before now"); + CHECK(ALFeedback::nextAttempt(now, 1, std::numeric_limits::infinity()) > now); } - template<> template<> - void object::test<25>() + TEST_CASE("alfeedback: a kept record keeps what the user wrote and refuses what is not one", "[alfeedback]") { - set_test_name("a kept record keeps what the user wrote, and refuses what is not one"); ALFeedback::Queued queued; queued.eventId = "0123abcd89abcdef0123456789abcdef"; queued.notBefore = 4102448500; queued.kind = ALFeedback::Kind::Idea; queued.message = "More knobs \xF0\x9F\x99\x82"; const auto back = ALFeedback::queuedFromJson(ALFeedback::queuedToJson(queued)); - ensure("parsed", back.has_value()); - ensure_equals("not before", back->notBefore, queued.notBefore); - ensure("kind", back->kind == ALFeedback::Kind::Idea); - ensure_equals("message", back->message, queued.message); - ensure("a path for an id", - !ALFeedback::queuedFromJson("{\"event_id\":\"../../x\",\"created\":1,\"attempts\":0}")); + UNSCOPED_INFO("parsed"); + REQUIRE(back.has_value()); + UNSCOPED_INFO("not before"); + CHECK(back->notBefore == queued.notBefore); + UNSCOPED_INFO("kind"); + CHECK(back->kind == ALFeedback::Kind::Idea); + UNSCOPED_INFO("message"); + CHECK(back->message == queued.message); + UNSCOPED_INFO("a path for an id"); + REQUIRE_FALSE(ALFeedback::queuedFromJson("{\"event_id\":\"../../x\",\"created\":1,\"attempts\":0}")); const auto wild = ALFeedback::queuedFromJson( "{\"event_id\":\"0123abcd89abcdef0123456789abcdef\",\"created\":1e300,\"next_at\":-5,\"attempts\":-3}"); - ensure("times that are not times", wild.has_value()); - ensure_equals("created", wild->created, 0); - ensure_equals("next", wild->nextAt, 0); - ensure_equals("attempts", wild->attempts, 0); + UNSCOPED_INFO("times that are not times"); + REQUIRE(wild.has_value()); + UNSCOPED_INFO("created"); + CHECK(wild->created == 0); + UNSCOPED_INFO("next"); + CHECK(wild->nextAt == 0); + UNSCOPED_INFO("attempts"); + CHECK(wild->attempts == 0); } - template<> template<> - void object::test<26>() + TEST_CASE("alfeedback: a draft round-trips and drops what is not an id or a link", "[alfeedback]") { - set_test_name("a draft round-trips, and what is not an id or a link is dropped"); ALFeedback::Draft draft; draft.kind = ALFeedback::Kind::Other; draft.message = "Half a thought"; @@ -499,31 +590,45 @@ namespace tut draft.linkedAt = "2026-10-09T12:00:00Z"; draft.linkedRunId = "run"; const auto back = ALFeedback::draftFromJson(ALFeedback::draftToJson(draft)); - ensure("parsed", back.has_value()); - ensure("kind", back->kind == ALFeedback::Kind::Other); - ensure_equals("message", back->message, draft.message); - ensure_equals("id", back->eventId, draft.eventId); - ensure_equals("associated", back->associatedEventId, draft.associatedEventId); - ensure_equals("linked", back->linked, "freeze"); - ensure_equals("when", back->linkedAt, draft.linkedAt); - ensure_equals("run", back->linkedRunId, "run"); + UNSCOPED_INFO("parsed"); + REQUIRE(back.has_value()); + UNSCOPED_INFO("kind"); + CHECK(back->kind == ALFeedback::Kind::Other); + UNSCOPED_INFO("message"); + CHECK(back->message == draft.message); + UNSCOPED_INFO("id"); + CHECK(back->eventId == draft.eventId); + UNSCOPED_INFO("associated"); + CHECK(back->associatedEventId == draft.associatedEventId); + UNSCOPED_INFO("linked"); + CHECK(back->linked == "freeze"); + UNSCOPED_INFO("when"); + CHECK(back->linkedAt == draft.linkedAt); + UNSCOPED_INFO("run"); + CHECK(back->linkedRunId == "run"); const auto odd = ALFeedback::draftFromJson( "{\"message\":\"hi there\",\"event_id\":\"../x\",\"linked\":\"party\",\"kind\":\"nonsense\"}"); - ensure("parsed", odd.has_value()); - ensure("no id", odd->eventId.empty()); - ensure("no link", odd->linked.empty()); - ensure("a problem", odd->kind == ALFeedback::Kind::Problem); - ensure("an empty draft is none", !ALFeedback::draftFromJson("{\"message\":\" \\n\"}")); + UNSCOPED_INFO("parsed"); + REQUIRE(odd.has_value()); + UNSCOPED_INFO("no id"); + REQUIRE(odd->eventId.empty()); + UNSCOPED_INFO("no link"); + REQUIRE(odd->linked.empty()); + UNSCOPED_INFO("a problem"); + CHECK(odd->kind == ALFeedback::Kind::Problem); + UNSCOPED_INFO("an empty draft is none"); + REQUIRE_FALSE(ALFeedback::draftFromJson("{\"message\":\" \\n\"}")); } - template<> template<> - void object::test<27>() + TEST_CASE("alfeedback: kinds and outcomes have names", "[alfeedback]") { - set_test_name("kinds and outcomes have names"); - ensure("idea", ALFeedback::kindFromName(ALFeedback::kindName(ALFeedback::Kind::Idea)) == ALFeedback::Kind::Idea); - ensure("other", ALFeedback::kindFromName("other") == ALFeedback::Kind::Other); - ensure("anything else", ALFeedback::kindFromName("bug") == ALFeedback::Kind::Problem); - ensure_equals(std::string(ALFeedback::outcomeName(ALFeedback::Outcome::RateLimited)), "rate limited"); + UNSCOPED_INFO("idea"); + CHECK(ALFeedback::kindFromName(ALFeedback::kindName(ALFeedback::Kind::Idea)) == ALFeedback::Kind::Idea); + UNSCOPED_INFO("other"); + CHECK(ALFeedback::kindFromName("other") == ALFeedback::Kind::Other); + UNSCOPED_INFO("anything else"); + CHECK(ALFeedback::kindFromName("bug") == ALFeedback::Kind::Problem); + CHECK(std::string(ALFeedback::outcomeName(ALFeedback::Outcome::RateLimited)) == "rate limited"); } } diff --git a/indra/newview/tests/alfeedbackoutbox_test.cpp b/indra/newview/tests/alfeedbackoutbox_test.cpp index 19fce656f5..91c4b88851 100644 --- a/indra/newview/tests/alfeedbackoutbox_test.cpp +++ b/indra/newview/tests/alfeedbackoutbox_test.cpp @@ -32,7 +32,7 @@ #include "llfile.h" #include "lluuid.h" -#include "../test/lltut.h" +#include #include @@ -70,7 +70,7 @@ namespace } } -namespace tut +namespace { struct alfeedbackoutbox_data { @@ -93,77 +93,82 @@ namespace tut } }; - typedef test_group alfeedbackoutbox_group; - typedef alfeedbackoutbox_group::object object; - alfeedbackoutbox_group alfeedbackoutboxgrp("alfeedbackoutbox"); - - template<> template<> - void object::test<1>() + TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: a kept report is a body and a record due a quarter hour later", "[alfeedbackoutbox]") { - set_test_name("a kept report is a body and a record, due a quarter hour later"); ALFeedbackOutbox box(mDir); std::vector given_up; const S64 now = now_seconds(); - ensure("kept", box.keep(report(id(1)), "body", now, given_up)); - ensure("has", box.has(id(1))); - ensure_equals("body", LLFile::getContents(path(id(1), ".envelope")), "body"); + UNSCOPED_INFO("kept"); + REQUIRE(box.keep(report(id(1)), "body", now, given_up)); + UNSCOPED_INFO("has"); + REQUIRE(box.has(id(1))); + UNSCOPED_INFO("body"); + CHECK(LLFile::getContents(path(id(1), ".envelope")) == "body"); const auto records = box.records(now, given_up); - ensure_equals("one", records.size(), 1u); - ensure_equals("made now", records[0].created, now); - ensure_equals("due", records[0].nextAt, now + ALFeedback::QUEUE_RETRY_SECONDS); - ensure_equals("what the user wrote", records[0].message, "It broke"); - ensure("nothing given up", given_up.empty()); + UNSCOPED_INFO("one"); + REQUIRE(records.size() == 1u); + UNSCOPED_INFO("made now"); + CHECK(records[0].created == now); + UNSCOPED_INFO("due"); + CHECK(records[0].nextAt == now + ALFeedback::QUEUE_RETRY_SECONDS); + UNSCOPED_INFO("what the user wrote"); + CHECK(records[0].message == "It broke"); + UNSCOPED_INFO("nothing given up"); + REQUIRE(given_up.empty()); } - template<> template<> - void object::test<2>() + TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: an id that would leave the folder names no file", "[alfeedbackoutbox]") { - set_test_name("an id that is not one names no file"); ALFeedbackOutbox box(mDir); std::vector given_up; - ensure("not kept", !box.keep(report("../escape"), "body", now_seconds(), given_up)); - ensure("not claimed", !box.claim("../escape")); - ensure("nothing written", gDirUtilp->getFilesInDir(mDir).empty()); + UNSCOPED_INFO("not kept"); + CHECK_FALSE(box.keep(report("../escape"), "body", now_seconds(), given_up)); + UNSCOPED_INFO("not claimed"); + CHECK_FALSE(box.claim("../escape")); + UNSCOPED_INFO("nothing written"); + REQUIRE(gDirUtilp->getFilesInDir(mDir).empty()); } - template<> template<> - void object::test<3>() + TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: a claimed report cannot be claimed again until released", "[alfeedbackoutbox]") { - set_test_name("a claim is one run's: a second claim finds nothing"); ALFeedbackOutbox box(mDir); ALFeedbackOutbox other(mDir); std::vector given_up; box.keep(report(id(1)), "body", now_seconds(), given_up); - ensure("claimed", box.claim(id(1))); - ensure("not twice", !other.claim(id(1))); - ensure_equals("its body", box.claimedBody(id(1)), "body"); - ensure("still kept", box.has(id(1))); + UNSCOPED_INFO("claimed"); + CHECK(box.claim(id(1))); + UNSCOPED_INFO("not twice"); + CHECK_FALSE(other.claim(id(1))); + UNSCOPED_INFO("its body"); + CHECK(box.claimedBody(id(1)) == "body"); + UNSCOPED_INFO("still kept"); + REQUIRE(box.has(id(1))); box.release(id(1)); - ensure("free again", other.claim(id(1))); + UNSCOPED_INFO("free again"); + CHECK(other.claim(id(1))); } - template<> template<> - void object::test<4>() + TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: another run leaves a fresh claim on an old report alone", "[alfeedbackoutbox]") { - set_test_name("a claim is fresh however old its report: another run leaves it alone"); ALFeedbackOutbox box(mDir); std::vector given_up; const S64 now = now_seconds(); box.keep(report(id(1)), "body", now, given_up); // A report kept for hours: the body's time is old, the claim's is not. age(path(id(1), ".envelope"), 3 * 60 * 60); - ensure("claimed", box.claim(id(1))); + UNSCOPED_INFO("claimed"); + CHECK(box.claim(id(1))); ALFeedbackOutbox(mDir).records(now, given_up); - ensure("still claimed", LLFile::isfile(path(id(1), ".sending"))); - ensure("not freed", !LLFile::isfile(path(id(1), ".envelope"))); + UNSCOPED_INFO("still claimed"); + CHECK(LLFile::isfile(path(id(1), ".sending"))); + UNSCOPED_INFO("not freed"); + CHECK_FALSE(LLFile::isfile(path(id(1), ".envelope"))); } - template<> template<> - void object::test<5>() + TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: a claim left by a run that ended mid-send is free after an hour", "[alfeedbackoutbox]") { - set_test_name("a claim left by a run that ended mid-send is free after an hour"); ALFeedbackOutbox box(mDir); std::vector given_up; const S64 now = now_seconds(); @@ -171,13 +176,12 @@ namespace tut box.claim(id(1)); age(path(id(1), ".sending"), ALFeedbackOutbox::CLAIM_STALE_SECONDS + 60); box.records(now, given_up); - ensure("freed", LLFile::isfile(path(id(1), ".envelope"))); + UNSCOPED_INFO("freed"); + CHECK(LLFile::isfile(path(id(1), ".envelope"))); } - template<> template<> - void object::test<6>() + TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: a sent or refused report goes and a rate-limited one waits", "[alfeedbackoutbox]") { - set_test_name("the server's answer settles a report"); ALFeedbackOutbox box(mDir); std::vector given_up; const S64 now = now_seconds(); @@ -185,25 +189,32 @@ namespace tut box.keep(report(id(2)), "body", now, given_up); box.keep(report(id(3)), "body", now, given_up); - ensure("sent is gone", !box.settle(id(1), false, ALFeedback::Outcome::Sent, 0.f, now).kept); - ensure("forgotten", !box.has(id(1))); - ensure("refused is gone", !box.settle(id(2), false, ALFeedback::Outcome::Rejected, 0.f, now).kept); + UNSCOPED_INFO("sent is gone"); + CHECK_FALSE(box.settle(id(1), false, ALFeedback::Outcome::Sent, 0.f, now).kept); + UNSCOPED_INFO("forgotten"); + REQUIRE_FALSE(box.has(id(1))); + UNSCOPED_INFO("refused is gone"); + CHECK_FALSE(box.settle(id(2), false, ALFeedback::Outcome::Rejected, 0.f, now).kept); box.claim(id(3)); const auto settled = box.settle(id(3), true, ALFeedback::Outcome::RateLimited, 7200.f, now); - ensure("unreached is kept", settled.kept); - ensure("released", LLFile::isfile(path(id(3), ".envelope"))); + UNSCOPED_INFO("unreached is kept"); + CHECK(settled.kept); + UNSCOPED_INFO("released"); + CHECK(LLFile::isfile(path(id(3), ".envelope"))); const auto records = box.records(now, given_up); - ensure_equals("one left", records.size(), 1u); - ensure_equals("tried", records[0].attempts, 1); - ensure_equals("waits as asked", records[0].nextAt, now + 7200); - ensure_equals("not before", records[0].notBefore, now + 7200); + UNSCOPED_INFO("one left"); + REQUIRE(records.size() == 1u); + UNSCOPED_INFO("tried"); + CHECK(records[0].attempts == 1); + UNSCOPED_INFO("waits as asked"); + CHECK(records[0].nextAt == now + 7200); + UNSCOPED_INFO("not before"); + CHECK(records[0].notBefore == now + 7200); } - template<> template<> - void object::test<7>() + TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: a report tried too often is given up with what the user wrote", "[alfeedbackoutbox]") { - set_test_name("a report tried too often is given up, with what the user wrote"); ALFeedbackOutbox box(mDir); std::vector given_up; const S64 now = now_seconds(); @@ -213,29 +224,30 @@ namespace tut { settled = box.settle(id(1), false, ALFeedback::Outcome::Unreachable, 0.f, now); } - ensure("given up", settled.givenUp.has_value()); - ensure_equals("its words", settled.givenUp->message, "Lost words"); - ensure("forgotten", !box.has(id(1))); + UNSCOPED_INFO("given up"); + REQUIRE(settled.givenUp.has_value()); + UNSCOPED_INFO("its words"); + CHECK(settled.givenUp->message == "Lost words"); + UNSCOPED_INFO("forgotten"); + REQUIRE_FALSE(box.has(id(1))); } - template<> template<> - void object::test<8>() + TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: a report forgotten while it was sending is not kept again", "[alfeedbackoutbox]") { - set_test_name("a report forgotten while it went is not kept again"); ALFeedbackOutbox box(mDir); std::vector given_up; const S64 now = now_seconds(); box.keep(report(id(1)), "body", now, given_up); box.claim(id(1)); box.forget(id(1)); - ensure("not kept", !box.settle(id(1), true, ALFeedback::Outcome::Unreachable, 0.f, now).kept); - ensure("nothing left", gDirUtilp->getFilesInDir(mDir).empty()); + UNSCOPED_INFO("not kept"); + CHECK_FALSE(box.settle(id(1), true, ALFeedback::Outcome::Unreachable, 0.f, now).kept); + UNSCOPED_INFO("nothing left"); + REQUIRE(gDirUtilp->getFilesInDir(mDir).empty()); } - template<> template<> - void object::test<9>() + TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: the oldest reports make room and are given back", "[alfeedbackoutbox]") { - set_test_name("the oldest reports make room, and are given back"); ALFeedbackOutbox box(mDir); std::vector given_up; const S64 now = now_seconds(); @@ -243,17 +255,19 @@ namespace tut { box.keep(report(id(i)), "body", now + i, given_up); } - ensure("room so far", given_up.empty()); + UNSCOPED_INFO("room so far"); + REQUIRE(given_up.empty()); box.keep(report(id(99)), "body", now + 99, given_up); - ensure_equals("one made room", given_up.size(), 1u); - ensure_equals("the oldest", given_up[0].eventId, id(0)); - ensure_equals("as many as fit", box.records(now + 100, given_up).size(), ALFeedback::QUEUE_MAX_ENTRIES); + UNSCOPED_INFO("one made room"); + REQUIRE(given_up.size() == 1u); + UNSCOPED_INFO("the oldest"); + CHECK(given_up[0].eventId == id(0)); + UNSCOPED_INFO("as many as fit"); + REQUIRE(box.records(now + 100, given_up).size() == ALFeedback::QUEUE_MAX_ENTRIES); } - template<> template<> - void object::test<10>() + TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: what a run left half-written is tidied away once it is old", "[alfeedbackoutbox]") { - set_test_name("what a run left half-written is tidied away once it is old"); ALFeedbackOutbox box(mDir); std::vector given_up; const S64 now = now_seconds(); @@ -266,24 +280,32 @@ namespace tut ALFeedbackOutbox::replaceFile(path(id(3), ".json"), "not json"); ALFeedbackOutbox::replaceFile(gDirUtilp->add(mDir, "x.json.0123.tmp"), "part"); - ensure("young: kept", gDirUtilp->getFilesInDir(mDir).size() == 4u && box.records(now, given_up).empty()); + { + INFO("young: kept"); + REQUIRE(gDirUtilp->getFilesInDir(mDir).size() == 4u); + REQUIRE(box.records(now, given_up).empty()); + } for (const std::string& name : gDirUtilp->getFilesInDir(mDir)) { age(gDirUtilp->add(mDir, name), ALFeedbackOutbox::ORPHAN_SECONDS + 60); } box.records(now, given_up); - ensure("old: gone", gDirUtilp->getFilesInDir(mDir).empty()); - ensure("nothing was a report", given_up.empty()); + UNSCOPED_INFO("old: gone"); + REQUIRE(gDirUtilp->getFilesInDir(mDir).empty()); + UNSCOPED_INFO("nothing was a report"); + REQUIRE(given_up.empty()); } - template<> template<> - void object::test<11>() + TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: replaceFile replaces a file whole and leaves no parts", "[alfeedbackoutbox]") { - set_test_name("a file is replaced whole"); const std::string file = gDirUtilp->add(mDir, "file.json"); - ensure("written", ALFeedbackOutbox::replaceFile(file, "first")); - ensure("replaced", ALFeedbackOutbox::replaceFile(file, "second")); - ensure_equals("the new", LLFile::getContents(file), "second"); - ensure_equals("no parts left", gDirUtilp->getFilesInDir(mDir).size(), 1u); + UNSCOPED_INFO("written"); + CHECK(ALFeedbackOutbox::replaceFile(file, "first")); + UNSCOPED_INFO("replaced"); + CHECK(ALFeedbackOutbox::replaceFile(file, "second")); + UNSCOPED_INFO("the new"); + CHECK(LLFile::getContents(file) == "second"); + UNSCOPED_INFO("no parts left"); + REQUIRE(gDirUtilp->getFilesInDir(mDir).size() == 1u); } } diff --git a/indra/newview/tests/algradehistory_test.cpp b/indra/newview/tests/algradehistory_test.cpp index dd6e84fc20..0c3350bbb9 100644 --- a/indra/newview/tests/algradehistory_test.cpp +++ b/indra/newview/tests/algradehistory_test.cpp @@ -17,13 +17,13 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include #include "../algradehistory.h" #include "llformat.h" -namespace tut +namespace { struct history_data { @@ -39,74 +39,81 @@ namespace tut } }; - typedef test_group history_group; - typedef history_group::object history_object; - tut::history_group hg("ALGradeHistory"); - // The basic contract: one change, one step, and undo hands back the value // it started from. - template<> template<> - void history_object::test<1>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: one change is one step whose undo hands back where it started", "[ALGradeHistory]") { - ensure("nothing to undo yet", !mHistory.canUndo()); - ensure("nothing to redo yet", !mHistory.canRedo()); + UNSCOPED_INFO("nothing to undo yet"); + CHECK_FALSE(mHistory.canUndo()); + UNSCOPED_INFO("nothing to redo yet"); + CHECK_FALSE(mHistory.canRedo()); mHistory.record("RenderColorGradeSaturation", LLSD(1.0), LLSD(1.5), 1.f); - ensure("something to undo", mHistory.canUndo()); - ensure_equals("one step", mHistory.depth(), (size_t)1); + UNSCOPED_INFO("something to undo"); + CHECK(mHistory.canUndo()); + UNSCOPED_INFO("one step"); + CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - ensure("undo returned a transaction", t != nullptr); - ensure_equals("covering one control", t->size(), (size_t)1); - ensure_equals("the right control", t->front().mName, std::string("RenderColorGradeSaturation")); - ensure_equals("restoring the original", t->front().mBefore.asReal(), 1.0); - ensure("nothing left to undo", !mHistory.canUndo()); - ensure("but something to redo", mHistory.canRedo()); + UNSCOPED_INFO("undo returned a transaction"); + REQUIRE(t != nullptr); + UNSCOPED_INFO("covering one control"); + REQUIRE(t->size() == (size_t)1); + UNSCOPED_INFO("the right control"); + CHECK(t->front().mName == std::string("RenderColorGradeSaturation")); + UNSCOPED_INFO("restoring the original"); + CHECK(t->front().mBefore.asReal() == 1.0); + UNSCOPED_INFO("nothing left to undo"); + CHECK_FALSE(mHistory.canUndo()); + UNSCOPED_INFO("but something to redo"); + CHECK(mHistory.canRedo()); } // The one everybody notices. A wheel drag emits a commit per mouse-move; // without coalescing one drag is a hundred undo steps and Ctrl+Z looks // broken. The whole drag must collapse to a single step -- and that step // must start from where the drag started, not from its penultimate value. - template<> template<> - void history_object::test<2>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: a whole drag coalesces into one step from where it began", "[ALGradeHistory]") { drag("RenderColorGradeLift", 100, 0.01f); - ensure_equals("a whole drag is one step", mHistory.depth(), (size_t)1); + UNSCOPED_INFO("a whole drag is one step"); + CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - ensure("got the step", t != nullptr); - ensure_equals("from where the drag began", t->front().mBefore.asReal(), 0.0); - ensure_equals("to where it ended", t->front().mAfter.asReal(), 100.0); + UNSCOPED_INFO("got the step"); + REQUIRE(t != nullptr); + UNSCOPED_INFO("from where the drag began"); + CHECK(t->front().mBefore.asReal() == 0.0); + UNSCOPED_INFO("to where it ended"); + CHECK(t->front().mAfter.asReal() == 100.0); } // Pausing ends the gesture: two deliberate edits are two steps, however // much the same control they touch. - template<> template<> - void history_object::test<3>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: a pause ends the gesture so two edits of one control are two steps", "[ALGradeHistory]") { mHistory.record("RenderColorGradeGain", LLSD(1.0), LLSD(1.1), 1.f); mHistory.record("RenderColorGradeGain", LLSD(1.1), LLSD(1.2), 1.f + ALGradeHistory::COALESCE_SECONDS * 2.f); - ensure_equals("two separate edits", mHistory.depth(), (size_t)2); + UNSCOPED_INFO("two separate edits"); + CHECK(mHistory.depth() == (size_t)2); } // A different control is always a different action, however fast the user // moved between them -- otherwise nudging saturation would swallow the // contrast change before it. - template<> template<> - void history_object::test<4>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: a different control is a different step however fast it follows", "[ALGradeHistory]") { mHistory.record("RenderColorGradeContrast", LLSD(1.0), LLSD(1.2), 1.f); mHistory.record("RenderColorGradeSaturation", LLSD(1.0), LLSD(1.2), 1.01f); - ensure_equals("two steps", mHistory.depth(), (size_t)2); + UNSCOPED_INFO("two steps"); + CHECK(mHistory.depth() == (size_t)2); } // A section's Reset All writes many controls; that is one thing the user // did, so it must undo in one go. - template<> template<> - void history_object::test<5>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: a group's writes to many controls undo as one step", "[ALGradeHistory]") { mHistory.beginGroup(); mHistory.record("A", LLSD(1.0), LLSD(0.0), 1.f); @@ -114,17 +121,19 @@ namespace tut mHistory.record("C", LLSD(3.0), LLSD(0.0), 1.f); mHistory.endGroup(); - ensure_equals("one step", mHistory.depth(), (size_t)1); + UNSCOPED_INFO("one step"); + CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - ensure("got it", t != nullptr); - ensure_equals("covering all three", t->size(), (size_t)3); + UNSCOPED_INFO("got it"); + REQUIRE(t != nullptr); + UNSCOPED_INFO("covering all three"); + REQUIRE(t->size() == (size_t)3); } // Within a group a control may be written more than once. The group should // still describe one before and one after for it, or undo would restore an // intermediate value. - template<> template<> - void history_object::test<6>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: a control written twice in a group keeps one before and one after", "[ALGradeHistory]") { mHistory.beginGroup(); mHistory.record("A", LLSD(1.0), LLSD(2.0), 1.f); @@ -132,91 +141,103 @@ namespace tut mHistory.endGroup(); const auto* t = mHistory.undo(); - ensure("got it", t != nullptr); - ensure_equals("still one control", t->size(), (size_t)1); - ensure_equals("from the original value", t->front().mBefore.asReal(), 1.0); - ensure_equals("to the final one", t->front().mAfter.asReal(), 3.0); + UNSCOPED_INFO("got it"); + REQUIRE(t != nullptr); + UNSCOPED_INFO("still one control"); + REQUIRE(t->size() == (size_t)1); + UNSCOPED_INFO("from the original value"); + CHECK(t->front().mBefore.asReal() == 1.0); + UNSCOPED_INFO("to the final one"); + CHECK(t->front().mAfter.asReal() == 3.0); } // An edit made after undoing discards the redo tail: that future is no // longer reachable. - template<> template<> - void history_object::test<7>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: an edit after an undo discards the redo tail", "[ALGradeHistory]") { mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); mHistory.record("B", LLSD(0.0), LLSD(1.0), 2.f); mHistory.undo(); - ensure("can redo before the new edit", mHistory.canRedo()); + UNSCOPED_INFO("can redo before the new edit"); + CHECK(mHistory.canRedo()); mHistory.record("C", LLSD(0.0), LLSD(1.0), 3.f); - ensure("redo tail is gone", !mHistory.canRedo()); - ensure_equals("and the stack was truncated", mHistory.depth(), (size_t)2); + UNSCOPED_INFO("redo tail is gone"); + CHECK_FALSE(mHistory.canRedo()); + UNSCOPED_INFO("and the stack was truncated"); + CHECK(mHistory.depth() == (size_t)2); } // Redo walks forward again and hands back the destination values. - template<> template<> - void history_object::test<8>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: redo walks forward and hands back the destination values", "[ALGradeHistory]") { mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); mHistory.undo(); const auto* t = mHistory.redo(); - ensure("redo returned the step", t != nullptr); - ensure_equals("with the destination", t->front().mAfter.asReal(), 1.0); - ensure("nothing further to redo", !mHistory.canRedo()); - ensure("and it is undoable again", mHistory.canUndo()); + UNSCOPED_INFO("redo returned the step"); + REQUIRE(t != nullptr); + UNSCOPED_INFO("with the destination"); + CHECK(t->front().mAfter.asReal() == 1.0); + UNSCOPED_INFO("nothing further to redo"); + CHECK_FALSE(mHistory.canRedo()); + UNSCOPED_INFO("and it is undoable again"); + CHECK(mHistory.canUndo()); } // Applying an undo writes settings, which is what feeds this class. If that // fed straight back in it would either loop or corrupt the step being // undone, so a write immediately after an undo must start a new step rather // than coalesce into the old one. - template<> template<> - void history_object::test<9>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: a write right after an undo starts a new step", "[ALGradeHistory]") { mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); mHistory.undo(); mHistory.record("A", LLSD(1.0), LLSD(2.0), 1.01f); - ensure_equals("the undone step was replaced, not extended", mHistory.depth(), (size_t)1); + UNSCOPED_INFO("the undone step was replaced, not extended"); + CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - ensure("got the new step", t != nullptr); - ensure_equals("carrying the new values", t->front().mBefore.asReal(), 1.0); + UNSCOPED_INFO("got the new step"); + REQUIRE(t != nullptr); + UNSCOPED_INFO("carrying the new values"); + CHECK(t->front().mBefore.asReal() == 1.0); } // A long session must not grow without bound, and it is the oldest history // that stops being interesting. - template<> template<> - void history_object::test<10>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: the stack is capped at MAX_DEPTH by dropping the oldest", "[ALGradeHistory]") { for (size_t i = 0; i < ALGradeHistory::MAX_DEPTH + 20; ++i) { mHistory.record("A", LLSD((F64)i), LLSD((F64)(i + 1)), (F32)i * 10.f); } - ensure_equals("capped", mHistory.depth(), ALGradeHistory::MAX_DEPTH); + UNSCOPED_INFO("capped"); + CHECK(mHistory.depth() == ALGradeHistory::MAX_DEPTH); // The newest is still the newest after the drop. const auto* t = mHistory.undo(); - ensure("got the newest", t != nullptr); - ensure_equals("which is the last one recorded", - t->front().mAfter.asReal(), (F64)(ALGradeHistory::MAX_DEPTH + 20)); + UNSCOPED_INFO("got the newest"); + REQUIRE(t != nullptr); + UNSCOPED_INFO("which is the last one recorded"); + CHECK(t->front().mAfter.asReal() == (F64)(ALGradeHistory::MAX_DEPTH + 20)); } // An empty group leaves nothing behind -- a Reset All on a section that was // already at defaults should not put a do-nothing step on the stack. - template<> template<> - void history_object::test<11>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: an empty group leaves no step", "[ALGradeHistory]") { mHistory.beginGroup(); mHistory.endGroup(); - ensure("no step", !mHistory.canUndo()); - ensure_equals("nothing recorded", mHistory.depth(), (size_t)0); + UNSCOPED_INFO("no step"); + CHECK_FALSE(mHistory.canUndo()); + UNSCOPED_INFO("nothing recorded"); + CHECK(mHistory.depth() == (size_t)0); } // Nested groups are still one step: applying a Look may reset sections on // the way through, and the user did one thing. - template<> template<> - void history_object::test<12>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: nested groups are still one step", "[ALGradeHistory]") { mHistory.beginGroup(); mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); @@ -226,37 +247,49 @@ namespace tut mHistory.record("C", LLSD(0.0), LLSD(1.0), 1.f); mHistory.endGroup(); - ensure_equals("one step", mHistory.depth(), (size_t)1); + UNSCOPED_INFO("one step"); + CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - ensure("got it", t != nullptr); - ensure_equals("covering all three", t->size(), (size_t)3); + UNSCOPED_INFO("got it"); + REQUIRE(t != nullptr); + UNSCOPED_INFO("covering all three"); + REQUIRE(t->size() == (size_t)3); } // Undoing past the beginning, or redoing past the end, answers null rather // than misbehaving -- the key handler calls these without checking first. - template<> template<> - void history_object::test<13>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: undo and redo past either end answer null", "[ALGradeHistory]") { - ensure("undo on empty is null", mHistory.undo() == nullptr); - ensure("redo on empty is null", mHistory.redo() == nullptr); + UNSCOPED_INFO("undo on empty is null"); + REQUIRE(mHistory.undo() == nullptr); + UNSCOPED_INFO("redo on empty is null"); + REQUIRE(mHistory.redo() == nullptr); mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); - ensure("undo works once", mHistory.undo() != nullptr); - ensure("and then stops", mHistory.undo() == nullptr); - ensure("redo works once", mHistory.redo() != nullptr); - ensure("and then stops", mHistory.redo() == nullptr); + UNSCOPED_INFO("undo works once"); + REQUIRE(mHistory.undo() != nullptr); + UNSCOPED_INFO("and then stops"); + REQUIRE(mHistory.undo() == nullptr); + UNSCOPED_INFO("redo works once"); + REQUIRE(mHistory.redo() != nullptr); + UNSCOPED_INFO("and then stops"); + REQUIRE(mHistory.redo() == nullptr); mHistory.clear(); - ensure("clear empties it", !mHistory.canUndo() && !mHistory.canRedo()); - ensure_equals("really empty", mHistory.depth(), (size_t)0); + { + INFO("clear empties it"); + CHECK_FALSE(mHistory.canUndo()); + CHECK_FALSE(mHistory.canRedo()); + } + UNSCOPED_INFO("really empty"); + CHECK(mHistory.depth() == (size_t)0); } // The cap holds for grouped steps too. Groups cannot evict as they push -- // that would shift the index the group is accumulating into -- so the // eviction happens when the group closes, and a session of nothing but // Look applies and section resets must stay bounded like any other. - template<> template<> - void history_object::test<14>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: the cap holds for grouped steps too", "[ALGradeHistory]") { for (size_t i = 0; i < ALGradeHistory::MAX_DEPTH + 20; ++i) { @@ -265,15 +298,19 @@ namespace tut mHistory.record("B", LLSD((F64)i), LLSD((F64)(i + 1)), 1.f); mHistory.endGroup(); } - ensure_equals("capped", mHistory.depth(), ALGradeHistory::MAX_DEPTH); - ensure_equals("everything on the stack is applied", mHistory.cursor(), mHistory.depth()); + UNSCOPED_INFO("capped"); + CHECK(mHistory.depth() == ALGradeHistory::MAX_DEPTH); + UNSCOPED_INFO("everything on the stack is applied"); + CHECK(mHistory.cursor() == mHistory.depth()); // The newest is still the newest after the drop, and still whole. const auto* t = mHistory.undo(); - ensure("got the newest", t != nullptr); - ensure_equals("still covering both controls", t->size(), (size_t)2); - ensure_equals("which is the last group recorded", - t->front().mAfter.asReal(), (F64)(ALGradeHistory::MAX_DEPTH + 20)); + UNSCOPED_INFO("got the newest"); + REQUIRE(t != nullptr); + UNSCOPED_INFO("still covering both controls"); + REQUIRE(t->size() == (size_t)2); + UNSCOPED_INFO("which is the last group recorded"); + CHECK(t->front().mAfter.asReal() == (F64)(ALGradeHistory::MAX_DEPTH + 20)); // And the walk back stops exactly at the cap, with no phantom steps // left over from the evictions. @@ -282,14 +319,14 @@ namespace tut { ++undone; } - ensure_equals("the whole stack is walkable", undone, ALGradeHistory::MAX_DEPTH); + UNSCOPED_INFO("the whole stack is walkable"); + CHECK(undone == ALGradeHistory::MAX_DEPTH); } // A group names the step it makes, for a history that is shown; a step // made any other way has no name, and the caller names it from its // changes. - template<> template<> - void history_object::test<15>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: a group names its step and a lone write's step has no name", "[ALGradeHistory]") { mHistory.beginGroup("Reset Bloom"); mHistory.record("A", LLSD(1.0), LLSD(0.0), 1.f); @@ -297,21 +334,24 @@ namespace tut mHistory.endGroup(); mHistory.record("C", LLSD(0.0), LLSD(1.0), 5.f); - ensure_equals("two steps", mHistory.depth(), (size_t)2); - ensure_equals("the group's step carries its name", mHistory.labelOf(0), std::string("Reset Bloom")); - ensure("a lone write's step has none", mHistory.labelOf(1).empty()); + UNSCOPED_INFO("two steps"); + CHECK(mHistory.depth() == (size_t)2); + UNSCOPED_INFO("the group's step carries its name"); + CHECK(mHistory.labelOf(0) == std::string("Reset Bloom")); + UNSCOPED_INFO("a lone write's step has none"); + REQUIRE(mHistory.labelOf(1).empty()); // And a group that follows an unnamed one is not named after it. mHistory.beginGroup(); mHistory.record("D", LLSD(0.0), LLSD(1.0), 9.f); mHistory.endGroup(); - ensure("an unnamed group stays unnamed", mHistory.labelOf(2).empty()); + UNSCOPED_INFO("an unnamed group stays unnamed"); + REQUIRE(mHistory.labelOf(2).empty()); } // Groups nest, and the one the user started is the one the step is named // for: applying a Look that resets a section on the way is "Look: X". - template<> template<> - void history_object::test<16>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: nested groups name their step for the outermost", "[ALGradeHistory]") { mHistory.beginGroup("Look: Soft Film"); mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); @@ -320,14 +360,15 @@ namespace tut mHistory.endGroup(); mHistory.endGroup(); - ensure_equals("one step", mHistory.depth(), (size_t)1); - ensure_equals("named by the outermost group", mHistory.labelOf(0), std::string("Look: Soft Film")); + UNSCOPED_INFO("one step"); + CHECK(mHistory.depth() == (size_t)1); + UNSCOPED_INFO("named by the outermost group"); + CHECK(mHistory.labelOf(0) == std::string("Look: Soft Film")); } // A name belongs to its step through everything that moves steps: the // oldest dropping off the front at the cap, and the redo tail being cut. - template<> template<> - void history_object::test<17>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: a name stays with its step through eviction and a cut redo tail", "[ALGradeHistory]") { const size_t made = ALGradeHistory::MAX_DEPTH + 5; for (size_t i = 0; i < made; ++i) @@ -336,9 +377,12 @@ namespace tut mHistory.record("A", LLSD((F64)i), LLSD((F64)(i + 1)), 1.f); mHistory.endGroup(); } - ensure_equals("capped", mHistory.depth(), ALGradeHistory::MAX_DEPTH); - ensure_equals("the oldest kept is the sixth made", mHistory.labelOf(0), std::string("step 5")); - ensure_equals("the newest is the last made", mHistory.labelOf(mHistory.depth() - 1), + UNSCOPED_INFO("capped"); + CHECK(mHistory.depth() == ALGradeHistory::MAX_DEPTH); + UNSCOPED_INFO("the oldest kept is the sixth made"); + CHECK(mHistory.labelOf(0) == std::string("step 5")); + UNSCOPED_INFO("the newest is the last made"); + CHECK(mHistory.labelOf(mHistory.depth() - 1) == llformat("step %d", (S32)(made - 1))); mHistory.clear(); @@ -353,51 +397,64 @@ namespace tut mHistory.beginGroup("four"); mHistory.record("four", LLSD(0.0), LLSD(1.0), 1.f); mHistory.endGroup(); - ensure_equals("the undone two were cut", mHistory.depth(), (size_t)2); - ensure_equals("the first kept its name", mHistory.labelOf(0), std::string("one")); - ensure_equals("and the new one has its own", mHistory.labelOf(1), std::string("four")); + UNSCOPED_INFO("the undone two were cut"); + CHECK(mHistory.depth() == (size_t)2); + UNSCOPED_INFO("the first kept its name"); + CHECK(mHistory.labelOf(0) == std::string("one")); + UNSCOPED_INFO("and the new one has its own"); + CHECK(mHistory.labelOf(1) == std::string("four")); } // A control a group moved and then put back is not part of what the // group did, and a group made of nothing else is not a step at all. - template<> template<> - void history_object::test<18>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: a control a group moved and put back is not part of its step", "[ALGradeHistory]") { mHistory.beginGroup("There and back"); mHistory.record("A", LLSD(1.0), LLSD(2.0), 1.f); mHistory.record("A", LLSD(2.0), LLSD(1.0), 1.f); mHistory.endGroup(); - ensure("no step", !mHistory.canUndo()); - ensure_equals("nothing kept", mHistory.depth(), (size_t)0); + UNSCOPED_INFO("no step"); + CHECK_FALSE(mHistory.canUndo()); + UNSCOPED_INFO("nothing kept"); + CHECK(mHistory.depth() == (size_t)0); mHistory.beginGroup(); mHistory.record("A", LLSD(1.0), LLSD(2.0), 1.f); mHistory.record("B", LLSD(0.0), LLSD(5.0), 1.f); mHistory.record("A", LLSD(2.0), LLSD(1.0), 1.f); mHistory.endGroup(); - ensure_equals("one step", mHistory.depth(), (size_t)1); + UNSCOPED_INFO("one step"); + CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - ensure("got it", t != nullptr); - ensure_equals("holding only what changed", t->size(), (size_t)1); - ensure_equals("which is B", t->front().mName, std::string("B")); + UNSCOPED_INFO("got it"); + REQUIRE(t != nullptr); + UNSCOPED_INFO("holding only what changed"); + REQUIRE(t->size() == (size_t)1); + UNSCOPED_INFO("which is B"); + CHECK(t->front().mName == std::string("B")); } // A drag that comes back to where it started did nothing, so it leaves no // step -- and if it carries on, it is a new step from that same value. - template<> template<> - void history_object::test<19>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: a drag back to where it started leaves no step", "[ALGradeHistory]") { mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); mHistory.record("A", LLSD(1.0), LLSD(0.0), 1.1f); - ensure_equals("back where it started, no step", mHistory.depth(), (size_t)0); - ensure("nothing to undo", !mHistory.canUndo()); + UNSCOPED_INFO("back where it started, no step"); + CHECK(mHistory.depth() == (size_t)0); + UNSCOPED_INFO("nothing to undo"); + CHECK_FALSE(mHistory.canUndo()); mHistory.record("A", LLSD(0.0), LLSD(2.0), 1.2f); - ensure_equals("carrying on is a step", mHistory.depth(), (size_t)1); + UNSCOPED_INFO("carrying on is a step"); + CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - ensure("got it", t != nullptr); - ensure_equals("from the value the drag began at", t->front().mBefore.asReal(), 0.0); - ensure_equals("to where it went", t->front().mAfter.asReal(), 2.0); + UNSCOPED_INFO("got it"); + REQUIRE(t != nullptr); + UNSCOPED_INFO("from the value the drag began at"); + CHECK(t->front().mBefore.asReal() == 0.0); + UNSCOPED_INFO("to where it went"); + CHECK(t->front().mAfter.asReal() == 2.0); // A drag that returns to its start does not take an earlier step with // it: only its own is dropped. @@ -405,80 +462,97 @@ namespace tut mHistory.record("B", LLSD(0.0), LLSD(3.0), 1.f); mHistory.record("A", LLSD(0.0), LLSD(1.0), 5.f); mHistory.record("A", LLSD(1.0), LLSD(0.0), 5.1f); - ensure_equals("the earlier step stays", mHistory.depth(), (size_t)1); - ensure_equals("and it is B's", mHistory.at(0).front().mName, std::string("B")); + UNSCOPED_INFO("the earlier step stays"); + CHECK(mHistory.depth() == (size_t)1); + UNSCOPED_INFO("and it is B's"); + CHECK(mHistory.at(0).front().mName == std::string("B")); } // Writing the value already there is not a change, so it must not cost the // user their redo tail. - template<> template<> - void history_object::test<20>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: writing the value already there keeps the redo tail", "[ALGradeHistory]") { mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); mHistory.record("B", LLSD(0.0), LLSD(1.0), 2.f); mHistory.undo(); - ensure("something to redo", mHistory.canRedo()); + UNSCOPED_INFO("something to redo"); + CHECK(mHistory.canRedo()); mHistory.record("C", LLSD(5.0), LLSD(5.0), 3.f); - ensure("still something to redo", mHistory.canRedo()); - ensure_equals("and nothing added", mHistory.depth(), (size_t)2); + UNSCOPED_INFO("still something to redo"); + CHECK(mHistory.canRedo()); + UNSCOPED_INFO("and nothing added"); + CHECK(mHistory.depth() == (size_t)2); } // The revision moves with the stack and the cursor and at no other time, // which is what lets a view of the history ask one number whether it is // out of date. - template<> template<> - void history_object::test<21>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: the revision moves with the stack and the cursor and at no other time", "[ALGradeHistory]") { const U32 start = mHistory.revision(); - ensure("reading an empty stack moves nothing", !mHistory.canUndo() && mHistory.revision() == start); + { + INFO("reading an empty stack moves nothing"); + CHECK_FALSE(mHistory.canUndo()); + CHECK(mHistory.revision() == start); + } mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); const U32 recorded = mHistory.revision(); - ensure("a write moves it", recorded != start); + UNSCOPED_INFO("a write moves it"); + CHECK(recorded != start); mHistory.depth(); mHistory.cursor(); mHistory.at(0); mHistory.labelOf(0); - ensure_equals("reads do not", mHistory.revision(), recorded); + UNSCOPED_INFO("reads do not"); + CHECK(mHistory.revision() == recorded); mHistory.record("A", LLSD(1.0), LLSD(1.0), 1.1f); - ensure_equals("nor does a write of the value already there", mHistory.revision(), recorded); + UNSCOPED_INFO("nor does a write of the value already there"); + CHECK(mHistory.revision() == recorded); mHistory.undo(); const U32 undone = mHistory.revision(); - ensure("an undo moves it", undone != recorded); + UNSCOPED_INFO("an undo moves it"); + CHECK(undone != recorded); mHistory.redo(); - ensure("a redo moves it", mHistory.revision() != undone); + UNSCOPED_INFO("a redo moves it"); + CHECK(mHistory.revision() != undone); const U32 before_clear = mHistory.revision(); mHistory.clear(); - ensure("a clear moves it", mHistory.revision() != before_clear); + UNSCOPED_INFO("a clear moves it"); + CHECK(mHistory.revision() != before_clear); } // What the stack shows is what undo will do. - template<> template<> - void history_object::test<22>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: what the stack shows is what undo will do", "[ALGradeHistory]") { mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); mHistory.record("B", LLSD(2.0), LLSD(3.0), 5.f); const ALGradeHistory::Transaction shown = mHistory.at(1); const auto* undone = mHistory.undo(); - ensure("got it", undone != nullptr); - ensure_equals("the same size", undone->size(), shown.size()); - ensure_equals("the same control", undone->front().mName, shown.front().mName); - ensure_equals("the same start", undone->front().mBefore.asReal(), shown.front().mBefore.asReal()); - ensure_equals("the same end", undone->front().mAfter.asReal(), shown.front().mAfter.asReal()); - ensure_equals("and the cursor says it is no longer in force", mHistory.cursor(), (size_t)1); + UNSCOPED_INFO("got it"); + REQUIRE(undone != nullptr); + UNSCOPED_INFO("the same size"); + REQUIRE(undone->size() == shown.size()); + UNSCOPED_INFO("the same control"); + CHECK(undone->front().mName == shown.front().mName); + UNSCOPED_INFO("the same start"); + CHECK(undone->front().mBefore.asReal() == shown.front().mBefore.asReal()); + UNSCOPED_INFO("the same end"); + CHECK(undone->front().mAfter.asReal() == shown.front().mAfter.asReal()); + UNSCOPED_INFO("and the cursor says it is no longer in force"); + CHECK(mHistory.cursor() == (size_t)1); } // The stack shown oldest first through its steps forward too, however // many; and a group closing is a change to what it shows, since it // trims its step, where one closing inside it is not. - template<> template<> - void history_object::test<23>() + TEST_CASE_METHOD(history_data, "ALGradeHistory: the stack lists redo steps and only the outermost close is a change", "[ALGradeHistory]") { for (const char* name : { "one", "two", "three" }) { @@ -488,10 +562,14 @@ namespace tut } mHistory.undo(); mHistory.undo(); - ensure_equals("in force", mHistory.labelOf(0), std::string("one")); - ensure_equals("the next redo", mHistory.labelOf(1), std::string("two")); - ensure_equals("the last redo", mHistory.labelOf(2), std::string("three")); - ensure_equals("its changes", mHistory.at(2).front().mName, std::string("three")); + UNSCOPED_INFO("in force"); + CHECK(mHistory.labelOf(0) == std::string("one")); + UNSCOPED_INFO("the next redo"); + CHECK(mHistory.labelOf(1) == std::string("two")); + UNSCOPED_INFO("the last redo"); + CHECK(mHistory.labelOf(2) == std::string("three")); + UNSCOPED_INFO("its changes"); + CHECK(mHistory.at(2).front().mName == std::string("three")); mHistory.clear(); mHistory.beginGroup("outer"); @@ -499,11 +577,14 @@ namespace tut mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); const U32 recorded = mHistory.revision(); mHistory.endGroup(); - ensure_equals("an inner group closing is not a change", mHistory.revision(), recorded); + UNSCOPED_INFO("an inner group closing is not a change"); + CHECK(mHistory.revision() == recorded); mHistory.endGroup(); - ensure("the outermost closing is", mHistory.revision() != recorded); + UNSCOPED_INFO("the outermost closing is"); + CHECK(mHistory.revision() != recorded); const U32 closed = mHistory.revision(); mHistory.endGroup(); - ensure_equals("nor is an end with no group open", mHistory.revision(), closed); + UNSCOPED_INFO("nor is an end with no group open"); + CHECK(mHistory.revision() == closed); } } diff --git a/indra/newview/tests/alhuddepth_gl_test.cpp b/indra/newview/tests/alhuddepth_gl_test.cpp index 502aa365a8..705a3b56e4 100644 --- a/indra/newview/tests/alhuddepth_gl_test.cpp +++ b/indra/newview/tests/alhuddepth_gl_test.cpp @@ -39,7 +39,7 @@ #include "../../llrender/tests/llheadlessgl_fixture.h" -#include "../test/lltut.h" +#include #include #include @@ -47,10 +47,8 @@ #include #include -namespace tut +namespace { - namespace - { constexpr S32 W = 64; constexpr S32 H = 64; constexpr F32 FOV = 1.f; @@ -178,10 +176,12 @@ namespace tut for (const char* object : { "deferred/textureUtilV.glsl", "objects/nonindexedTextureV.glsl" }) { S32 level = 1; - ensure(std::string("compiled ") + object, mShaders.loadShaderFile(object, level, GL_VERTEX_SHADER, &defines) != 0); + UNSCOPED_INFO(std::string("compiled ") + object); + REQUIRE(mShaders.loadShaderFile(object, level, GL_VERTEX_SHADER, &defines) != 0); } S32 level = 1; - ensure("compiled deferred/globalF.glsl", mShaders.loadShaderFile("deferred/globalF.glsl", level, GL_FRAGMENT_SHADER, &defines) != 0); + UNSCOPED_INFO("compiled deferred/globalF.glsl"); + REQUIRE(mShaders.loadShaderFile("deferred/globalF.glsl", level, GL_FRAGMENT_SHADER, &defines) != 0); mBlitProgram.mName = "Copy Depth Blit"; mBlitProgram.mShaderFiles.clear(); @@ -190,7 +190,8 @@ namespace tut mBlitProgram.clearPermutations(); mBlitProgram.addPermutation("COPY_DEPTH", "1"); mBlitProgram.mShaderLevel = 1; - ensure("blit copy builds", mBlitProgram.createShader()); + UNSCOPED_INFO("blit copy builds"); + REQUIRE(mBlitProgram.createShader()); mCopyDepthProgram.mName = "Copy Depth Shader"; mCopyDepthProgram.mShaderFiles.clear(); @@ -200,11 +201,16 @@ namespace tut mCopyDepthProgram.addPermutation("COPY_DEPTH", "1"); mCopyDepthProgram.addPermutation("DEPTH_ONLY", "1"); mCopyDepthProgram.mShaderLevel = 1; - ensure("depth copy builds", mCopyDepthProgram.createShader()); + UNSCOPED_INFO("depth copy builds"); + REQUIRE(mCopyDepthProgram.createShader()); const GLuint vs = ll_test::compileTestShader(GL_VERTEX_SHADER, kQuadVertex); const GLuint fs = ll_test::compileTestShader(GL_FRAGMENT_SHADER, kQuadFragment); - ensure("quad shaders compile", vs && fs); + { + INFO("quad shaders compile"); + REQUIRE(vs); + REQUIRE(fs); + } mQuadProgram = glCreateProgram(); glAttachShader(mQuadProgram, vs); glAttachShader(mQuadProgram, fs); @@ -213,17 +219,21 @@ namespace tut glDeleteShader(fs); GLint linked = GL_FALSE; glGetProgramiv(mQuadProgram, GL_LINK_STATUS, &linked); - ensure("quad program links", linked == GL_TRUE); + UNSCOPED_INFO("quad program links"); + REQUIRE(linked == GL_TRUE); glGenVertexArrays(1, &mVAO); glGenBuffers(1, &mVBO); - ensure("window", mWindow.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, + UNSCOPED_INFO("window"); + REQUIRE(mWindow.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, LLRenderTarget::DEPTH_FMT_24)); - ensure("scene", mScene.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, + UNSCOPED_INFO("scene"); + REQUIRE(mScene.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, reverse ? LLRenderTarget::DEPTH_FMT_32F : LLRenderTarget::DEPTH_FMT_24)); mTriangle = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX); - ensure("triangle", mTriangle->allocateBuffer(3, 0)); + UNSCOPED_INFO("triangle"); + REQUIRE(mTriangle->allocateBuffer(3, 0)); LLStrider vert; mTriangle->getVertexStrider(vert); vert[0].set(-1.f, 1.f, 0.f); @@ -400,14 +410,9 @@ namespace tut bool mReverse = false; }; - typedef test_group alhuddepth_t; - typedef alhuddepth_t::object alhuddepth_object_t; - tut::alhuddepth_t alhuddepth_testcase("ALHUDDepth"); - } // The final blit's copy fills the window's depth with the scene's, as the window's 24 bits hold it. - template<> template<> - void alhuddepth_object_t::test<1>() + TEST_CASE_METHOD(alhuddepth_data, "ALHUDDepth: the final blit fills the window's depth with the scene's", "[ALHUDDepth]") { for (bool reverse : conventions()) { @@ -420,40 +425,45 @@ namespace tut { worst = llmax(worst, std::fabs(scene[i] - window[i])); } - ensure(named(reverse, "the window holds the scene's depth"), worst < 1e-6f); - ensure(named(reverse, "and its colour"), colourAt(40, 24) == unorm(MID_COLOUR)); + UNSCOPED_INFO(named(reverse, "the window holds the scene's depth")); + REQUIRE(worst < 1e-6f); + UNSCOPED_INFO(named(reverse, "and its colour")); + REQUIRE(colourAt(40, 24) == unorm(MID_COLOUR)); const F32 cleared = reverse ? 0.f : 1.f; - ensure_equals(named(reverse, "sky is the cleared depth"), window[(size_t)40 * W + 40], cleared); - ensure(named(reverse, "the near surface is nearer than the mid one"), - reverse ? window[(size_t)24 * W + 24] > window[(size_t)24 * W + 40] : window[(size_t)24 * W + 24] < window[(size_t)24 * W + 40]); + UNSCOPED_INFO(named(reverse, "sky is the cleared depth")); + REQUIRE(window[(size_t)40 * W + 40] == cleared); + UNSCOPED_INFO(named(reverse, "the near surface is nearer than the mid one")); + REQUIRE((reverse ? window[(size_t)24 * W + 24] > window[(size_t)24 * W + 40] : window[(size_t)24 * W + 24] < window[(size_t)24 * W + 40])); } } // The reported clipping: against the scene's depth the HUD loses to a world surface at the near plane. With the // depth under it cleared, it draws over it. - template<> template<> - void alhuddepth_object_t::test<2>() + TEST_CASE_METHOD(alhuddepth_data, "ALHUDDepth: with the depth under it cleared the HUD draws over the near world", "[ALHUDDepth]") { for (bool reverse : conventions()) { setUp(reverse); blit(); drawHUD(); - ensure(named(reverse, "uncleared, the near world hides the HUD"), colourAt(24, 24) == unorm(NEAR_COLOUR)); - ensure(named(reverse, "where there is sky, the HUD shows anyway"), colourAt(24, 40) == unorm(HUD_COLOUR)); + UNSCOPED_INFO(named(reverse, "uncleared, the near world hides the HUD")); + REQUIRE(colourAt(24, 24) == unorm(NEAR_COLOUR)); + UNSCOPED_INFO(named(reverse, "where there is sky, the HUD shows anyway")); + REQUIRE(colourAt(24, 40) == unorm(HUD_COLOUR)); blit(); clearUnderHUD(); drawHUD(); - ensure(named(reverse, "cleared, the HUD shows over the near world"), colourAt(24, 24) == unorm(HUD_COLOUR)); - ensure(named(reverse, "and over the sky"), colourAt(24, 40) == unorm(HUD_COLOUR)); + UNSCOPED_INFO(named(reverse, "cleared, the HUD shows over the near world")); + REQUIRE(colourAt(24, 24) == unorm(HUD_COLOUR)); + UNSCOPED_INFO(named(reverse, "and over the sky")); + REQUIRE(colourAt(24, 40) == unorm(HUD_COLOUR)); } } // After the scene's depth is written back, the 3D UI under the HUD's rect is hidden by the world as before, and // by the HUD where the HUD is in front. Without it, what the world hides shows through. - template<> template<> - void alhuddepth_object_t::test<3>() + TEST_CASE_METHOD(alhuddepth_data, "ALHUDDepth: the restored depth hides 3D UI behind the world under the HUD", "[ALHUDDepth]") { for (bool reverse : conventions()) { @@ -466,30 +476,40 @@ namespace tut overlay(44, 20, 3.f); overlay(24, 40, 3.f); overlay(40, 40, 3.f); - ensure(named(reverse, "behind the world, off the HUD: hidden"), colourAt(40, 24) == unorm(MID_COLOUR)); - ensure(named(reverse, "in front of the world, off the HUD: shown"), colourAt(44, 20) == unorm(OVERLAY_COLOUR)); - ensure(named(reverse, "on the HUD: hidden behind it"), colourAt(24, 40) == unorm(HUD_COLOUR)); - ensure(named(reverse, "over sky, off the HUD: shown"), colourAt(40, 40) == unorm(OVERLAY_COLOUR)); + UNSCOPED_INFO(named(reverse, "behind the world, off the HUD: hidden")); + REQUIRE(colourAt(40, 24) == unorm(MID_COLOUR)); + UNSCOPED_INFO(named(reverse, "in front of the world, off the HUD: shown")); + REQUIRE(colourAt(44, 20) == unorm(OVERLAY_COLOUR)); + UNSCOPED_INFO(named(reverse, "on the HUD: hidden behind it")); + REQUIRE(colourAt(24, 40) == unorm(HUD_COLOUR)); + UNSCOPED_INFO(named(reverse, "over sky, off the HUD: shown")); + REQUIRE(colourAt(40, 40) == unorm(OVERLAY_COLOUR)); blit(); clearUnderHUD(); drawHUD(); overlay(40, 24, 8.f); - ensure(named(reverse, "unrestored, what the world hides shows through"), colourAt(40, 24) == unorm(OVERLAY_COLOUR)); + UNSCOPED_INFO(named(reverse, "unrestored, what the world hides shows through")); + REQUIRE(colourAt(40, 24) == unorm(OVERLAY_COLOUR)); } } // Outside every rect nothing changes: the clear empties the rects alone, and with nothing drawn between, the // restore gives back exactly the depth the blit wrote. - template<> template<> - void alhuddepth_object_t::test<4>() + TEST_CASE_METHOD(alhuddepth_data, "ALHUDDepth: clear and restore change nothing outside the rects", "[ALHUDDepth]") { for (bool reverse : conventions()) { setUp(reverse); - ensure_equals(named(reverse, "one rect"), mRects.size(), size_t(1)); - ensure(named(reverse, "the rect is inside the window and not all of it"), - mRects[0].mLeft > 0 && mRects[0].mRight < W && mRects[0].mBottom > 0 && mRects[0].mTop < H); + UNSCOPED_INFO(named(reverse, "one rect")); + REQUIRE(mRects.size() == size_t(1)); + { + INFO(named(reverse, "the rect is inside the window and not all of it")); + REQUIRE(mRects[0].mLeft > 0); + REQUIRE(mRects[0].mRight < W); + REQUIRE(mRects[0].mBottom > 0); + REQUIRE(mRects[0].mTop < H); + } blit(); const std::vector before = depths(mWindow); @@ -513,8 +533,10 @@ namespace tut } } } - ensure_equals(named(reverse, "the clear leaves the outside alone"), changed_outside, size_t(0)); - ensure_equals(named(reverse, "and empties the inside"), uncleared_inside, size_t(0)); + UNSCOPED_INFO(named(reverse, "the clear leaves the outside alone")); + REQUIRE(changed_outside == size_t(0)); + UNSCOPED_INFO(named(reverse, "and empties the inside")); + REQUIRE(uncleared_inside == size_t(0)); restoreUnderHUD(); const std::vector restored = depths(mWindow); @@ -523,54 +545,61 @@ namespace tut { differing += restored[i] != before[i] ? 1 : 0; } - ensure_equals(named(reverse, "the restore gives back the blit's depth"), differing, size_t(0)); + UNSCOPED_INFO(named(reverse, "the restore gives back the blit's depth")); + REQUIRE(differing == size_t(0)); } } // boxRect: the pixels a box covers through an orthographic projection, grown a pixel each way, clipped to the // viewport, empty off it. - template<> template<> - void alhuddepth_object_t::test<5>() + TEST_CASE_METHOD(alhuddepth_data, "ALHUDDepth: boxRect covers a box's pixels grown by one and clipped to the viewport", "[ALHUDDepth]") { const LLMatrix4a ortho = LLMatrix4a::ortho(-0.5f, 0.5f, -0.5f, 0.5f, 0.f, HUD_DEPTH); LLRect rect = ALHUDDepth::boxRect(ortho, LLVector3(-0.25f, -0.25f, -2.f), LLVector3(0.25f, 0.25f, 0.f), W, H); - ensure("pixels 16 to 48 grown to 15 to 49", rect == LLRect(15, 49, 49, 15)); + UNSCOPED_INFO("pixels 16 to 48 grown to 15 to 49"); + CHECK(rect == LLRect(15, 49, 49, 15)); // x from -0.1 to 0.13: pixels 25.6 to 40.32; y from 0 to 0.2: pixels 32 to 44.8. rect = ALHUDDepth::boxRect(ortho, LLVector3(-0.1f, 0.f, -1.f), LLVector3(0.13f, 0.2f, -1.f), W, H); - ensure("fractional edges floored and ceiled before the growth", rect == LLRect(24, 46, 42, 31)); + UNSCOPED_INFO("fractional edges floored and ceiled before the growth"); + CHECK(rect == LLRect(24, 46, 42, 31)); // x from 0.4 to 0.8: pixels 57.6 to 83.2. rect = ALHUDDepth::boxRect(ortho, LLVector3(0.4f, -0.1f, -1.f), LLVector3(0.8f, 0.1f, -1.f), W, H); - ensure("clipped to the viewport", rect == LLRect(56, 40, 64, 24)); + UNSCOPED_INFO("clipped to the viewport"); + CHECK(rect == LLRect(56, 40, 64, 24)); rect = ALHUDDepth::boxRect(ortho, LLVector3(0.6f, -0.1f, -1.f), LLVector3(0.9f, 0.1f, -1.f), W, H); - ensure("off the viewport, empty", rect.isEmpty()); + UNSCOPED_INFO("off the viewport, empty"); + CHECK(rect.isEmpty()); } // mergeRect: overlapping rects fold into one, disjoint ones are kept, and a rect bridging two folds them all. - template<> template<> - void alhuddepth_object_t::test<6>() + TEST_CASE_METHOD(alhuddepth_data, "ALHUDDepth: mergeRect folds overlapping rects and keeps disjoint ones apart", "[ALHUDDepth]") { std::vector rects; ALHUDDepth::mergeRect(rects, LLRect(0, 10, 10, 0)); ALHUDDepth::mergeRect(rects, LLRect(5, 15, 15, 5)); - ensure_equals("overlapping, one", rects.size(), size_t(1)); - ensure("their union", rects[0] == LLRect(0, 15, 15, 0)); + UNSCOPED_INFO("overlapping, one"); + REQUIRE(rects.size() == size_t(1)); + UNSCOPED_INFO("their union"); + CHECK(rects[0] == LLRect(0, 15, 15, 0)); ALHUDDepth::mergeRect(rects, LLRect(30, 40, 40, 30)); - ensure_equals("disjoint, kept apart", rects.size(), size_t(2)); + UNSCOPED_INFO("disjoint, kept apart"); + REQUIRE(rects.size() == size_t(2)); ALHUDDepth::mergeRect(rects, LLRect(14, 31, 31, 14)); - ensure_equals("bridged, one", rects.size(), size_t(1)); - ensure("around all three", rects[0] == LLRect(0, 40, 40, 0)); + UNSCOPED_INFO("bridged, one"); + REQUIRE(rects.size() == size_t(1)); + UNSCOPED_INFO("around all three"); + CHECK(rects[0] == LLRect(0, 40, 40, 0)); } // Without the copy program to put the scene's depth back, the depth under the HUD is not cleared: the HUD tests // against the scene's as before, and what the world hides from the 3D UI after it stays hidden. - template<> template<> - void alhuddepth_object_t::test<7>() + TEST_CASE_METHOD(alhuddepth_data, "ALHUDDepth: without the copy program the depth under the HUD is not cleared", "[ALHUDDepth]") { for (bool reverse : conventions()) { @@ -579,12 +608,15 @@ namespace tut blit(); const std::vector before = depths(mWindow); clearUnderHUD(&unloaded); - ensure(named(reverse, "nothing cleared"), depths(mWindow) == before); + UNSCOPED_INFO(named(reverse, "nothing cleared")); + REQUIRE(depths(mWindow) == before); drawHUD(); restoreUnderHUD(&unloaded); overlay(40, 24, 8.f); - ensure(named(reverse, "behind the world under the HUD's rect: hidden"), colourAt(40, 24) == unorm(MID_COLOUR)); - ensure(named(reverse, "the near world still hides the HUD"), colourAt(24, 24) == unorm(NEAR_COLOUR)); + UNSCOPED_INFO(named(reverse, "behind the world under the HUD's rect: hidden")); + REQUIRE(colourAt(40, 24) == unorm(MID_COLOUR)); + UNSCOPED_INFO(named(reverse, "the near world still hides the HUD")); + REQUIRE(colourAt(24, 24) == unorm(NEAR_COLOUR)); } } } diff --git a/indra/newview/tests/almotionpredictor_test.cpp b/indra/newview/tests/almotionpredictor_test.cpp index 551e131cf6..f73058b416 100644 --- a/indra/newview/tests/almotionpredictor_test.cpp +++ b/indra/newview/tests/almotionpredictor_test.cpp @@ -14,13 +14,14 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include +#include "altestmatchers.h" #include "../almotionpredictor.h" #include -namespace tut +namespace { struct predictor_data { @@ -67,79 +68,68 @@ namespace tut } }; - typedef test_group predictor_group_t; - typedef predictor_group_t::object predictor_object_t; - tut::predictor_group_t predictor_group("ALMotionPredictor"); - // ---------------------------------------------------------------- cadence - template<> template<> - void predictor_object_t::test<1>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: one update establishes no rate", "[ALMotionPredictor]") { - set_test_name("one update establishes no rate"); - - ensure("nothing seen yet", !mPredictor.hasCadence()); + UNSCOPED_INFO("nothing seen yet"); + CHECK_FALSE(mPredictor.hasCadence()); mPredictor.noteUpdate(100.0); - ensure("a single update is a timestamp, not a rate", !mPredictor.hasCadence()); + UNSCOPED_INFO("a single update is a timestamp, not a rate"); + CHECK_FALSE(mPredictor.hasCadence()); mPredictor.noteUpdate(100.1); - ensure("a second update gives a rate", mPredictor.hasCadence()); - ensure_approximately_equals("interval is the observed gap", - mPredictor.getUpdateInterval(), 0.1f, 16); + UNSCOPED_INFO("a second update gives a rate"); + CHECK(mPredictor.hasCadence()); + UNSCOPED_INFO("interval is the observed gap"); + CHECK_THAT(mPredictor.getUpdateInterval(), ll_test::WithinBits(0.1f, 16)); } - template<> template<> - void predictor_object_t::test<2>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: cadence converges on a steady rate", "[ALMotionPredictor]") { - set_test_name("cadence converges on a steady rate"); - feedCadence(0.1f); - ensure_approximately_equals("10 Hz", mPredictor.getUpdateInterval(), 0.1f, 16); + UNSCOPED_INFO("10 Hz"); + CHECK_THAT(mPredictor.getUpdateInterval(), ll_test::WithinBits(0.1f, 16)); ALMotionPredictor slow; // Drive the second one directly so both start clean. F64 t = 100.0; for (S32 i = 0; i < 12; ++i) { slow.noteUpdate(t); t += 1.0; } - ensure_approximately_equals("1 Hz", slow.getUpdateInterval(), 1.0f, 16); + UNSCOPED_INFO("1 Hz"); + CHECK_THAT(slow.getUpdateInterval(), ll_test::WithinBits(1.0f, 16)); } - template<> template<> - void predictor_object_t::test<3>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: silence is not folded back into the rate", "[ALMotionPredictor]") { - set_test_name("silence is not folded back into the rate"); - feedCadence(0.1f); const F32 before = mPredictor.getUpdateInterval(); // The gap the window exists to detect must not move the threshold to wherever the object // already is, or an object can never be late. mPredictor.noteUpdate(200.0); - ensure_equals("a long gap is not evidence about a send rate", - mPredictor.getUpdateInterval(), before); + UNSCOPED_INFO("a long gap is not evidence about a send rate"); + CHECK(mPredictor.getUpdateInterval() == before); mPredictor.forgetCadence(); - ensure("a handoff clears it", !mPredictor.hasCadence()); + UNSCOPED_INFO("a handoff clears it"); + CHECK_FALSE(mPredictor.hasCadence()); } // ----------------------------------------------------------------- window - template<> template<> - void predictor_object_t::test<4>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: no observed cadence means no taper", "[ALMotionPredictor]") { - set_test_name("no observed cadence means no taper"); - mTuning.mCadenceAware = true; const ALMotionPredictor::Window w = mPredictor.phaseOutWindow(mTuning); - ensure("a ballistic object the sim never corrects keeps coasting", !w.isTapering()); - ensure_equals("and keeps its full step", ALMotionPredictor::phaseOutFactor(60.f, w), 1.f); + UNSCOPED_INFO("a ballistic object the sim never corrects keeps coasting"); + CHECK_FALSE(w.isTapering()); + UNSCOPED_INFO("and keeps its full step"); + CHECK(ALMotionPredictor::phaseOutFactor(60.f, w) == 1.f); } - template<> template<> - void predictor_object_t::test<5>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: window scales with the object's own update rate", "[ALMotionPredictor]") { - set_test_name("window scales with the object's own update rate"); - mTuning.mCadenceAware = true; struct { F32 mInterval; F32 mStart; F32 mEnd; } cases[] = { { 0.1f, 1.f, 3.f }, // ~10 Hz: floored at the configured phase-out time @@ -154,18 +144,19 @@ namespace tut for (S32 i = 0; i < 12; ++i) { p.noteUpdate(t); t += c.mInterval; } const ALMotionPredictor::Window w = p.phaseOutWindow(mTuning); - ensure("tapers", w.isTapering()); - ensure_approximately_equals("start", w.mStart, c.mStart, 16); - ensure_approximately_equals("end", w.mEnd, c.mEnd, 16); - ensure("taper span is preserved", w.mEnd - w.mStart >= 2.f - 1e-4f); + UNSCOPED_INFO("tapers"); + REQUIRE(w.isTapering()); + UNSCOPED_INFO("start"); + REQUIRE_THAT(w.mStart, ll_test::WithinBits(c.mStart, 16)); + UNSCOPED_INFO("end"); + REQUIRE_THAT(w.mEnd, ll_test::WithinBits(c.mEnd, 16)); + UNSCOPED_INFO("taper span is preserved"); + REQUIRE(w.mEnd - w.mStart >= 2.f - 1e-4f); } } - template<> template<> - void predictor_object_t::test<6>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: a very slow mover is still bounded by the cap", "[ALMotionPredictor]") { - set_test_name("a very slow mover is still bounded by the cap"); - ALMotionPredictor p; F64 t = 100.0; for (S32 i = 0; i < 12; ++i) { p.noteUpdate(t); t += 2.4; } // just inside credible @@ -175,41 +166,44 @@ namespace tut mTuning.mCadenceFactor = 8.f; const ALMotionPredictor::Window w = p.phaseOutWindow(mTuning); - ensure("tapers", w.isTapering()); - ensure_approximately_equals("clamped to the cap", w.mStart, mTuning.mCadenceCap, 16); - ensure_approximately_equals("and the taper still follows it", - w.mEnd, mTuning.mCadenceCap + 2.f, 16); + UNSCOPED_INFO("tapers"); + CHECK(w.isTapering()); + UNSCOPED_INFO("clamped to the cap"); + CHECK_THAT(w.mStart, ll_test::WithinBits(mTuning.mCadenceCap, 16)); + UNSCOPED_INFO("and the taper still follows it"); + CHECK_THAT(w.mEnd, ll_test::WithinBits(mTuning.mCadenceCap + 2.f, 16)); } - template<> template<> - void predictor_object_t::test<7>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: legacy mode ignores cadence entirely", "[ALMotionPredictor]") { - set_test_name("legacy mode ignores cadence entirely"); - // No cadence observed at all, yet the window still exists -- that is the default. const ALMotionPredictor::Window w = mPredictor.phaseOutWindow(mTuning); - ensure("tapers", w.isTapering()); - ensure_approximately_equals("start", w.mStart, 1.f, 4); - ensure_approximately_equals("end", w.mEnd, 3.f, 4); + UNSCOPED_INFO("tapers"); + CHECK(w.isTapering()); + UNSCOPED_INFO("start"); + CHECK_THAT(w.mStart, ll_test::WithinBits(1.f, 4)); + UNSCOPED_INFO("end"); + CHECK_THAT(w.mEnd, ll_test::WithinBits(3.f, 4)); } // ------------------------------------------------------------------- ramp - template<> template<> - void predictor_object_t::test<8>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: the phase-out ramp is continuous and monotone and bounded", "[ALMotionPredictor]") { - set_test_name("ramp is continuous, monotone and bounded"); - ALMotionPredictor::Window w; w.mStart = 1.f; w.mEnd = 3.f; - ensure_equals("full before the window", ALMotionPredictor::phaseOutFactor(0.5f, w), 1.f); - ensure_equals("full at the start", ALMotionPredictor::phaseOutFactor(1.f, w), 1.f); - ensure_equals("stopped at the end", ALMotionPredictor::phaseOutFactor(3.f, w), 0.f); - ensure_equals("stopped after it", ALMotionPredictor::phaseOutFactor(9.f, w), 0.f); - ensure_approximately_equals("halfway", - ALMotionPredictor::phaseOutFactor(2.f, w), 0.5f, 16); + UNSCOPED_INFO("full before the window"); + CHECK(ALMotionPredictor::phaseOutFactor(0.5f, w) == 1.f); + UNSCOPED_INFO("full at the start"); + CHECK(ALMotionPredictor::phaseOutFactor(1.f, w) == 1.f); + UNSCOPED_INFO("stopped at the end"); + CHECK(ALMotionPredictor::phaseOutFactor(3.f, w) == 0.f); + UNSCOPED_INFO("stopped after it"); + CHECK(ALMotionPredictor::phaseOutFactor(9.f, w) == 0.f); + UNSCOPED_INFO("halfway"); + CHECK_THAT(ALMotionPredictor::phaseOutFactor(2.f, w), ll_test::WithinBits(0.5f, 16)); // The step the two-branch form put in was about a third of full speed. Walking the ramp at // 240 fps, no single frame may drop by anything like that. @@ -219,54 +213,48 @@ namespace tut for (F32 t = 0.f; t < 4.f; t += dt) { const F32 v = ALMotionPredictor::phaseOutFactor(t, w); - ensure("monotone non-increasing", v <= prev + 1e-6f); + UNSCOPED_INFO("monotone non-increasing"); + REQUIRE(v <= prev + 1e-6f); worst = llmax(worst, prev - v); prev = v; } - ensure("no step in the curve", worst < 0.01f); + UNSCOPED_INFO("no step in the curve"); + CHECK(worst < 0.01f); } // --------------------------------------------------------------- dt clamp - template<> template<> - void predictor_object_t::test<9>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: a stalled frame cannot carry an object the whole stall", "[ALMotionPredictor]") { - set_test_name("a stalled frame cannot carry an object the whole stall"); - - ensure_approximately_equals("an ordinary frame passes through", - ALMotionPredictor::clampFrameStep(1.f / 60.f, mTuning), - 1.f / 60.f, 5); - ensure_equals("a 30 s pause is bounded", - ALMotionPredictor::clampFrameStep(30.f, mTuning), mTuning.mMaxFrameStep); - ensure_equals("time never runs backwards", - ALMotionPredictor::clampFrameStep(-1.f, mTuning), 0.f); + UNSCOPED_INFO("an ordinary frame passes through"); + CHECK_THAT(ALMotionPredictor::clampFrameStep(1.f / 60.f, mTuning), + ll_test::WithinBits(1.f / 60.f, 5)); + UNSCOPED_INFO("a 30 s pause is bounded"); + CHECK(ALMotionPredictor::clampFrameStep(30.f, mTuning) == mTuning.mMaxFrameStep); + UNSCOPED_INFO("time never runs backwards"); + CHECK(ALMotionPredictor::clampFrameStep(-1.f, mTuning) == 0.f); mTuning.mMaxFrameStep = 0.f; - ensure_equals("zero disables the clamp", - ALMotionPredictor::clampFrameStep(30.f, mTuning), 30.f); + UNSCOPED_INFO("zero disables the clamp"); + CHECK(ALMotionPredictor::clampFrameStep(30.f, mTuning) == 30.f); } // ------------------------------------------------------------ integration - template<> template<> - void predictor_object_t::test<10>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: integration is independent of frame rate", "[ALMotionPredictor]") { - set_test_name("integration is independent of frame rate"); - const F32 reference = drop(60.f, 1.f); const F32 fps[] = { 30.f, 45.f, 90.f, 120.f, 144.f, 240.f, 300.f }; for (F32 f : fps) { - ensure_approximately_equals("same fall at any frame rate", drop(f, 1.f), reference, 8); + UNSCOPED_INFO("same fall at any frame rate"); + REQUIRE_THAT(drop(f, 1.f), ll_test::WithinBits(reference, 8)); } } - template<> template<> - void predictor_object_t::test<11>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: converting once reproduces the old per-frame form exactly", "[ALMotionPredictor]") { - set_test_name("converting once reproduces the old per-frame form exactly"); - // The viewer used to fold the timestep correction into every frame as // (vel + 0.5 * (dt - PHYSICS_TIMESTEP) * accel) * dt // rather than converting the velocity once on arrival. Expanding both shows they are the @@ -297,16 +285,13 @@ namespace tut new_vel += accel * dt; } - ensure_approximately_equals("same trajectory as the form it replaces", - new_pos, old_pos, 20); + UNSCOPED_INFO("same trajectory as the form it replaces"); + REQUIRE_THAT(new_pos, ll_test::WithinBits(old_pos, 20)); } } - template<> template<> - void predictor_object_t::test<12>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: the timestep correction currently opposes the acceleration", "[ALMotionPredictor]") { - set_test_name("the timestep correction currently opposes the acceleration"); - // Characterisation, not endorsement. With the direction the viewer has always used, a // dropped object is handed an initial velocity *against* gravity of half a timestep's // worth -- so for the first ~11 ms it rises, and whether any given frame shows that @@ -323,36 +308,37 @@ namespace tut drop(30.f, 0.2f, &first_at_30); drop(60.f, 0.2f, &first_at_60); - ensure("first frame is downward when the frame outlasts the correction", - first_at_30 < 0.f); - ensure("and upward when it does not -- this is the open question, not a feature", - first_at_60 > 0.f); + UNSCOPED_INFO("first frame is downward when the frame outlasts the correction"); + CHECK(first_at_30 < 0.f); + UNSCOPED_INFO("and upward when it does not -- this is the open question, not a feature"); + CHECK(first_at_60 > 0.f); const LLVector3 accel(0.f, 0.f, GRAVITY); const LLVector3 converted = ALMotionPredictor::finalVelocity(LLVector3::zero, accel); - ensure("the offset opposes the acceleration", converted.mV[VZ] * GRAVITY < 0.f); + UNSCOPED_INFO("the offset opposes the acceleration"); + CHECK(converted.mV[VZ] * GRAVITY < 0.f); } - template<> template<> - void predictor_object_t::test<13>() + TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: the sim timestep correction is small and only along the acceleration", "[ALMotionPredictor]") { - set_test_name("the sim timestep correction is applied once, and is small"); - const LLVector3 accel(0.f, 0.f, GRAVITY); const LLVector3 converted = ALMotionPredictor::finalVelocity(LLVector3::zero, accel); // Half a timestep of gravity, ~0.109 m/s. Direction is deliberately whatever the viewer // has always used; see SIGN_AVERAGE_TO_FINAL. - ensure_approximately_equals("offset magnitude", - fabsf(converted.mV[VZ]), - fabsf(0.5f * GRAVITY * ALMotionPredictor::SIM_TIMESTEP), 16); - ensure("horizontal axes untouched", - converted.mV[VX] == 0.f && converted.mV[VY] == 0.f); + UNSCOPED_INFO("offset magnitude"); + CHECK_THAT(fabsf(converted.mV[VZ]), + ll_test::WithinBits(fabsf(0.5f * GRAVITY * ALMotionPredictor::SIM_TIMESTEP), 16)); + { + INFO("horizontal axes untouched"); + CHECK(converted.mV[VX] == 0.f); + CHECK(converted.mV[VY] == 0.f); + } // With no acceleration there is nothing to convert, which is the overwhelmingly common // case -- an avatar walking, a scripted mover at constant velocity. const LLVector3 walking(3.2f, 0.f, 0.f); - ensure_equals("unaccelerated velocity passes through untouched", - ALMotionPredictor::finalVelocity(walking, LLVector3::zero), walking); + UNSCOPED_INFO("unaccelerated velocity passes through untouched"); + CHECK(ALMotionPredictor::finalVelocity(walking, LLVector3::zero) == walking); } } diff --git a/indra/newview/tests/alnotecardembedded_test.cpp b/indra/newview/tests/alnotecardembedded_test.cpp index 995e21ea10..334002c83d 100644 --- a/indra/newview/tests/alnotecardembedded_test.cpp +++ b/indra/newview/tests/alnotecardembedded_test.cpp @@ -40,7 +40,7 @@ #include "../../llui/tests/alheadlessui_fixture.h" -#include "../test/lltut.h" +#include #include #include @@ -99,7 +99,7 @@ namespace }; } -namespace tut +namespace { struct alnotecardembedded_data { @@ -125,7 +125,7 @@ namespace tut { if (!ll_test::HeadlessUI::get().ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } notecard.object.generate(); notecard.item.generate(); @@ -183,123 +183,165 @@ namespace tut return accept; } }; - typedef test_group alnotecardembedded_group; - typedef alnotecardembedded_group::object alnotecardembedded_object; - alnotecardembedded_group alnotecardembedded_instance("ALNotecardEmbedded"); - template<> template<> - void alnotecardembedded_object::test<1>() + TEST_CASE_METHOD(alnotecardembedded_data, "ALNotecardEmbedded: a save sends only the items the text stands and renumbers them in order", "[ALNotecardEmbedded]") { - set_test_name("a save sends only the items the text still stands, numbered afresh in the order it stands them"); const auto a = item("A"), b = item("B"), c = item("C"); ALNotecardEmbedded& card = make("one " + at(2) + " two " + at(0) + "\n", { a, b, c }); - ensure("a button over each item the text stands", view->atomAt(ALTextPos(0, 4)) != nullptr); + UNSCOPED_INFO("a button over each item the text stands"); + REQUIRE(view->atomAt(ALTextPos(0, 4)) != nullptr); std::string text; ALNotecardEmbedded::items_t items; card.forSave(text, items); - ensure_equals("renumbered", text, "one " + at(0) + " two " + at(1) + "\n"); - ensure("C, then A; B left behind", items.size() == 2 && items[0] == c && items[1] == a); - ensure_equals("the editor's own text as it was", view->text(), "one " + at(2) + " two " + at(0) + "\n"); + UNSCOPED_INFO("renumbered"); + CHECK(text == "one " + at(0) + " two " + at(1) + "\n"); + { + INFO("C, then A; B left behind"); + REQUIRE(items.size() == 2); + REQUIRE(items[0] == c); + CHECK(items[1] == a); + } + UNSCOPED_INFO("the editor's own text as it was"); + CHECK(view->text() == "one " + at(2) + " two " + at(0) + "\n"); } - template<> template<> - void alnotecardembedded_object::test<2>() + TEST_CASE_METHOD(alnotecardembedded_data, "ALNotecardEmbedded: items dropped together land in a row and a later drop at the pointer", "[ALNotecardEmbedded]") { - set_test_name("several items dropped together land one after another; a later drop lands at the pointer"); const auto a = item("A"), b = item("B"), c = item("C"); make("text\n"); const LLRect rect = view->textRect(); const ALTextPos where = view->posAtLocal(rect.mLeft + 1, rect.mTop - 2, true); - ensure("taken", drop(a, true) == ACCEPT_YES_COPY_MULTI); - ensure("taken", drop(b, true) == ACCEPT_YES_COPY_MULTI); + UNSCOPED_INFO("taken"); + CHECK(drop(a, true) == ACCEPT_YES_COPY_MULTI); + UNSCOPED_INFO("taken"); + CHECK(drop(b, true) == ACCEPT_YES_COPY_MULTI); const std::string line = view->document().line(where.line); - ensure_equals("A, then B after it", line.substr(where.column, 8), at(0) + at(1)); - ensure("each with its button", view->atomAt(ALTextPos(where.line, where.column)) && view->atomAt(ALTextPos(where.line, where.column + 4))); + UNSCOPED_INFO("A, then B after it"); + CHECK(line.substr(where.column, 8) == at(0) + at(1)); + { + INFO("each with its button"); + REQUIRE(view->atomAt(ALTextPos(where.line, where.column))); + REQUIRE(view->atomAt(ALTextPos(where.line, where.column + 4))); + } world.frameNow = 2; drop(c, true); - ensure_equals("a new frame's drop lands where the pointer is", view->document().line(where.line).substr(where.column, 4), at(2)); - ensure_equals("three carried", tab->items().size(), size_t(3)); - ensure("one undo takes the last away", view->undoJournal().canUndo()); + UNSCOPED_INFO("a new frame's drop lands where the pointer is"); + CHECK(view->document().line(where.line).substr(where.column, 4) == at(2)); + UNSCOPED_INFO("three carried"); + REQUIRE(tab->items().size() == size_t(3)); + UNSCOPED_INFO("one undo takes the last away"); + CHECK(view->undoJournal().canUndo()); } - template<> template<> - void alnotecardembedded_object::test<3>() + TEST_CASE_METHOD(alnotecardembedded_data, "ALNotecardEmbedded: a drop of what a notecard may not carry is refused and says why", "[ALNotecardEmbedded]") { - set_test_name("a drop is refused, and says why, for what a notecard may not carry"); make("text\n"); std::string tip; - ensure("not whole to the next owner", drop(item("A", false), false, &tip) == ACCEPT_NO && !tip.empty()); + { + INFO("not whole to the next owner"); + CHECK(drop(item("A", false), false, &tip) == ACCEPT_NO); + REQUIRE_FALSE(tip.empty()); + } world.copyable = false; - ensure("not the agent's to copy", drop(item("B"), false, &tip) == ACCEPT_NO); - ensure("said so", !tip.empty()); + UNSCOPED_INFO("not the agent's to copy"); + CHECK(drop(item("B"), false, &tip) == ACCEPT_NO); + UNSCOPED_INFO("said so"); + REQUIRE_FALSE(tip.empty()); world.copyable = true; world.settings = false; - ensure("settings where the grid has none", drop(item("C"), false, &tip, DAD_SETTINGS) == ACCEPT_NO); + UNSCOPED_INFO("settings where the grid has none"); + CHECK(drop(item("C"), false, &tip, DAD_SETTINGS) == ACCEPT_NO); world.fromNotecard = true; EAcceptance accept = ACCEPT_YES_COPY_MULTI; std::string ignored; - ensure("out of another notecard: left to someone else", !tab->drop(1, 1, false, DAD_NOTECARD, item("D").get(), &accept, ignored)); + UNSCOPED_INFO("out of another notecard: left to someone else"); + CHECK_FALSE(tab->drop(1, 1, false, DAD_NOTECARD, item("D").get(), &accept, ignored)); world.fromNotecard = false; changeable = false; - ensure("a notecard that may not be changed", drop(item("E"), false, &tip) == ACCEPT_NO); - ensure("said so", !tip.empty()); - ensure("nothing taken", tab->items().empty()); + UNSCOPED_INFO("a notecard that may not be changed"); + CHECK(drop(item("E"), false, &tip) == ACCEPT_NO); + UNSCOPED_INFO("said so"); + REQUIRE_FALSE(tip.empty()); + UNSCOPED_INFO("nothing taken"); + REQUIRE(tab->items().empty()); } - template<> template<> - void alnotecardembedded_object::test<4>() + TEST_CASE_METHOD(alnotecardembedded_data, "ALNotecardEmbedded: only the saved asset's items copy out and a late answer does nothing", "[ALNotecardEmbedded]") { - set_test_name("only what the saved asset carries is copied out; a save changes what that is; an answer after the tab has gone does nothing"); const auto saved = item("Saved"), dropped = item("Dropped"); ALNotecardEmbedded& card = make(at(0) + "\n", { saved }); drop(dropped, true); - ensure("a drop not saved: refused", !card.copy(dropped, LLUUID::null)); - ensure("said so, as an error", !said.empty() && said.back().second && said.back().first.find("Dropped") != std::string::npos); - ensure("nothing asked of the region", world.copies.empty()); - ensure("one saved: asked", card.copy(saved, LLUUID::null) && world.copies.size() == 1 && world.copies.back() == saved->getUUID()); + UNSCOPED_INFO("a drop not saved: refused"); + CHECK_FALSE(card.copy(dropped, LLUUID::null)); + { + INFO("said so, as an error"); + REQUIRE_FALSE(said.empty()); + CHECK(said.back().second); + REQUIRE(said.back().first.find("Dropped") != std::string::npos); + } + UNSCOPED_INFO("nothing asked of the region"); + REQUIRE(world.copies.empty()); + { + INFO("one saved: asked"); + REQUIRE(card.copy(saved, LLUUID::null)); + REQUIRE(world.copies.size() == 1); + CHECK(world.copies.back() == saved->getUUID()); + } world.refused("no such item"); - ensure("the region's no, said", said.back().second && said.back().first.find("Saved") != std::string::npos && - said.back().first.find("no such item") != std::string::npos); + { + INFO("the region's no, said"); + CHECK(said.back().second); + REQUIRE(said.back().first.find("Saved") != std::string::npos); + REQUIRE(said.back().first.find("no such item") != std::string::npos); + } // Saved with only the drop in it. card.saved({ dropped->getUUID() }); - ensure("the drop now", card.copy(dropped, LLUUID::null)); - ensure("the old one no longer", !card.copy(saved, LLUUID::null)); + UNSCOPED_INFO("the drop now"); + CHECK(card.copy(dropped, LLUUID::null)); + UNSCOPED_INFO("the old one no longer"); + CHECK_FALSE(card.copy(saved, LLUUID::null)); // Pressed: offered, where the world does not take it all. card.open(dropped); - ensure("asked whether to copy", world.confirms.size() == 1); + UNSCOPED_INFO("asked whether to copy"); + REQUIRE(world.confirms.size() == 1); world.confirms.back()(); - ensure("and copied on yes", world.copies.back() == dropped->getUUID()); + UNSCOPED_INFO("and copied on yes"); + CHECK(world.copies.back() == dropped->getUUID()); const size_t copies = world.copies.size(); card.open(saved); - ensure("not offered for what cannot be copied", world.confirms.size() == 1); + UNSCOPED_INFO("not offered for what cannot be copied"); + REQUIRE(world.confirms.size() == 1); // The tab gone before the answers: nothing happens. card.open(dropped); const std::function late = world.confirms.back(); tab.reset(); late(); - ensure("no copy asked for a tab that has gone", world.copies.size() == copies); + UNSCOPED_INFO("no copy asked for a tab that has gone"); + REQUIRE(world.copies.size() == copies); } - template<> template<> - void alnotecardembedded_object::test<5>() + TEST_CASE_METHOD(alnotecardembedded_data, "ALNotecardEmbedded: asLLSD and fromLLSD keep each item in its place and a gap as a gap", "[ALNotecardEmbedded]") { - set_test_name("items kept and read back in their places"); const auto a = item("A"), b = item("B"); const LLSD kept = ALNotecardEmbedded::asLLSD({ a, LLPointer(), b }); const ALNotecardEmbedded::items_t back = ALNotecardEmbedded::fromLLSD(kept); - ensure_equals("each in its place", back.size(), size_t(3)); - ensure("a missing one stays missing", back[1].isNull()); - ensure("the rest as they were", back[0]->getUUID() == a->getUUID() && back[2]->getName() == "B"); + UNSCOPED_INFO("each in its place"); + REQUIRE(back.size() == size_t(3)); + UNSCOPED_INFO("a missing one stays missing"); + REQUIRE(back[1].isNull()); + { + INFO("the rest as they were"); + REQUIRE(back[0]->getUUID() == a->getUUID()); + CHECK(back[2]->getName() == "B"); + } } - template<> template<> - void alnotecardembedded_object::test<6>() + TEST_CASE_METHOD(alnotecardembedded_data, "ALNotecardEmbedded: an item button dragged far drags a saved item out but not an unsaved one", "[ALNotecardEmbedded]") { - set_test_name("an item's button dragged far enough drags the item out of the notecard; one not saved yet is said to need a save"); const auto saved = item("Saved"), dropped = item("Dropped"); make(at(0) + "\n", { saved }); drop(dropped, true); @@ -316,41 +358,66 @@ namespace tut return nullptr; }; LLButton* button = buttonOf(0); - ensure("a button over the saved item", button != nullptr); + UNSCOPED_INFO("a button over the saved item"); + REQUIRE(button != nullptr); button->handleMouseDown(2, 2, MASK_NONE); - ensure("the press measured from", world.pressed); + UNSCOPED_INFO("the press measured from"); + CHECK(world.pressed); button->handleHover(3, 3, MASK_NONE); - ensure("not far enough: no drag", world.dragged.empty()); + UNSCOPED_INFO("not far enough: no drag"); + REQUIRE(world.dragged.empty()); world.past = true; button->handleHover(20, 3, MASK_NONE); - ensure("far enough: dragged out", world.dragged.size() == 1 && world.dragged.back() == saved->getUUID()); - ensure("out of this notecard", world.draggedFrom.item == notecard.item && world.draggedFrom.object == notecard.object); + { + INFO("far enough: dragged out"); + REQUIRE(world.dragged.size() == 1); + CHECK(world.dragged.back() == saved->getUUID()); + } + { + INFO("out of this notecard"); + CHECK(world.draggedFrom.item == notecard.item); + CHECK(world.draggedFrom.object == notecard.object); + } button->handleMouseUp(20, 3, MASK_NONE); LLButton* unsaved = buttonOf(1); - ensure("a button over the drop", unsaved != nullptr); + UNSCOPED_INFO("a button over the drop"); + REQUIRE(unsaved != nullptr); said.clear(); unsaved->handleMouseDown(2, 2, MASK_NONE); unsaved->handleHover(20, 3, MASK_NONE); - ensure("a drop not saved is not dragged out", world.dragged.size() == 1); - ensure("and a save is said to be needed", !said.empty() && said.back().second && said.back().first.find("Dropped") != std::string::npos); + UNSCOPED_INFO("a drop not saved is not dragged out"); + REQUIRE(world.dragged.size() == 1); + { + INFO("and a save is said to be needed"); + REQUIRE_FALSE(said.empty()); + CHECK(said.back().second); + REQUIRE(said.back().first.find("Dropped") != std::string::npos); + } unsaved->handleMouseUp(20, 3, MASK_NONE); } - template<> template<> - void alnotecardembedded_object::test<7>() + TEST_CASE_METHOD(alnotecardembedded_data, "ALNotecardEmbedded: a line holding an item grows to fit its icon and its neighbours do not", "[ALNotecardEmbedded]") { - set_test_name("a line holding an item is tall enough for its icon inside the chip's frame; the lines around it keep the text's height"); ALNotecardEmbedded& card = make("above\nhere " + at(0) + " it is\nbelow\n", { item("A") }); (void)card; const S32 text_h = view->layout().rowHeight(); - ensure("a row an inventory icon is taller than: " + std::to_string(text_h), text_h < 16 + 4); + UNSCOPED_INFO("a row an inventory icon is taller than: " + std::to_string(text_h)); + CHECK(text_h < 16 + 4); view->placeAtomViews(); - ensure_equals("the item's line: the icon, a pixel either side, and a pixel off the rows", view->layout().lineHeight(1), 16 + 4); - ensure_equals("the line above as it was", view->layout().lineHeight(0), text_h); - ensure_equals("and the line below", view->layout().lineHeight(2), text_h); + UNSCOPED_INFO("the item's line: the icon, a pixel either side, and a pixel off the rows"); + CHECK(view->layout().lineHeight(1) == 16 + 4); + UNSCOPED_INFO("the line above as it was"); + CHECK(view->layout().lineHeight(0) == text_h); + UNSCOPED_INFO("and the line below"); + CHECK(view->layout().lineHeight(2) == text_h); const ALTextView::Atom* atom = view->atomAt(ALTextPos(1, 5)); - ensure("the item's button", atom && atom->view); - ensure_equals("as tall as its line", atom->view->getRect().getHeight(), 16 + 4); + { + INFO("the item's button"); + REQUIRE(atom); + REQUIRE(atom->view); + } + UNSCOPED_INFO("as tall as its line"); + CHECK(atom->view->getRect().getHeight() == 16 + 4); } } diff --git a/indra/newview/tests/alrecoverykeeper_test.cpp b/indra/newview/tests/alrecoverykeeper_test.cpp index a81229a4cd..7c4946d9da 100644 --- a/indra/newview/tests/alrecoverykeeper_test.cpp +++ b/indra/newview/tests/alrecoverykeeper_test.cpp @@ -31,12 +31,12 @@ #include "fsyspath.h" #include "llfile.h" -#include "../test/lltut.h" +#include #include #include -namespace tut +namespace { struct alrecoverykeeper_data { @@ -95,55 +95,66 @@ namespace tut return std::nullopt; } }; - typedef test_group alrecoverykeeper_group; - typedef alrecoverykeeper_group::object alrecoverykeeper_object; - alrecoverykeeper_group alrecoverykeeper_instance("ALRecoveryKeeper"); - template<> template<> - void alrecoverykeeper_object::test<1>() + TEST_CASE_METHOD(alrecoverykeeper_data, "ALRecoveryKeeper: unsaved text is written a moment after it changes until it is saved", "[ALRecoveryKeeper]") { - set_test_name("written a moment after it first changed, under the window's own key, again for each change, and forgotten once saved"); ALRecoveryKeeper keeper(holder()); keeper.setItem(object, item); - ensure("the window's own key", ALRecoveryStore::isWindowKey(keeper.key())); + UNSCOPED_INFO("the window's own key"); + CHECK(ALRecoveryStore::isWindowKey(keeper.key())); keeper.pump(1, 10.0); - ensure("nothing unsaved, nothing written", !mine()); + UNSCOPED_INFO("nothing unsaved, nothing written"); + REQUIRE_FALSE(mine()); unsaved = true; text = "typed"; keeper.pump(2, 10.0); - ensure("not at once", !mine()); + UNSCOPED_INFO("not at once"); + REQUIRE_FALSE(mine()); keeper.pump(3, 10.5); keeper.pump(3, 10.0 + ALRecoveryKeeper::DELAY); - ensure("a moment after it first changed, whatever was typed meanwhile", mine() && mine()->text == "typed" && mine()->name == "Card"); + { + INFO("a moment after it first changed, whatever was typed meanwhile"); + REQUIRE(mine()); + CHECK(mine()->text == "typed"); + CHECK(mine()->name == "Card"); + } text = "typed more"; keeper.pump(4, 12.0); keeper.pump(4, 12.0 + ALRecoveryKeeper::DELAY); - ensure("again for the next change", mine() && mine()->text == "typed more"); + { + INFO("again for the next change"); + REQUIRE(mine()); + CHECK(mine()->text == "typed more"); + } unsaved = false; keeper.pump(4, 20.0); - ensure("saved: forgotten", !mine()); - ensure("nothing failed", failed == 0); + UNSCOPED_INFO("saved: forgotten"); + REQUIRE_FALSE(mine()); + UNSCOPED_INFO("nothing failed"); + CHECK(failed == 0); } - template<> template<> - void alrecoverykeeper_object::test<2>() + TEST_CASE_METHOD(alrecoverykeeper_data, "ALRecoveryKeeper: setAside discards and what another session left is taken up or turned down", "[ALRecoveryKeeper]") { - set_test_name("thrown away: set aside, and the window's own gone; what another session left offered, taken up once the window's own is written, or turned down"); ALRecoveryKeeper keeper(holder()); keeper.setItem(object, item); unsaved = true; text = "thrown away"; keeper.pump(1, 0.0); keeper.pump(1, ALRecoveryKeeper::DELAY); - ensure("written", mine().has_value()); - ensure("set aside", keeper.setAside()); - ensure("its own gone", !mine()); + UNSCOPED_INFO("written"); + REQUIRE(mine().has_value()); + UNSCOPED_INFO("set aside"); + CHECK(keeper.setAside()); + UNSCOPED_INFO("its own gone"); + REQUIRE_FALSE(mine()); bool discarded = false; for (const ALRecoveryEntry& entry : store->list()) { discarded |= entry.state == ALRecoveryEntry::State::Discarded && entry.key == keeper.key(); } - ensure("among the discarded", discarded); + UNSCOPED_INFO("among the discarded"); + CHECK(discarded); // What a session that ended left of the same item. { @@ -154,14 +165,24 @@ namespace tut left.item = item; left.name = "Card"; left.text = "left behind"; - ensure("left", before.write(left)); + UNSCOPED_INFO("left"); + CHECK(before.write(left)); } std::optional offered = keeper.left(); - ensure("offered", offered && offered->text == "left behind"); + { + INFO("offered"); + REQUIRE(offered); + CHECK(offered->text == "left behind"); + } text = "left behind"; keeper.took(*offered, 7); - ensure("the window's own written", mine() && mine()->text == "left behind"); - ensure("and the one taken up gone", !keeper.left()); + { + INFO("the window's own written"); + REQUIRE(mine()); + CHECK(mine()->text == "left behind"); + } + UNSCOPED_INFO("and the one taken up gone"); + REQUIRE_FALSE(keeper.left()); // Turned down: among the discarded, and offered no more. { @@ -173,21 +194,25 @@ namespace tut before.write(left); } offered = keeper.left(); - ensure("offered again", offered && offered->text == "not wanted"); + { + INFO("offered again"); + REQUIRE(offered); + CHECK(offered->text == "not wanted"); + } keeper.turnDown(*offered); - ensure("turned down: offered no more", !keeper.left()); + UNSCOPED_INFO("turned down: offered no more"); + REQUIRE_FALSE(keeper.left()); } - template<> template<> - void alrecoverykeeper_object::test<3>() + TEST_CASE_METHOD(alrecoverykeeper_data, "ALRecoveryKeeper: a new item or none moves the key and a failed write is said once", "[ALRecoveryKeeper]") { - set_test_name("another item after a save: the old key forgotten, the new one kept; no item, nothing kept; a write that fails said once"); ALRecoveryKeeper keeper(holder()); keeper.setItem(object, item); unsaved = true; keeper.pump(1, 0.0); keeper.pump(1, ALRecoveryKeeper::DELAY); - ensure("written", mine().has_value()); + UNSCOPED_INFO("written"); + REQUIRE(mine().has_value()); const LLUUID was = item; item = LLUUID::generateNewID(); keeper.setItem(object, item); @@ -197,12 +222,15 @@ namespace tut { old_left |= entry.key == ALRecoveryStore::windowKeyOf(object, was); } - ensure("the old key forgotten", !old_left); + UNSCOPED_INFO("the old key forgotten"); + CHECK_FALSE(old_left); keeper.pump(2, 5.0); keeper.pump(2, 5.0 + ALRecoveryKeeper::DELAY); - ensure("the new one kept", mine().has_value()); + UNSCOPED_INFO("the new one kept"); + REQUIRE(mine().has_value()); keeper.setItem(object, LLUUID::null); - ensure("no item, no key", keeper.key().empty()); + UNSCOPED_INFO("no item, no key"); + REQUIRE(keeper.key().empty()); // Where the store cannot write: said once. const std::string blocked = folder + "/blocked"; @@ -218,19 +246,19 @@ namespace tut failing.pump(1, ALRecoveryKeeper::DELAY); nowhere.flush(); failing.pump(1, 10.0); - ensure_equals("said", failed, 1); + UNSCOPED_INFO("said"); + CHECK(failed == 1); failing.pump(2, 11.0); failing.pump(2, 11.0 + ALRecoveryKeeper::DELAY); nowhere.flush(); failing.pump(2, 20.0); - ensure_equals("once", failed, 1); + UNSCOPED_INFO("once"); + CHECK(failed == 1); ALRecovery::useStore(store.get()); } - template<> template<> - void alrecoverykeeper_object::test<4>() + TEST_CASE_METHOD(alrecoverykeeper_data, "ALRecoveryKeeper: the legacy editors' backups are imported as an ended session and removed", "[ALRecoveryKeeper]") { - set_test_name("the legacy editors' backups taken into the store as a session that ended, named as they named them, a notecard's text out of its format, and the files gone"); const std::string temp = folder + "/temp"; std::filesystem::create_directories(fsyspath(temp)); // Written as the editors wrote them, byte for byte. @@ -246,19 +274,29 @@ namespace tut llofstream other(temp + "/unrelated.txt"); other << "left alone"; } - ensure_equals("two taken", ALRecovery::importLegacyBackups(temp), 2); - ensure("the backups gone", !LLFile::isfile(temp + "/Door Script-1A2B3C4D.lslbackup") && !LLFile::isfile(temp + "/Settings-0000ABCD.ncbackup")); - ensure("anything else left alone", LLFile::isfile(temp + "/unrelated.txt")); + UNSCOPED_INFO("two taken"); + CHECK(ALRecovery::importLegacyBackups(temp) == 2); + { + INFO("the backups gone"); + CHECK_FALSE(LLFile::isfile(temp + "/Door Script-1A2B3C4D.lslbackup")); + CHECK_FALSE(LLFile::isfile(temp + "/Settings-0000ABCD.ncbackup")); + } + UNSCOPED_INFO("anything else left alone"); + CHECK(LLFile::isfile(temp + "/unrelated.txt")); bool script = false, card = false; for (ALRecoveryEntry& entry : store->left()) { - ensure("whole", store->load(entry)); + UNSCOPED_INFO("whole"); + REQUIRE(store->load(entry)); script |= entry.name == "Door Script" && !entry.notecard && entry.text == "default { state_entry() {} }\n" && entry.state == ALRecoveryEntry::State::Unsaved; card |= entry.name == "Settings" && entry.notecard && entry.text == "speed = 2\n"; } - ensure("the script, as left by a session that ended", script); - ensure("the notecard, its text out of its format", card); - ensure_equals("nothing more the next time", ALRecovery::importLegacyBackups(temp), 0); + UNSCOPED_INFO("the script, as left by a session that ended"); + CHECK(script); + UNSCOPED_INFO("the notecard, its text out of its format"); + CHECK(card); + UNSCOPED_INFO("nothing more the next time"); + CHECK(ALRecovery::importLegacyBackups(temp) == 0); } } diff --git a/indra/newview/tests/alsceneexplorerpredicate_test.cpp b/indra/newview/tests/alsceneexplorerpredicate_test.cpp index f8808c3c5d..5b28c3b880 100644 --- a/indra/newview/tests/alsceneexplorerpredicate_test.cpp +++ b/indra/newview/tests/alsceneexplorerpredicate_test.cpp @@ -14,11 +14,11 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include #include "../alsceneexplorerpredicate.h" -namespace tut +namespace { using namespace ALSceneExplorerPredicate; @@ -68,273 +68,323 @@ namespace tut } }; - typedef test_group predicate_group; - typedef predicate_group::object predicate_object; - tut::predicate_group pred("ALSceneExplorerPredicate"); - // Default constraints match anything (and a null record never does). - template<> template<> - void predicate_object::test<1>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: default constraints match anything but a null record", "[ALSceneExplorerPredicate]") { - ensure("defaults match", matches(mFacts, mC)); + UNSCOPED_INFO("defaults match"); + CHECK(matches(mFacts, mC)); ItemFacts no_record; - ensure("null record never matches", !matches(no_record, mC)); + UNSCOPED_INFO("null record never matches"); + CHECK_FALSE(matches(no_record, mC)); } // Name search: targeted field only; caller pre-lowercases both sides. - template<> template<> - void predicate_object::test<2>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: a name search looks in the name and nowhere else", "[ALSceneExplorerPredicate]") { mC.mSearchType = SEARCH_NAME; mC.mFilterSubString = "oak"; - ensure("name substring matches", matches(mFacts, mC)); + UNSCOPED_INFO("name substring matches"); + CHECK(matches(mFacts, mC)); mC.mFilterSubString = "weathered"; // description text - ensure("name search ignores description", !matches(mFacts, mC)); + UNSCOPED_INFO("name search ignores description"); + CHECK_FALSE(matches(mFacts, mC)); } // Description / UUID / owner searches hit only their own field. - template<> template<> - void predicate_object::test<3>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: description / UUID / owner searches hit only their own field", "[ALSceneExplorerPredicate]") { mC.mSearchType = SEARCH_DESCRIPTION; mC.mFilterSubString = "weathered"; - ensure("description matches", matches(mFacts, mC)); + UNSCOPED_INFO("description matches"); + CHECK(matches(mFacts, mC)); mC.mFilterSubString = "oak"; - ensure("description search ignores name", !matches(mFacts, mC)); + UNSCOPED_INFO("description search ignores name"); + CHECK_FALSE(matches(mFacts, mC)); mC.mSearchType = SEARCH_UUID; mC.mFilterSubString = mUUID.substr(0, 8); - ensure("uuid prefix matches", matches(mFacts, mC)); + UNSCOPED_INFO("uuid prefix matches"); + CHECK(matches(mFacts, mC)); mC.mFilterSubString = "oak"; - ensure("uuid search ignores name", !matches(mFacts, mC)); + UNSCOPED_INFO("uuid search ignores name"); + CHECK_FALSE(matches(mFacts, mC)); mC.mSearchType = SEARCH_OWNER; mC.mFilterSubString = "rye"; - ensure("owner matches", matches(mFacts, mC)); + UNSCOPED_INFO("owner matches"); + CHECK(matches(mFacts, mC)); mC.mFilterSubString = "oak"; - ensure("owner search ignores name", !matches(mFacts, mC)); + UNSCOPED_INFO("owner search ignores name"); + CHECK_FALSE(matches(mFacts, mC)); } // ALL searches every field; a miss everywhere fails. - template<> template<> - void predicate_object::test<4>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: SEARCH_ALL finds text in any field and fails a miss in all", "[ALSceneExplorerPredicate]") { mC.mSearchType = SEARCH_ALL; for (const char* needle : { "oak", "weathered", "rye" }) { mC.mFilterSubString = needle; - ensure(std::string("all-search finds ") + needle, matches(mFacts, mC)); + UNSCOPED_INFO(std::string("all-search finds ") + needle); + REQUIRE(matches(mFacts, mC)); } mC.mFilterSubString = mUUID.substr(4, 8); - ensure("all-search finds uuid", matches(mFacts, mC)); + UNSCOPED_INFO("all-search finds uuid"); + CHECK(matches(mFacts, mC)); mC.mFilterSubString = "no such text"; - ensure("all-search can fail", !matches(mFacts, mC)); + UNSCOPED_INFO("all-search can fail"); + CHECK_FALSE(matches(mFacts, mC)); } // Owner modes for an owned object. - template<> template<> - void predicate_object::test<5>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: mine / others / group owner modes for an owned object", "[ALSceneExplorerPredicate]") { mC.mOwnerMode = OWNER_MINE; - ensure("someone else's object is not mine", !matches(mFacts, mC)); + UNSCOPED_INFO("someone else's object is not mine"); + CHECK_FALSE(matches(mFacts, mC)); mRec.mOwnerId = mAgentId; - ensure("my object is mine", matches(mFacts, mC)); + UNSCOPED_INFO("my object is mine"); + CHECK(matches(mFacts, mC)); mC.mOwnerMode = OWNER_OTHERS; - ensure("my object is not others'", !matches(mFacts, mC)); + UNSCOPED_INFO("my object is not others'"); + CHECK_FALSE(matches(mFacts, mC)); mRec.mOwnerId = mOtherId; - ensure("their object is others'", matches(mFacts, mC)); + UNSCOPED_INFO("their object is others'"); + CHECK(matches(mFacts, mC)); mC.mOwnerMode = OWNER_GROUP; - ensure("user-owned is not group-owned", !matches(mFacts, mC)); + UNSCOPED_INFO("user-owned is not group-owned"); + CHECK_FALSE(matches(mFacts, mC)); mRec.mGroupOwned = true; mRec.mGroupId = mGroupId; - ensure("group-owned passes group mode", matches(mFacts, mC)); + UNSCOPED_INFO("group-owned passes group mode"); + CHECK(matches(mFacts, mC)); mC.mOwnerMode = OWNER_OTHERS; - ensure("group-owned is excluded from others'", !matches(mFacts, mC)); + UNSCOPED_INFO("group-owned is excluded from others'"); + CHECK_FALSE(matches(mFacts, mC)); } // OWNER_SPECIFIC: direct owner or the deeding group. - template<> template<> - void predicate_object::test<6>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: OWNER_SPECIFIC matches the direct owner or the deeding group", "[ALSceneExplorerPredicate]") { mC.mOwnerMode = OWNER_SPECIFIC; mC.mOwnerId = mOtherId; - ensure("specific owner matches", matches(mFacts, mC)); + UNSCOPED_INFO("specific owner matches"); + CHECK(matches(mFacts, mC)); mC.mOwnerId = mAgentId; - ensure("specific owner mismatch fails", !matches(mFacts, mC)); + UNSCOPED_INFO("specific owner mismatch fails"); + CHECK_FALSE(matches(mFacts, mC)); mRec.mGroupOwned = true; mRec.mGroupId = mGroupId; mC.mOwnerId = mGroupId; - ensure("specific deeding group matches", matches(mFacts, mC)); + UNSCOPED_INFO("specific deeding group matches"); + CHECK(matches(mFacts, mC)); } // Owner gating: avatars are their own owner; objects without props yet // fail owner modes until the reply lands. - template<> template<> - void predicate_object::test<7>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: owner modes take avatars as their own owner and wait for props", "[ALSceneExplorerPredicate]") { mFacts.mIsAvatar = true; mFacts.mItemId = mAgentId; mC.mOwnerMode = OWNER_MINE; - ensure("own avatar row is mine", matches(mFacts, mC)); + UNSCOPED_INFO("own avatar row is mine"); + CHECK(matches(mFacts, mC)); mFacts.mItemId = mOtherId; - ensure("other avatar row is not mine", !matches(mFacts, mC)); + UNSCOPED_INFO("other avatar row is not mine"); + CHECK_FALSE(matches(mFacts, mC)); mFacts.mIsAvatar = false; mFacts.mItemId = mRec.mId; mRec.mPropsValid = false; - ensure("unresolved props fail owner modes", !matches(mFacts, mC)); + UNSCOPED_INFO("unresolved props fail owner modes"); + CHECK_FALSE(matches(mFacts, mC)); mRec.mPropsValid = true; mRec.mOwnerId = mAgentId; - ensure("resolved props re-apply owner modes", matches(mFacts, mC)); + UNSCOPED_INFO("resolved props re-apply owner modes"); + CHECK(matches(mFacts, mC)); mRec.mPropsValid = false; mC.mOwnerMode = OWNER_ANY; - ensure("unresolved props pass without an owner mode", matches(mFacts, mC)); + UNSCOPED_INFO("unresolved props pass without an owner mode"); + CHECK(matches(mFacts, mC)); } // Geometry mask: empty = any; otherwise the item's kind must be in it. - template<> template<> - void predicate_object::test<8>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: a geometry mask passes an item only if its kind is in it", "[ALSceneExplorerPredicate]") { mC.mGeomMask = 1u << ALObjectProperties::GEOM_MESH; - ensure("mesh passes mesh mask", matches(mFacts, mC)); + UNSCOPED_INFO("mesh passes mesh mask"); + CHECK(matches(mFacts, mC)); mC.mGeomMask = 1u << ALObjectProperties::GEOM_PRIM; - ensure("mesh fails prim-only mask", !matches(mFacts, mC)); + UNSCOPED_INFO("mesh fails prim-only mask"); + CHECK_FALSE(matches(mFacts, mC)); mC.mGeomMask = (1u << ALObjectProperties::GEOM_PRIM) | (1u << ALObjectProperties::GEOM_MESH); - ensure("mesh passes prim|mesh mask", matches(mFacts, mC)); + UNSCOPED_INFO("mesh passes prim|mesh mask"); + CHECK(matches(mFacts, mC)); } // Flag mask requires ALL set bits. - template<> template<> - void predicate_object::test<9>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: a flag mask requires every bit it sets", "[ALSceneExplorerPredicate]") { mC.mFlagMask = ALObjectProperties::FLAG_SCRIPTED; - ensure("single present flag passes", matches(mFacts, mC)); + UNSCOPED_INFO("single present flag passes"); + CHECK(matches(mFacts, mC)); mC.mFlagMask = ALObjectProperties::FLAG_SCRIPTED | ALObjectProperties::FLAG_LIGHT; - ensure("two present flags pass", matches(mFacts, mC)); + UNSCOPED_INFO("two present flags pass"); + CHECK(matches(mFacts, mC)); mC.mFlagMask = ALObjectProperties::FLAG_SCRIPTED | ALObjectProperties::FLAG_PHANTOM; - ensure("one missing flag fails the AND", !matches(mFacts, mC)); + UNSCOPED_INFO("one missing flag fails the AND"); + CHECK_FALSE(matches(mFacts, mC)); mRec.mFlags |= ALObjectProperties::FLAG_FOR_SALE | ALObjectProperties::FLAG_PAYABLE; mC.mFlagMask = ALObjectProperties::FLAG_FOR_SALE | ALObjectProperties::FLAG_PAYABLE; - ensure("commerce flags filter", matches(mFacts, mC)); + UNSCOPED_INFO("commerce flags filter"); + CHECK(matches(mFacts, mC)); } // Scope: region ignores position; radius compares distance; parcel uses // the caller-resolved containment fact. - template<> template<> - void predicate_object::test<10>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: region scope ignores distance while radius and parcel scopes filter", "[ALSceneExplorerPredicate]") { mRec.mDistance = 100.f; mC.mScope = SCOPE_REGION; - ensure("region scope ignores distance", matches(mFacts, mC)); + UNSCOPED_INFO("region scope ignores distance"); + CHECK(matches(mFacts, mC)); mC.mScope = SCOPE_RADIUS; mC.mRadius = 64.f; - ensure("beyond radius fails", !matches(mFacts, mC)); + UNSCOPED_INFO("beyond radius fails"); + CHECK_FALSE(matches(mFacts, mC)); mC.mRadius = 128.f; - ensure("within radius passes", matches(mFacts, mC)); + UNSCOPED_INFO("within radius passes"); + CHECK(matches(mFacts, mC)); mC.mScope = SCOPE_PARCEL; mFacts.mInAgentParcel = true; - ensure("inside parcel passes", matches(mFacts, mC)); + UNSCOPED_INFO("inside parcel passes"); + CHECK(matches(mFacts, mC)); mFacts.mInAgentParcel = false; - ensure("outside parcel fails", !matches(mFacts, mC)); + UNSCOPED_INFO("outside parcel fails"); + CHECK_FALSE(matches(mFacts, mC)); } // Heaviness thresholds: roots gated, child prims exempt, zero = off. - template<> template<> - void predicate_object::test<11>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: land impact and triangle minimums gate roots but not child prims", "[ALSceneExplorerPredicate]") { mC.mMinLandImpact = 50.f; // record has 40 - ensure("under LI threshold fails", !matches(mFacts, mC)); + UNSCOPED_INFO("under LI threshold fails"); + CHECK_FALSE(matches(mFacts, mC)); mC.mMinLandImpact = 40.f; - ensure("at LI threshold passes", matches(mFacts, mC)); + UNSCOPED_INFO("at LI threshold passes"); + CHECK(matches(mFacts, mC)); mC.mMinLandImpact = 0.f; mC.mMinTriangles = 20000; // record has 12000 - ensure("under triangle threshold fails", !matches(mFacts, mC)); + UNSCOPED_INFO("under triangle threshold fails"); + CHECK_FALSE(matches(mFacts, mC)); mC.mMinTriangles = 12000; - ensure("at triangle threshold passes", matches(mFacts, mC)); + UNSCOPED_INFO("at triangle threshold passes"); + CHECK(matches(mFacts, mC)); mC.mMinTriangles = 20000; mFacts.mIsChildPrim = true; - ensure("child prims are exempt from thresholds", matches(mFacts, mC)); + UNSCOPED_INFO("child prims are exempt from thresholds"); + CHECK(matches(mFacts, mC)); + } + + // Predicates compose: every constraint must hold at once. + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: constraints compose and every one must hold at once", "[ALSceneExplorerPredicate]") + { + mC.mSearchType = SEARCH_NAME; + mC.mFilterSubString = "oak"; + mC.mGeomMask = 1u << ALObjectProperties::GEOM_MESH; + mC.mFlagMask = ALObjectProperties::FLAG_SCRIPTED; + mC.mScope = SCOPE_RADIUS; + mC.mRadius = 64.f; + mC.mMinLandImpact = 10.f; + UNSCOPED_INFO("all constraints satisfied"); + CHECK(matches(mFacts, mC)); + + mC.mFlagMask |= ALObjectProperties::FLAG_PHANTOM; + UNSCOPED_INFO("one failing constraint fails the set"); + CHECK_FALSE(matches(mFacts, mC)); } // Change classification: substring extension/shrink (the typing and // backspacing cases), including the empty-needle transitions. - template<> template<> - void predicate_object::test<13>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: classifySubstringChange tells typing from backspacing", "[ALSceneExplorerPredicate]") { - ensure_equals("same needle", classifySubstringChange("oak", "oak"), CHANGE_NONE); - ensure_equals("typing from empty", classifySubstringChange("", "oak"), CHANGE_MORE_RESTRICTIVE); - ensure_equals("extending", classifySubstringChange("oak", "oak t"), CHANGE_MORE_RESTRICTIVE); - ensure_equals("backspacing", classifySubstringChange("oak t", "oak"), CHANGE_LESS_RESTRICTIVE); - ensure_equals("clearing", classifySubstringChange("oak", ""), CHANGE_LESS_RESTRICTIVE); - ensure_equals("unrelated text", classifySubstringChange("oak", "pine"), CHANGE_RESTART); + UNSCOPED_INFO("same needle"); + CHECK(classifySubstringChange("oak", "oak") == CHANGE_NONE); + UNSCOPED_INFO("typing from empty"); + CHECK(classifySubstringChange("", "oak") == CHANGE_MORE_RESTRICTIVE); + UNSCOPED_INFO("extending"); + CHECK(classifySubstringChange("oak", "oak t") == CHANGE_MORE_RESTRICTIVE); + UNSCOPED_INFO("backspacing"); + CHECK(classifySubstringChange("oak t", "oak") == CHANGE_LESS_RESTRICTIVE); + UNSCOPED_INFO("clearing"); + CHECK(classifySubstringChange("oak", "") == CHANGE_LESS_RESTRICTIVE); + UNSCOPED_INFO("unrelated text"); + CHECK(classifySubstringChange("oak", "pine") == CHANGE_RESTART); } // Change classification: require-all mask (the feature checkboxes). - template<> template<> - void predicate_object::test<14>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: classifyRequireAllMaskChange restricts on added bits", "[ALSceneExplorerPredicate]") { const U32 a = ALObjectProperties::FLAG_SCRIPTED; const U32 b = ALObjectProperties::FLAG_LIGHT; const U32 c = ALObjectProperties::FLAG_PHANTOM; - ensure_equals("same mask", classifyRequireAllMaskChange(a | b, a | b), CHANGE_NONE); - ensure_equals("first requirement", classifyRequireAllMaskChange(0, a), CHANGE_MORE_RESTRICTIVE); - ensure_equals("added requirement", classifyRequireAllMaskChange(a, a | b), CHANGE_MORE_RESTRICTIVE); - ensure_equals("removed requirement", classifyRequireAllMaskChange(a | b, a), CHANGE_LESS_RESTRICTIVE); - ensure_equals("last requirement off", classifyRequireAllMaskChange(a, 0), CHANGE_LESS_RESTRICTIVE); - ensure_equals("swapped requirement", classifyRequireAllMaskChange(a | b, a | c), CHANGE_RESTART); + UNSCOPED_INFO("same mask"); + CHECK(classifyRequireAllMaskChange(a | b, a | b) == CHANGE_NONE); + UNSCOPED_INFO("first requirement"); + CHECK(classifyRequireAllMaskChange(0, a) == CHANGE_MORE_RESTRICTIVE); + UNSCOPED_INFO("added requirement"); + CHECK(classifyRequireAllMaskChange(a, a | b) == CHANGE_MORE_RESTRICTIVE); + UNSCOPED_INFO("removed requirement"); + CHECK(classifyRequireAllMaskChange(a | b, a) == CHANGE_LESS_RESTRICTIVE); + UNSCOPED_INFO("last requirement off"); + CHECK(classifyRequireAllMaskChange(a, 0) == CHANGE_LESS_RESTRICTIVE); + UNSCOPED_INFO("swapped requirement"); + CHECK(classifyRequireAllMaskChange(a | b, a | c) == CHANGE_RESTART); } // Change classification: allowed-set mask (the type checkboxes; 0 = any). - template<> template<> - void predicate_object::test<15>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: classifyAllowedMaskChange relaxes on added kinds with 0 as any", "[ALSceneExplorerPredicate]") { const U32 prim = 1u << ALObjectProperties::GEOM_PRIM; const U32 mesh = 1u << ALObjectProperties::GEOM_MESH; - ensure_equals("same set", classifyAllowedMaskChange(prim, prim), CHANGE_NONE); - ensure_equals("any to one kind", classifyAllowedMaskChange(0, prim), CHANGE_MORE_RESTRICTIVE); - ensure_equals("one kind to any", classifyAllowedMaskChange(prim, 0), CHANGE_LESS_RESTRICTIVE); - ensure_equals("allowing another kind", classifyAllowedMaskChange(prim, prim | mesh), CHANGE_LESS_RESTRICTIVE); - ensure_equals("disallowing a kind", classifyAllowedMaskChange(prim | mesh, prim), CHANGE_MORE_RESTRICTIVE); - ensure_equals("swapped kind", classifyAllowedMaskChange(prim, mesh), CHANGE_RESTART); + UNSCOPED_INFO("same set"); + CHECK(classifyAllowedMaskChange(prim, prim) == CHANGE_NONE); + UNSCOPED_INFO("any to one kind"); + CHECK(classifyAllowedMaskChange(0, prim) == CHANGE_MORE_RESTRICTIVE); + UNSCOPED_INFO("one kind to any"); + CHECK(classifyAllowedMaskChange(prim, 0) == CHANGE_LESS_RESTRICTIVE); + UNSCOPED_INFO("allowing another kind"); + CHECK(classifyAllowedMaskChange(prim, prim | mesh) == CHANGE_LESS_RESTRICTIVE); + UNSCOPED_INFO("disallowing a kind"); + CHECK(classifyAllowedMaskChange(prim | mesh, prim) == CHANGE_MORE_RESTRICTIVE); + UNSCOPED_INFO("swapped kind"); + CHECK(classifyAllowedMaskChange(prim, mesh) == CHANGE_RESTART); } // Change classification: minimum thresholds (0 = off). - template<> template<> - void predicate_object::test<16>() + TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: classifyMinThresholdChange restricts on a raise with 0 as off", "[ALSceneExplorerPredicate]") { - ensure_equals("same threshold", classifyMinThresholdChange(50.f, 50.f), CHANGE_NONE); - ensure_equals("enabling", classifyMinThresholdChange(0.f, 50.f), CHANGE_MORE_RESTRICTIVE); - ensure_equals("raising", classifyMinThresholdChange(50.f, 100.f), CHANGE_MORE_RESTRICTIVE); - ensure_equals("lowering", classifyMinThresholdChange(100.f, 50.f), CHANGE_LESS_RESTRICTIVE); - ensure_equals("disabling", classifyMinThresholdChange(50.f, 0.f), CHANGE_LESS_RESTRICTIVE); - } - - // Predicates compose: every constraint must hold at once. - template<> template<> - void predicate_object::test<12>() - { - mC.mSearchType = SEARCH_NAME; - mC.mFilterSubString = "oak"; - mC.mGeomMask = 1u << ALObjectProperties::GEOM_MESH; - mC.mFlagMask = ALObjectProperties::FLAG_SCRIPTED; - mC.mScope = SCOPE_RADIUS; - mC.mRadius = 64.f; - mC.mMinLandImpact = 10.f; - ensure("all constraints satisfied", matches(mFacts, mC)); - - mC.mFlagMask |= ALObjectProperties::FLAG_PHANTOM; - ensure("one failing constraint fails the set", !matches(mFacts, mC)); + UNSCOPED_INFO("same threshold"); + CHECK(classifyMinThresholdChange(50.f, 50.f) == CHANGE_NONE); + UNSCOPED_INFO("enabling"); + CHECK(classifyMinThresholdChange(0.f, 50.f) == CHANGE_MORE_RESTRICTIVE); + UNSCOPED_INFO("raising"); + CHECK(classifyMinThresholdChange(50.f, 100.f) == CHANGE_MORE_RESTRICTIVE); + UNSCOPED_INFO("lowering"); + CHECK(classifyMinThresholdChange(100.f, 50.f) == CHANGE_LESS_RESTRICTIVE); + UNSCOPED_INFO("disabling"); + CHECK(classifyMinThresholdChange(50.f, 0.f) == CHANGE_LESS_RESTRICTIVE); } } diff --git a/indra/newview/tests/alscopedata_test.cpp b/indra/newview/tests/alscopedata_test.cpp index 53d5d9c174..f7e3df8dbc 100644 --- a/indra/newview/tests/alscopedata_test.cpp +++ b/indra/newview/tests/alscopedata_test.cpp @@ -14,13 +14,14 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include +#include "altestmatchers.h" #include "../alscopedata.h" #include -namespace tut +namespace { struct scope_data { @@ -100,55 +101,56 @@ namespace tut } }; - typedef test_group scope_group; - typedef scope_group::object scope_object; - tut::scope_group sg("ALScopeData"); - // A fresh object measures nothing and reports nothing. - template<> template<> - void scope_object::test<1>() + TEST_CASE_METHOD(scope_data, "ALScopeData: a fresh object measures nothing and reports nothing", "[ALScopeData]") { - ensure("starts empty", mScope.isEmpty()); - ensure_equals("no samples", mScope.getSampleCount(), 0); - ensure_approximately_equals("no peak", mScope.getPeak(ALScopeData::CH_LUMA), 0.f, 6); - ensure_approximately_equals("no bins", binSum(mScope, ALScopeData::CH_RED), 0.f, 6); + UNSCOPED_INFO("starts empty"); + CHECK(mScope.isEmpty()); + UNSCOPED_INFO("no samples"); + CHECK(mScope.getSampleCount() == 0); + UNSCOPED_INFO("no peak"); + CHECK_THAT(mScope.getPeak(ALScopeData::CH_LUMA), ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("no bins"); + CHECK_THAT(binSum(mScope, ALScopeData::CH_RED), ll_test::WithinBits(0.f, 6)); } // A flat image puts everything in one bin per channel. - template<> template<> - void scope_object::test<2>() + TEST_CASE_METHOD(scope_data, "ALScopeData: a flat image puts everything in one bin per channel", "[ALScopeData]") { const std::vector px = flat(64, 128, 192, 100); mScope.accumulate(px.data(), 100, 1); - ensure_equals("sample count", mScope.getSampleCount(), 100); - ensure_approximately_equals("all red in bin 64", mScope.getBin(ALScopeData::CH_RED, 64), 1.f, 5); - ensure_approximately_equals("all green in bin 128", mScope.getBin(ALScopeData::CH_GREEN, 128), 1.f, 5); - ensure_approximately_equals("all blue in bin 192", mScope.getBin(ALScopeData::CH_BLUE, 192), 1.f, 5); - ensure_approximately_equals("nothing anywhere else", mScope.getBin(ALScopeData::CH_RED, 65), 0.f, 6); + UNSCOPED_INFO("sample count"); + CHECK(mScope.getSampleCount() == 100); + UNSCOPED_INFO("all red in bin 64"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 64), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("all green in bin 128"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_GREEN, 128), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("all blue in bin 192"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_BLUE, 192), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("nothing anywhere else"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 65), ll_test::WithinBits(0.f, 6)); } // Bins are shares of the sample, so they sum to one whatever the size. - template<> template<> - void scope_object::test<3>() + TEST_CASE_METHOD(scope_data, "ALScopeData: bins are shares of the sample and sum to one whatever its size", "[ALScopeData]") { const std::vector px = ramp(); mScope.accumulate(px.data(), ALScopeData::BIN_COUNT, 1); for (S32 c = 0; c < ALScopeData::CH_COUNT; ++c) { - ensure_approximately_equals("bins sum to 1", - binSum(mScope, (ALScopeData::EChannel)c), 1.f, 4); + UNSCOPED_INFO("bins sum to 1"); + REQUIRE_THAT(binSum(mScope, (ALScopeData::EChannel)c), ll_test::WithinBits(1.f, 4)); } - ensure_approximately_equals("a flat ramp peaks at 1/256", - mScope.getPeak(ALScopeData::CH_RED), - 1.f / (F32)ALScopeData::BIN_COUNT, 5); + UNSCOPED_INFO("a flat ramp peaks at 1/256"); + CHECK_THAT(mScope.getPeak(ALScopeData::CH_RED), + ll_test::WithinBits(1.f / (F32)ALScopeData::BIN_COUNT, 5)); } // Two samples of different sizes but the same content compare equal, // which is the property that lets the display ignore the sample size. - template<> template<> - void scope_object::test<4>() + TEST_CASE_METHOD(scope_data, "ALScopeData: samples of different sizes but the same content compare equal", "[ALScopeData]") { ALScopeData small_sample; ALScopeData large_sample; @@ -159,16 +161,15 @@ namespace tut for (S32 i = 0; i < ALScopeData::BIN_COUNT; ++i) { - ensure_approximately_equals("size independent", - small_sample.getBin(ALScopeData::CH_RED, i), - large_sample.getBin(ALScopeData::CH_RED, i), 5); + UNSCOPED_INFO("size independent"); + REQUIRE_THAT(small_sample.getBin(ALScopeData::CH_RED, i), + ll_test::WithinBits(large_sample.getBin(ALScopeData::CH_RED, i), 5)); } } // Luma uses Rec.709 on the encoded values. Pure green must land far above // pure blue; equal grey must land on itself. - template<> template<> - void scope_object::test<5>() + TEST_CASE_METHOD(scope_data, "ALScopeData: luma uses Rec.709 on the encoded values", "[ALScopeData]") { ALScopeData green; ALScopeData blue; @@ -181,15 +182,17 @@ namespace tut grey.accumulate(n.data(), 16, 1); // 0.7152 * 255 = 182.4; 0.0722 * 255 = 18.4 - ensure_approximately_equals("green luma", green.getBin(ALScopeData::CH_LUMA, 182), 1.f, 5); - ensure_approximately_equals("blue luma", blue.getBin(ALScopeData::CH_LUMA, 18), 1.f, 5); - ensure_approximately_equals("grey is its own luma", grey.getBin(ALScopeData::CH_LUMA, 137), 1.f, 5); + UNSCOPED_INFO("green luma"); + CHECK_THAT(green.getBin(ALScopeData::CH_LUMA, 182), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("blue luma"); + CHECK_THAT(blue.getBin(ALScopeData::CH_LUMA, 18), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("grey is its own luma"); + CHECK_THAT(grey.getBin(ALScopeData::CH_LUMA, 137), ll_test::WithinBits(1.f, 5)); } // The weights sum to unity in fixed point, so white cannot overflow the // last bin and black cannot underflow the first. - template<> template<> - void scope_object::test<6>() + TEST_CASE_METHOD(scope_data, "ALScopeData: white lands in the last luma bin and black in the first", "[ALScopeData]") { ALScopeData white; ALScopeData black; @@ -198,15 +201,14 @@ namespace tut white.accumulate(w.data(), 4, 1); black.accumulate(k.data(), 4, 1); - ensure_approximately_equals("white luma is 255", - white.getBin(ALScopeData::CH_LUMA, ALScopeData::BIN_COUNT - 1), 1.f, 5); - ensure_approximately_equals("black luma is 0", - black.getBin(ALScopeData::CH_LUMA, 0), 1.f, 5); + UNSCOPED_INFO("white luma is 255"); + CHECK_THAT(white.getBin(ALScopeData::CH_LUMA, ALScopeData::BIN_COUNT - 1), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("black luma is 0"); + CHECK_THAT(black.getBin(ALScopeData::CH_LUMA, 0), ll_test::WithinBits(1.f, 5)); } // Clipping readouts are the extreme bins, reported as a share of sample. - template<> template<> - void scope_object::test<7>() + TEST_CASE_METHOD(scope_data, "ALScopeData: clipping readouts are the shares in the extreme bins", "[ALScopeData]") { std::vector px; // 10 blown, 30 crushed, 60 mid. @@ -215,80 +217,85 @@ namespace tut for (S32 i = 0; i < 60; ++i) { px.insert(px.end(), { 128, 128, 128, 255 }); } mScope.accumulate(px.data(), 100, 1); - ensure_approximately_equals("10% blown", - mScope.getClippedHigh(ALScopeData::CH_RED), 0.10f, 4); - ensure_approximately_equals("30% crushed", - mScope.getClippedLow(ALScopeData::CH_RED), 0.30f, 4); - ensure_approximately_equals("luma agrees on the blown share", - mScope.getClippedHigh(ALScopeData::CH_LUMA), 0.10f, 4); + UNSCOPED_INFO("10% blown"); + CHECK_THAT(mScope.getClippedHigh(ALScopeData::CH_RED), ll_test::WithinBits(0.10f, 4)); + UNSCOPED_INFO("30% crushed"); + CHECK_THAT(mScope.getClippedLow(ALScopeData::CH_RED), ll_test::WithinBits(0.30f, 4)); + UNSCOPED_INFO("luma agrees on the blown share"); + CHECK_THAT(mScope.getClippedHigh(ALScopeData::CH_LUMA), ll_test::WithinBits(0.10f, 4)); } // A single blown pixel in a large sample still registers. This is the // case a box-filtered downsample would have averaged away, and the reason // the capture point-samples. - template<> template<> - void scope_object::test<8>() + TEST_CASE_METHOD(scope_data, "ALScopeData: a single blown pixel in a large sample still registers", "[ALScopeData]") { std::vector px = flat(100, 100, 100, 10000); px[0] = px[1] = px[2] = 255; mScope.accumulate(px.data(), 10000, 1); - ensure("one blown pixel is visible", mScope.getClippedHigh(ALScopeData::CH_RED) > 0.f); - ensure_approximately_equals("and it is 1 in 10000", - mScope.getClippedHigh(ALScopeData::CH_RED), 0.0001f, 6); + UNSCOPED_INFO("one blown pixel is visible"); + CHECK(mScope.getClippedHigh(ALScopeData::CH_RED) > 0.f); + UNSCOPED_INFO("and it is 1 in 10000"); + CHECK_THAT(mScope.getClippedHigh(ALScopeData::CH_RED), ll_test::WithinBits(0.0001f, 6)); } // Accumulating replaces rather than adding to the previous measurement. - template<> template<> - void scope_object::test<9>() + TEST_CASE_METHOD(scope_data, "ALScopeData: accumulating replaces rather than adds to the previous measurement", "[ALScopeData]") { const std::vector a = flat(10, 10, 10, 50); const std::vector b = flat(200, 200, 200, 50); mScope.accumulate(a.data(), 50, 1); mScope.accumulate(b.data(), 50, 1); - ensure_approximately_equals("old bin cleared", mScope.getBin(ALScopeData::CH_RED, 10), 0.f, 6); - ensure_approximately_equals("new bin full", mScope.getBin(ALScopeData::CH_RED, 200), 1.f, 5); - ensure_equals("count is the latest", mScope.getSampleCount(), 50); + UNSCOPED_INFO("old bin cleared"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 10), ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("new bin full"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 200), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("count is the latest"); + CHECK(mScope.getSampleCount() == 50); } // Degenerate input clears rather than reading past the buffer. - template<> template<> - void scope_object::test<10>() + TEST_CASE_METHOD(scope_data, "ALScopeData: degenerate input clears rather than reading past the buffer", "[ALScopeData]") { const std::vector px = flat(60, 60, 60, 8); mScope.accumulate(px.data(), 8, 1); - ensure("measured", !mScope.isEmpty()); + UNSCOPED_INFO("measured"); + CHECK_FALSE(mScope.isEmpty()); mScope.accumulate(px.data(), 0, 1); - ensure("zero count clears", mScope.isEmpty()); + UNSCOPED_INFO("zero count clears"); + CHECK(mScope.isEmpty()); mScope.accumulate(px.data(), 8, 1); mScope.accumulate(nullptr, 8, 1); - ensure("null clears", mScope.isEmpty()); + UNSCOPED_INFO("null clears"); + CHECK(mScope.isEmpty()); mScope.accumulate(px.data(), 8, 1); mScope.accumulate(px.data(), -5, 1); - ensure("negative count clears", mScope.isEmpty()); + UNSCOPED_INFO("negative count clears"); + CHECK(mScope.isEmpty()); } // The first blend takes the new sample whole; fading up from zero would // read as the scope being broken for the first few updates. - template<> template<> - void scope_object::test<11>() + TEST_CASE_METHOD(scope_data, "ALScopeData: the first blend takes the new sample whole", "[ALScopeData]") { ALScopeData fresh; const std::vector px = flat(90, 90, 90, 20); fresh.accumulate(px.data(), 20, 1); mScope.blendToward(fresh, 0.25f); - ensure_approximately_equals("taken whole", mScope.getBin(ALScopeData::CH_RED, 90), 1.f, 5); - ensure_equals("count carried", mScope.getSampleCount(), 20); + UNSCOPED_INFO("taken whole"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 90), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("count carried"); + CHECK(mScope.getSampleCount() == 20); } // A later blend moves partway and converges on repetition. - template<> template<> - void scope_object::test<12>() + TEST_CASE_METHOD(scope_data, "ALScopeData: a later blend moves partway and converges on repetition", "[ALScopeData]") { ALScopeData first; ALScopeData second; @@ -299,24 +306,23 @@ namespace tut mScope.blendToward(first, 1.f); mScope.blendToward(second, 0.5f); - ensure_approximately_equals("halfway out of the old bin", - mScope.getBin(ALScopeData::CH_RED, 40), 0.5f, 4); - ensure_approximately_equals("halfway into the new one", - mScope.getBin(ALScopeData::CH_RED, 200), 0.5f, 4); + UNSCOPED_INFO("halfway out of the old bin"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 40), ll_test::WithinBits(0.5f, 4)); + UNSCOPED_INFO("halfway into the new one"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 200), ll_test::WithinBits(0.5f, 4)); for (S32 i = 0; i < 40; ++i) { mScope.blendToward(second, 0.5f); } - ensure_approximately_equals("converges on the new sample", - mScope.getBin(ALScopeData::CH_RED, 200), 1.f, 4); - ensure_approximately_equals("and leaves the old", - mScope.getBin(ALScopeData::CH_RED, 40), 0.f, 4); + UNSCOPED_INFO("converges on the new sample"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 200), ll_test::WithinBits(1.f, 4)); + UNSCOPED_INFO("and leaves the old"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 40), ll_test::WithinBits(0.f, 4)); } // Blending never leaves the peak below a bin it will be asked to scale. - template<> template<> - void scope_object::test<13>() + TEST_CASE_METHOD(scope_data, "ALScopeData: blending never leaves the peak below a bin it will be asked to scale", "[ALScopeData]") { ALScopeData first; ALScopeData second; @@ -334,46 +340,46 @@ namespace tut const F32 peak = mScope.getPeak(ch); for (S32 i = 0; i < ALScopeData::BIN_COUNT; ++i) { - ensure("no bin exceeds the peak", mScope.getBin(ch, i) <= peak + 1e-6f); + UNSCOPED_INFO("no bin exceeds the peak"); + REQUIRE(mScope.getBin(ch, i) <= peak + 1e-6f); } } } // Blending toward nothing keeps what is already measured, so closing and // reopening the source does not wipe the display. - template<> template<> - void scope_object::test<14>() + TEST_CASE_METHOD(scope_data, "ALScopeData: blending toward nothing keeps what is already measured", "[ALScopeData]") { const std::vector px = flat(150, 150, 150, 32); mScope.accumulate(px.data(), 32, 1); const ALScopeData nothing; mScope.blendToward(nothing, 0.5f); - ensure_approximately_equals("unchanged", mScope.getBin(ALScopeData::CH_RED, 150), 1.f, 5); + UNSCOPED_INFO("unchanged"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 150), ll_test::WithinBits(1.f, 5)); } // Out-of-range queries are answered, not asserted on. - template<> template<> - void scope_object::test<15>() + TEST_CASE_METHOD(scope_data, "ALScopeData: out-of-range bin and peak queries answer zero", "[ALScopeData]") { const std::vector px = flat(1, 2, 3, 4); mScope.accumulate(px.data(), 4, 1); - ensure_approximately_equals("negative bin", mScope.getBin(ALScopeData::CH_RED, -1), 0.f, 6); - ensure_approximately_equals("past the end", - mScope.getBin(ALScopeData::CH_RED, ALScopeData::BIN_COUNT), 0.f, 6); - ensure_approximately_equals("bad channel", - mScope.getBin((ALScopeData::EChannel)99, 0), 0.f, 6); - ensure_approximately_equals("bad channel peak", - mScope.getPeak((ALScopeData::EChannel)-3), 0.f, 6); + UNSCOPED_INFO("negative bin"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, -1), ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("past the end"); + CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, ALScopeData::BIN_COUNT), ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("bad channel"); + CHECK_THAT(mScope.getBin((ALScopeData::EChannel)99, 0), ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("bad channel peak"); + CHECK_THAT(mScope.getPeak((ALScopeData::EChannel)-3), ll_test::WithinBits(0.f, 6)); } // --- vectorscope --------------------------------------------------------- // Grey has no chroma, so every neutral sample lands in the middle. That is // the reading a colourist checks first: a trace off-centre at the origin // means a cast. - template<> template<> - void scope_object::test<16>() + TEST_CASE_METHOD(scope_data, "ALScopeData: grey has no chroma so every neutral sample lands in the middle", "[ALScopeData]") { for (U8 level : { (U8)0, (U8)64, (U8)128, (U8)200, (U8)255 }) { @@ -382,105 +388,120 @@ namespace tut S32 u = -1, v = -1; soleCell(mScope, u, v); // Two central cells straddle zero on an even grid; either is right. - ensure("grey sits at the centre in u", u == ALScopeData::CHROMA_SIZE / 2 || - u == ALScopeData::CHROMA_SIZE / 2 - 1); - ensure("grey sits at the centre in v", v == ALScopeData::CHROMA_SIZE / 2 || - v == ALScopeData::CHROMA_SIZE / 2 - 1); + UNSCOPED_INFO("grey sits at the centre in u"); + REQUIRE((u == ALScopeData::CHROMA_SIZE / 2 || + u == ALScopeData::CHROMA_SIZE / 2 - 1)); + UNSCOPED_INFO("grey sits at the centre in v"); + REQUIRE((v == ALScopeData::CHROMA_SIZE / 2 || + v == ALScopeData::CHROMA_SIZE / 2 - 1)); } } // The primaries land in the directions the wheels put them, so pushing a // wheel and watching the trace agree is meaningful. Red at angle 0 means // right of centre; green and blue at 120 and 240 degrees. - template<> template<> - void scope_object::test<17>() + TEST_CASE_METHOD(scope_data, "ALScopeData: the primaries land in the directions the wheels put them", "[ALScopeData]") { const S32 mid = ALScopeData::CHROMA_SIZE / 2; mScope.accumulate(flat(255, 0, 0, 8).data(), 8, 1); S32 u = -1, v = -1; soleCell(mScope, u, v); - ensure("red is right of centre", u > mid); - ensure("and level with it", v == mid || v == mid - 1); + UNSCOPED_INFO("red is right of centre"); + CHECK(u > mid); + UNSCOPED_INFO("and level with it"); + CHECK((v == mid || v == mid - 1)); mScope.accumulate(flat(0, 255, 0, 8).data(), 8, 1); soleCell(mScope, u, v); - ensure("green is left of centre", u < mid); - ensure("and above it", v > mid); + UNSCOPED_INFO("green is left of centre"); + CHECK(u < mid); + UNSCOPED_INFO("and above it"); + CHECK(v > mid); mScope.accumulate(flat(0, 0, 255, 8).data(), 8, 1); soleCell(mScope, u, v); - ensure("blue is left of centre", u < mid); - ensure("and below it", v < mid); + UNSCOPED_INFO("blue is left of centre"); + CHECK(u < mid); + UNSCOPED_INFO("and below it"); + CHECK(v < mid); } // Cells are shares of the sample, like the histogram's bins, so they sum // to one and blend the same way. - template<> template<> - void scope_object::test<18>() + TEST_CASE_METHOD(scope_data, "ALScopeData: chroma cells are shares that sum to one and blend like bins", "[ALScopeData]") { mScope.accumulate(ramp().data(), ALScopeData::BIN_COUNT, 1); - ensure_approximately_equals("cells sum to one", chromaSum(mScope), 1.f, 4); - ensure("peak is a real share", mScope.getChromaPeak() > 0.f && - mScope.getChromaPeak() <= 1.f); + UNSCOPED_INFO("cells sum to one"); + CHECK_THAT(chromaSum(mScope), ll_test::WithinBits(1.f, 4)); + { + INFO("peak is a real share"); + CHECK(mScope.getChromaPeak() > 0.f); + CHECK(mScope.getChromaPeak() <= 1.f); + } // A ramp is entirely neutral, so all of it is in one place. - ensure_approximately_equals("a grey ramp is a point", mScope.getChromaPeak(), 1.f, 4); + UNSCOPED_INFO("a grey ramp is a point"); + CHECK_THAT(mScope.getChromaPeak(), ll_test::WithinBits(1.f, 4)); ALScopeData red; red.accumulate(flat(255, 0, 0, 8).data(), 8, 1); mScope.blendToward(red, 0.5f); - ensure_approximately_equals("still sums to one after a blend", - chromaSum(mScope), 1.f, 4); - ensure_approximately_equals("and the peak matches the cells", - mScope.getChromaPeak(), 0.5f, 4); + UNSCOPED_INFO("still sums to one after a blend"); + CHECK_THAT(chromaSum(mScope), ll_test::WithinBits(1.f, 4)); + UNSCOPED_INFO("and the peak matches the cells"); + CHECK_THAT(mScope.getChromaPeak(), ll_test::WithinBits(0.5f, 4)); } // Out-of-range cells answer zero rather than assert, and clear() empties // the grid along with everything else. - template<> template<> - void scope_object::test<19>() + TEST_CASE_METHOD(scope_data, "ALScopeData: out-of-range cells answer zero and clear empties the grid", "[ALScopeData]") { mScope.accumulate(flat(200, 30, 30, 4).data(), 4, 1); - ensure("something was measured", mScope.getChromaPeak() > 0.f); - - ensure_approximately_equals("negative u", mScope.getChromaCell(-1, 0), 0.f, 6); - ensure_approximately_equals("negative v", mScope.getChromaCell(0, -1), 0.f, 6); - ensure_approximately_equals("past the end in u", - mScope.getChromaCell(ALScopeData::CHROMA_SIZE, 0), 0.f, 6); - ensure_approximately_equals("past the end in v", - mScope.getChromaCell(0, ALScopeData::CHROMA_SIZE), 0.f, 6); + UNSCOPED_INFO("something was measured"); + CHECK(mScope.getChromaPeak() > 0.f); + + UNSCOPED_INFO("negative u"); + CHECK_THAT(mScope.getChromaCell(-1, 0), ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("negative v"); + CHECK_THAT(mScope.getChromaCell(0, -1), ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("past the end in u"); + CHECK_THAT(mScope.getChromaCell(ALScopeData::CHROMA_SIZE, 0), ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("past the end in v"); + CHECK_THAT(mScope.getChromaCell(0, ALScopeData::CHROMA_SIZE), ll_test::WithinBits(0.f, 6)); mScope.clear(); - ensure_approximately_equals("cleared peak", mScope.getChromaPeak(), 0.f, 6); - ensure_approximately_equals("cleared cells", chromaSum(mScope), 0.f, 6); + UNSCOPED_INFO("cleared peak"); + CHECK_THAT(mScope.getChromaPeak(), ll_test::WithinBits(0.f, 6)); + UNSCOPED_INFO("cleared cells"); + CHECK_THAT(chromaSum(mScope), ll_test::WithinBits(0.f, 6)); } // Cell centres run -1 to 1 in units of MAX_CHROMA, and the binning is the // inverse of that mapping -- so a plot laid out from chromaCellCentre puts // the trace where accumulate() put it, not half a cell away. - template<> template<> - void scope_object::test<20>() + TEST_CASE_METHOD(scope_data, "ALScopeData: chroma cell centres rise from -1 to 1 and straddle zero", "[ALScopeData]") { const S32 last = ALScopeData::CHROMA_SIZE - 1; - ensure("first cell is at the low edge", ALScopeData::chromaCellCentre(0) < -0.9f); - ensure("last cell is at the high edge", ALScopeData::chromaCellCentre(last) > 0.9f); - ensure_approximately_equals("the grid straddles zero", - ALScopeData::chromaCellCentre(ALScopeData::CHROMA_SIZE / 2) + + UNSCOPED_INFO("first cell is at the low edge"); + CHECK(ALScopeData::chromaCellCentre(0) < -0.9f); + UNSCOPED_INFO("last cell is at the high edge"); + CHECK(ALScopeData::chromaCellCentre(last) > 0.9f); + UNSCOPED_INFO("the grid straddles zero"); + CHECK_THAT(ALScopeData::chromaCellCentre(ALScopeData::CHROMA_SIZE / 2) + ALScopeData::chromaCellCentre(ALScopeData::CHROMA_SIZE / 2 - 1), - 0.f, 5); + ll_test::WithinBits(0.f, 5)); for (S32 i = 1; i < ALScopeData::CHROMA_SIZE; ++i) { - ensure("centres increase", - ALScopeData::chromaCellCentre(i) > ALScopeData::chromaCellCentre(i - 1)); + UNSCOPED_INFO("centres increase"); + REQUIRE(ALScopeData::chromaCellCentre(i) > ALScopeData::chromaCellCentre(i - 1)); } } // The whole reason the waveform exists: a histogram cannot tell a blown sky // from a blown face, and this must. Left half black, right half white -- // they have to land in different columns, at opposite ends of the scale. - template<> template<> - void scope_object::test<21>() + TEST_CASE_METHOD(scope_data, "ALScopeData: the waveform puts black and white halves in different columns", "[ALScopeData]") { const S32 W = 64, H = 8; std::vector px((size_t)W * H * 4, 255); @@ -500,21 +521,20 @@ namespace tut const S32 left = ALScopeData::WAVE_COLUMNS / 4; // inside the black half const S32 right = 3 * ALScopeData::WAVE_COLUMNS / 4; // inside the white half - ensure_approximately_equals("black column is entirely at the bottom", - mScope.getWaveCell(ALScopeData::CH_LUMA, left, 0), 1.f, 5); - ensure_equals("black column has nothing at the top", - mScope.getWaveCell(ALScopeData::CH_LUMA, left, top), 0.f); - ensure_approximately_equals("white column is entirely at the top", - mScope.getWaveCell(ALScopeData::CH_LUMA, right, top), 1.f, 5); - ensure_equals("white column has nothing at the bottom", - mScope.getWaveCell(ALScopeData::CH_LUMA, right, 0), 0.f); + UNSCOPED_INFO("black column is entirely at the bottom"); + CHECK_THAT(mScope.getWaveCell(ALScopeData::CH_LUMA, left, 0), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("black column has nothing at the top"); + CHECK(mScope.getWaveCell(ALScopeData::CH_LUMA, left, top) == 0.f); + UNSCOPED_INFO("white column is entirely at the top"); + CHECK_THAT(mScope.getWaveCell(ALScopeData::CH_LUMA, right, top), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("white column has nothing at the bottom"); + CHECK(mScope.getWaveCell(ALScopeData::CH_LUMA, right, 0) == 0.f); } // A left-to-right ramp is the shape everyone recognises: the trace climbs // across the frame. If columns and levels were ever transposed, or the // column mapping inverted, this is what catches it. - template<> template<> - void scope_object::test<22>() + TEST_CASE_METHOD(scope_data, "ALScopeData: a left-to-right ramp draws a trace that climbs across the frame", "[ALScopeData]") { const S32 W = ALScopeData::WAVE_COLUMNS, H = 4; std::vector px((size_t)W * H * 4, 255); @@ -540,22 +560,25 @@ namespace tut { if (mScope.getWaveCell(ALScopeData::CH_LUMA, column, level) > 0.f) { - ensure_equals("only one level per column", lit, -1); + UNSCOPED_INFO("only one level per column"); + REQUIRE(lit == -1); lit = level; } } - ensure("every column is lit somewhere", lit >= 0); - ensure("the trace never descends", lit >= previous); + UNSCOPED_INFO("every column is lit somewhere"); + REQUIRE(lit >= 0); + UNSCOPED_INFO("the trace never descends"); + REQUIRE(lit >= previous); previous = lit; } - ensure("and it does climb", previous > 0); + UNSCOPED_INFO("and it does climb"); + CHECK(previous > 0); } // Shares are per column, not per sample -- that is what lets the plot's // intensity mean the same thing whatever the sample's width was. So a flat // frame reads 1.0 in every column, not 1/WAVE_COLUMNS. - template<> template<> - void scope_object::test<23>() + TEST_CASE_METHOD(scope_data, "ALScopeData: waveform shares are per column so a flat frame reads 1 in each", "[ALScopeData]") { auto column_total = [&](S32 column) { @@ -575,11 +598,11 @@ namespace tut mScope.accumulate(flat(128, 128, 128, W * H).data(), W, H); for (S32 column = 0; column < ALScopeData::WAVE_COLUMNS; ++column) { - ensure_approximately_equals("every column holds one column's worth", - column_total(column), 1.f, 5); + UNSCOPED_INFO("every column holds one column's worth"); + REQUIRE_THAT(column_total(column), ll_test::WithinBits(1.f, 5)); } - ensure_approximately_equals("peak is a full column", - mScope.getWavePeak(ALScopeData::CH_LUMA), 1.f, 5); + UNSCOPED_INFO("peak is a full column"); + CHECK_THAT(mScope.getWavePeak(ALScopeData::CH_LUMA), ll_test::WithinBits(1.f, 5)); // Narrower than the grid: some columns have no pixels behind them at // all. Those stay empty rather than dividing by zero, and the ones that @@ -593,16 +616,17 @@ namespace tut if (total > 0.f) { ++filled; - ensure_approximately_equals("a filled column is still whole", total, 1.f, 5); + UNSCOPED_INFO("a filled column is still whole"); + REQUIRE_THAT(total, ll_test::WithinBits(1.f, 5)); } } - ensure_equals("one filled column per source column", filled, NARROW); + UNSCOPED_INFO("one filled column per source column"); + CHECK(filled == NARROW); } // Channels are measured separately, which is the whole point of a parade: a // cast shows as the three traces sitting at different heights. - template<> template<> - void scope_object::test<24>() + TEST_CASE_METHOD(scope_data, "ALScopeData: each channel lands at its own level in the parade", "[ALScopeData]") { const S32 W = 32, H = 4; mScope.accumulate(flat(255, 128, 0, W * H).data(), W, H); @@ -610,38 +634,45 @@ namespace tut const S32 column = ALScopeData::WAVE_COLUMNS / 2; const S32 top = ALScopeData::WAVE_LEVELS - 1; - ensure_approximately_equals("red is at the top", - mScope.getWaveCell(ALScopeData::CH_RED, column, top), 1.f, 5); - ensure_approximately_equals("blue is at the bottom", - mScope.getWaveCell(ALScopeData::CH_BLUE, column, 0), 1.f, 5); - ensure_equals("red is not also at the bottom", - mScope.getWaveCell(ALScopeData::CH_RED, column, 0), 0.f); - ensure("green is at neither end", - mScope.getWaveCell(ALScopeData::CH_GREEN, column, 0) == 0.f && - mScope.getWaveCell(ALScopeData::CH_GREEN, column, top) == 0.f); + UNSCOPED_INFO("red is at the top"); + CHECK_THAT(mScope.getWaveCell(ALScopeData::CH_RED, column, top), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("blue is at the bottom"); + CHECK_THAT(mScope.getWaveCell(ALScopeData::CH_BLUE, column, 0), ll_test::WithinBits(1.f, 5)); + UNSCOPED_INFO("red is not also at the bottom"); + CHECK(mScope.getWaveCell(ALScopeData::CH_RED, column, 0) == 0.f); + { + INFO("green is at neither end"); + CHECK(mScope.getWaveCell(ALScopeData::CH_GREEN, column, 0) == 0.f); + CHECK(mScope.getWaveCell(ALScopeData::CH_GREEN, column, top) == 0.f); + } } // A plot walks the whole grid without checking, so out-of-range reads and a // scope that has never measured anything both have to answer zero rather // than index a vector that is deliberately empty until first use. - template<> template<> - void scope_object::test<25>() + TEST_CASE_METHOD(scope_data, "ALScopeData: waveform reads answer zero when unmeasured or cleared or out of range", "[ALScopeData]") { ALScopeData fresh; - ensure_equals("unmeasured reads zero", fresh.getWaveCell(ALScopeData::CH_LUMA, 0, 0), 0.f); - ensure_equals("unmeasured has no peak", fresh.getWavePeak(ALScopeData::CH_LUMA), 0.f); + UNSCOPED_INFO("unmeasured reads zero"); + CHECK(fresh.getWaveCell(ALScopeData::CH_LUMA, 0, 0) == 0.f); + UNSCOPED_INFO("unmeasured has no peak"); + CHECK(fresh.getWavePeak(ALScopeData::CH_LUMA) == 0.f); mScope.accumulate(flat(200, 200, 200, 16).data(), 16, 1); - ensure_equals("negative column", mScope.getWaveCell(ALScopeData::CH_LUMA, -1, 0), 0.f); - ensure_equals("column past the end", - mScope.getWaveCell(ALScopeData::CH_LUMA, ALScopeData::WAVE_COLUMNS, 0), 0.f); - ensure_equals("level past the end", - mScope.getWaveCell(ALScopeData::CH_LUMA, 0, ALScopeData::WAVE_LEVELS), 0.f); - ensure_equals("bad channel", mScope.getWaveCell(ALScopeData::CH_COUNT, 0, 0), 0.f); + UNSCOPED_INFO("negative column"); + CHECK(mScope.getWaveCell(ALScopeData::CH_LUMA, -1, 0) == 0.f); + UNSCOPED_INFO("column past the end"); + CHECK(mScope.getWaveCell(ALScopeData::CH_LUMA, ALScopeData::WAVE_COLUMNS, 0) == 0.f); + UNSCOPED_INFO("level past the end"); + CHECK(mScope.getWaveCell(ALScopeData::CH_LUMA, 0, ALScopeData::WAVE_LEVELS) == 0.f); + UNSCOPED_INFO("bad channel"); + CHECK(mScope.getWaveCell(ALScopeData::CH_COUNT, 0, 0) == 0.f); // And clearing has to let go of the grid again. mScope.clear(); - ensure_equals("cleared reads zero", mScope.getWaveCell(ALScopeData::CH_LUMA, 0, 0), 0.f); - ensure_equals("cleared has no peak", mScope.getWavePeak(ALScopeData::CH_LUMA), 0.f); + UNSCOPED_INFO("cleared reads zero"); + CHECK(mScope.getWaveCell(ALScopeData::CH_LUMA, 0, 0) == 0.f); + UNSCOPED_INFO("cleared has no peak"); + CHECK(mScope.getWavePeak(ALScopeData::CH_LUMA) == 0.f); } } diff --git a/indra/newview/tests/alscriptanalysislane_test.cpp b/indra/newview/tests/alscriptanalysislane_test.cpp index 1bbdf7d2b1..80f256296d 100644 --- a/indra/newview/tests/alscriptanalysislane_test.cpp +++ b/indra/newview/tests/alscriptanalysislane_test.cpp @@ -27,7 +27,7 @@ #include "../alscriptanalysislane.h" #include "../alscriptanalyzers.h" -#include "../test/lltut.h" +#include #include "Luau/Cancellation.h" @@ -38,8 +38,6 @@ #include #include -namespace tut -{ namespace { // What the lanes answered, in the order they did, from their threads. @@ -151,7 +149,6 @@ namespace bool mStops = false; bool mStopped = false; }; -} // anonymous namespace struct alscriptanalysislane_data { @@ -187,121 +184,151 @@ namespace } }; - typedef test_group alscriptanalysislane_group; - typedef alscriptanalysislane_group::object alscriptanalysislane_object; - alscriptanalysislane_group alscriptanalysislane_instance("alscriptanalysislane"); - - template<> template<> - void alscriptanalysislane_object::test<1>() + TEST_CASE_METHOD(alscriptanalysislane_data, "alscriptanalysislane: a long check on one lane holds up nothing on the other", "[alscriptanalysislane]") { - set_test_name("a long check on one lane holds nothing of the other's: each engine its own thread and queue"); auto gate = std::make_shared(); ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, false); }, main()); ALScriptAnalysisLane lsl("TestLSL", [gate] { return std::make_unique(gate, false); }, main()); - ensure("taken", post(luau, job("slow", ALScriptAnalysis::Kind::Check, true))); - ensure("held", gate->waitEntered()); - ensure("taken too", post(lsl, job("other", ALScriptAnalysis::Kind::Hover, true))); - ensure("the other lane's question answered while the check is held", answers.waitFor(1)); - ensure_equals("it alone", answers.all(), std::string("other/2")); + UNSCOPED_INFO("taken"); + CHECK(post(luau, job("slow", ALScriptAnalysis::Kind::Check, true))); + UNSCOPED_INFO("held"); + CHECK(gate->waitEntered()); + UNSCOPED_INFO("taken too"); + CHECK(post(lsl, job("other", ALScriptAnalysis::Kind::Hover, true))); + UNSCOPED_INFO("the other lane's question answered while the check is held"); + CHECK(answers.waitFor(1)); + UNSCOPED_INFO("it alone"); + CHECK(answers.all() == std::string("other/2")); gate->release(); - ensure("then the check", answers.waitFor(2)); - ensure_equals("in that order", answers.all(), std::string("other/2 slow/0")); + UNSCOPED_INFO("then the check"); + CHECK(answers.waitFor(2)); + UNSCOPED_INFO("in that order"); + CHECK(answers.all() == std::string("other/2 slow/0")); luau.close(); lsl.close(); - ensure("closed: refused", !post(luau, job("late", ALScriptAnalysis::Kind::Hover, true))); + UNSCOPED_INFO("closed: refused"); + CHECK_FALSE(post(luau, job("late", ALScriptAnalysis::Kind::Hover, true))); } - template<> template<> - void alscriptanalysislane_object::test<2>() + TEST_CASE_METHOD(alscriptanalysislane_data, "alscriptanalysislane: another tab's check gives way to the front tab's question and reruns", "[alscriptanalysislane]") { - set_test_name("another tab's check gives way to a question of the tab in front, waits again behind it, and answers after"); auto gate = std::make_shared(); ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, true); }, main()); - ensure("taken", post(luau, job("slow", ALScriptAnalysis::Kind::Check, false))); - ensure("held", gate->waitEntered()); - ensure("asked", post(luau, job("front", ALScriptAnalysis::Kind::Complete, true))); - ensure("both answered", answers.waitFor(2)); - ensure_equals("the question first, then the check, run again", answers.all(), std::string("front/1 slow/0")); + UNSCOPED_INFO("taken"); + CHECK(post(luau, job("slow", ALScriptAnalysis::Kind::Check, false))); + UNSCOPED_INFO("held"); + CHECK(gate->waitEntered()); + UNSCOPED_INFO("asked"); + CHECK(post(luau, job("front", ALScriptAnalysis::Kind::Complete, true))); + UNSCOPED_INFO("both answered"); + CHECK(answers.waitFor(2)); + UNSCOPED_INFO("the question first, then the check, run again"); + CHECK(answers.all() == std::string("front/1 slow/0")); luau.close(); } - template<> template<> - void alscriptanalysislane_object::test<3>() + TEST_CASE_METHOD(alscriptanalysislane_data, "alscriptanalysislane: the front tab's own check runs on through its questions", "[alscriptanalysislane]") { - set_test_name("the front tab's own check runs on through its questions, and is answered as it was asked"); auto gate = std::make_shared(); ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, true); }, main()); - ensure("taken", post(luau, job("slow", ALScriptAnalysis::Kind::Check, true))); - ensure("held", gate->waitEntered()); - ensure("asked", post(luau, job("front", ALScriptAnalysis::Kind::Complete, true))); + UNSCOPED_INFO("taken"); + CHECK(post(luau, job("slow", ALScriptAnalysis::Kind::Check, true))); + UNSCOPED_INFO("held"); + CHECK(gate->waitEntered()); + UNSCOPED_INFO("asked"); + CHECK(post(luau, job("front", ALScriptAnalysis::Kind::Complete, true))); gate->release(); - ensure("both answered", answers.waitFor(2)); - ensure_equals("the check first, not stopped", answers.all(), std::string("slow/0 front/1")); + UNSCOPED_INFO("both answered"); + CHECK(answers.waitFor(2)); + UNSCOPED_INFO("the check first, not stopped"); + CHECK(answers.all() == std::string("slow/0 front/1")); luau.close(); } - template<> template<> - void alscriptanalysislane_object::test<4>() + TEST_CASE_METHOD(alscriptanalysislane_data, "alscriptanalysislane: another tab's check gives way once and its rerun holds the next question", "[alscriptanalysislane]") { - set_test_name("another tab's check gives way once: run again, it runs through the next question of the tab in front, which waits for it"); auto gate = std::make_shared(); gate->always = true; ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, true); }, main()); - ensure("taken", post(luau, job("slow", ALScriptAnalysis::Kind::Check, false))); - ensure("held", gate->waitEntered()); - ensure("asked", post(luau, job("front", ALScriptAnalysis::Kind::Complete, true))); - ensure("the question answered", answers.waitFor(1)); - ensure("the check run again, and held", gate->waitEntered(2)); - ensure("asked again", post(luau, job("again", ALScriptAnalysis::Kind::Hover, true))); + UNSCOPED_INFO("taken"); + CHECK(post(luau, job("slow", ALScriptAnalysis::Kind::Check, false))); + UNSCOPED_INFO("held"); + CHECK(gate->waitEntered()); + UNSCOPED_INFO("asked"); + CHECK(post(luau, job("front", ALScriptAnalysis::Kind::Complete, true))); + UNSCOPED_INFO("the question answered"); + CHECK(answers.waitFor(1)); + UNSCOPED_INFO("the check run again, and held"); + CHECK(gate->waitEntered(2)); + UNSCOPED_INFO("asked again"); + CHECK(post(luau, job("again", ALScriptAnalysis::Kind::Hover, true))); // A moment, in which a question that stopped it would be answered. std::this_thread::sleep_for(std::chrono::milliseconds(200)); - ensure_equals("the second question waits for the check", answers.all(), std::string("front/1")); - ensure_equals("not started over", gate->enteredNow(), 2); + UNSCOPED_INFO("the second question waits for the check"); + CHECK(answers.all() == std::string("front/1")); + UNSCOPED_INFO("not started over"); + CHECK(gate->enteredNow() == 2); gate->release(); - ensure("all answered", answers.waitFor(3)); - ensure_equals("the check, then the question", answers.all(), std::string("front/1 slow/0 again/2")); + UNSCOPED_INFO("all answered"); + CHECK(answers.waitFor(3)); + UNSCOPED_INFO("the check, then the question"); + CHECK(answers.all() == std::string("front/1 slow/0 again/2")); luau.close(); } - template<> template<> - void alscriptanalysislane_object::test<5>() + TEST_CASE_METHOD(alscriptanalysislane_data, "alscriptanalysislane: a tab let go of mid-check has the check stopped unanswered and not rerun", "[alscriptanalysislane]") { - set_test_name("a tab let go of while its check runs: the check stopped, answered to nobody, and not run again"); auto gate = std::make_shared(); ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, true); }, main()); - ensure("taken", post(luau, job("slow", ALScriptAnalysis::Kind::Check, false))); - ensure("held", gate->waitEntered()); + UNSCOPED_INFO("taken"); + CHECK(post(luau, job("slow", ALScriptAnalysis::Kind::Check, false))); + UNSCOPED_INFO("held"); + CHECK(gate->waitEntered()); luau.forget("slow"); - ensure("asked", post(luau, job("front", ALScriptAnalysis::Kind::Hover, true))); - ensure("the question answered", answers.waitFor(1)); + UNSCOPED_INFO("asked"); + CHECK(post(luau, job("front", ALScriptAnalysis::Kind::Hover, true))); + UNSCOPED_INFO("the question answered"); + CHECK(answers.waitFor(1)); gate->release(); - ensure("asked again", post(luau, job("last", ALScriptAnalysis::Kind::Hover, true))); - ensure("answered", answers.waitFor(2)); - ensure_equals("nothing for the tab let go of", answers.all(), std::string("front/2 last/2")); - ensure_equals("run once", gate->enteredNow(), 1); + UNSCOPED_INFO("asked again"); + CHECK(post(luau, job("last", ALScriptAnalysis::Kind::Hover, true))); + UNSCOPED_INFO("answered"); + CHECK(answers.waitFor(2)); + UNSCOPED_INFO("nothing for the tab let go of"); + CHECK(answers.all() == std::string("front/2 last/2")); + UNSCOPED_INFO("run once"); + CHECK(gate->enteredNow() == 1); luau.close(); } - template<> template<> - void alscriptanalysislane_object::test<6>() + TEST_CASE_METHOD(alscriptanalysislane_data, "alscriptanalysislane: lookups and other tabs' checks yield to the front tab but not LSL or weighs", "[alscriptanalysislane]") { - set_test_name("a lookup's question of another script gives way to the tab in front as another tab's check does; the front tab's own, LSL's and a weigh do not"); using Kind = ALScriptAnalysis::Kind; - ensure("another tab's check", ALScriptAnalysisLane::yieldsOf(job("x", Kind::Check, false).request)); - ensure("a lookup's", ALScriptAnalysisLane::yieldsOf(job("lookup:a:b", Kind::References, false).request)); - ensure("not the front tab's", !ALScriptAnalysisLane::yieldsOf(job("x", Kind::Check, true).request)); - ensure("not a weigh", !ALScriptAnalysisLane::yieldsOf(job("x", Kind::Weigh, false).request)); + UNSCOPED_INFO("another tab's check"); + CHECK(ALScriptAnalysisLane::yieldsOf(job("x", Kind::Check, false).request)); + UNSCOPED_INFO("a lookup's"); + CHECK(ALScriptAnalysisLane::yieldsOf(job("lookup:a:b", Kind::References, false).request)); + UNSCOPED_INFO("not the front tab's"); + CHECK_FALSE(ALScriptAnalysisLane::yieldsOf(job("x", Kind::Check, true).request)); + UNSCOPED_INFO("not a weigh"); + CHECK_FALSE(ALScriptAnalysisLane::yieldsOf(job("x", Kind::Weigh, false).request)); ALScriptAnalysisLane::Job lsl = job("x", Kind::Check, false); lsl.request.lua = false; - ensure("not LSL's", !ALScriptAnalysisLane::yieldsOf(lsl.request)); + UNSCOPED_INFO("not LSL's"); + CHECK_FALSE(ALScriptAnalysisLane::yieldsOf(lsl.request)); auto gate = std::make_shared(); ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, true); }, main()); - ensure("taken", post(luau, job("slow", Kind::References, false))); - ensure("held", gate->waitEntered()); - ensure("asked", post(luau, job("front", Kind::Complete, true))); - ensure("both answered", answers.waitFor(2)); - ensure_equals("the question first, then the lookup's, run again", answers.all(), std::string("front/1 slow/5")); + UNSCOPED_INFO("taken"); + CHECK(post(luau, job("slow", Kind::References, false))); + UNSCOPED_INFO("held"); + CHECK(gate->waitEntered()); + UNSCOPED_INFO("asked"); + CHECK(post(luau, job("front", Kind::Complete, true))); + UNSCOPED_INFO("both answered"); + CHECK(answers.waitFor(2)); + UNSCOPED_INFO("the question first, then the lookup's, run again"); + CHECK(answers.all() == std::string("front/1 slow/5")); luau.close(); } } diff --git a/indra/newview/tests/alscriptanalyzers_test.cpp b/indra/newview/tests/alscriptanalyzers_test.cpp index e9e21ce246..3539e36b15 100644 --- a/indra/newview/tests/alscriptanalyzers_test.cpp +++ b/indra/newview/tests/alscriptanalyzers_test.cpp @@ -26,9 +26,9 @@ #include "../alscriptanalyzers.h" -#include "../test/lltut.h" +#include -namespace tut +namespace { struct alscriptanalyzers_data { @@ -46,47 +46,55 @@ namespace tut } }; - typedef test_group alscriptanalyzers_group; - typedef alscriptanalyzers_group::object alscriptanalyzers_object; - alscriptanalyzers_group alscriptanalyzers_instance("alscriptanalyzers"); - - template<> template<> - void alscriptanalyzers_object::test<1>() + TEST_CASE_METHOD(alscriptanalyzers_data, "alscriptanalyzers: an LSL check reports its parse and a later weigh reports its own", "[alscriptanalyzers]") { - set_test_name("an LSL check says whether its text parsed; a weigh after it, which asks the compiler and not the service, says nothing of another text's"); ALLSLAnalyzer lsl; const ALScriptAnalysis::Request broken = request(ALScriptAnalysis::Kind::Check, "default { state_entry() { llSay(0, \"x\" } }\n"); ALScriptAnalysis::Result checked; lsl.answer(broken, *broken.text, setup, checked); - ensure("builtins loaded: " + checked.definitionsError, checked.definitionsError.empty()); - ensure("the broken text did not parse", !checked.parsed); + UNSCOPED_INFO("builtins loaded: " + checked.definitionsError); + REQUIRE(checked.definitionsError.empty()); + UNSCOPED_INFO("the broken text did not parse"); + CHECK_FALSE(checked.parsed); ALScriptAnalysis::Request weighing = request(ALScriptAnalysis::Kind::Weigh, "default { state_entry() { llSay(0, \"x\"); } }\n"); weighing.targets = { ALScriptWeight::Target::Mono }; ALScriptAnalysis::Result weighed; lsl.answer(weighing, *weighing.text, setup, weighed); - ensure_equals("weighed", weighed.weights.size(), size_t(1)); - ensure("not the check's parse", weighed.parsed); + UNSCOPED_INFO("weighed"); + REQUIRE(weighed.weights.size() == size_t(1)); + UNSCOPED_INFO("not the check's parse"); + CHECK(weighed.parsed); } - template<> template<> - void alscriptanalyzers_object::test<2>() + TEST_CASE_METHOD(alscriptanalyzers_data, "alscriptanalyzers: a shape outlines LSL states and events and untyped SLua functions", "[alscriptanalyzers]") { - set_test_name("a shape: what a text declares from its parse, LSL's states and events, SLua's functions with no types and nothing loaded for them"); ALLSLAnalyzer lsl; const ALScriptAnalysis::Request shaped = request(ALScriptAnalysis::Kind::Shape, "go() {}\ndefault {\n state_entry() { go(); }\n}\n"); ALScriptAnalysis::Result lsl_shape; lsl.answer(shaped, *shaped.text, setup, lsl_shape); - ensure_equals("LSL: the function, the state, its event", lsl_shape.outline.size(), size_t(3)); - ensure("the event in its state", lsl_shape.outline[1].kind == ALScriptSymbolKind::State && lsl_shape.outline[2].name == "state_entry" && - lsl_shape.outline[2].depth == 1); - ensure("nothing else answered", lsl_shape.problems.empty()); + UNSCOPED_INFO("LSL: the function, the state, its event"); + REQUIRE(lsl_shape.outline.size() == size_t(3)); + { + INFO("the event in its state"); + CHECK(lsl_shape.outline[1].kind == ALScriptSymbolKind::State); + CHECK(lsl_shape.outline[2].name == "state_entry"); + CHECK(lsl_shape.outline[2].depth == 1); + } + UNSCOPED_INFO("nothing else answered"); + REQUIRE(lsl_shape.problems.empty()); ALLuauAnalyzer luau; ALScriptAnalysis::Request slua = request(ALScriptAnalysis::Kind::Shape, "local function half(n: number)\n return n / 2\nend\n"); slua.lua = true; ALScriptAnalysis::Result luau_shape; luau.answer(slua, *slua.text, ALScriptAnalyzer::Setup(), luau_shape); - ensure("SLua: the function, untyped", luau_shape.outline.size() == 1 && luau_shape.outline[0].name == "half" && luau_shape.outline[0].detail.empty()); - ensure("no definitions asked for", luau_shape.definitionsError.empty()); + { + INFO("SLua: the function, untyped"); + REQUIRE(luau_shape.outline.size() == 1); + CHECK(luau_shape.outline[0].name == "half"); + REQUIRE(luau_shape.outline[0].detail.empty()); + } + UNSCOPED_INFO("no definitions asked for"); + REQUIRE(luau_shape.definitionsError.empty()); } } diff --git a/indra/newview/tests/alscriptcontentsindex_test.cpp b/indra/newview/tests/alscriptcontentsindex_test.cpp index b0b24ace3d..9f19e22d85 100644 --- a/indra/newview/tests/alscriptcontentsindex_test.cpp +++ b/indra/newview/tests/alscriptcontentsindex_test.cpp @@ -26,7 +26,7 @@ #include "../alscriptcontentsindex.h" -#include "../test/lltut.h" +#include #include #include @@ -34,7 +34,7 @@ #include #include -namespace tut +namespace { struct alscriptcontentsindex_data { @@ -144,66 +144,93 @@ namespace tut return out; } }; - typedef test_group alscriptcontentsindex_group; - typedef alscriptcontentsindex_group::object alscriptcontentsindex_object; - tut::alscriptcontentsindex_group alscriptcontentsindex_instance("alscriptcontentsindex"); - template<> template<> - void alscriptcontentsindex_object::test<1>() + TEST_CASE_METHOD(alscriptcontentsindex_data, "alscriptcontentsindex: a prim is asked once for all who ask and not again while current", "[alscriptcontentsindex]") { - set_test_name("a prim is asked once however many ask, every one hears the answer, and one known and current is not asked again"); const LLUUID chair = object(10); S32 heard = 0; index.onHeard([&heard, chair](const Index::Contents& contents) { heard += contents.prim == chair; }); - ensure("asked", index.ask(chair)); - ensure("not again while it is not answered", !index.ask(chair)); - ensure("asking", index.asking(chair)); - ensure_equals(asked.size(), size_t(1)); - ensure("not known yet", !index.fetched(chair) && index.prim(chair) == nullptr); - ensure("answered", answer(chair, { "sit.lsl", "readme" }, true, "Chair")); - ensure_equals("heard once", heard, 1); - ensure_equals(names(chair), std::string("sit.lsl readme")); - ensure_equals("its name", index.prim(chair)->name, std::string("Chair")); - ensure("no longer asking", !index.asking(chair)); + UNSCOPED_INFO("asked"); + CHECK(index.ask(chair)); + UNSCOPED_INFO("not again while it is not answered"); + CHECK_FALSE(index.ask(chair)); + UNSCOPED_INFO("asking"); + CHECK(index.asking(chair)); + REQUIRE(asked.size() == size_t(1)); + { + INFO("not known yet"); + CHECK_FALSE(index.fetched(chair)); + REQUIRE(index.prim(chair) == nullptr); + } + UNSCOPED_INFO("answered"); + CHECK(answer(chair, { "sit.lsl", "readme" }, true, "Chair")); + UNSCOPED_INFO("heard once"); + CHECK(heard == 1); + CHECK(names(chair) == std::string("sit.lsl readme")); + UNSCOPED_INFO("its name"); + CHECK(index.prim(chair)->name == std::string("Chair")); + UNSCOPED_INFO("no longer asking"); + CHECK_FALSE(index.asking(chair)); // Known: asked again only where the object's copy is not current, // where asked again by a person, or of the region. - ensure("not current, asked", index.ask(chair) && answer(chair, { "sit.lsl" })); + { + INFO("not current, asked"); + CHECK(index.ask(chair)); + CHECK(answer(chair, { "sit.lsl" })); + } current.insert(chair); - ensure("current, not asked", !index.ask(chair)); - ensure("a refetch is", index.ask(chair, true) && answer(chair, { "sit.lsl" })); - ensure("and of the region", index.ask(chair, false, true) && asked.back().second); - ensure("a refetch while asked asks again", index.ask(chair, true)); + UNSCOPED_INFO("current, not asked"); + CHECK_FALSE(index.ask(chair)); + { + INFO("a refetch is"); + CHECK(index.ask(chair, true)); + CHECK(answer(chair, { "sit.lsl" })); + } + { + INFO("and of the region"); + CHECK(index.ask(chair, false, true)); + CHECK(asked.back().second); + } + UNSCOPED_INFO("a refetch while asked asks again"); + CHECK(index.ask(chair, true)); } - template<> template<> - void alscriptcontentsindex_object::test<2>() + TEST_CASE_METHOD(alscriptcontentsindex_data, "alscriptcontentsindex: a missed answer keeps the contents and a script's running is asked once", "[alscriptcontentsindex]") { - set_test_name("an answer that did not come leaves what was known; each script is asked once whether it runs, until let go of"); const LLUUID chair = object(10); index.ask(chair); answer(chair, { "sit.lsl", "pose.lsl", "readme" }); - ensure_equals("each script asked whether it runs", askedRunning.size(), size_t(2)); + UNSCOPED_INFO("each script asked whether it runs"); + REQUIRE(askedRunning.size() == size_t(2)); index.running(askedRunning[0], true); - ensure("known", index.running(askedRunning[0]) == std::optional(true)); - ensure("not known", !index.running(askedRunning[1])); + UNSCOPED_INFO("known"); + CHECK(index.running(askedRunning[0]) == std::optional(true)); + UNSCOPED_INFO("not known"); + REQUIRE_FALSE(index.running(askedRunning[1])); index.ask(chair, true); answer(chair, {}, false); - ensure_equals("no answer is not an empty prim", names(chair), std::string("sit.lsl pose.lsl readme")); - ensure("still fetched", index.fetched(chair)); - ensure_equals("only the one not known asked again", askedRunning.size(), size_t(3)); + UNSCOPED_INFO("no answer is not an empty prim"); + CHECK(names(chair) == std::string("sit.lsl pose.lsl readme")); + UNSCOPED_INFO("still fetched"); + CHECK(index.fetched(chair)); + UNSCOPED_INFO("only the one not known asked again"); + REQUIRE(askedRunning.size() == size_t(3)); index.forgetRunning({ chair }); - ensure("let go of", !index.running(askedRunning[0])); + UNSCOPED_INFO("let go of"); + REQUIRE_FALSE(index.running(askedRunning[0])); index.forget(chair); - ensure("all of it", index.prim(chair) == nullptr && names(chair).empty()); + { + INFO("all of it"); + REQUIRE(index.prim(chair) == nullptr); + REQUIRE(names(chair).empty()); + } } - template<> template<> - void alscriptcontentsindex_object::test<3>() + TEST_CASE_METHOD(alscriptcontentsindex_data, "alscriptcontentsindex: ensureListed tells once every prim has answered and names the unlisted", "[alscriptcontentsindex]") { - set_test_name("an object listed whole: every prim asked, told once all have answered, and which could not be listed said"); const LLUUID house = object(20, 4); // A prim known and current is not asked; one asked by someone else // is waited for. @@ -215,16 +242,26 @@ namespace tut std::optional listed; index.ensureListed(id(23), [&listed](const Index::Listed& out) { listed = out; }); - ensure_equals("the root and the one never asked", asked.size() - before, size_t(2)); - ensure("not yet", !listed); + UNSCOPED_INFO("the root and the one never asked"); + REQUIRE(asked.size() - before == size_t(2)); + UNSCOPED_INFO("not yet"); + REQUIRE_FALSE(listed); answer(id(20), { "main.lsl" }); answer(id(22), { "light.lsl" }); - ensure("not while one is out", !listed); + UNSCOPED_INFO("not while one is out"); + REQUIRE_FALSE(listed); answer(id(23), {}, false); - ensure("told", listed.has_value()); - ensure("by its root", listed->root == house && listed->present); - ensure_equals("every prim", listed->prims.size(), size_t(4)); - ensure("the one that did not answer said", listed->unlisted == std::vector{ id(23) }); + UNSCOPED_INFO("told"); + REQUIRE(listed.has_value()); + { + INFO("by its root"); + REQUIRE(listed->root == house); + CHECK(listed->present); + } + UNSCOPED_INFO("every prim"); + REQUIRE(listed->prims.size() == size_t(4)); + UNSCOPED_INFO("the one that did not answer said"); + CHECK(listed->unlisted == std::vector{ id(23) }); // Everything known and current: told at once. for (U32 i = 20; i < 24; ++i) @@ -235,18 +272,25 @@ namespace tut answer(id(23), {}); listed.reset(); index.ensureListed(house, [&listed](const Index::Listed& out) { listed = out; }); - ensure("at once", listed.has_value() && listed->unlisted.empty()); + { + INFO("at once"); + REQUIRE(listed.has_value()); + REQUIRE(listed->unlisted.empty()); + } // Not in sight: no prims, not present, told at once. listed.reset(); index.ensureListed(id(99), [&listed](const Index::Listed& out) { listed = out; }); - ensure("away", listed.has_value() && !listed->present && listed->prims.empty()); + { + INFO("away"); + REQUIRE(listed.has_value()); + REQUIRE_FALSE(listed->present); + REQUIRE(listed->prims.empty()); + } } - template<> template<> - void alscriptcontentsindex_object::test<4>() + TEST_CASE_METHOD(alscriptcontentsindex_data, "alscriptcontentsindex: an answer on the spot reaches the wait and a listener may list again", "[alscriptcontentsindex]") { - set_test_name("a world that answers on the spot answers into the wait, and one told may list again"); const LLUUID shed = object(30, 2); Index::World world; world.linkset = [this](const LLUUID& any) { return objects[any]; }; @@ -261,59 +305,77 @@ namespace tut S32 told = 0; spot.ensureListed(shed, [&](const Index::Listed& listed) { ++told; - ensure("all listed", listed.unlisted.empty() && listed.prims.size() == 2); + { + INFO("all listed"); + REQUIRE(listed.unlisted.empty()); + REQUIRE(listed.prims.size() == 2); + } if (told == 1) { spot.ensureListed(shed, [&told](const Index::Listed&) { ++told; }); } }); - ensure_equals("each told once", told, 2); + UNSCOPED_INFO("each told once"); + CHECK(told == 2); } - template<> template<> - void alscriptcontentsindex_object::test<5>() + TEST_CASE_METHOD(alscriptcontentsindex_data, "alscriptcontentsindex: refresh asks a prim again once its serial moved or its copy went", "[alscriptcontentsindex]") { - set_test_name("what a prim holds asked again as the studio draws once it changed -- its serial moved, or its object's copy was let " - "go of -- looking once a second, and a prim at most every few seconds"); const LLUUID chair = object(40); current.insert(chair); serials[chair] = 3; index.ask(chair); answer(chair, { "sit.lsl" }); index.refresh(10.0); - ensure("unchanged: not asked", pending.empty()); + UNSCOPED_INFO("unchanged: not asked"); + REQUIRE(pending.empty()); // A script added from the build tools. serials[chair] = 4; index.refresh(10.5); - ensure("not looked at again within the second", pending.empty()); + UNSCOPED_INFO("not looked at again within the second"); + REQUIRE(pending.empty()); index.refresh(11.0); - ensure("its serial moved: asked", pending.size() == 1 && asked.back().first == chair); + { + INFO("its serial moved: asked"); + REQUIRE(pending.size() == 1); + CHECK(asked.back().first == chair); + } answer(chair, { "sit.lsl", "new.lsl" }); - ensure_equals("what it holds now", names(chair), std::string("sit.lsl new.lsl")); + UNSCOPED_INFO("what it holds now"); + CHECK(names(chair) == std::string("sit.lsl new.lsl")); index.refresh(12.0); - ensure("heard at its serial: not asked", pending.empty()); + UNSCOPED_INFO("heard at its serial: not asked"); + REQUIRE(pending.empty()); // Its object's copy let go of, and no answer coming. current.erase(chair); index.refresh(13.0); - ensure("not asked again so soon", pending.empty()); + UNSCOPED_INFO("not asked again so soon"); + REQUIRE(pending.empty()); index.refresh(16.0); - ensure("asked", pending.size() == 1); + UNSCOPED_INFO("asked"); + REQUIRE(pending.size() == 1); index.refresh(17.0); - ensure("not while it is asked", pending.size() == 1); + UNSCOPED_INFO("not while it is asked"); + REQUIRE(pending.size() == 1); answer(chair, {}, false); - ensure_equals("no answer keeps what was known", names(chair), std::string("sit.lsl new.lsl")); + UNSCOPED_INFO("no answer keeps what was known"); + CHECK(names(chair) == std::string("sit.lsl new.lsl")); index.refresh(18.0); - ensure("not asked again at once", pending.empty()); + UNSCOPED_INFO("not asked again at once"); + REQUIRE(pending.empty()); index.refresh(21.0); - ensure("asked again a while after", pending.size() == 1); + UNSCOPED_INFO("asked again a while after"); + REQUIRE(pending.size() == 1); answer(chair, { "sit.lsl" }); // Asked for directly, a prim that changed is asked though known. current.insert(chair); - ensure("current: not asked", !index.ask(chair)); + UNSCOPED_INFO("current: not asked"); + CHECK_FALSE(index.ask(chair)); serials[chair] = 5; - ensure("its serial moved: asked", index.ask(chair)); + UNSCOPED_INFO("its serial moved: asked"); + CHECK(index.ask(chair)); } } diff --git a/indra/newview/tests/alscriptcrumbsbar_test.cpp b/indra/newview/tests/alscriptcrumbsbar_test.cpp index ee586112d6..3ec537a038 100644 --- a/indra/newview/tests/alscriptcrumbsbar_test.cpp +++ b/indra/newview/tests/alscriptcrumbsbar_test.cpp @@ -39,7 +39,7 @@ #include "lltimer.h" #include "lluicolortable.h" -#include "../test/lltut.h" +#include #include @@ -140,7 +140,7 @@ namespace }; } -namespace tut +namespace { struct alscriptcrumbsbar_data { @@ -156,7 +156,7 @@ namespace tut ALScriptCrumbsBar* found = window.find("crumbs"); if (!found) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } return found; } @@ -244,69 +244,84 @@ namespace tut } }; - typedef test_group alscriptcrumbsbar_group; - typedef alscriptcrumbsbar_group::object alscriptcrumbsbar_object; - alscriptcrumbsbar_group alscriptcrumbsbar_instance("alscriptcrumbsbar"); - - template<> template<> - void alscriptcrumbsbar_object::test<1>() + TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: the caret's path offers each step's siblings and follows changes", "[alscriptcrumbsbar]") { - set_test_name("the path the caret is in, each step offering those beside it; made again where the path, the tab or its name changed"); ALScriptCrumbsBar* crumbs = bar(); Doc& doc = tab("a"); doc.editor->setCaret(ALTextPos(3, 5)); place(crumbs, doc); const std::string top = "Script a [default, f, g, h, other]"; - ensure_equals("the path", path(), top + ", default [default, f, g, h, other], state_entry [state_entry, touch_start]"); - ensure_equals("kept", doc.caret->crumbPath.size(), size_t(2)); - ensure_equals("the script's step", jump()->path()[0].value, std::string("top")); - ensure_equals("said", jump()->path()[0].toolTip, + UNSCOPED_INFO("the path"); + CHECK(path() == top + ", default [default, f, g, h, other], state_entry [state_entry, touch_start]"); + UNSCOPED_INFO("kept"); + REQUIRE(doc.caret->crumbPath.size() == size_t(2)); + UNSCOPED_INFO("the script's step"); + CHECK(jump()->path()[0].value == std::string("top")); + UNSCOPED_INFO("said"); + CHECK(jump()->path()[0].toolTip == std::string("Script a: click to go to the top; the arrow lists the script's declarations")); - ensure_equals("a symbol's", jump()->path()[2].toolTip, std::string("Go to state_entry; the arrow lists other items at this level")); + UNSCOPED_INFO("a symbol's"); + CHECK(jump()->path()[2].toolTip == std::string("Go to state_entry; the arrow lists other items at this level")); doc.editor->setCaret(ALTextPos(4, 0)); place(crumbs, doc); - ensure("the trailer is", trailer().find("Ln 5, Col 1") != std::string::npos); + UNSCOPED_INFO("the trailer is"); + REQUIRE(trailer().find("Ln 5, Col 1") != std::string::npos); doc.editor->setCaret(ALTextPos(11, 0)); place(crumbs, doc); - ensure_equals("in f", path(), top + ", f [default, f, g, h, other]"); + UNSCOPED_INFO("in f"); + CHECK(path() == top + ", f [default, f, g, h, other]"); doc.editor->setCaret(ALTextPos(9, 0)); place(crumbs, doc); - ensure_equals("between: the script", path(), top); + UNSCOPED_INFO("between: the script"); + CHECK(path() == top); doc.editor->setCaret(ALTextPos(4, 5)); place(crumbs, doc); - ensure("at a symbol's very end: still in it", path().find("state_entry [") != std::string::npos); + UNSCOPED_INFO("at a symbol's very end: still in it"); + REQUIRE(path().find("state_entry [") != std::string::npos); doc.editor->setCaret(ALTextPos(13, 5)); place(crumbs, doc); - ensure_equals("where two meet: the later", jump()->path().back().label, std::string("h")); + UNSCOPED_INFO("where two meet: the later"); + CHECK(jump()->path().back().label == std::string("h")); doc.editor->setCaret(ALTextPos(17, 0)); place(crumbs, doc); - ensure_equals("alone in its state: nothing beside it", path(), top + ", other [default, f, g, h, other], timer"); + UNSCOPED_INFO("alone in its state: nothing beside it"); + CHECK(path() == top + ", other [default, f, g, h, other], timer"); doc.name = "Renamed"; place(crumbs, doc); - ensure_equals("a new name: again", jump()->path()[0].label, std::string("Renamed")); + UNSCOPED_INFO("a new name: again"); + CHECK(jump()->path()[0].label == std::string("Renamed")); Doc& other = tab("b"); other.name = "Other"; place(crumbs, other); - ensure_equals("not in front: nothing", jump()->path()[0].label, std::string("Renamed")); + UNSCOPED_INFO("not in front: nothing"); + CHECK(jump()->path()[0].label == std::string("Renamed")); crumbs->forget(); - ensure("forgotten", jump()->path().empty() && jump()->trailer().empty()); + { + INFO("forgotten"); + REQUIRE(jump()->path().empty()); + REQUIRE(jump()->trailer().empty()); + } place(crumbs, doc); - ensure_equals("and shown again whatever", jump()->path()[0].label, std::string("Renamed")); + UNSCOPED_INFO("and shown again whatever"); + CHECK(jump()->path()[0].label == std::string("Renamed")); } - template<> template<> - void alscriptcrumbsbar_object::test<2>() + TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: the trailer's parts and tips and which go first where it is narrow", "[alscriptcrumbsbar]") { - set_test_name("the trailer: read only, vim's word, the caret, what is selected and the problems, each pressable one with its tip; what goes first where narrow"); ALScriptCrumbsBar* crumbs = bar(); Doc& doc = tab("a"); crumbs->setTips({ "line tip", "problems tip", "source tip", "expanded tip" }); doc.editor->setCaret(ALTextPos(2, 6)); crumbs->showTrailer(doc); - ensure_equals("the caret and the indentation", trailer(), std::string("Ln 3, Col 7, Tab Size: 4")); - ensure("pressed for a line", part("Ln")->value == "line" && part("Ln")->toolTip == "line tip"); + UNSCOPED_INFO("the caret and the indentation"); + CHECK(trailer() == std::string("Ln 3, Col 7, Tab Size: 4")); + { + INFO("pressed for a line"); + CHECK(part("Ln")->value == "line"); + CHECK(part("Ln")->toolTip == "line tip"); + } doc.modifiable = false; told().banner = "-- INSERT --"; @@ -314,36 +329,63 @@ namespace tut told().warnings = 1; doc.editor->setSelection(ALTextRange(ALTextPos(2, 0), ALTextPos(4, 0))); crumbs->showTrailer(doc); - ensure_equals("in order", trailer(), std::string("Read-only, -- INSERT --, Ln 5, Col 1, 2 lines selected, Tab Size: 4, 2 errors, 1 warning")); + UNSCOPED_INFO("in order"); + CHECK(trailer() == std::string("Read-only, -- INSERT --, Ln 5, Col 1, 2 lines selected, Tab Size: 4, 2 errors, 1 warning")); const std::vector& raw = jump()->trailer(); - ensure("a dot between each", raw.size() == 13 && raw[1].text == " \xC2\xB7 " && raw[11].text == raw[1].text); - ensure_equals("the last a part", raw[12].text, std::string("1 warning")); - ensure("the dots only between", raw[1].between && raw[11].between && !raw[12].between); - ensure("where narrow: the indentation first, then the selection, the counts and read only last, the place never", - part("Tab")->drop > part("2 lines")->drop && part("2 lines")->drop > part("2 errors")->drop && part("2 errors")->drop > 0 && - part("Read")->drop > 0 && part("Ln")->drop == 0); - ensure_equals("read only, said", part("Read")->toolTip, std::string("You can view this script but not change it")); - ensure("the problems pressable", part("2 errors")->value == "problems" && part("1 warning")->toolTip == "problems tip"); + { + INFO("a dot between each"); + REQUIRE(raw.size() == 13); + CHECK(raw[1].text == " \xC2\xB7 "); + CHECK(raw[11].text == raw[1].text); + } + UNSCOPED_INFO("the last a part"); + CHECK(raw[12].text == std::string("1 warning")); + { + INFO("the dots only between"); + CHECK(raw[1].between); + CHECK(raw[11].between); + CHECK_FALSE(raw[12].between); + } + { + INFO("where narrow: the indentation first, then the selection, the counts and read only last, the place never"); + CHECK(part("Tab")->drop > part("2 lines")->drop); + CHECK(part("2 lines")->drop > part("2 errors")->drop); + CHECK(part("2 errors")->drop > 0); + CHECK(part("Read")->drop > 0); + CHECK(part("Ln")->drop == 0); + } + UNSCOPED_INFO("read only, said"); + CHECK(part("Read")->toolTip == std::string("You can view this script but not change it")); + { + INFO("the problems pressable"); + CHECK(part("2 errors")->value == "problems"); + CHECK(part("1 warning")->toolTip == "problems tip"); + } doc.editor->setSelection(ALTextRange(ALTextPos(2, 0), ALTextPos(4, 2))); crumbs->showTrailer(doc); - ensure("a line begun counts", part("3 lines") != nullptr); + UNSCOPED_INFO("a line begun counts"); + REQUIRE(part("3 lines") != nullptr); doc.editor->setText("a\tb\xC3\xA9\n"); doc.editor->setSelection(ALTextRange(ALTextPos(0, 0), ALTextPos(0, 5))); crumbs->showTrailer(doc); - ensure("characters, a tab one and an accented one one", part("4 characters selected") != nullptr); + UNSCOPED_INFO("characters, a tab one and an accented one one"); + REQUIRE(part("4 characters selected") != nullptr); doc.editor->setCaret(ALTextPos(0, 2)); crumbs->showTrailer(doc); - ensure_equals("the column as seen, past the tab", part("Ln")->text, + UNSCOPED_INFO("the column as seen, past the tab"); + CHECK(part("Ln")->text == "Ln 1, Col " + std::to_string(doc.editor->getTabWidth() + 1)); doc.loaded = false; crumbs->showTrailer(doc); - ensure("not loaded: not said read only, nor how it is indented", part("Read") == nullptr && part("Tab") == nullptr); + { + INFO("not loaded: not said read only, nor how it is indented"); + REQUIRE(part("Read") == nullptr); + REQUIRE(part("Tab") == nullptr); + } } - template<> template<> - void alscriptcrumbsbar_object::test<3>() + TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: code and save sizes coloured near their limits and the view pressable", "[alscriptcrumbsbar]") { - set_test_name("its code size, coloured near and past its limit; what a save would send, past half; the view, pressable"); ALScriptCrumbsBar* crumbs = bar(); Doc& doc = tab("a"); const LLColor4 error = doc.editor->markColor(ALCodeEditor::Mark::Error); @@ -355,41 +397,61 @@ namespace tut doc.weighing->weight = weight; crumbs->showTrailer(doc); const Part* weighed = part("LSL (Mono)"); - ensure("weighed", weighed && weighed->text == "LSL (Mono) 40.0 of 64 KB used" && !weighed->color); - ensure("before the optimizer", weighed->toolTip.find("Measured before the preprocessor") != std::string::npos); + { + INFO("weighed"); + REQUIRE(weighed); + REQUIRE(weighed->text == "LSL (Mono) 40.0 of 64 KB used"); + REQUIRE_FALSE(weighed->color); + } + UNSCOPED_INFO("before the optimizer"); + REQUIRE(weighed->toolTip.find("Measured before the preprocessor") != std::string::npos); doc.weighing->exact = true; doc.weighing->sent = true; doc.weighing->weight->total = 60000; crumbs->showTrailer(doc); - ensure("as sent", part("LSL (Mono)")->toolTip.find("as it is saved") != std::string::npos); - ensure("near: the warning's", part("LSL (Mono)")->color == warn); + UNSCOPED_INFO("as sent"); + REQUIRE(part("LSL (Mono)")->toolTip.find("as it is saved") != std::string::npos); + UNSCOPED_INFO("near: the warning's"); + CHECK(part("LSL (Mono)")->color == warn); doc.weighing->weight->total = 70000; crumbs->showTrailer(doc); - ensure("past: the error's", part("LSL (Mono)")->color == error); + UNSCOPED_INFO("past: the error's"); + CHECK(part("LSL (Mono)")->color == error); doc.weighing->weight->estimate = true; crumbs->showTrailer(doc); - ensure("an estimate", part("LSL (Mono) ~") != nullptr); + UNSCOPED_INFO("an estimate"); + REQUIRE(part("LSL (Mono) ~") != nullptr); doc.weighing->weight.reset(); const size_t LIMIT = ALScriptEnvelope::MAX_ASSET_BYTES; doc.weighing->assetBytes = LIMIT / 2; crumbs->showTrailer(doc); - ensure("half: nothing", parts().size() == 2); + UNSCOPED_INFO("half: nothing"); + REQUIRE(parts().size() == 2); doc.weighing->assetBytes = LIMIT / 2 + 1; crumbs->showTrailer(doc); - ensure("past half", part(std::to_string((LIMIT / 2 + 1 + 1023) / 1024) + " KB") != nullptr); - ensure("said", parts().back().toolTip.find("Save size") != std::string::npos && !parts().back().color); + UNSCOPED_INFO("past half"); + REQUIRE(part(std::to_string((LIMIT / 2 + 1 + 1023) / 1024) + " KB") != nullptr); + { + INFO("said"); + REQUIRE(parts().back().toolTip.find("Save size") != std::string::npos); + REQUIRE_FALSE(parts().back().color); + } doc.weighing->assetBytes = LIMIT * 9 / 10 + 1; crumbs->showTrailer(doc); - ensure("near: the warning's", parts().back().color == warn); + UNSCOPED_INFO("near: the warning's"); + CHECK(parts().back().color == warn); doc.weighing->assetBytes = LIMIT + 1; crumbs->showTrailer(doc); - ensure("over: the error's", parts().back().color == error); - ensure("and by how much", parts().back().toolTip.find("1 over the") != std::string::npos); + UNSCOPED_INFO("over: the error's"); + CHECK(parts().back().color == error); + UNSCOPED_INFO("and by how much"); + REQUIRE(parts().back().toolTip.find("1 over the") != std::string::npos); doc.notecard = true; doc.weighing->assetBytes = static_cast(LLNotecard::MAX_SIZE) / 2 + 1; crumbs->showTrailer(doc); - ensure("a notecard's by its own limit", parts().back().toolTip.find("Notecard text") != std::string::npos); + UNSCOPED_INFO("a notecard's by its own limit"); + REQUIRE(parts().back().toolTip.find("Notecard text") != std::string::npos); doc.notecard = false; doc.weighing->assetBytes = 0; @@ -397,18 +459,26 @@ namespace tut doc.expandedEditor = editor("expanded_a", "integer x;\n"); crumbs->showTrailer(doc); const Part shown = parts().back(); - ensure("the source in front", shown.text == "Source" && shown.value == "expanded" && shown.toolTip == "source tip"); + { + INFO("the source in front"); + CHECK(shown.text == "Source"); + CHECK(shown.value == "expanded"); + CHECK(shown.toolTip == "source tip"); + } doc.view = Doc::View::Expanded; doc.expandedEditor->setCaret(ALTextPos(0, 3)); crumbs->showTrailer(doc); - ensure("the expansion", parts().back().text == "Preprocessed" && parts().back().toolTip == "expanded tip"); - ensure("its own caret", part("Ln 1, Col 4") != nullptr); + { + INFO("the expansion"); + CHECK(parts().back().text == "Preprocessed"); + CHECK(parts().back().toolTip == "expanded tip"); + } + UNSCOPED_INFO("its own caret"); + REQUIRE(part("Ln 1, Col 4") != nullptr); } - template<> template<> - void alscriptcrumbsbar_object::test<4>() + TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: the optimizer's sizes replace the weight while the expansion is in front", "[alscriptcrumbsbar]") { - set_test_name("what the optimizer made of it, in place of its weight, while the preprocessed view is in front"); ALScriptCrumbsBar* crumbs = bar(); Doc& doc = tab("a"); ALScriptWeight weight; @@ -425,31 +495,39 @@ namespace tut doc.uploaded.codeAfter = 10240; told().target = ALScriptWeight::Target::Mono; crumbs->showTrailer(doc); - ensure_equals("before and after", part("LSL (Mono)")->text, std::string("LSL (Mono) ~20.0 \xE2\x86\x92 ~10.0 of 64 KB used")); - ensure_equals("once", parts().size(), size_t(4)); + UNSCOPED_INFO("before and after"); + CHECK(part("LSL (Mono)")->text == std::string("LSL (Mono) ~20.0 \xE2\x86\x92 ~10.0 of 64 KB used")); + UNSCOPED_INFO("once"); + REQUIRE(parts().size() == size_t(4)); doc.uploaded.codeAfter = 60000; crumbs->showTrailer(doc); - ensure("near: the warning's", part("LSL (Mono)")->color == doc.editor->markColor(ALCodeEditor::Mark::Warning)); + UNSCOPED_INFO("near: the warning's"); + CHECK(part("LSL (Mono)")->color == doc.editor->markColor(ALCodeEditor::Mark::Warning)); doc.uploaded.codeAfter = 70000; crumbs->showTrailer(doc); - ensure("past: the error's", part("LSL (Mono)")->color == doc.editor->markColor(ALCodeEditor::Mark::Error)); + UNSCOPED_INFO("past: the error's"); + CHECK(part("LSL (Mono)")->color == doc.editor->markColor(ALCodeEditor::Mark::Error)); told().target = ALScriptWeight::Target::LSO; crumbs->showTrailer(doc); - ensure("measured, not estimated", part("LSL (LSO)") && part("LSL (LSO)")->text.find('~') == std::string::npos); + { + INFO("measured, not estimated"); + REQUIRE(part("LSL (LSO)")); + REQUIRE(part("LSL (LSO)")->text.find('~') == std::string::npos); + } doc.editor->insertText("x"); crumbs->showTrailer(doc); - ensure("typed since: its weight", part("LSL (Mono) 40.0") != nullptr); + UNSCOPED_INFO("typed since: its weight"); + REQUIRE(part("LSL (Mono) 40.0") != nullptr); doc.view = Doc::View::Source; doc.uploaded.version = doc.editor->document().version(); told().target = ALScriptWeight::Target::Mono; crumbs->showTrailer(doc); - ensure("the source in front: its weight", part("LSL (Mono) 40.0") != nullptr); + UNSCOPED_INFO("the source in front: its weight"); + REQUIRE(part("LSL (Mono) 40.0") != nullptr); } - template<> template<> - void alscriptcrumbsbar_object::test<5>() + TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: a chosen step goes to the top or a symbol's name or nowhere if gone", "[alscriptcrumbsbar]") { - set_test_name("a step chosen: the script's top as a place, a symbol's name as a stretch, one gone as nowhere"); ALScriptCrumbsBar* crumbs = bar(); Doc& doc = tab("a"); crumbs->choose("top"); @@ -457,48 +535,79 @@ namespace tut crumbs->choose("9\ngone"); doc.outline.erase(doc.outline.begin()); crumbs->choose("1\ntouch_start"); - ensure_equals("each", joined(told().chosen), std::string("a 0:0-0:0, a 2:4-2:15, a nowhere, a 5:4-5:15")); + UNSCOPED_INFO("each"); + CHECK(joined(told().chosen) == std::string("a 0:0-0:0, a 2:4-2:15, a nowhere, a 5:4-5:15")); } - template<> template<> - void alscriptcrumbsbar_object::test<6>() + TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: the indentation part names its source and its menu sets this script only", "[alscriptcrumbsbar]") { - set_test_name("how the script is indented: a tab's width or a level's spaces, pressable, the tip saying where it was said; the menu's choices for that script alone"); ALScriptCrumbsBar* crumbs = bar(); Doc& doc = tab("a"); crumbs->showTrailer(doc); - ensure("tabs, by default", part("Tab Size: 4") && part("Tab Size")->value == "indent"); - ensure("the default's tip", part("Tab Size")->toolTip.find("Default indentation from Preferences") != std::string::npos); - ensure("checked as it is", crumbs->indentChecked("tabs") && crumbs->indentChecked("width_4") && !crumbs->indentChecked("spaces")); - ensure("nothing chosen to forget", !crumbs->indentEnabled("read")); + { + INFO("tabs, by default"); + REQUIRE(part("Tab Size: 4")); + CHECK(part("Tab Size")->value == "indent"); + } + UNSCOPED_INFO("the default's tip"); + REQUIRE(part("Tab Size")->toolTip.find("Default indentation from Preferences") != std::string::npos); + { + INFO("checked as it is"); + REQUIRE(crumbs->indentChecked("tabs")); + REQUIRE(crumbs->indentChecked("width_4")); + CHECK_FALSE(crumbs->indentChecked("spaces")); + } + UNSCOPED_INFO("nothing chosen to forget"); + CHECK_FALSE(crumbs->indentEnabled("read")); doc.editor->setReadsIndentation(true); doc.editor->setText("a\n b\n"); crumbs->showTrailer(doc); - ensure("read from the script", part("Spaces: 2") && part("Spaces")->toolTip.find("detected from this script's lines") != std::string::npos); + { + INFO("read from the script"); + REQUIRE(part("Spaces: 2")); + REQUIRE(part("Spaces")->toolTip.find("detected from this script's lines") != std::string::npos); + } crumbs->indentAct("width_4"); - ensure("a width chosen", part("Spaces: 4") && part("Spaces")->toolTip.find("set for this script") != std::string::npos); - ensure("and checked", crumbs->indentChecked("width_4") && !crumbs->indentChecked("width_2")); - ensure("the text untouched", doc.editor->text() == "a\n b\n"); + { + INFO("a width chosen"); + REQUIRE(part("Spaces: 4")); + REQUIRE(part("Spaces")->toolTip.find("set for this script") != std::string::npos); + } + { + INFO("and checked"); + REQUIRE(crumbs->indentChecked("width_4")); + CHECK_FALSE(crumbs->indentChecked("width_2")); + } + UNSCOPED_INFO("the text untouched"); + CHECK(doc.editor->text() == "a\n b\n"); crumbs->indentAct("tabs"); - ensure("tabs chosen", part("Tab Size: 4") != nullptr && crumbs->indentChecked("tabs")); - ensure("to be forgotten", crumbs->indentEnabled("read")); + { + INFO("tabs chosen"); + REQUIRE(part("Tab Size: 4") != nullptr); + CHECK(crumbs->indentChecked("tabs")); + } + UNSCOPED_INFO("to be forgotten"); + CHECK(crumbs->indentEnabled("read")); crumbs->indentAct("read"); - ensure("the script's own again", part("Spaces: 2") != nullptr); + UNSCOPED_INFO("the script's own again"); + REQUIRE(part("Spaces: 2") != nullptr); crumbs->indentAct("convert_tabs"); - ensure_equals("converted, a tab of the width", doc.editor->text(), std::string("a\n\tb\n")); - ensure("and tabs from here on", part("Tab Size: 2") != nullptr); + UNSCOPED_INFO("converted, a tab of the width"); + CHECK(doc.editor->text() == std::string("a\n\tb\n")); + UNSCOPED_INFO("and tabs from here on"); + REQUIRE(part("Tab Size: 2") != nullptr); doc.modifiable = false; - ensure("not a script that may only be read", !crumbs->indentEnabled("convert_spaces")); + UNSCOPED_INFO("not a script that may only be read"); + CHECK_FALSE(crumbs->indentEnabled("convert_spaces")); crumbs->indentAct("convert_spaces"); - ensure_equals("left as it was", doc.editor->text(), std::string("a\n\tb\n")); + UNSCOPED_INFO("left as it was"); + CHECK(doc.editor->text() == std::string("a\n\tb\n")); } - template<> template<> - void alscriptcrumbsbar_object::test<7>() + TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: a check out a while is said but one just asked or answered is not", "[alscriptcrumbsbar]") { - set_test_name("a check out a while is said, and pressed shows the problems; one just asked, or answered, is not"); ALScriptCrumbsBar* crumbs = bar(); Doc& doc = tab("a"); doc.loaded = true; @@ -507,20 +616,24 @@ namespace tut doc.check->analysisVersion = doc.check->requestedVersion + 1; doc.check->askedAt = now; crumbs->showTrailer(doc); - ensure("just asked: nothing", part("Checking") == nullptr); + UNSCOPED_INFO("just asked: nothing"); + REQUIRE(part("Checking") == nullptr); doc.check->askedAt = now - 1.0; crumbs->showTrailer(doc); const Part* checking = part("Checking"); - ensure("out a while: said", checking != nullptr && checking->value == "problems"); + { + INFO("out a while: said"); + REQUIRE(checking != nullptr); + CHECK(checking->value == "problems"); + } doc.check->analysisVersion = doc.check->requestedVersion; crumbs->showTrailer(doc); - ensure("answered: gone", part("Checking") == nullptr); + UNSCOPED_INFO("answered: gone"); + REQUIRE(part("Checking") == nullptr); } - template<> template<> - void alscriptcrumbsbar_object::test<8>() + TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: only what changed is said again so a caret move says just its place", "[alscriptcrumbsbar]") { - set_test_name("a caret moving says its place and the selection again, and nothing else; the rest said again where what it says changed"); ALScriptCrumbsBar* crumbs = bar(); Doc& doc = tab("a"); told().errors = 2; @@ -529,72 +642,109 @@ namespace tut said = 0; doc.editor->setCaret(ALTextPos(4, 0)); crumbs->showTrailer(doc); - ensure_equals("the place alone said", said, 1); - ensure_equals("and the rest kept", trailer(), std::string("Ln 5, Col 1, Tab Size: 4, 2 errors")); + UNSCOPED_INFO("the place alone said"); + CHECK(said == 1); + UNSCOPED_INFO("and the rest kept"); + CHECK(trailer() == std::string("Ln 5, Col 1, Tab Size: 4, 2 errors")); doc.editor->setSelection(ALTextRange(ALTextPos(2, 0), ALTextPos(4, 0))); said = 0; crumbs->showTrailer(doc); - ensure_equals("and the selection", said, 2); + UNSCOPED_INFO("and the selection"); + CHECK(said == 2); said = 0; told().errors = 3; crumbs->showTrailer(doc); - ensure("counted again: said again", said > 2 && part("3 errors") != nullptr); + { + INFO("counted again: said again"); + CHECK(said > 2); + REQUIRE(part("3 errors") != nullptr); + } said = 0; doc.editor->setTabWidth(2); crumbs->showTrailer(doc); - ensure("indented otherwise", said > 2 && part("Tab Size: 2") != nullptr); + { + INFO("indented otherwise"); + CHECK(said > 2); + REQUIRE(part("Tab Size: 2") != nullptr); + } said = 0; crumbs->setTips({ "line", "problems", "source", "expanded" }); crumbs->showTrailer(doc); - ensure("other tips: said again", said > 2 && part("3 errors")->toolTip == "problems"); + { + INFO("other tips: said again"); + CHECK(said > 2); + CHECK(part("3 errors")->toolTip == "problems"); + } said = 0; Doc& other = tab("b"); crumbs->showTrailer(other); - ensure("another tab: its own", said > 2 && part("3 errors") != nullptr && part("Tab Size: 4") != nullptr); + { + INFO("another tab: its own"); + CHECK(said > 2); + REQUIRE(part("3 errors") != nullptr); + REQUIRE(part("Tab Size: 4") != nullptr); + } } - template<> template<> - void alscriptcrumbsbar_object::test<9>() + TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: what is left from LSL is counted and pressable and not said when none", "[alscriptcrumbsbar]") { - set_test_name("what is left from LSL counted, pressed to show it; none, not said"); ALScriptCrumbsBar* crumbs = bar(); Doc& doc = tab("a"); crumbs->showTrailer(doc); - ensure("none: not said", trailer().find("left from LSL") == std::string::npos); + UNSCOPED_INFO("none: not said"); + REQUIRE(trailer().find("left from LSL") == std::string::npos); doc.shownMigration = 3; crumbs->showTrailer(doc); const Part* left = part("3 left from LSL"); - ensure("counted", left != nullptr && left->value == "migration" && !left->toolTip.empty()); + { + INFO("counted"); + REQUIRE(left != nullptr); + REQUIRE(left->value == "migration"); + REQUIRE_FALSE(left->toolTip.empty()); + } doc.shownMigration = 1; crumbs->showTrailer(doc); - ensure("counted again", part("1 left from LSL") != nullptr); + UNSCOPED_INFO("counted again"); + REQUIRE(part("1 left from LSL") != nullptr); } - template<> template<> - void alscriptcrumbsbar_object::test<10>() + TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: the view's tip says why a save preprocesses and warns where it will not", "[alscriptcrumbsbar]") { - set_test_name("the view's tip says why a save preprocesses the script; a preprocessed view of one a save sends as written says so, in the warning's colour"); ALScriptCrumbsBar* crumbs = bar(); Doc& doc = tab("a"); doc.expandedEditor = editor("expanded_a", "integer x;\n"); doc.view = Doc::View::Expanded; told().wanted = ALPreprocessor::Wanted::Directives; crumbs->showTrailer(doc); - ensure("not warned where a save preprocesses it", part("Not preprocessed on save") == nullptr); + UNSCOPED_INFO("not warned where a save preprocesses it"); + REQUIRE(part("Not preprocessed on save") == nullptr); const Part* view = part("Preprocessed"); - ensure("why, on the view's tip: " + (view ? view->toolTip : std::string()), view && view->toolTip.find("it has directives") != std::string::npos); + { + INFO("why, on the view's tip: " + (view ? view->toolTip : std::string())); + REQUIRE(view); + REQUIRE(view->toolTip.find("it has directives") != std::string::npos); + } told().wanted = ALPreprocessor::Wanted::Enveloped; crumbs->showTrailer(doc); - ensure("saved with it before", part("Preprocessed") && part("Preprocessed")->toolTip.find("saved with the preprocessor before") != std::string::npos); + { + INFO("saved with it before"); + REQUIRE(part("Preprocessed")); + REQUIRE(part("Preprocessed")->toolTip.find("saved with the preprocessor before") != std::string::npos); + } told().wanted = ALPreprocessor::Wanted::No; crumbs->showTrailer(doc); const Part* warned = part("Not preprocessed on save"); - ensure("said where a save sends it as written", warned && warned->color == doc.editor->markColor(ALCodeEditor::Mark::Warning) && - warned->toolTip.find("as written") != std::string::npos); + { + INFO("said where a save sends it as written"); + REQUIRE(warned); + REQUIRE(warned->color == doc.editor->markColor(ALCodeEditor::Mark::Warning)); + REQUIRE(warned->toolTip.find("as written") != std::string::npos); + } doc.expandedEditor = nullptr; doc.view = Doc::View::Source; crumbs->showTrailer(doc); - ensure("nothing said with no preprocessed view", part("Not preprocessed on save") == nullptr); + UNSCOPED_INFO("nothing said with no preprocessed view"); + REQUIRE(part("Not preprocessed on save") == nullptr); } } diff --git a/indra/newview/tests/alscriptexplorermodel_test.cpp b/indra/newview/tests/alscriptexplorermodel_test.cpp index 82b3fbbaa6..ed26f15609 100644 --- a/indra/newview/tests/alscriptexplorermodel_test.cpp +++ b/indra/newview/tests/alscriptexplorermodel_test.cpp @@ -26,7 +26,7 @@ #include "../alscriptexplorermodel.h" -#include "../test/lltut.h" +#include #include #include @@ -34,7 +34,7 @@ #include #include -namespace tut +namespace { struct alscriptexplorermodel_data { @@ -210,14 +210,9 @@ namespace tut return found != all.end() ? &*found : nullptr; } }; - typedef test_group alscriptexplorermodel_group; - typedef alscriptexplorermodel_group::object alscriptexplorermodel_object; - tut::alscriptexplorermodel_group alscriptexplorermodel_instance("alscriptexplorermodel"); - template<> template<> - void alscriptexplorermodel_object::test<1>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: pins come first then the selection then the open scripts' objects", "[alscriptexplorermodel]") { - set_test_name("the objects in hand, each once: the pinned first, one not in sight by its pin's name, then the selected, then the open scripts' objects"); const LLUUID chair = object(10, "Chair"); const LLUUID table = object(20, "Table", 3); const LLUUID lamp = object(30, "Lamp"); @@ -231,42 +226,56 @@ namespace tut selected = { chair, lamp }; open = { id(21) }; list(); - ensure_equals(names(), std::string("Lamp* Gone(away)* (unnamed)(away)* Chair Table")); - ensure("an object by a prim of it, listed by its root", model.objects().back().root == table && model.objects().back().prims.size() == 3); - ensure("listed prims", model.listed(id(22)) && !model.listed(id(90))); - ensure("what coming or going concerns: a listed prim, a pin away", model.concerns(id(22)) && model.concerns(id(90))); - ensure("not what it neither lists nor asked for", !model.concerns(id(55))); + CHECK(names() == std::string("Lamp* Gone(away)* (unnamed)(away)* Chair Table")); + { + INFO("an object by a prim of it, listed by its root"); + CHECK(model.objects().back().root == table); + REQUIRE(model.objects().back().prims.size() == 3); + } + { + INFO("listed prims"); + CHECK(model.listed(id(22))); + CHECK_FALSE(model.listed(id(90))); + } + { + INFO("what coming or going concerns: a listed prim, a pin away"); + CHECK(model.concerns(id(22))); + CHECK(model.concerns(id(90))); + } + UNSCOPED_INFO("not what it neither lists nor asked for"); + CHECK_FALSE(model.concerns(id(55))); // Across sessions, the pins as they were read. LLSD kept; model.saveState(kept); - ensure_equals(kept["pinned"].size(), size_t(3)); - ensure_equals(kept["pinned"][1]["name"].asString(), std::string("Gone")); + REQUIRE(kept["pinned"].size() == size_t(3)); + CHECK(kept["pinned"][1]["name"].asString() == std::string("Gone")); } - template<> template<> - void alscriptexplorermodel_object::test<2>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: what a prim holds is kept through a relisting and an unfetched answer", "[alscriptexplorermodel]") { - set_test_name("what a prim was known to hold is kept through a listing again, and a listing that did not come leaves it"); const LLUUID chair = object(10, "Chair"); selected = { chair }; list(); - ensure("what a prim holds not known yet, a folder of it may still be opened", !model.rows(std::string()).front().known); + UNSCOPED_INFO("what a prim holds not known yet, a folder of it may still be opened"); + CHECK_FALSE(model.rows(std::string()).front().known); holds(chair, { "sit.lsl", "readme" }); - ensure("known", model.rows(std::string()).front().known); - ensure_equals(rows(), std::string("O:Chair I:sit.lsl I:readme")); + UNSCOPED_INFO("known"); + CHECK(model.rows(std::string()).front().known); + CHECK(rows() == std::string("O:Chair I:sit.lsl I:readme")); list(); - ensure_equals("kept through a listing", rows(), std::string("O:Chair I:sit.lsl I:readme")); + UNSCOPED_INFO("kept through a listing"); + CHECK(rows() == std::string("O:Chair I:sit.lsl I:readme")); holds(chair, {}, false); - ensure_equals("no answer is not an empty prim", rows(), std::string("O:Chair I:sit.lsl I:readme")); + UNSCOPED_INFO("no answer is not an empty prim"); + CHECK(rows() == std::string("O:Chair I:sit.lsl I:readme")); holds(chair, { "sit.lsl" }); - ensure_equals("an answer is", rows(), std::string("O:Chair I:sit.lsl")); + UNSCOPED_INFO("an answer is"); + CHECK(rows() == std::string("O:Chair I:sit.lsl")); } - template<> template<> - void alscriptexplorermodel_object::test<3>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: two or more empty prims besides the root fold under one row at the end", "[alscriptexplorermodel]") { - set_test_name("a linkset's prims holding nothing go under one row after the rest -- two or more, never the root -- folded until opened, which takes no drop"); const LLUUID house = object(10, "House", 5); selected = { house }; list(); @@ -274,25 +283,34 @@ namespace tut holds(id(11), { "door.lsl" }); holds(id(12), {}); holds(id(13), {}); - ensure_equals("the root, empty, stays first; the two others holding nothing go under one row, folded; one not answered stays", rows(), + UNSCOPED_INFO("the root, empty, stays first; the two others holding nothing go under one row, folded; one not answered stays"); + CHECK(rows() == std::string("O:House P:House P:House.1 I:door.lsl P:House.4 E:2+ P:House.2 P:House.3")); const std::vector all = model.rows(std::string()); const Model::Row& group = all[all.size() - 3]; - ensure("the row of them is of no prim to act on or drop into", !Model::Choice::of(group.value) && Model::primOf(group.value).isNull()); - ensure("opened, it asks only to be filled again", model.foldRow(group.value) == Model::Refold::Refill); - ensure_equals(rows(), std::string("O:House P:House P:House.1 I:door.lsl P:House.4 E:2 P:House.2 P:House.3")); - ensure("folded again", model.foldEmpties(house, true) == Model::Refold::Refill && model.foldEmpties(house, true) == Model::Refold::None); + { + INFO("the row of them is of no prim to act on or drop into"); + REQUIRE_FALSE(Model::Choice::of(group.value)); + CHECK(Model::primOf(group.value).isNull()); + } + UNSCOPED_INFO("opened, it asks only to be filled again"); + CHECK(model.foldRow(group.value) == Model::Refold::Refill); + CHECK(rows() == std::string("O:House P:House P:House.1 I:door.lsl P:House.4 E:2 P:House.2 P:House.3")); + { + INFO("folded again"); + CHECK(model.foldEmpties(house, true) == Model::Refold::Refill); + CHECK(model.foldEmpties(house, true) == Model::Refold::None); + } holds(id(14), { "light.lsl" }); holds(id(13), { "bell.lsl" }); - ensure_equals("one alone holding nothing is not put under a row", rows(), + UNSCOPED_INFO("one alone holding nothing is not put under a row"); + CHECK(rows() == std::string("O:House P:House P:House.1 I:door.lsl P:House.2 P:House.3 I:bell.lsl P:House.4 I:light.lsl")); } - template<> template<> - void alscriptexplorermodel_object::test<4>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: a filter shows matches with what holds them and no row of empty prims", "[alscriptexplorermodel]") { - set_test_name("a filter shows an item and what holds it, an object or a prim by its name with all it holds, whatever is folded, and no row of prims holding nothing"); const LLUUID house = object(10, "House", 4); const LLUUID chair = object(20, "Chair"); selected = { house, chair }; @@ -303,53 +321,76 @@ namespace tut holds(id(13), {}); holds(chair, { "sit.lsl" }); model.fold(house, false, true); - ensure_equals("folded, what the object holds is still listed, for the tree to show opened", rows(), + UNSCOPED_INFO("folded, what the object holds is still listed, for the tree to show opened"); + CHECK(rows() == std::string("O:House+ P:House I:main.lsl P:House.1 I:door.lsl I:notes E:2+ P:House.2 P:House.3 O:Chair I:sit.lsl")); - ensure_equals("an item by its name, and what holds it, unfolded", rows("DOOR"), std::string("O:House P:House.1 I:door.lsl")); - ensure_equals("a prim by its name, with all it holds", rows("house.1"), std::string("O:House P:House.1 I:door.lsl I:notes")); - ensure_equals("an object by its name, with every prim, the empty ones by name", rows("house"), + UNSCOPED_INFO("an item by its name, and what holds it, unfolded"); + CHECK(rows("DOOR") == std::string("O:House P:House.1 I:door.lsl")); + UNSCOPED_INFO("a prim by its name, with all it holds"); + CHECK(rows("house.1") == std::string("O:House P:House.1 I:door.lsl I:notes")); + UNSCOPED_INFO("an object by its name, with every prim, the empty ones by name"); + CHECK(rows("house") == std::string("O:House P:House I:main.lsl P:House.1 I:door.lsl I:notes P:House.2 P:House.3")); - ensure_equals("nothing", rows("zzz"), std::string()); + UNSCOPED_INFO("nothing"); + CHECK(rows("zzz") == std::string()); } - template<> template<> - void alscriptexplorermodel_object::test<5>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: a large linkset's prims start folded and are asked only when filtered", "[alscriptexplorermodel]") { - set_test_name("a large linkset's prims are folded when first listed, but the root and any with a script open; folded, they are not asked what they hold unless a filter looks"); const size_t count = Model::LARGE_LINKSET + 4; const LLUUID big = object(100, "Big", count); selected = { big }; open = { id(105) }; list(); std::vector asked = ask(false, false); - ensure_equals("the root and the one open", asked.size(), size_t(2)); + UNSCOPED_INFO("the root and the one open"); + REQUIRE(asked.size() == size_t(2)); const std::vector all = model.rows(std::string()); const Model::Row* one = rowNamed(all, "Big.1"); - ensure("a folded prim is listed, folded, what it holds not known", one && one->folded && !one->known); - ensure("the linkset's own row is known: its prims are", all.front().known); - ensure("which", asked[0] == id(100) && asked[1] == id(105)); - ensure("asked, not again until answered", ask(false, false).empty()); - ensure_equals("a filter looks through the rest", ask(false, true).size(), count - 2); - ensure_equals("a refetch asks them all again", ask(true, true).size(), count); + { + INFO("a folded prim is listed, folded, what it holds not known"); + REQUIRE(one); + REQUIRE(one->folded); + CHECK_FALSE(one->known); + } + UNSCOPED_INFO("the linkset's own row is known: its prims are"); + CHECK(all.front().known); + { + INFO("which"); + CHECK(asked[0] == id(100)); + CHECK(asked[1] == id(105)); + } + UNSCOPED_INFO("asked, not again until answered"); + REQUIRE(ask(false, false).empty()); + UNSCOPED_INFO("a filter looks through the rest"); + REQUIRE(ask(false, true).size() == count - 2); + UNSCOPED_INFO("a refetch asks them all again"); + REQUIRE(ask(true, true).size() == count); holds(id(100), { "core.lsl" }); - ensure("answered and current: not asked", ask(false, false).empty()); + UNSCOPED_INFO("answered and current: not asked"); + REQUIRE(ask(false, false).empty()); stale.insert(id(100)); std::vector again = ask(false, false); - ensure("answered, but changed since: asked again", again.size() == 1 && again[0] == id(100)); + { + INFO("answered, but changed since: asked again"); + REQUIRE(again.size() == 1); + CHECK(again[0] == id(100)); + } // Opened, a folded prim asks to be listed again, for what it holds. - ensure("unfolded", model.fold(id(101), true, false) == Model::Refold::Relist); + UNSCOPED_INFO("unfolded"); + CHECK(model.fold(id(101), true, false) == Model::Refold::Relist); holds(id(101), {}); list(); - ensure("through a listing again, one opened stays open", model.fold(id(101), true, false) == Model::Refold::None); - ensure("and the rest stay folded", model.fold(id(102), true, true) == Model::Refold::None); + UNSCOPED_INFO("through a listing again, one opened stays open"); + CHECK(model.fold(id(101), true, false) == Model::Refold::None); + UNSCOPED_INFO("and the rest stay folded"); + CHECK(model.fold(id(102), true, true) == Model::Refold::None); } - template<> template<> - void alscriptexplorermodel_object::test<6>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: a new item opens once listed and whether a script runs is asked once", "[alscriptexplorermodel]") { - set_test_name("a new item opens once its prim lists it, by id or by name, with its text; and a script not known to run is asked about once"); const LLUUID chair = object(10, "Chair"); selected = { chair }; list(); @@ -359,27 +400,44 @@ namespace tut contents.fetched = true; contents.items.push_back({ id(500), "old.lsl", true, false }); Model::Heard heard = feed(contents); - ensure("not listed yet, nothing opens", heard.listed && heard.opening.empty()); - ensure("the script asked whether it runs", askedRunning == std::vector{ ALScriptRef(chair, id(500)) }); + { + INFO("not listed yet, nothing opens"); + CHECK(heard.listed); + REQUIRE(heard.opening.empty()); + } + UNSCOPED_INFO("the script asked whether it runs"); + CHECK(askedRunning == std::vector{ ALScriptRef(chair, id(500)) }); index.running(ALScriptRef(chair, id(500)), true); contents.items.push_back({ id(501), "new.lsl", true, false }); heard = feed(contents); - ensure("listed, opened with its text", heard.opening.size() == 1 && heard.opening[0].ref == ALScriptRef(chair, id(501)) && - heard.opening[0].text == std::optional("default {}")); - ensure("the one known to run not asked again", askedRunning.size() == 2 && askedRunning[1].item == id(501)); + { + INFO("listed, opened with its text"); + REQUIRE(heard.opening.size() == 1); + CHECK(heard.opening[0].ref == ALScriptRef(chair, id(501))); + CHECK(heard.opening[0].text == std::optional("default {}")); + } + { + INFO("the one known to run not asked again"); + REQUIRE(askedRunning.size() == 2); + CHECK(askedRunning[1].item == id(501)); + } heard = feed(contents); - ensure("once", heard.opening.empty()); - ensure("a prim not listed is no answer", !model.contents(ALScriptContents{ id(77) }).listed); - ensure("what runs, known", model.knownRunning(ALScriptRef(chair, id(500))) == std::optional(true) && - !model.knownRunning(ALScriptRef(chair, id(501)))); + UNSCOPED_INFO("once"); + REQUIRE(heard.opening.empty()); + UNSCOPED_INFO("a prim not listed is no answer"); + CHECK_FALSE(model.contents(ALScriptContents{ id(77) }).listed); + { + INFO("what runs, known"); + CHECK(model.knownRunning(ALScriptRef(chair, id(500))) == std::optional(true)); + REQUIRE_FALSE(model.knownRunning(ALScriptRef(chair, id(501)))); + } model.forgetRunning(); - ensure("let go of for the listed prims, to be asked again", !model.knownRunning(ALScriptRef(chair, id(500)))); + UNSCOPED_INFO("let go of for the listed prims, to be asked again"); + REQUIRE_FALSE(model.knownRunning(ALScriptRef(chair, id(500)))); } - template<> template<> - void alscriptexplorermodel_object::test<7>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: chosen rows reach their prims and scripts and count each script once", "[alscriptexplorermodel]") { - set_test_name("what rows chosen reach: an object every prim, a prim itself; a script with its prim is the queue's; each script counted once"); const LLUUID house = object(10, "House", 3); selected = { house }; list(); @@ -388,47 +446,88 @@ namespace tut holds(id(12), {}); const std::vector all = model.rows(std::string()); Model::Choice whole = *Model::Choice::of(all.front().value); - ensure("an object row", !whole.isItem() && !whole.primRow && whole.prim == house); - ensure_equals("every prim of it", model.containerPrims({ whole }).size(), size_t(3)); - ensure_equals("each script once", model.scriptsReached({ whole }), 3); + { + INFO("an object row"); + CHECK_FALSE(whole.isItem()); + CHECK_FALSE(whole.primRow); + CHECK(whole.prim == house); + } + UNSCOPED_INFO("every prim of it"); + REQUIRE(model.containerPrims({ whole }).size() == size_t(3)); + UNSCOPED_INFO("each script once"); + CHECK(model.scriptsReached({ whole }) == 3); Model::Choice prim = *Model::Choice::of(rowNamed(all, "House.1")->value); Model::Choice c = *Model::Choice::of(rowNamed(all, "c.lsl")->value); Model::Choice a = *Model::Choice::of(rowNamed(all, "a.lsl")->value); - ensure("a prim row", prim.primRow && prim.prim == id(11)); + { + INFO("a prim row"); + CHECK(prim.primRow); + CHECK(prim.prim == id(11)); + } const auto prims = model.containerPrims({ prim, c, a }); - ensure("the prim itself", prims.size() == 1 && prims[0].first == id(11) && prims[0].second == "House.1"); - ensure("its script is the queue's", Model::walkedByQueue(c, prims) && !Model::walkedByQueue(a, prims)); - ensure_equals("counted once", model.scriptsReached({ prim, c, a }), 2); - ensure("a notecard chosen reaches no script", model.scriptsReached({ *Model::Choice::of(rowNamed(all, "notes")->value) }) == 0); + { + INFO("the prim itself"); + REQUIRE(prims.size() == 1); + CHECK(prims[0].first == id(11)); + CHECK(prims[0].second == "House.1"); + } + { + INFO("its script is the queue's"); + CHECK(Model::walkedByQueue(c, prims)); + CHECK_FALSE(Model::walkedByQueue(a, prims)); + } + UNSCOPED_INFO("counted once"); + CHECK(model.scriptsReached({ prim, c, a }) == 2); + UNSCOPED_INFO("a notecard chosen reaches no script"); + CHECK(model.scriptsReached({ *Model::Choice::of(rowNamed(all, "notes")->value) }) == 0); } - template<> template<> - void alscriptexplorermodel_object::test<8>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: a rename shows at once and a root's new name reaches its object's pin", "[alscriptexplorermodel]") { - set_test_name("a prim renamed here is called so at once, the root its object and its pin too; names heard change them the same way"); const LLUUID house = object(10, "House", 2); selected = { house }; model.togglePinned(house, "House"); list(); model.renamed(id(11), "Door"); - ensure_equals(model.objects().front().prims[1].name, std::string("Door")); - ensure("a prim is not its object", model.objects().front().name == "House" && !model.takePinsChanged()); + CHECK(model.objects().front().prims[1].name == std::string("Door")); + { + INFO("a prim is not its object"); + CHECK(model.objects().front().name == "House"); + CHECK_FALSE(model.takePinsChanged()); + } model.renamed(house, "Home"); - ensure("the root is", model.objects().front().name == "Home" && model.takePinsChanged() && model.pins().front().name == "Home"); - ensure("told once", !model.takePinsChanged()); - ensure("heard as it is, nothing changes", !model.rereadNames([](const LLUUID& prim) { return prim == alscriptexplorermodel_data::id(10) ? std::string("Home") : std::string(); })); - ensure("heard otherwise, it does", model.rereadNames([](const LLUUID& prim) { return prim == alscriptexplorermodel_data::id(10) ? std::string("Villa") : std::string(); })); - ensure("the pin with it", model.nameOf(house) == "Villa" && model.takePinsChanged() && model.pins().front().name == "Villa"); - ensure("a name asked once while listed", model.askName(id(11)) && !model.askName(id(11)) && !model.askName(id(99))); + { + INFO("the root is"); + CHECK(model.objects().front().name == "Home"); + CHECK(model.takePinsChanged()); + CHECK(model.pins().front().name == "Home"); + } + UNSCOPED_INFO("told once"); + CHECK_FALSE(model.takePinsChanged()); + UNSCOPED_INFO("heard as it is, nothing changes"); + CHECK_FALSE(model.rereadNames([](const LLUUID& prim) { return prim == alscriptexplorermodel_data::id(10) ? std::string("Home") : std::string(); })); + UNSCOPED_INFO("heard otherwise, it does"); + CHECK(model.rereadNames([](const LLUUID& prim) { return prim == alscriptexplorermodel_data::id(10) ? std::string("Villa") : std::string(); })); + { + INFO("the pin with it"); + CHECK(model.nameOf(house) == "Villa"); + CHECK(model.takePinsChanged()); + CHECK(model.pins().front().name == "Villa"); + } + { + INFO("a name asked once while listed"); + CHECK(model.askName(id(11))); + CHECK_FALSE(model.askName(id(11))); + CHECK_FALSE(model.askName(id(99))); + } model.renamed(id(11), "Gate"); - ensure("renamed, asked again", model.askName(id(11))); + UNSCOPED_INFO("renamed, asked again"); + CHECK(model.askName(id(11))); } - template<> template<> - void alscriptexplorermodel_object::test<9>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: folding objects and revealing prims and pinning from the rows", "[alscriptexplorermodel]") { - set_test_name("an object folded is a folded row, opened asks to be listed again, and a prim revealed unfolds what holds it; pins from the rows"); const LLUUID house = object(10, "House", 2); const LLUUID chair = object(20, "Chair"); selected = { house, chair }; @@ -436,78 +535,120 @@ namespace tut holds(id(10), { "a.lsl" }); holds(id(11), { "b.lsl" }); holds(chair, {}); - ensure("folded", model.fold(house, false) == Model::Refold::Refill && model.folded(house)); - ensure_equals(rows(), std::string("O:House+ P:House I:a.lsl P:House.1 I:b.lsl O:Chair")); - ensure("a prim revealed unfolds what holds it, and was asked what it holds", !model.unfoldTo(id(11)) && !model.folded(house)); - ensure("opened", model.fold(house, false, false) == Model::Refold::None); + { + INFO("folded"); + CHECK(model.fold(house, false) == Model::Refold::Refill); + CHECK(model.folded(house)); + } + CHECK(rows() == std::string("O:House+ P:House I:a.lsl P:House.1 I:b.lsl O:Chair")); + { + INFO("a prim revealed unfolds what holds it, and was asked what it holds"); + CHECK_FALSE(model.unfoldTo(id(11))); + CHECK_FALSE(model.folded(house)); + } + UNSCOPED_INFO("opened"); + CHECK(model.fold(house, false, false) == Model::Refold::None); model.fold(house, false, true); - ensure("opened again asks to be listed", model.fold(house, false) == Model::Refold::Relist); + UNSCOPED_INFO("opened again asks to be listed"); + CHECK(model.fold(house, false) == Model::Refold::Relist); // Pinned from the rows: every object among them, as the first is not. const std::vector all = model.rows(std::string()); model.pin({ *Model::Choice::of(all[0].value), *Model::Choice::of(rowNamed(all, "b.lsl")->value), *Model::Choice::of(rowNamed(all, "Chair")->value) }); - ensure("both pinned, each once", model.pins().size() == 2 && model.isPinned(house) && model.isPinned(chair)); + { + INFO("both pinned, each once"); + REQUIRE(model.pins().size() == 2); + CHECK(model.isPinned(house)); + CHECK(model.isPinned(chair)); + } model.pin({ *Model::Choice::of(rowNamed(all, "Chair")->value) }); - ensure("let go", model.pins().size() == 1 && !model.isPinned(chair)); + { + INFO("let go"); + REQUIRE(model.pins().size() == 1); + CHECK_FALSE(model.isPinned(chair)); + } } - template<> template<> - void alscriptexplorermodel_object::test<10>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: a prim dropped into is asked again of the region until let go of", "[alscriptexplorermodel]") { - set_test_name("a prim dropped into, whose object keeps its copy of what it held, is asked again, and of the region, until let go of"); const LLUUID house = object(10, "House", 2); selected = { house }; list(); - ensure_equals("both asked first", ask(false, false).size(), size_t(2)); + UNSCOPED_INFO("both asked first"); + REQUIRE(ask(false, false).size() == size_t(2)); holds(id(10), { "a.lsl" }); holds(id(11), {}); - ensure("known and current: nothing asked", ask(false, false).empty()); + UNSCOPED_INFO("known and current: nothing asked"); + REQUIRE(ask(false, false).empty()); model.askRegion(id(11)); - ensure("the one dropped into, though its object says current", ask(false, false) == std::vector({ id(11) })); - ensure("and of the region", model.asksRegion(id(11)) && !model.asksRegion(id(10)) && asks.back().second); + UNSCOPED_INFO("the one dropped into, though its object says current"); + CHECK(ask(false, false) == std::vector({ id(11) })); + { + INFO("and of the region"); + CHECK(model.asksRegion(id(11))); + CHECK_FALSE(model.asksRegion(id(10))); + CHECK(asks.back().second); + } holds(id(11), { "b.lsl" }); - ensure("still, for the ask a moment later", ask(false, false) == std::vector({ id(11) })); + UNSCOPED_INFO("still, for the ask a moment later"); + CHECK(ask(false, false) == std::vector({ id(11) })); holds(id(11), { "b.lsl" }); model.doneAskingRegion(); - ensure("let go of: as any other", ask(false, false).empty() && !model.asksRegion(id(11))); + { + INFO("let go of: as any other"); + REQUIRE(ask(false, false).empty()); + CHECK_FALSE(model.asksRegion(id(11))); + } } - template<> template<> - void alscriptexplorermodel_object::test<11>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: folds of an object no longer listed reset and prims are found by id", "[alscriptexplorermodel]") { - set_test_name("what was folded of an object no longer listed is let go of, and folded as at first should it come back; prims found by id"); const size_t count = Model::LARGE_LINKSET + 2; const LLUUID big = object(200, "Big", count); selected = { big }; list(); - ensure("a prim of a large linkset folded at first", model.fold(id(201), true, true) == Model::Refold::None); - ensure("opened", model.fold(id(201), true, false) == Model::Refold::Relist); - ensure("folded shut", model.fold(big, false, true) == Model::Refold::Refill); + UNSCOPED_INFO("a prim of a large linkset folded at first"); + CHECK(model.fold(id(201), true, true) == Model::Refold::None); + UNSCOPED_INFO("opened"); + CHECK(model.fold(id(201), true, false) == Model::Refold::Relist); + UNSCOPED_INFO("folded shut"); + CHECK(model.fold(big, false, true) == Model::Refold::Refill); list(); - ensure("open through a listing again", model.fold(id(201), true, false) == Model::Refold::None); - ensure("and the object shut", model.folded(big)); + UNSCOPED_INFO("open through a listing again"); + CHECK(model.fold(id(201), true, false) == Model::Refold::None); + UNSCOPED_INFO("and the object shut"); + CHECK(model.folded(big)); selected.clear(); list(); - ensure("not listed: nothing folded", !model.folded(big)); + UNSCOPED_INFO("not listed: nothing folded"); + CHECK_FALSE(model.folded(big)); selected = { big }; list(); - ensure("back: its prims folded as at first", model.fold(id(201), true, true) == Model::Refold::None); - ensure("the object open", !model.folded(big)); + UNSCOPED_INFO("back: its prims folded as at first"); + CHECK(model.fold(id(201), true, true) == Model::Refold::None); + UNSCOPED_INFO("the object open"); + CHECK_FALSE(model.folded(big)); // By id, wherever it is in the list. - ensure("a prim revealed, never asked what it holds, is to be asked", model.unfoldTo(id(205))); - ensure("unfolded to", model.fold(id(205), true, false) == Model::Refold::None); + UNSCOPED_INFO("a prim revealed, never asked what it holds, is to be asked"); + CHECK(model.unfoldTo(id(205))); + UNSCOPED_INFO("unfolded to"); + CHECK(model.fold(id(205), true, false) == Model::Refold::None); model.renamed(id(203), "Middle"); - ensure("renamed in place", rowNamed(model.rows(std::string()), "Middle") != nullptr); - ensure_equals("named by its root", model.nameOf(big), std::string("Big")); - ensure("present", model.present(big) && !model.present(id(203))); + UNSCOPED_INFO("renamed in place"); + REQUIRE(rowNamed(model.rows(std::string()), "Middle") != nullptr); + UNSCOPED_INFO("named by its root"); + CHECK(model.nameOf(big) == std::string("Big")); + { + INFO("present"); + CHECK(model.present(big)); + CHECK_FALSE(model.present(id(203))); + } } - template<> template<> - void alscriptexplorermodel_object::test<12>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: link numbers and the permissions of items and prims", "[alscriptexplorermodel]") { - set_test_name("a prim by its link number, an item by what the agent may not do with it, a prim by whether it may be changed"); const LLUUID house = object(10, "House", 3); world[house].prims[2].modify = false; const LLUUID lone = object(40, "Lone"); @@ -527,22 +668,45 @@ namespace tut const std::vector all = model.rows(std::string()); const Model::Row* hinge = rowNamed(all, "House.1"); - ensure("the second prim is link 2", hinge && hinge->kind == Model::Row::Kind::Prim && hinge->link == 2); + { + INFO("the second prim is link 2"); + REQUIRE(hinge); + REQUIRE(hinge->kind == Model::Row::Kind::Prim); + CHECK(hinge->link == 2); + } const Model::Row* latch = rowNamed(all, "House.2"); - ensure("the third, 3", latch && latch->link == 3); - ensure_equals("the root is link 1", model.linkNumber(house), 1); - ensure_equals("a prim alone is 0", model.linkNumber(lone), 0); + { + INFO("the third, 3"); + REQUIRE(latch); + CHECK(latch->link == 3); + } + UNSCOPED_INFO("the root is link 1"); + CHECK(model.linkNumber(house) == 1); + UNSCOPED_INFO("a prim alone is 0"); + CHECK(model.linkNumber(lone) == 0); const Model::Row* item = rowNamed(all, "locked.lsl"); - ensure("no modify, no copy", item && item->noModify && item->noCopy); - ensure("found by its ref", model.itemAt(ALScriptRef(id(11), id(2000))).has_value() && !model.itemAt(ALScriptRef(id(11), id(2000)))->modify); - ensure("a prim the agent may not change", !model.primModifiable(id(12)) && model.primModifiable(id(11))); - ensure("one not seen, yes", model.primModifiable(id(99))); + { + INFO("no modify, no copy"); + REQUIRE(item); + REQUIRE(item->noModify); + CHECK(item->noCopy); + } + { + INFO("found by its ref"); + REQUIRE(model.itemAt(ALScriptRef(id(11), id(2000))).has_value()); + CHECK_FALSE(model.itemAt(ALScriptRef(id(11), id(2000)))->modify); + } + { + INFO("a prim the agent may not change"); + CHECK_FALSE(model.primModifiable(id(12))); + CHECK(model.primModifiable(id(11))); + } + UNSCOPED_INFO("one not seen, yes"); + CHECK(model.primModifiable(id(99))); } - template<> template<> - void alscriptexplorermodel_object::test<13>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: a pin keeps its object's last place and region across sessions", "[alscriptexplorermodel]") { - set_test_name("a pin keeps the place its object was last seen at, and the region's name, across sessions, for one away"); const LLUUID house = object(10, "House"); world[house].position = LLVector3d(256000.0 + 10.0, 256000.0 + 20.0, 30.0); world[house].region = "Ahern"; @@ -553,23 +717,42 @@ namespace tut rows[0].prim = house; model.pin(rows); const Model::Pin* pin = model.pinOf(house); - ensure("pinned with its place", pin && pin->position && pin->position->mdV[VZ] == 30.0 && pin->region == "Ahern"); + { + INFO("pinned with its place"); + REQUIRE(pin); + REQUIRE(pin->position); + REQUIRE(pin->position->mdV[VZ] == 30.0); + CHECK(pin->region == "Ahern"); + } // Moved a little: kept as it was; far, or to another region: kept anew. world[house].position = LLVector3d(256000.0 + 12.0, 256000.0 + 20.0, 30.0); list(); - ensure("a step is no new place", !model.takePinsChanged() && model.pinOf(house)->position->mdV[VX] == 256010.0); + { + INFO("a step is no new place"); + REQUIRE_FALSE(model.takePinsChanged()); + CHECK(model.pinOf(house)->position->mdV[VX] == 256010.0); + } world[house].position = LLVector3d(256000.0 + 100.0, 256000.0 + 20.0, 30.0); world[house].region = "Morris"; list(); - ensure("far, and elsewhere: kept, and said", model.takePinsChanged() && model.pinOf(house)->region == "Morris"); + { + INFO("far, and elsewhere: kept, and said"); + REQUIRE(model.takePinsChanged()); + CHECK(model.pinOf(house)->region == "Morris"); + } // Across sessions, and away. LLSD state; model.saveState(state); Model again(index); again.readState(state); - ensure("read back", again.pinOf(house) && again.pinOf(house)->position && again.pinOf(house)->region == "Morris"); + { + INFO("read back"); + REQUIRE(again.pinOf(house)); + REQUIRE(again.pinOf(house)->position); + CHECK(again.pinOf(house)->region == "Morris"); + } world.clear(); selected.clear(); Model::Listing listing; @@ -577,13 +760,16 @@ namespace tut listing.unnamed = "(unnamed)"; again.list(listing); const std::vector all = again.rows(std::string()); - ensure("listed away, with its region", !all.empty() && !all[0].present && all[0].region == "Morris"); + { + INFO("listed away, with its region"); + REQUIRE_FALSE(all.empty()); + CHECK_FALSE(all[0].present); + CHECK(all[0].region == "Morris"); + } } - template<> template<> - void alscriptexplorermodel_object::test<14>() + TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: two items of one kind compare and the candidates list same names first", "[alscriptexplorermodel]") { - set_test_name("two scripts or two notecards compare; what one compares with is its kind elsewhere, its name first; and where each is"); const LLUUID door = object(10, "Door", 2); const LLUUID lamp = object(20, "Lamp"); selected = { door, lamp }; @@ -626,12 +812,22 @@ namespace tut prim.prim = id(11); const auto pair = Model::comparing({ here, there }); - ensure("two scripts, in their order", pair && pair->first.ref() == here.ref() && pair->second.ref() == there.ref()); - ensure("not a script and a notecard", !Model::comparing({ here, notes })); - ensure("not one", !Model::comparing({ here })); - ensure("not three", !Model::comparing({ here, there, blink })); - ensure("not a prim", !Model::comparing({ here, prim })); - ensure("not the same twice", !Model::comparing({ here, here })); + { + INFO("two scripts, in their order"); + REQUIRE(pair); + REQUIRE(pair->first.ref() == here.ref()); + CHECK(pair->second.ref() == there.ref()); + } + UNSCOPED_INFO("not a script and a notecard"); + REQUIRE_FALSE(Model::comparing({ here, notes })); + UNSCOPED_INFO("not one"); + REQUIRE_FALSE(Model::comparing({ here })); + UNSCOPED_INFO("not three"); + REQUIRE_FALSE(Model::comparing({ here, there, blink })); + UNSCOPED_INFO("not a prim"); + REQUIRE_FALSE(Model::comparing({ here, prim })); + UNSCOPED_INFO("not the same twice"); + REQUIRE_FALSE(Model::comparing({ here, here })); const std::vector others = model.comparableWith(here); std::string said; @@ -639,11 +835,16 @@ namespace tut { said += (said.empty() ? "" : " ") + model.placeOf(one) + "/" + one.name; } - ensure_equals("scripts only, its name first, not itself", said, + UNSCOPED_INFO("scripts only, its name first, not itself"); + CHECK(said == "Door" + std::string(Model::PLACE_SEPARATOR) + "Door.1/open.lsl Lamp/open.lsl Lamp/blink.lsl"); - ensure_equals("a notecard's are notecards", model.comparableWith(notes).size(), 1U); - ensure("a prim compares with nothing", model.comparableWith(prim).empty()); - ensure_equals("a root's place is its object", model.placeOf(here), std::string("Door")); - ensure_equals("a child's has its prim", model.placeOf(child), "Door" + std::string(Model::PLACE_SEPARATOR) + "Door.1"); + UNSCOPED_INFO("a notecard's are notecards"); + REQUIRE(model.comparableWith(notes).size() == 1U); + UNSCOPED_INFO("a prim compares with nothing"); + REQUIRE(model.comparableWith(prim).empty()); + UNSCOPED_INFO("a root's place is its object"); + CHECK(model.placeOf(here) == std::string("Door")); + UNSCOPED_INFO("a child's has its prim"); + CHECK(model.placeOf(child) == "Door" + std::string(Model::PLACE_SEPARATOR) + "Door.1"); } } diff --git a/indra/newview/tests/alscriptexplorertree_test.cpp b/indra/newview/tests/alscriptexplorertree_test.cpp index 0af6561178..3abfe22fc4 100644 --- a/indra/newview/tests/alscriptexplorertree_test.cpp +++ b/indra/newview/tests/alscriptexplorertree_test.cpp @@ -33,7 +33,7 @@ #include "../../llui/tests/alheadlessui_fixture.h" -#include "../test/lltut.h" +#include #include #include @@ -46,7 +46,7 @@ void LLOpenFilteredFolders::doItem(LLFolderViewItem* item) {} void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder) {} void LLSelectFirstFilteredItem::doItem(LLFolderViewItem* item) {} -namespace tut +namespace { struct alscriptexplorertree_data { @@ -78,7 +78,7 @@ namespace tut { if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } LLPanel::Params p(LLUICtrlFactory::getDefaultParams()); p.name = "explorer_tree"; @@ -171,14 +171,9 @@ namespace tut return LLSD(); } }; - typedef test_group alscriptexplorertree_group; - typedef alscriptexplorertree_group::object alscriptexplorertree_object; - tut::alscriptexplorertree_group alscriptexplorertree_instance("alscriptexplorertree"); - template<> template<> - void alscriptexplorertree_object::test<1>() + TEST_CASE_METHOD(alscriptexplorertree_data, "alscriptexplorertree: rows nest by object and prim and empty prims gather under their own row", "[alscriptexplorertree]") { - set_test_name("rows become a tree: an object at the top, a linkset's prims in it, those holding nothing under a row of their own, and each item in its prim, or in an object of one prim"); ALScriptExplorerTree& t = make(); const LLUUID house = object(10, "House", 3); const LLUUID chair = object(20, "Chair"); @@ -189,23 +184,42 @@ namespace tut holds(id(12), {}); holds(chair, { "sit.lsl", "notes" }); show(); - ensure("the objects at the top", t.parentOf(objectRow(house)).isUndefined() && t.parentOf(objectRow(chair)).isUndefined()); - ensure("a prim in its object", llsd_equals(t.parentOf(primRow(house, id(10))), objectRow(house))); - ensure("an item in its prim", llsd_equals(t.parentOf(itemRow("a.lsl")), primRow(house, id(10)))); - ensure("the prims holding nothing under their own row", llsd_equals(t.parentOf(primRow(house, id(11))), emptiesRow(house)) && - llsd_equals(t.parentOf(primRow(house, id(12))), emptiesRow(house))); - ensure("in an object of one prim, the object holds them", llsd_equals(t.parentOf(itemRow("sit.lsl")), objectRow(chair)) && - t.has(itemRow("notes"))); - ensure("each as the owner said", t.label(primRow(house, id(10))) == "House" && t.suffix(itemRow("a.lsl")) == " (running)" && - t.suffix(itemRow("notes")).empty()); - ensure("open as the rows say: the object open, the prims holding nothing folded", t.isOpen(objectRow(house)) && !t.isOpen(emptiesRow(house))); - ensure("and nothing told of it: it was the rows' doing", folds.empty()); + { + INFO("the objects at the top"); + REQUIRE(t.parentOf(objectRow(house)).isUndefined()); + REQUIRE(t.parentOf(objectRow(chair)).isUndefined()); + } + UNSCOPED_INFO("a prim in its object"); + CHECK(llsd_equals(t.parentOf(primRow(house, id(10))), objectRow(house))); + UNSCOPED_INFO("an item in its prim"); + CHECK(llsd_equals(t.parentOf(itemRow("a.lsl")), primRow(house, id(10)))); + { + INFO("the prims holding nothing under their own row"); + CHECK(llsd_equals(t.parentOf(primRow(house, id(11))), emptiesRow(house))); + CHECK(llsd_equals(t.parentOf(primRow(house, id(12))), emptiesRow(house))); + } + { + INFO("in an object of one prim, the object holds them"); + CHECK(llsd_equals(t.parentOf(itemRow("sit.lsl")), objectRow(chair))); + REQUIRE(t.has(itemRow("notes"))); + } + { + INFO("each as the owner said"); + CHECK(t.label(primRow(house, id(10))) == "House"); + CHECK(t.suffix(itemRow("a.lsl")) == " (running)"); + REQUIRE(t.suffix(itemRow("notes")).empty()); + } + { + INFO("open as the rows say: the object open, the prims holding nothing folded"); + CHECK(t.isOpen(objectRow(house))); + CHECK_FALSE(t.isOpen(emptiesRow(house))); + } + UNSCOPED_INFO("and nothing told of it: it was the rows' doing"); + REQUIRE(folds.empty()); } - template<> template<> - void alscriptexplorertree_object::test<2>() + TEST_CASE_METHOD(alscriptexplorertree_data, "alscriptexplorertree: showing again updates rows in place and drops the ones gone", "[alscriptexplorertree]") { - set_test_name("told again, a row is kept -- what is chosen stays chosen -- and changed in place; a row gone goes with what it held; a prim no longer holding nothing moves out from under that row"); ALScriptExplorerTree& t = make(); const LLUUID house = object(10, "House", 3); const LLUUID chair = object(20, "Chair"); @@ -216,30 +230,49 @@ namespace tut holds(id(12), {}); holds(chair, { "sit.lsl" }); show(); - ensure("chosen", t.choose(itemRow("a.lsl"), false) && t.chosen().size() == 1); + { + INFO("chosen"); + CHECK(t.choose(itemRow("a.lsl"), false)); + REQUIRE(t.chosen().size() == 1); + } state = "stopped"; show(); - ensure("still chosen, told again", t.chosen().size() == 1 && llsd_equals(t.chosen().front(), itemRow("a.lsl"))); - ensure("its state changed in place", t.suffix(itemRow("a.lsl")) == " (stopped)"); + { + INFO("still chosen, told again"); + REQUIRE(t.chosen().size() == 1); + CHECK(llsd_equals(t.chosen().front(), itemRow("a.lsl"))); + } + UNSCOPED_INFO("its state changed in place"); + CHECK(t.suffix(itemRow("a.lsl")) == " (stopped)"); holds(id(11), { "b.lsl" }); show(); - ensure("one alone holding nothing: no row for them", !t.has(emptiesRow(house))); - ensure("both prims in the object again", llsd_equals(t.parentOf(primRow(house, id(11))), objectRow(house)) && - llsd_equals(t.parentOf(primRow(house, id(12))), objectRow(house))); - ensure("and what they hold in them", llsd_equals(t.parentOf(itemRow("b.lsl")), primRow(house, id(11)))); + UNSCOPED_INFO("one alone holding nothing: no row for them"); + REQUIRE_FALSE(t.has(emptiesRow(house))); + { + INFO("both prims in the object again"); + CHECK(llsd_equals(t.parentOf(primRow(house, id(11))), objectRow(house))); + CHECK(llsd_equals(t.parentOf(primRow(house, id(12))), objectRow(house))); + } + UNSCOPED_INFO("and what they hold in them"); + CHECK(llsd_equals(t.parentOf(itemRow("b.lsl")), primRow(house, id(11)))); selected = { chair }; show(); - ensure("an object gone, with all it held", !t.has(objectRow(house)) && !t.has(primRow(house, id(10))) && !t.has(itemRow("a.lsl"))); - ensure("what was chosen in it let go of", t.chosen().empty()); - ensure("the rest kept", t.has(itemRow("sit.lsl"))); + { + INFO("an object gone, with all it held"); + REQUIRE_FALSE(t.has(objectRow(house))); + REQUIRE_FALSE(t.has(primRow(house, id(10)))); + REQUIRE_FALSE(t.has(itemRow("a.lsl"))); + } + UNSCOPED_INFO("what was chosen in it let go of"); + REQUIRE(t.chosen().empty()); + UNSCOPED_INFO("the rest kept"); + REQUIRE(t.has(itemRow("sit.lsl"))); } - template<> template<> - void alscriptexplorertree_object::test<3>() + TEST_CASE_METHOD(alscriptexplorertree_data, "alscriptexplorertree: a person's fold is told and kept and the rows' folds are not told", "[alscriptexplorertree]") { - set_test_name("a folder folded by a person tells the owner, and stays folded while the rows say nothing new of it; the rows folding or opening it tell nothing"); ALScriptExplorerTree& t = make(); const LLUUID house = object(10, "House", 2); selected = { house }; @@ -248,22 +281,34 @@ namespace tut holds(id(11), { "b.lsl" }); show(); t.toggle(objectRow(house)); - ensure("folded, and told", !t.isOpen(objectRow(house)) && folds.size() == 1 && folds[0].second); + { + INFO("folded, and told"); + CHECK_FALSE(t.isOpen(objectRow(house))); + REQUIRE(folds.size() == 1); + CHECK(folds[0].second); + } show("b"); - ensure("a filter's rows say it open, as they did: it stays as the person left it", !t.isOpen(objectRow(house))); + UNSCOPED_INFO("a filter's rows say it open, as they did: it stays as the person left it"); + CHECK_FALSE(t.isOpen(objectRow(house))); show(); model.fold(house, false, true); show(); - ensure("the rows fold it: nothing told", !t.isOpen(objectRow(house)) && folds.size() == 1); + { + INFO("the rows fold it: nothing told"); + CHECK_FALSE(t.isOpen(objectRow(house))); + REQUIRE(folds.size() == 1); + } model.fold(house, false, false); show(); - ensure("and open it", t.isOpen(objectRow(house)) && folds.size() == 1); + { + INFO("and open it"); + CHECK(t.isOpen(objectRow(house))); + REQUIRE(folds.size() == 1); + } } - template<> template<> - void alscriptexplorertree_object::test<4>() + TEST_CASE_METHOD(alscriptexplorertree_data, "alscriptexplorertree: choosing a shown row opens what holds it and tells the owner", "[alscriptexplorertree]") { - set_test_name("a row chosen opens what holds it, as a person would, which the owner is told of; one not shown is not chosen"); ALScriptExplorerTree& t = make(); const LLUUID house = object(10, "House", 2); selected = { house }; @@ -272,20 +317,30 @@ namespace tut holds(id(11), { "b.lsl" }); model.fold(id(11), true, true); show(); - ensure("folded as the rows say", !t.isOpen(primRow(house, id(11)))); - ensure("chosen", t.choose(itemRow("b.lsl"), false)); - ensure("what holds it opened", t.isOpen(primRow(house, id(11)))); - ensure("and the owner told, to ask what it holds", folds.size() == 1 && !folds[0].second && - llsd_equals(folds[0].first, primRow(house, id(11)))); - ensure("nothing chosen that is not a row", !t.choose(itemRow("nothing"), false) && t.chosen().size() == 1); + UNSCOPED_INFO("folded as the rows say"); + CHECK_FALSE(t.isOpen(primRow(house, id(11)))); + UNSCOPED_INFO("chosen"); + CHECK(t.choose(itemRow("b.lsl"), false)); + UNSCOPED_INFO("what holds it opened"); + CHECK(t.isOpen(primRow(house, id(11)))); + { + INFO("and the owner told, to ask what it holds"); + REQUIRE(folds.size() == 1); + CHECK_FALSE(folds[0].second); + CHECK(llsd_equals(folds[0].first, primRow(house, id(11)))); + } + { + INFO("nothing chosen that is not a row"); + CHECK_FALSE(t.choose(itemRow("nothing"), false)); + REQUIRE(t.chosen().size() == 1); + } t.chooseNone(); - ensure("none", t.chosen().empty()); + UNSCOPED_INFO("none"); + REQUIRE(t.chosen().empty()); } - template<> template<> - void alscriptexplorertree_object::test<5>() + TEST_CASE_METHOD(alscriptexplorertree_data, "alscriptexplorertree: keyboard focus goes to the folder view and escape passes through", "[alscriptexplorertree]") { - set_test_name("the keyboard given to the tree is where the folder view hears it, not the panel; and escape goes on past the panel, not taken to leave nothing with the keyboard"); ALScriptExplorerTree& t = make(); const LLUUID house = object(10, "House", 2); selected = { house }; @@ -293,22 +348,29 @@ namespace tut holds(id(10), { "a.lsl" }); holds(id(11), { "b.lsl" }); show(); - ensure("chosen, with the keyboard", t.choose(objectRow(house), true)); + UNSCOPED_INFO("chosen, with the keyboard"); + CHECK(t.choose(objectRow(house), true)); LLView* focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); - ensure("in the tree, not the panel itself", focus && focus != &t && t.hasFocus()); + { + INFO("in the tree, not the panel itself"); + REQUIRE(focus); + CHECK(focus != &t); + CHECK(t.hasFocus()); + } // What the folder view does with the arrows goes by its layout, which // a test without the viewer's fonts cannot make; F2 it takes whatever // is chosen, which says the keys reach it. - ensure("F2 is the folder view's", focus->handleKey(KEY_F2, MASK_NONE, false)); - ensure("escape not taken", !focus->handleKey(KEY_ESCAPE, MASK_NONE, false)); - ensure("the keyboard still there", t.hasFocus()); + UNSCOPED_INFO("F2 is the folder view's"); + CHECK(focus->handleKey(KEY_F2, MASK_NONE, false)); + UNSCOPED_INFO("escape not taken"); + CHECK_FALSE(focus->handleKey(KEY_ESCAPE, MASK_NONE, false)); + UNSCOPED_INFO("the keyboard still there"); + CHECK(t.hasFocus()); gFocusMgr.setKeyboardFocus(nullptr); } - template<> template<> - void alscriptexplorertree_object::test<6>() + TEST_CASE_METHOD(alscriptexplorertree_data, "alscriptexplorertree: only an item may be dragged out and the owner starts the drag", "[alscriptexplorertree]") { - set_test_name("an item may be dragged out, which the owner starts; a prim or an object may not"); ALScriptExplorerTree& t = make(); const LLUUID house = object(10, "House"); selected = { house }; @@ -324,12 +386,23 @@ namespace tut t.setHooks(std::move(hooks)); // The folder view drags only from a row that says it may move; the // press and the move themselves want a window this has none of. - ensure("chosen", t.choose(itemRow("a.lsl"), false)); + UNSCOPED_INFO("chosen"); + CHECK(t.choose(itemRow("a.lsl"), false)); LLFolderViewItem* item = t.folderView()->getCurSelectedItem(); - ensure("an item may move", item && item->isMovable()); - ensure("and the drag is the owner's", t.folderView()->startDrag() && drags == 1); - ensure("chosen", t.choose(objectRow(house), false)); - ensure("an object may not", !t.folderView()->getCurSelectedItem()->isMovable()); + { + INFO("an item may move"); + REQUIRE(item); + CHECK(item->isMovable()); + } + { + INFO("and the drag is the owner's"); + CHECK(t.folderView()->startDrag()); + CHECK(drags == 1); + } + UNSCOPED_INFO("chosen"); + CHECK(t.choose(objectRow(house), false)); + UNSCOPED_INFO("an object may not"); + CHECK_FALSE(t.folderView()->getCurSelectedItem()->isMovable()); gFocusMgr.setKeyboardFocus(nullptr); } } diff --git a/indra/newview/tests/alscriptexternaleditor_test.cpp b/indra/newview/tests/alscriptexternaleditor_test.cpp index 794e723c4c..ef5da3a5df 100644 --- a/indra/newview/tests/alscriptexternaleditor_test.cpp +++ b/indra/newview/tests/alscriptexternaleditor_test.cpp @@ -32,7 +32,7 @@ #include "fsyspath.h" -#include "../test/lltut.h" +#include #include #include @@ -88,7 +88,7 @@ namespace }; } -namespace tut +namespace { struct alscriptexternaleditor_data { @@ -117,7 +117,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } files = std::make_unique(services); unit = std::make_unique(services, studio, studio, files->unit, studio); @@ -154,81 +154,114 @@ namespace tut } }; - typedef test_group alscriptexternaleditor_group; - typedef alscriptexternaleditor_group::object alscriptexternaleditor_object; - alscriptexternaleditor_group alscriptexternaleditor_instance("alscriptexternaleditor"); - - template<> template<> - void alscriptexternaleditor_object::test<1>() + TEST_CASE_METHOD(alscriptexternaleditor_data, "alscriptexternaleditor: the copy is named for the tab and the bridge in the temp folder", "[alscriptexternaleditor]") { - set_test_name("the copy's name: the tab's without what a file system refuses, the bridge's id, the language's extension, in the temp folder"); ALScriptExternalEditor& unit = make(); Doc& a = tab("a", "x"); a.name = "myipt:?"; const std::string temp = LLFile::tmpdir(); - ensure_equals("LSL", unit.fileName(a), temp + "sl_script_myscript_" + studio.bridge + ".lsl"); + UNSCOPED_INFO("LSL"); + CHECK(unit.fileName(a) == temp + "sl_script_myscript_" + studio.bridge + ".lsl"); a.language.lua = true; a.name = "<>"; - ensure_equals("SLua, and a name of nothing but those", unit.fileName(a), temp + "sl_script_" + studio.bridge + ".luau"); + UNSCOPED_INFO("SLua, and a name of nothing but those"); + CHECK(unit.fileName(a) == temp + "sl_script_" + studio.bridge + ".luau"); } - template<> template<> - void alscriptexternaleditor_object::test<2>() + TEST_CASE_METHOD(alscriptexternaleditor_data, "alscriptexternaleditor: Edit Externally writes and watches a copy and starts the editor", "[alscriptexternaleditor]") { - set_test_name("Edit Externally writes the copy and watches it, tells the bridge and starts the editor; a file on disk as it is; a notecard not"); ALScriptExternalEditor& unit = make(); studio.bridgeThere = true; Doc& a = tab("a", "default {}"); unit.edit(a); const std::string file = unit.fileName(a); - ensure_equals("the copy", contents(file), std::string("default {}")); - ensure("watched", a.watch && a.watch->path() == file); - ensure("the log beside it", a.external->log && a.external->log->path() == file + ".log"); - ensure("the bridge told", studio.subscribed == Names{ "a" } && a.external->subscribed); - ensure("the editor started on it", studio.started == Names{ file }); - ensure_equals("what it holds, known", a.external->written, std::string("default {}")); + UNSCOPED_INFO("the copy"); + CHECK(contents(file) == std::string("default {}")); + { + INFO("watched"); + REQUIRE(a.watch); + CHECK(a.watch->path() == file); + } + { + INFO("the log beside it"); + REQUIRE(a.external->log); + CHECK(a.external->log->path() == file + ".log"); + } + { + INFO("the bridge told"); + CHECK(studio.subscribed == Names{ "a" }); + CHECK(a.external->subscribed); + } + UNSCOPED_INFO("the editor started on it"); + CHECK(studio.started == Names{ file }); + UNSCOPED_INFO("what it holds, known"); + CHECK(a.external->written == std::string("default {}")); Doc& e = tab("e", ""); unit.edit(e); - ensure_equals("an empty script is one space", contents(unit.fileName(e)), std::string(" ")); + UNSCOPED_INFO("an empty script is one space"); + CHECK(contents(unit.fileName(e)) == std::string(" ")); Doc& d = tab("d", "x"); d.file = "/somewhere/d.lsl"; unit.edit(d); - ensure("a file on disk watched where it is", - d.watch && d.watch->path() == "/somewhere/d.lsl" && studio.started.back() == "/somewhere/d.lsl on disk"); - ensure("with no log, and nothing for the bridge", !d.external->log && studio.subscribed.size() == 2); + { + INFO("a file on disk watched where it is"); + REQUIRE(d.watch); + CHECK(d.watch->path() == "/somewhere/d.lsl"); + CHECK(studio.started.back() == "/somewhere/d.lsl on disk"); + } + { + INFO("with no log, and nothing for the bridge"); + REQUIRE_FALSE(d.external->log); + REQUIRE(studio.subscribed.size() == 2); + } Doc& n = tab("n", "x"); n.notecard = true; unit.edit(n); - ensure("a notecard not", studio.started.size() == 3 && !n.watch); + { + INFO("a notecard not"); + REQUIRE(studio.started.size() == 3); + REQUIRE_FALSE(n.watch); + } } - template<> template<> - void alscriptexternaleditor_object::test<3>() + TEST_CASE_METHOD(alscriptexternaleditor_data, "alscriptexternaleditor: a save outside over an unchanged tab is taken and saved from here", "[alscriptexternaleditor]") { - set_test_name("a save outside over nothing changed here is taken, as one step, and saved from here"); ALScriptExternalEditor& unit = make(); Doc& a = tab("a", "one"); unit.edit(a); write(unit.fileName(a), "two"); unit.changed("a", unit.fileName(a)); - ensure("taken", studio.taken == Names{ "two" } && a.editor->text() == "two"); - ensure("saved from here, as the editor's", studio.saved == Names{ "a" } && a.save.external()); - ensure_equals("what the copy holds, known", a.external->written, std::string("two")); - ensure("nothing asked", !asked()); + { + INFO("taken"); + CHECK(studio.taken == Names{ "two" }); + CHECK(a.editor->text() == "two"); + } + { + INFO("saved from here, as the editor's"); + CHECK(studio.saved == Names{ "a" }); + CHECK(a.save.external()); + } + UNSCOPED_INFO("what the copy holds, known"); + CHECK(a.external->written == std::string("two")); + UNSCOPED_INFO("nothing asked"); + CHECK_FALSE(asked()); a.editor->resetDirty(); unit.changed("a", unit.fileName(a)); - ensure("the same again, with the tab saved: nothing to take or save", studio.taken.size() == 1 && studio.saved.size() == 1); + { + INFO("the same again, with the tab saved: nothing to take or save"); + REQUIRE(studio.taken.size() == 1); + REQUIRE(studio.saved.size() == 1); + } unit.changed("nobody", unit.fileName(a)); - ensure("a tab gone: nothing", studio.taken.size() == 1); + UNSCOPED_INFO("a tab gone: nothing"); + REQUIRE(studio.taken.size() == 1); } - template<> template<> - void alscriptexternaleditor_object::test<4>() + TEST_CASE_METHOD(alscriptexternaleditor_data, "alscriptexternaleditor: a save outside over changes here is held until the author takes it", "[alscriptexternaleditor]") { - set_test_name("a save outside over changes made here is held and asked about; taken when the author says so"); ALScriptExternalEditor& unit = make(); Doc& a = tab("a", "one"); unit.edit(a); @@ -236,76 +269,106 @@ namespace tut a.editor->insertText(" here"); write(unit.fileName(a), "two"); unit.changed("a", unit.fileName(a)); - ensure("not taken", studio.taken.empty() && a.editor->text() == "one here"); - ensure("held", a.external->waiting && *a.external->waiting == "two"); - ensure("and asked about", asked() && services.reports.back().failure && services.reports.back().doc == "a"); + { + INFO("not taken"); + REQUIRE(studio.taken.empty()); + CHECK(a.editor->text() == "one here"); + } + { + INFO("held"); + REQUIRE(a.external->waiting); + CHECK(*a.external->waiting == "two"); + } + { + INFO("and asked about"); + CHECK(asked()); + CHECK(services.reports.back().failure); + CHECK(services.reports.back().doc == "a"); + } unit.take(a, *a.external->waiting); - ensure("taken once said", studio.taken == Names{ "two" } && !a.external->waiting && studio.saved == Names{ "a" }); + { + INFO("taken once said"); + CHECK(studio.taken == Names{ "two" }); + REQUIRE_FALSE(a.external->waiting); + CHECK(studio.saved == Names{ "a" }); + } } - template<> template<> - void alscriptexternaleditor_object::test<5>() + TEST_CASE_METHOD(alscriptexternaleditor_data, "alscriptexternaleditor: a save with CRLF endings after one taken is taken without asking", "[alscriptexternaleditor]") { - set_test_name("a save with CRLF endings after one taken is taken, not asked about"); ALScriptExternalEditor& unit = make(); Doc& a = tab("a", "one"); unit.edit(a); write(unit.fileName(a), "a\r\nb"); unit.changed("a", unit.fileName(a)); - ensure("the first, its endings as the editor keeps them", studio.taken == Names{ "a\nb" }); + UNSCOPED_INFO("the first, its endings as the editor keeps them"); + CHECK(studio.taken == Names{ "a\nb" }); write(unit.fileName(a), "a\r\nb\r\nc"); unit.changed("a", unit.fileName(a)); - ensure("the second taken too", studio.taken == Names{ "a\nb", "a\nb\nc" } && !asked()); + { + INFO("the second taken too"); + CHECK(studio.taken == Names{ "a\nb", "a\nb\nc" }); + CHECK_FALSE(asked()); + } } - template<> template<> - void alscriptexternaleditor_object::test<6>() + TEST_CASE_METHOD(alscriptexternaleditor_data, "alscriptexternaleditor: an emptied copy is taken only if still empty a moment later", "[alscriptexternaleditor]") { - set_test_name("an emptied copy waits a moment; looked at again, taken if still empty, and left where the editor's second step came"); ALScriptExternalEditor& unit = make(); Doc& a = tab("a", "one"); unit.edit(a); write(unit.fileName(a), ""); unit.changed("a", unit.fileName(a)); - ensure("not taken at once", studio.taken.empty()); + UNSCOPED_INFO("not taken at once"); + REQUIRE(studio.taken.empty()); unit.changed("a", unit.fileName(a), true); - ensure("still empty a moment later: taken", studio.taken == Names{ "" }); + UNSCOPED_INFO("still empty a moment later: taken"); + CHECK(studio.taken == Names{ "" }); write(unit.fileName(a), "two"); unit.changed("a", unit.fileName(a)); unit.changed("a", unit.fileName(a), true); - ensure("the second step heard first: the look after takes nothing more", - studio.taken == Names{ "", "two" } && studio.saved.size() == 2); + { + INFO("the second step heard first: the look after takes nothing more"); + CHECK(studio.taken == Names{ "", "two" }); + REQUIRE(studio.saved.size() == 2); + } } - template<> template<> - void alscriptexternaleditor_object::test<7>() + TEST_CASE_METHOD(alscriptexternaleditor_data, "alscriptexternaleditor: a sync rewrites a changed copy and the compiler's words go in the log", "[alscriptexternaleditor]") { - set_test_name("after a save from here the copy is written again where it holds something else; the compiler's words go in the log"); ALScriptExternalEditor& unit = make(); Doc& a = tab("a", "one"); unit.edit(a); a.editor->setCaret(a.editor->document().end()); a.editor->insertText(" two"); unit.sync(a); - ensure_equals("written again", contents(unit.fileName(a)), std::string("one two")); - ensure_equals("and known", a.external->written, std::string("one two")); + UNSCOPED_INFO("written again"); + CHECK(contents(unit.fileName(a)) == std::string("one two")); + UNSCOPED_INFO("and known"); + CHECK(a.external->written == std::string("one two")); ALScriptCompileResult result; result.messages = { "(1, 2) : ERROR : Syntax error\x07" }; unit.log(a, result); const std::string log = contents(a.external->log->path()); - ensure("the log: when, then the words, what cannot be printed dropped", - log.find("// [when]") == 0 && log.find("Syntax error\n") != std::string::npos && log.find('\x07') == std::string::npos); + { + INFO("the log: when, then the words, what cannot be printed dropped"); + CHECK(log.find("// [when]") == 0); + REQUIRE(log.find("Syntax error\n") != std::string::npos); + REQUIRE(log.find('\x07') == std::string::npos); + } Doc& d = tab("d", "x"); d.file = "/somewhere/d.lsl"; unit.log(d, result); unit.sync(d); - ensure("a tab not held outside: nothing", !d.external->log && !d.watch); + { + INFO("a tab not held outside: nothing"); + REQUIRE_FALSE(d.external->log); + REQUIRE_FALSE(d.watch); + } } - template<> template<> - void alscriptexternaleditor_object::test<8>() + TEST_CASE_METHOD(alscriptexternaleditor_data, "alscriptexternaleditor: letting go tells the bridge and removes the watch and copy and log", "[alscriptexternaleditor]") { - set_test_name("letting go tells the bridge, and the watch, the copy and the log go"); ALScriptExternalEditor& unit = make(); studio.bridgeThere = true; Doc& a = tab("a", "one"); @@ -314,19 +377,34 @@ namespace tut unit.log(a, result); const std::string file = unit.fileName(a); const std::string log = a.external->log->path(); - ensure("both there", exists(file) && exists(log)); + { + INFO("both there"); + CHECK(exists(file)); + CHECK(exists(log)); + } a.save.fromExternal(1); unit.stop(a); - ensure("the bridge told", studio.unsubscribed == Names{ "a" } && !a.external->subscribed); - ensure("the watch gone, and the studio's copy with it", !a.watch && !exists(file)); - ensure("the log gone", !exists(log) && !a.external->log); - ensure("a save under way is no longer the editor's", !a.save.external()); + { + INFO("the bridge told"); + CHECK(studio.unsubscribed == Names{ "a" }); + CHECK_FALSE(a.external->subscribed); + } + { + INFO("the watch gone, and the studio's copy with it"); + REQUIRE_FALSE(a.watch); + CHECK_FALSE(exists(file)); + } + { + INFO("the log gone"); + CHECK_FALSE(exists(log)); + REQUIRE_FALSE(a.external->log); + } + UNSCOPED_INFO("a save under way is no longer the editor's"); + CHECK_FALSE(a.save.external()); } - template<> template<> - void alscriptexternaleditor_object::test<9>() + TEST_CASE_METHOD(alscriptexternaleditor_data, "alscriptexternaleditor: keeping the tab's text over a held save lets it go and says so", "[alscriptexternaleditor]") { - set_test_name("a save outside held over changes made here, kept from when the author says so: let go, the tab's text standing, and said"); ALScriptExternalEditor& unit = make(); Doc& a = tab("a", "one"); unit.edit(a); @@ -334,9 +412,22 @@ namespace tut a.editor->insertText(" here"); write(unit.fileName(a), "two"); unit.changed("a", unit.fileName(a)); - ensure("held", a.external->waiting && *a.external->waiting == "two"); + { + INFO("held"); + REQUIRE(a.external->waiting); + CHECK(*a.external->waiting == "two"); + } unit.keep(a); - ensure("let go, the tab's text standing", !a.external->waiting && studio.taken.empty() && a.editor->text() == "one here"); - ensure("said", !services.statuses.empty() && services.statuses.back().find("ExternalKept") == 0); + { + INFO("let go, the tab's text standing"); + REQUIRE_FALSE(a.external->waiting); + REQUIRE(studio.taken.empty()); + CHECK(a.editor->text() == "one here"); + } + { + INFO("said"); + REQUIRE_FALSE(services.statuses.empty()); + CHECK(services.statuses.back().find("ExternalKept") == 0); + } } } diff --git a/indra/newview/tests/alscriptinspectorpane_test.cpp b/indra/newview/tests/alscriptinspectorpane_test.cpp index cbee6c51f4..a968d8fea5 100644 --- a/indra/newview/tests/alscriptinspectorpane_test.cpp +++ b/indra/newview/tests/alscriptinspectorpane_test.cpp @@ -33,7 +33,7 @@ #include "altextview.h" #include "llfocusmgr.h" -#include "../test/lltut.h" +#include #include @@ -70,7 +70,7 @@ namespace } } -namespace tut +namespace { struct alscriptinspectorpane_data { @@ -99,7 +99,7 @@ namespace tut ALScriptInspectorPane* found = window.find("inspector_pane"); if (!found) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } return found; } @@ -123,14 +123,8 @@ namespace tut std::string shown() { return pane()->view()->document().text(); } }; - typedef test_group alscriptinspectorpane_group; - typedef alscriptinspectorpane_group::object alscriptinspectorpane_object; - alscriptinspectorpane_group alscriptinspectorpane_instance("alscriptinspectorpane"); - - template<> template<> - void alscriptinspectorpane_object::test<1>() + TEST_CASE_METHOD(alscriptinspectorpane_data, "alscriptinspectorpane: a hover shows its declaration as a link and its type as code and page", "[alscriptinspectorpane]") { - set_test_name("a name's declaration, where it is declared as a link there, what is expected, its type as code, its words and page"); ALScriptInspectorPane* inspector = pane(); Doc& doc = tab("a"); ALScriptAnalysis::Result result = hover("integer count"); @@ -142,7 +136,8 @@ namespace tut result.hover.documentation = "How many."; result.hover.link = "https://example.com/count"; inspector->inspected(doc, result, ALTextPos(0, 8)); - ensure_equals("said", shown(), + UNSCOPED_INFO("said"); + CHECK(shown() == std::string("integer count\nDeclared on line 1.\nExpected here: float\n\ninteger\n count\n\nHow many.\n" "https://example.com/count")); const std::vector& links = inspector->view()->substitutions(); @@ -153,18 +148,41 @@ namespace tut to = link.range.begin == ALTextPos(1, 0) ? &link : to; url = link.range.begin == ALTextPos(8, 0) ? &link : url; } - ensure("the declaration's line a link there", to && to->link && to->tooltip == "Go to the declaration"); - ensure("to the line", to->value["line"].asInteger() == 0 && to->value["column"].asInteger() == 8); - ensure("in the script", to->value["path"].asString().empty()); - ensure("the page a link", url && url->link); + { + INFO("the declaration's line a link there"); + REQUIRE(to); + REQUIRE(to->link); + CHECK(to->tooltip == "Go to the declaration"); + } + { + INFO("to the line"); + REQUIRE(to->value["line"].asInteger() == 0); + CHECK(to->value["column"].asInteger() == 8); + } + UNSCOPED_INFO("in the script"); + REQUIRE(to->value["path"].asString().empty()); + { + INFO("the page a link"); + REQUIRE(url); + CHECK(url->link); + } std::set styled; for (const ALTextView::Style& style : inspector->view()->styles()) { styled.insert(style.range.begin.line); } - ensure("the declaration as code", styled.count(0) == 1); - ensure("the type as code", styled.count(4) == 1 && styled.count(5) == 1); - ensure("the words not", styled.count(7) == 0 && styled.count(2) == 0); + UNSCOPED_INFO("the declaration as code"); + REQUIRE(styled.count(0) == 1); + { + INFO("the type as code"); + REQUIRE(styled.count(4) == 1); + REQUIRE(styled.count(5) == 1); + } + { + INFO("the words not"); + REQUIRE(styled.count(7) == 0); + REQUIRE(styled.count(2) == 0); + } // Followed: the window's. window.floater->setVisible(true); @@ -174,57 +192,64 @@ namespace tut view->handleMouseDown(4, y, MASK_NONE); view->handleMouseUp(4, y, MASK_NONE); } - ensure("followed", told().went.size() == 1 && told().went[0]["line"].asInteger() == 0); + { + INFO("followed"); + REQUIRE(told().went.size() == 1); + CHECK(told().went[0]["line"].asInteger() == 0); + } } - template<> template<> - void alscriptinspectorpane_object::test<2>() + TEST_CASE_METHOD(alscriptinspectorpane_data, "alscriptinspectorpane: an answer for another tab or a place the caret has left is not shown", "[alscriptinspectorpane]") { - set_test_name("an answer for another tab, or a place the caret has left, not shown"); ALScriptInspectorPane* inspector = pane(); Doc& doc = tab("a"); Doc& other = tab("b"); inspector->show("before"); inspector->inspected(other, hover("x"), ALTextPos(0, 8)); - ensure_equals("another tab's", shown(), std::string("before")); + UNSCOPED_INFO("another tab's"); + CHECK(shown() == std::string("before")); inspector->inspected(doc, hover("x"), ALTextPos(1, 0)); - ensure_equals("the caret gone", shown(), std::string("before")); + UNSCOPED_INFO("the caret gone"); + CHECK(shown() == std::string("before")); inspector->inspected(doc, hover("x"), ALTextPos(0, 8)); - ensure_equals("this one", shown(), std::string("x")); + UNSCOPED_INFO("this one"); + CHECK(shown() == std::string("x")); inspector->forget(); - ensure_equals("forgotten", shown(), std::string()); + UNSCOPED_INFO("forgotten"); + CHECK(shown() == std::string()); } - template<> template<> - void alscriptinspectorpane_object::test<3>() + TEST_CASE_METHOD(alscriptinspectorpane_data, "alscriptinspectorpane: a built-in the analyzer has no words for shows the definitions' words", "[alscriptinspectorpane]") { - set_test_name("a word of the language's the analyzer has no words for: the definitions', and its page"); ALScriptInspectorPane* inspector = pane(); Doc& doc = tab("a", "default { state_entry() { llSay(0, \"hi\"); } }\n"); doc.editor->setCaret(ALTextPos(0, 28)); inspector->inspected(doc, hover("llSay(integer channel, string msg)"), ALTextPos(0, 8)); - ensure_equals("the definitions' words and page", shown(), + UNSCOPED_INFO("the definitions' words and page"); + CHECK(shown() == std::string("llSay(integer channel, string msg)\n\nSays it.\nhttps://wiki.example/llSay")); ALScriptAnalysis::Result own = hover("llSay(integer channel, string msg)"); own.hover.documentation = "The analyzer's."; inspector->inspected(doc, own, ALTextPos(0, 8)); - ensure_equals("the analyzer's first", shown(), std::string("llSay(integer channel, string msg)\n\nThe analyzer's.")); + UNSCOPED_INFO("the analyzer's first"); + CHECK(shown() == std::string("llSay(integer channel, string msg)\n\nThe analyzer's.")); own.hover.link = "https://mine.example"; inspector->inspected(doc, own, ALTextPos(0, 8)); - ensure("its own page", shown().find("\nhttps://mine.example") != std::string::npos); + UNSCOPED_INFO("its own page"); + REQUIRE(shown().find("\nhttps://mine.example") != std::string::npos); own.hover.documentation.clear(); inspector->inspected(doc, own, ALTextPos(0, 8)); - ensure_equals("the definitions' words, its own page", shown(), + UNSCOPED_INFO("the definitions' words, its own page"); + CHECK(shown() == std::string("llSay(integer channel, string msg)\n\nSays it.\nhttps://mine.example")); doc.editor->setCaret(ALTextPos(0, 0)); inspector->inspected(doc, hover("default"), ALTextPos(0, 8)); - ensure_equals("a word the definitions have not", shown(), std::string("default")); + UNSCOPED_INFO("a word the definitions have not"); + CHECK(shown() == std::string("default")); } - template<> template<> - void alscriptinspectorpane_object::test<4>() + TEST_CASE_METHOD(alscriptinspectorpane_data, "alscriptinspectorpane: a name declared in an include is said to be there and linked there", "[alscriptinspectorpane]") { - set_test_name("declared in an include, through the expansion: said in it, and linked there"); ALScriptInspectorPane* inspector = pane(); Doc& doc = tab("a"); told().expanded = true; @@ -242,35 +267,41 @@ namespace tut result.hover.definitionLine = 0; result.hover.definitionColumn = 8; inspector->inspected(doc, result, ALTextPos(0, 8)); - ensure_equals("in the include", shown(), std::string("integer count\nDeclared in inc.lsl on line 5.")); + UNSCOPED_INFO("in the include"); + CHECK(shown() == std::string("integer count\nDeclared in inc.lsl on line 5.")); const ALTextView::Substitution& to = inspector->view()->substitutions().back(); - ensure("linked there", to.value["path"].asString() == "disk:/inc.lsl" && to.value["line"].asInteger() == 4); + { + INFO("linked there"); + CHECK(to.value["path"].asString() == "disk:/inc.lsl"); + CHECK(to.value["line"].asInteger() == 4); + } result.hover.definitionLine = 3; inspector->inspected(doc, result, ALTextPos(0, 8)); - ensure_equals("from nothing of the source: not said", shown(), std::string("integer count")); + UNSCOPED_INFO("from nothing of the source: not said"); + CHECK(shown() == std::string("integer count")); } - template<> template<> - void alscriptinspectorpane_object::test<5>() + TEST_CASE_METHOD(alscriptinspectorpane_data, "alscriptinspectorpane: the squiggles under the caret are listed under the hover or alone", "[alscriptinspectorpane]") { - set_test_name("what is squiggled where the caret is, each with what it says, under the name or alone"); ALScriptInspectorPane* inspector = pane(); Doc& doc = tab("a"); doc.editor->setDecorations({ squiggle(0, 8, 13, "Unused."), squiggle(0, 0, 13, "Twice."), squiggle(0, 8, 13, ""), squiggle(0, 8, 13, "Lit.", ALCodeEditor::Decoration::Style::Background), squiggle(1, 0, 5, "Elsewhere.") }); - ensure_equals("each", inspector->problemsAt(doc, ALTextPos(0, 9)), std::string("Problem: Unused.\nProblem: Twice.")); - ensure_equals("none", inspector->problemsAt(doc, ALTextPos(2, 0)), std::string()); + UNSCOPED_INFO("each"); + CHECK(inspector->problemsAt(doc, ALTextPos(0, 9)) == std::string("Problem: Unused.\nProblem: Twice.")); + UNSCOPED_INFO("none"); + CHECK(inspector->problemsAt(doc, ALTextPos(2, 0)) == std::string()); inspector->inspected(doc, hover("integer count"), ALTextPos(0, 8)); - ensure_equals("under the name", shown(), std::string("integer count\n\nProblem: Unused.\nProblem: Twice.")); + UNSCOPED_INFO("under the name"); + CHECK(shown() == std::string("integer count\n\nProblem: Unused.\nProblem: Twice.")); inspector->inspected(doc, ALScriptAnalysis::Result(), ALTextPos(0, 8)); - ensure_equals("alone", shown(), std::string("Problem: Unused.\nProblem: Twice.")); + UNSCOPED_INFO("alone"); + CHECK(shown() == std::string("Problem: Unused.\nProblem: Twice.")); } - template<> template<> - void alscriptinspectorpane_object::test<6>() + TEST_CASE_METHOD(alscriptinspectorpane_data, "alscriptinspectorpane: a name from a required module is said to be in its file and linked there", "[alscriptinspectorpane]") { - set_test_name("declared in a module the script requires, which the analyzers read apart: said in its file, and linked there"); ALScriptInspectorPane* inspector = pane(); Doc& doc = tab("a", "local util = require(\"util\")\nprint(util.twice(2))\n"); told().expanded = true; @@ -296,16 +327,23 @@ namespace tut result.hover.definitionColumn = 11; result.hover.definitionFile = "disk:/lib/util.luau"; inspector->inspected(doc, result, ALTextPos(0, 8)); - ensure_equals("in the module", shown(), std::string("function M.twice(n: number): number\nDeclared in util.luau on line 4.")); + UNSCOPED_INFO("in the module"); + CHECK(shown() == std::string("function M.twice(n: number): number\nDeclared in util.luau on line 4.")); const ALTextView::Substitution& to = inspector->view()->substitutions().back(); - ensure("linked there", to.value["path"].asString() == "disk:/lib/util.luau" && to.value["line"].asInteger() == 3 && - to.value["column"].asInteger() == 11); + { + INFO("linked there"); + CHECK(to.value["path"].asString() == "disk:/lib/util.luau"); + CHECK(to.value["line"].asInteger() == 3); + CHECK(to.value["column"].asInteger() == 11); + } result.hover.definitionFile = "disk:/lib/gone.luau"; inspector->inspected(doc, result, ALTextPos(0, 8)); - ensure_equals("a module the expansion has not: not said", shown(), std::string("function M.twice(n: number): number")); + UNSCOPED_INFO("a module the expansion has not: not said"); + CHECK(shown() == std::string("function M.twice(n: number): number")); result.hover.definitionFile = "disk:/lib/util.luau"; told().expanded = false; inspector->inspected(doc, result, ALTextPos(0, 8)); - ensure_equals("nor where the script is not expanded", shown(), std::string("function M.twice(n: number): number")); + UNSCOPED_INFO("nor where the script is not expanded"); + CHECK(shown() == std::string("function M.twice(n: number): number")); } } diff --git a/indra/newview/tests/alscriptitemdrop_test.cpp b/indra/newview/tests/alscriptitemdrop_test.cpp index 605164b940..8b063e1b21 100644 --- a/indra/newview/tests/alscriptitemdrop_test.cpp +++ b/indra/newview/tests/alscriptitemdrop_test.cpp @@ -34,11 +34,11 @@ #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include #include -namespace tut +namespace { struct alscriptitemdrop_data { @@ -53,7 +53,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } LLUUID object, item; object.generate(); @@ -103,47 +103,58 @@ namespace tut return accept; } }; - typedef test_group alscriptitemdrop_group; - typedef alscriptitemdrop_group::object alscriptitemdrop_object; - alscriptitemdrop_group alscriptitemdrop_instance("ALScriptItemDrop"); - template<> template<> - void alscriptitemdrop_object::test<1>() + TEST_CASE_METHOD(alscriptitemdrop_data, "ALScriptItemDrop: a dropped item's name goes in escaped and with Shift its key if seen", "[ALScriptItemDrop]") { - set_test_name("its name goes in where it lands, as a string, its quotes escaped; with Shift its key, where it may be seen"); - ensure_equals("quoted and escaped", ALScriptItemDrop::literal("a \"b\" \\ c"), std::string("\"a \\\"b\\\" \\\\ c\"")); + UNSCOPED_INFO("quoted and escaped"); + CHECK(ALScriptItemDrop::literal("a \"b\" \\ c") == std::string("\"a \\\"b\\\" \\\\ c\"")); make("x;"); const auto wood = item("Wood \"oak\""); std::string tip; - ensure("offered", drop(wood, false, MASK_NONE, &tip) == ACCEPT_YES_SINGLE); - ensure("the tip says what goes in", tip.find("\"Wood \\\"oak\\\"\"") != std::string::npos); - ensure("nothing yet", doc->editor->text() == "x;"); + UNSCOPED_INFO("offered"); + CHECK(drop(wood, false, MASK_NONE, &tip) == ACCEPT_YES_SINGLE); + UNSCOPED_INFO("the tip says what goes in"); + REQUIRE(tip.find("\"Wood \\\"oak\\\"\"") != std::string::npos); + UNSCOPED_INFO("nothing yet"); + CHECK(doc->editor->text() == "x;"); drop(wood, true); - ensure_equals("in where it lands", doc->editor->text(), std::string("\"Wood \\\"oak\\\"\"x;")); - ensure("the caret after it", doc->editor->caret() == ALTextPos(0, 14)); + UNSCOPED_INFO("in where it lands"); + CHECK(doc->editor->text() == std::string("\"Wood \\\"oak\\\"\"x;")); + UNSCOPED_INFO("the caret after it"); + CHECK(doc->editor->caret() == ALTextPos(0, 14)); doc->editor->setText("x;"); - ensure("its key not to be seen: refused", drop(wood, false, MASK_SHIFT, &tip) == ACCEPT_NO && !tip.empty()); + { + INFO("its key not to be seen: refused"); + CHECK(drop(wood, false, MASK_SHIFT, &tip) == ACCEPT_NO); + REQUIRE_FALSE(tip.empty()); + } shown.generate(); drop(wood, true, MASK_SHIFT); - ensure_equals("its key", doc->editor->text(), "\"" + shown.asString() + "\"x;"); + UNSCOPED_INFO("its key"); + CHECK(doc->editor->text() == "\"" + shown.asString() + "\"x;"); } - template<> template<> - void alscriptitemdrop_object::test<2>() + TEST_CASE_METHOD(alscriptitemdrop_data, "ALScriptItemDrop: a read-only script refuses a drop and folders and notecards go elsewhere", "[ALScriptItemDrop]") { - set_test_name("a script that may not be changed refuses it; a folder, and a notecard, are left to someone else"); make("x;"); const auto wood = item("Wood"); doc->modifiable = false; std::string tip; - ensure("refused, and said why", drop(wood, true, MASK_NONE, &tip) == ACCEPT_NO && !tip.empty() && doc->editor->text() == "x;"); + { + INFO("refused, and said why"); + CHECK(drop(wood, true, MASK_NONE, &tip) == ACCEPT_NO); + REQUIRE_FALSE(tip.empty()); + CHECK(doc->editor->text() == "x;"); + } doc->modifiable = true; bool taken = true; drop(wood, false, MASK_NONE, nullptr, DAD_CATEGORY, &taken); - ensure("a folder: not taken", !taken); + UNSCOPED_INFO("a folder: not taken"); + CHECK_FALSE(taken); doc->notecard = true; drop(wood, false, MASK_NONE, nullptr, DAD_TEXTURE, &taken); - ensure("a notecard: not taken", !taken); + UNSCOPED_INFO("a notecard: not taken"); + CHECK_FALSE(taken); } } diff --git a/indra/newview/tests/alscriptjobqueue_test.cpp b/indra/newview/tests/alscriptjobqueue_test.cpp index b604706826..fc0dc478cc 100644 --- a/indra/newview/tests/alscriptjobqueue_test.cpp +++ b/indra/newview/tests/alscriptjobqueue_test.cpp @@ -26,9 +26,9 @@ #include "../alscriptjobqueue.h" -#include "../test/lltut.h" +#include -namespace tut +namespace { struct alscriptjobqueue_data { @@ -47,130 +47,176 @@ namespace tut } }; - typedef test_group alscriptjobqueue_group; - typedef alscriptjobqueue_group::object alscriptjobqueue_object; - alscriptjobqueue_group alscriptjobqueue_instance("alscriptjobqueue"); - - template<> template<> - void alscriptjobqueue_object::test<1>() + TEST_CASE_METHOD(alscriptjobqueue_data, "alscriptjobqueue: the latest job of each key waits and they run by rank then by age", "[alscriptjobqueue]") { - set_test_name("only the latest of each kind about each script waits, and the lowest rank goes first, the oldest first among equals"); queue.add("back/check", "back", 1, 3, "back-check-1"); queue.add("front/check", "front", 1, 1, "front-check-1"); queue.add("front/check", "front", 2, 1, "front-check-2"); queue.add("front/hover", "front", 2, 0, "front-hover"); queue.add("front/weigh", "front", 2, 2, "front-weigh"); queue.add("other/check", "other", 4, 3, "other-check"); - ensure_equals("one of each key", queue.waiting(), size_t(5)); - ensure_equals("by rank, then by when", drained(), std::string("front-hover front-check-2 front-weigh back-check-1 other-check")); - ensure_equals("nothing passed over", queue.passedOver(), size_t(0)); + UNSCOPED_INFO("one of each key"); + CHECK(queue.waiting() == size_t(5)); + UNSCOPED_INFO("by rank, then by when"); + CHECK(drained() == std::string("front-hover front-check-2 front-weigh back-check-1 other-check")); + UNSCOPED_INFO("nothing passed over"); + CHECK(queue.passedOver() == size_t(0)); } - template<> template<> - void alscriptjobqueue_object::test<2>() + TEST_CASE_METHOD(alscriptjobqueue_data, "alscriptjobqueue: a question about a stale text is passed over but not across a reopen", "[alscriptjobqueue]") { - set_test_name("a question about a text older than one asked about since is passed over; one asked before a newer text of a script opened again is not"); queue.add("a/hover", "a", 5, 0, "hover-5"); queue.add("a/check", "a", 6, 1, "check-6"); - ensure_equals("the hover of the older text dropped as it is reached", drained(), std::string("check-6")); - ensure_equals("and counted", queue.passedOver(), size_t(1)); + UNSCOPED_INFO("the hover of the older text dropped as it is reached"); + CHECK(drained() == std::string("check-6")); + UNSCOPED_INFO("and counted"); + CHECK(queue.passedOver() == size_t(1)); // A script closed and opened again starts its versions over: what // its old text left waiting does not make the new one's stale. queue.add("b/hover", "b", 40, 0, "old-hover-40"); queue.add("b/check", "b", 1, 1, "new-check-1"); - ensure_equals("both run", drained(), std::string("old-hover-40 new-check-1")); + UNSCOPED_INFO("both run"); + CHECK(drained() == std::string("old-hover-40 new-check-1")); queue.add("c/check", "c", 1, 1, "c-check"); queue.add("d/check", "d", 1, 1, "d-check"); queue.forget("c"); - ensure_equals("a script let go of: nothing it asked runs", drained(), std::string("d-check")); + UNSCOPED_INFO("a script let go of: nothing it asked runs"); + CHECK(drained() == std::string("d-check")); } - template<> template<> - void alscriptjobqueue_object::test<3>() + TEST_CASE_METHOD(alscriptjobqueue_data, "alscriptjobqueue: the running job is superseded only by its own key or a newer text", "[alscriptjobqueue]") { - set_test_name("the running job is told its answer is unwanted by its own key asked again or a newer text of its script, and by nothing else"); queue.add("a/check", "a", 3, 1, "check-3"); - ensure("taken", queue.take().has_value()); - ensure("nothing asked since", !queue.superseded()); - ensure("another script's question leaves it be", !queue.add("b/check", "b", 9, 1, "b-check")); - ensure("another kind, the same text, leaves it be", !queue.add("a/hover", "a", 3, 0, "hover-3")); - ensure("an older text's leaves it be", !queue.add("a/signature", "a", 2, 0, "signature-2")); - ensure("not yet", !queue.superseded()); - ensure("its own key asked again stops it", queue.add("a/check", "a", 3, 1, "check-3-again")); - ensure("unwanted", queue.superseded()); - ensure("said once", !queue.add("a/check", "a", 4, 1, "check-4")); + UNSCOPED_INFO("taken"); + REQUIRE(queue.take().has_value()); + UNSCOPED_INFO("nothing asked since"); + CHECK_FALSE(queue.superseded()); + UNSCOPED_INFO("another script's question leaves it be"); + CHECK_FALSE(queue.add("b/check", "b", 9, 1, "b-check")); + UNSCOPED_INFO("another kind, the same text, leaves it be"); + CHECK_FALSE(queue.add("a/hover", "a", 3, 0, "hover-3")); + UNSCOPED_INFO("an older text's leaves it be"); + CHECK_FALSE(queue.add("a/signature", "a", 2, 0, "signature-2")); + UNSCOPED_INFO("not yet"); + CHECK_FALSE(queue.superseded()); + UNSCOPED_INFO("its own key asked again stops it"); + CHECK(queue.add("a/check", "a", 3, 1, "check-3-again")); + UNSCOPED_INFO("unwanted"); + CHECK(queue.superseded()); + UNSCOPED_INFO("said once"); + CHECK_FALSE(queue.add("a/check", "a", 4, 1, "check-4")); queue.finished(); - ensure("done with", !queue.superseded()); + UNSCOPED_INFO("done with"); + CHECK_FALSE(queue.superseded()); queue.add("x/hover", "x", 1, 0, "x-hover"); - ensure("taken", queue.take().has_value()); - ensure("a newer text of its script stops it", queue.add("x/check", "x", 2, 1, "x-check")); + UNSCOPED_INFO("taken"); + REQUIRE(queue.take().has_value()); + UNSCOPED_INFO("a newer text of its script stops it"); + CHECK(queue.add("x/check", "x", 2, 1, "x-check")); queue.finished(); } - template<> template<> - void alscriptjobqueue_object::test<4>() + TEST_CASE_METHOD(alscriptjobqueue_data, "alscriptjobqueue: a yielding job stops for a rank 0 question and runs after it", "[alscriptjobqueue]") { - set_test_name("a job that yields is stopped by a question of the lowest rank, waits again behind it and runs after; one that does not yield runs on"); queue.add("back/check", "back", 1, 4, "back-check", true); - ensure("taken", queue.take().has_value()); - ensure("a check of the front tab leaves it be", !queue.add("front/check", "front", 1, 1, "front-check")); - ensure("a question of the front tab stops it", queue.add("front/hover", "front", 1, 0, "front-hover")); - ensure("as it yields", queue.yielded()); - ensure("its answer wanted still", !queue.superseded()); - ensure("said once", !queue.add("front/signature", "front", 1, 0, "front-signature")); + UNSCOPED_INFO("taken"); + REQUIRE(queue.take().has_value()); + UNSCOPED_INFO("a check of the front tab leaves it be"); + CHECK_FALSE(queue.add("front/check", "front", 1, 1, "front-check")); + UNSCOPED_INFO("a question of the front tab stops it"); + CHECK(queue.add("front/hover", "front", 1, 0, "front-hover")); + UNSCOPED_INFO("as it yields"); + CHECK(queue.yielded()); + UNSCOPED_INFO("its answer wanted still"); + CHECK_FALSE(queue.superseded()); + UNSCOPED_INFO("said once"); + CHECK_FALSE(queue.add("front/signature", "front", 1, 0, "front-signature")); queue.requeue("back-check"); queue.finished(); - ensure_equals("it runs after what it yielded to", drained(), std::string("front-hover front-signature front-check back-check")); + UNSCOPED_INFO("it runs after what it yielded to"); + CHECK(drained() == std::string("front-hover front-signature front-check back-check")); // Asked again while it ran: the newer stands for it. queue.add("back/check", "back", 1, 4, "back-check-1", true); - ensure("taken", queue.take().has_value()); - ensure("stopped", queue.add("front/hover", "front", 2, 0, "front-hover-2")); + UNSCOPED_INFO("taken"); + REQUIRE(queue.take().has_value()); + UNSCOPED_INFO("stopped"); + CHECK(queue.add("front/hover", "front", 2, 0, "front-hover-2")); queue.add("back/check", "back", 2, 4, "back-check-2", true); queue.requeue("back-check-1"); queue.finished(); - ensure_equals("the newer alone", drained(), std::string("front-hover-2 back-check-2")); + UNSCOPED_INFO("the newer alone"); + CHECK(drained() == std::string("front-hover-2 back-check-2")); // One that does not yield runs on. queue.add("back/weigh", "back", 3, 3, "back-weigh"); - ensure("taken", queue.take().has_value()); - ensure("left be", !queue.add("front/hover", "front", 3, 0, "front-hover-3") && !queue.yielded()); + UNSCOPED_INFO("taken"); + REQUIRE(queue.take().has_value()); + { + INFO("left be"); + CHECK_FALSE(queue.add("front/hover", "front", 3, 0, "front-hover-3")); + CHECK_FALSE(queue.yielded()); + } queue.finished(); drained(); } - template<> template<> - void alscriptjobqueue_object::test<5>() + TEST_CASE_METHOD(alscriptjobqueue_data, "alscriptjobqueue: a yielded job keeps its turn and one forgotten while running is dropped", "[alscriptjobqueue]") { - set_test_name("a job that yielded waits again in the turn it was asked at, and runs through the next time; one let go of as it runs is unwanted and waits no more"); queue.add("back/check", "back", 1, 4, "back-check", true); - ensure("taken", queue.take().has_value()); + UNSCOPED_INFO("taken"); + REQUIRE(queue.take().has_value()); queue.add("other/check", "other", 1, 4, "other-check", true); - ensure("stopped by a question of the front tab", queue.add("front/hover", "front", 1, 0, "front-hover") && queue.yielded()); + { + INFO("stopped by a question of the front tab"); + CHECK(queue.add("front/hover", "front", 1, 0, "front-hover")); + CHECK(queue.yielded()); + } queue.requeue("back-check"); queue.finished(); auto next = queue.take(); - ensure("the question first", next && next->second == "front-hover"); + { + INFO("the question first"); + REQUIRE(next); + CHECK(next->second == "front-hover"); + } queue.finished(); next = queue.take(); - ensure("then it, ahead of what was asked after it", next && next->second == "back-check"); - ensure("not stopped again", !queue.add("front/hover", "front", 1, 0, "front-hover-again") && !queue.yielded()); - ensure("its answer wanted", !queue.superseded()); + { + INFO("then it, ahead of what was asked after it"); + REQUIRE(next); + CHECK(next->second == "back-check"); + } + { + INFO("not stopped again"); + CHECK_FALSE(queue.add("front/hover", "front", 1, 0, "front-hover-again")); + CHECK_FALSE(queue.yielded()); + } + UNSCOPED_INFO("its answer wanted"); + CHECK_FALSE(queue.superseded()); queue.finished(); - ensure_equals("the rest after", drained(), std::string("front-hover-again other-check")); + UNSCOPED_INFO("the rest after"); + CHECK(drained() == std::string("front-hover-again other-check")); // Let go of while it runs: unwanted, said once, and not put back // though it was stopped as it yielded. queue.add("gone/check", "gone", 1, 4, "gone-check", true); - ensure("taken", queue.take().has_value()); + UNSCOPED_INFO("taken"); + REQUIRE(queue.take().has_value()); queue.add("gone/hover", "gone", 1, 0, "gone-hover"); - ensure("yielded", queue.yielded()); - ensure("let go of: to be stopped", queue.forget("gone")); - ensure("unwanted", queue.superseded()); - ensure("said once", !queue.forget("gone")); + UNSCOPED_INFO("yielded"); + CHECK(queue.yielded()); + UNSCOPED_INFO("let go of: to be stopped"); + CHECK(queue.forget("gone")); + UNSCOPED_INFO("unwanted"); + CHECK(queue.superseded()); + UNSCOPED_INFO("said once"); + CHECK_FALSE(queue.forget("gone")); queue.requeue("gone-check"); queue.finished(); - ensure_equals("nothing of it waits", queue.waiting(), size_t(0)); - ensure("another script's running job left be", !queue.forget("other")); + UNSCOPED_INFO("nothing of it waits"); + CHECK(queue.waiting() == size_t(0)); + UNSCOPED_INFO("another script's running job left be"); + CHECK_FALSE(queue.forget("other")); } } diff --git a/indra/newview/tests/alscriptkeymap_test.cpp b/indra/newview/tests/alscriptkeymap_test.cpp index 4a75dec821..d2fc4d475c 100644 --- a/indra/newview/tests/alscriptkeymap_test.cpp +++ b/indra/newview/tests/alscriptkeymap_test.cpp @@ -33,7 +33,7 @@ #include "llcontrol.h" #include "llkeyboard.h" -#include "../test/lltut.h" +#include #include #include @@ -50,7 +50,7 @@ namespace }; } -namespace tut +namespace { struct alscriptkeymap_data { @@ -92,107 +92,150 @@ namespace tut return std::find(keys.begin(), keys.end(), chord) != keys.end(); } }; - typedef test_group alscriptkeymap_group; - typedef alscriptkeymap_group::object alscriptkeymap_object; - alscriptkeymap_group alscriptkeymap_instance("alscriptkeymap"); - template<> template<> - void alscriptkeymap_object::test<1>() + TEST_CASE_METHOD(alscriptkeymap_data, "alscriptkeymap: a person's editor keys replace the standard's and follow the setting", "[alscriptkeymap]") { - set_test_name("the editors' keymap: the standard's, a person's keys over it, built again only when the setting changes"); const ALKeymap* first = &ALScriptKeymap::current(); - ensure("the standard's", first->lookup('F', MASK_CONTROL) == C::Find); - ensure("the same keymap asked again", &ALScriptKeymap::current() == first); + UNSCOPED_INFO("the standard's"); + CHECK(first->lookup('F', MASK_CONTROL) == C::Find); + UNSCOPED_INFO("the same keymap asked again"); + CHECK(&ALScriptKeymap::current() == first); ALScriptKeymap::rebind(C::Find, { { 'Y', MASK_CONTROL | MASK_SHIFT } }); - ensure("the new key", ALScriptKeymap::current().lookup('Y', MASK_CONTROL | MASK_SHIFT) == C::Find); - ensure("the old one gone", ALScriptKeymap::current().lookup('F', MASK_CONTROL) == C::None); - ensure("said rebound", ALScriptKeymap::isRebound(C::Find) && !ALScriptKeymap::isRebound(C::Replace)); + UNSCOPED_INFO("the new key"); + CHECK(ALScriptKeymap::current().lookup('Y', MASK_CONTROL | MASK_SHIFT) == C::Find); + UNSCOPED_INFO("the old one gone"); + CHECK(ALScriptKeymap::current().lookup('F', MASK_CONTROL) == C::None); + { + INFO("said rebound"); + CHECK(ALScriptKeymap::isRebound(C::Find)); + CHECK_FALSE(ALScriptKeymap::isRebound(C::Replace)); + } // Set by anything else -- the preferences' Cancel putting it back. gSavedSettings.setLLSD("ALScriptStudioKeymap", LLSD::emptyMap()); - ensure("the standard's again", ALScriptKeymap::current().lookup('F', MASK_CONTROL) == C::Find); + UNSCOPED_INFO("the standard's again"); + CHECK(ALScriptKeymap::current().lookup('F', MASK_CONTROL) == C::Find); ALScriptKeymap::rebind(C::Find, {}); - ensure("none: unbound", ALScriptKeymap::keysOf(ALScriptKeymap::current(), C::Find).empty()); + UNSCOPED_INFO("none: unbound"); + REQUIRE(ALScriptKeymap::keysOf(ALScriptKeymap::current(), C::Find).empty()); ALScriptKeymap::restore(C::Find); - ensure("restored", ALScriptKeymap::current().lookup('F', MASK_CONTROL) == C::Find && !ALScriptKeymap::isRebound(C::Find)); + { + INFO("restored"); + CHECK(ALScriptKeymap::current().lookup('F', MASK_CONTROL) == C::Find); + CHECK_FALSE(ALScriptKeymap::isRebound(C::Find)); + } } - template<> template<> - void alscriptkeymap_object::test<2>() + TEST_CASE_METHOD(alscriptkeymap_data, "alscriptkeymap: menu keys may be several or two in turn and restore to the standard's", "[alscriptkeymap]") { - set_test_name("the menus' keys: several as standard, two in turn, a person's in their place, and the standard's again"); #if LL_DARWIN constexpr MASK REAL_CONTROL = MASK_MAC_CONTROL; #else constexpr MASK REAL_CONTROL = MASK_CONTROL; #endif const ALScriptKeymap::chords_t next = ALScriptKeymap::menuKeys("next_tab"); - ensure("next tab: Control-PgDn, which the menu shows", !next.empty() && next.front() == ALKeyChord{ KEY_PAGE_DOWN, MASK_CONTROL }); - ensure("and Control-Tab", has(next, ALKeyChord{ KEY_TAB, REAL_CONTROL })); - ensure("save all: Control-K, then S", ALScriptKeymap::menuKey("save_all") == (ALKeyChord{ 'S', MASK_NONE, 'K', MASK_CONTROL })); - ensure("a command with none", ALScriptKeymap::menuKeys("revert").empty() && ALScriptKeymap::isMenuCommand("revert")); - ensure("no such command", !ALScriptKeymap::isMenuCommand("frobnicate") && ALScriptKeymap::menuKeys("frobnicate").empty()); + { + INFO("next tab: Control-PgDn, which the menu shows"); + REQUIRE_FALSE(next.empty()); + CHECK(next.front() == ALKeyChord{ KEY_PAGE_DOWN, MASK_CONTROL }); + } + UNSCOPED_INFO("and Control-Tab"); + CHECK(has(next, ALKeyChord{ KEY_TAB, REAL_CONTROL })); + UNSCOPED_INFO("save all: Control-K, then S"); + CHECK(ALScriptKeymap::menuKey("save_all") == (ALKeyChord{ 'S', MASK_NONE, 'K', MASK_CONTROL })); + { + INFO("a command with none"); + REQUIRE(ALScriptKeymap::menuKeys("revert").empty()); + CHECK(ALScriptKeymap::isMenuCommand("revert")); + } + { + INFO("no such command"); + CHECK_FALSE(ALScriptKeymap::isMenuCommand("frobnicate")); + REQUIRE(ALScriptKeymap::menuKeys("frobnicate").empty()); + } const ALKeyChord two{ 'T', MASK_NONE, 'K', MASK_CONTROL }; ALScriptKeymap::rebindMenu("revert", { two, ALKeyChord{ KEY_F9, MASK_SHIFT } }); const ALScriptKeymap::chords_t mine = ALScriptKeymap::menuKeys("revert"); - ensure("kept, two in turn among them", mine.size() == 2 && mine[0] == two && mine[1] == (ALKeyChord{ KEY_F9, MASK_SHIFT })); - ensure("said rebound", ALScriptKeymap::isMenuRebound("revert")); + { + INFO("kept, two in turn among them"); + REQUIRE(mine.size() == 2); + CHECK(mine[0] == two); + CHECK(mine[1] == (ALKeyChord{ KEY_F9, MASK_SHIFT })); + } + UNSCOPED_INFO("said rebound"); + CHECK(ALScriptKeymap::isMenuRebound("revert")); ALScriptKeymap::rebindMenu("next_tab", {}); - ensure("none at all, in place of the standard's", ALScriptKeymap::menuKeys("next_tab").empty() && ALScriptKeymap::menuKey("next_tab").none()); + { + INFO("none at all, in place of the standard's"); + REQUIRE(ALScriptKeymap::menuKeys("next_tab").empty()); + CHECK(ALScriptKeymap::menuKey("next_tab").none()); + } ALScriptKeymap::restoreMenu("next_tab"); - ensure("the standard's again", ALScriptKeymap::menuKeys("next_tab") == next && !ALScriptKeymap::isMenuRebound("next_tab")); + { + INFO("the standard's again"); + CHECK(ALScriptKeymap::menuKeys("next_tab") == next); + CHECK_FALSE(ALScriptKeymap::isMenuRebound("next_tab")); + } ALScriptKeymap::restoreAll(); - ensure("all of them", ALScriptKeymap::menuKeys("revert").empty()); + UNSCOPED_INFO("all of them"); + REQUIRE(ALScriptKeymap::menuKeys("revert").empty()); } - template<> template<> - void alscriptkeymap_object::test<3>() + TEST_CASE_METHOD(alscriptkeymap_data, "alscriptkeymap: the menus' table has unique ids and keys and no Control-Alt typing key", "[alscriptkeymap]") { - set_test_name("the menus' table: each command once in its ids, each key the standard's once, and no Control-Alt with a key that types"); const std::vector& ids = ALScriptKeymap::menuIds(); - ensure_equals("each once", std::set(ids.begin(), ids.end()).size(), ids.size()); + UNSCOPED_INFO("each once"); + REQUIRE(std::set(ids.begin(), ids.end()).size() == ids.size()); std::set> seen; for (const std::string& id : ids) { for (const ALKeyChord& chord : ALScriptKeymap::menuKeys(id)) { - ensure("one command's key: " + id + " " + chord.describe(), seen.insert({ chord.key, chord.mask, chord.leadKey, chord.leadMask }).second); + UNSCOPED_INFO("one command's key: " + id + " " + chord.describe()); + REQUIRE(seen.insert({ chord.key, chord.mask, chord.leadKey, chord.leadMask }).second); for (const auto& [key, mask] : { std::pair{ chord.key, chord.mask }, std::pair{ chord.leadKey, chord.leadMask } }) { const bool types = key >= 0x20 && key < 0x80; - ensure("no Control-Alt: " + id, !types || (mask & (MASK_CONTROL | MASK_ALT)) != (MASK_CONTROL | MASK_ALT)); + UNSCOPED_INFO("no Control-Alt: " + id); + REQUIRE((!types || (mask & (MASK_CONTROL | MASK_ALT)) != (MASK_CONTROL | MASK_ALT))); } } } } - template<> template<> - void alscriptkeymap_object::test<4>() + TEST_CASE_METHOD(alscriptkeymap_data, "alscriptkeymap: every studio menu bar item can take keys and has a unique id and a path", "[alscriptkeymap]") { - set_test_name("every item of the studio's menu bar can take keys: the editors' command, or one of the table's; named by where it is, and the only one so named"); LLXMLNodePtr root; - ensure("the studio's file", LLXMLNode::parseFile(std::string(LLUI_TEST_APP_DIR) + "/skins/default/xui/en/floater_script_studio.xml", root)); + UNSCOPED_INFO("the studio's file"); + REQUIRE(LLXMLNode::parseFile(std::string(LLUI_TEST_APP_DIR) + "/skins/default/xui/en/floater_script_studio.xml", root)); const std::vector items = ALScriptKeymap::menuItemsIn(root); - ensure("its menus", items.size() > 50); + UNSCOPED_INFO("its menus"); + REQUIRE(items.size() > 50); std::set ids; for (const ALScriptKeymap::MenuItem& item : items) { - ensure("the only item so named: " + item.id, ids.insert(item.id).second); - ensure("can take keys: " + item.id, alEditorCommandFromName(item.id).has_value() || ALScriptKeymap::isMenuCommand(item.id)); - ensure("named by its menus: " + item.id, item.path.find(" > ") != std::string::npos); + UNSCOPED_INFO("the only item so named: " + item.id); + REQUIRE(ids.insert(item.id).second); + UNSCOPED_INFO("can take keys: " + item.id); + REQUIRE((alEditorCommandFromName(item.id).has_value() || ALScriptKeymap::isMenuCommand(item.id))); + UNSCOPED_INFO("named by its menus: " + item.id); + REQUIRE(item.path.find(" > ") != std::string::npos); } for (const std::string& id : ALScriptKeymap::menuIds()) { - ensure("the table's commands are the menus': " + id, ids.count(id) == 1); + UNSCOPED_INFO("the table's commands are the menus': " + id); + REQUIRE(ids.count(id) == 1); } const auto map = std::find_if(items.begin(), items.end(), [](const ALScriptKeymap::MenuItem& item) { return item.id == "map_left"; }); - ensure("as deep as it goes", map != items.end() && map->path == "View > Editor > Scrollbar > Map on the Left"); + { + INFO("as deep as it goes"); + REQUIRE(map != items.end()); + CHECK(map->path == "View > Editor > Scrollbar > Map on the Left"); + } } - template<> template<> - void alscriptkeymap_object::test<5>() + TEST_CASE_METHOD(alscriptkeymap_data, "alscriptkeymap: takeKeys takes a chord from whichever commands held it", "[alscriptkeymap]") { - set_test_name("keys given take them from whatever had them: an editor's command by the first key, the menus' by the keys, their first, or the given's first"); ALScriptKeymap::Owner revert; revert.menu = "revert"; const auto named = [](const std::vector& owners, const std::string& menu, C command = C::None) { @@ -201,20 +244,40 @@ namespace tut }; std::vector from = ALScriptKeymap::takeKeys(revert, ALKeyChord{ 'F', MASK_CONTROL }, false); - ensure("Find's, the editor's", from.size() == 1 && named(from, "", C::Find)); - ensure("named, not taken", ALScriptKeymap::current().lookup('F', MASK_CONTROL) == C::Find); + { + INFO("Find's, the editor's"); + REQUIRE(from.size() == 1); + CHECK(named(from, "", C::Find)); + } + UNSCOPED_INFO("named, not taken"); + CHECK(ALScriptKeymap::current().lookup('F', MASK_CONTROL) == C::Find); ALScriptKeymap::takeKeys(revert, ALKeyChord{ 'F', MASK_CONTROL }, true); - ensure("taken", ALScriptKeymap::current().lookup('F', MASK_CONTROL) == C::None); + UNSCOPED_INFO("taken"); + CHECK(ALScriptKeymap::current().lookup('F', MASK_CONTROL) == C::None); ALScriptKeymap::restoreAll(); from = ALScriptKeymap::takeKeys(revert, ALKeyChord{ 'K', MASK_CONTROL }, true); - ensure("every two keys it was the first of", named(from, "save_all") && named(from, "explorer") && named(from, "expanded")); - ensure("which have none now", ALScriptKeymap::menuKeys("save_all").empty() && ALScriptKeymap::menuKeys("explorer").empty()); + { + INFO("every two keys it was the first of"); + CHECK(named(from, "save_all")); + CHECK(named(from, "explorer")); + CHECK(named(from, "expanded")); + } + { + INFO("which have none now"); + REQUIRE(ALScriptKeymap::menuKeys("save_all").empty()); + REQUIRE(ALScriptKeymap::menuKeys("explorer").empty()); + } ALScriptKeymap::restoreAll(); from = ALScriptKeymap::takeKeys(revert, ALKeyChord{ 'X', MASK_NONE, 'P', MASK_CONTROL }, true); - ensure("the key that is the first of the two given", from.size() == 1 && named(from, "quick_open")); - ensure("which it had alone", ALScriptKeymap::menuKeys("quick_open").empty()); + { + INFO("the key that is the first of the two given"); + REQUIRE(from.size() == 1); + CHECK(named(from, "quick_open")); + } + UNSCOPED_INFO("which it had alone"); + REQUIRE(ALScriptKeymap::menuKeys("quick_open").empty()); ALScriptKeymap::restoreAll(); #if LL_DARWIN @@ -225,70 +288,92 @@ namespace tut ALScriptKeymap::chords_t rest = ALScriptKeymap::menuKeys("next_tab"); rest.erase(std::remove(rest.begin(), rest.end(), ALKeyChord{ KEY_TAB, REAL_CONTROL }), rest.end()); from = ALScriptKeymap::takeKeys(revert, ALKeyChord{ KEY_TAB, REAL_CONTROL }, true); - ensure("one of several keys: the rest kept", named(from, "next_tab") && !rest.empty() && ALScriptKeymap::menuKeys("next_tab") == rest); + { + INFO("one of several keys: the rest kept"); + CHECK(named(from, "next_tab")); + REQUIRE_FALSE(rest.empty()); + CHECK(ALScriptKeymap::menuKeys("next_tab") == rest); + } ALScriptKeymap::restoreAll(); ALScriptKeymap::Owner save_all; save_all.menu = "save_all"; - ensure("its own keys given again: nobody's", ALScriptKeymap::takeKeys(save_all, ALKeyChord{ 'S', MASK_NONE, 'K', MASK_CONTROL }, false).empty()); + UNSCOPED_INFO("its own keys given again: nobody's"); + REQUIRE(ALScriptKeymap::takeKeys(save_all, ALKeyChord{ 'S', MASK_NONE, 'K', MASK_CONTROL }, false).empty()); ALScriptKeymap::Owner find; find.command = C::Find; - ensure("nor an editor's own", ALScriptKeymap::takeKeys(find, ALKeyChord{ 'F', MASK_CONTROL }, false).empty()); + UNSCOPED_INFO("nor an editor's own"); + REQUIRE(ALScriptKeymap::takeKeys(find, ALKeyChord{ 'F', MASK_CONTROL }, false).empty()); } - template<> template<> - void alscriptkeymap_object::test<6>() + TEST_CASE_METHOD(alscriptkeymap_data, "alscriptkeymap: the zoom keys are the usual Control ones and back and forward avoid them", "[alscriptkeymap]") { - set_test_name("the text's size on Control-=, Control-minus and Control-0, as everywhere; back and forward off them"); const auto has = [](const char* id, const ALKeyChord& chord) { const ALScriptKeymap::chords_t keys = ALScriptKeymap::menuKeys(id); return std::find(keys.begin(), keys.end(), chord) != keys.end(); }; - ensure("zoom in, the '=' key as Windows and SDL say it", has("zoom_in", ALKeyChord{ '=', MASK_CONTROL }) && has("zoom_in", ALKeyChord{ KEY_EQUALS, MASK_CONTROL })); - ensure("and Control-plus", has("zoom_in", ALKeyChord{ '=', MASK_CONTROL | MASK_SHIFT }) && has("zoom_in", ALKeyChord{ KEY_ADD, MASK_CONTROL })); - ensure("zoom out", has("zoom_out", ALKeyChord{ '-', MASK_CONTROL })); - ensure("the size chosen", has("zoom_reset", ALKeyChord{ '0', MASK_CONTROL })); - ensure("back not on Control-minus", !has("back", ALKeyChord{ '-', MASK_CONTROL })); + { + INFO("zoom in, the '=' key as Windows and SDL say it"); + CHECK(has("zoom_in", ALKeyChord{ '=', MASK_CONTROL })); + CHECK(has("zoom_in", ALKeyChord{ KEY_EQUALS, MASK_CONTROL })); + } + { + INFO("and Control-plus"); + CHECK(has("zoom_in", ALKeyChord{ '=', MASK_CONTROL | MASK_SHIFT })); + CHECK(has("zoom_in", ALKeyChord{ KEY_ADD, MASK_CONTROL })); + } + UNSCOPED_INFO("zoom out"); + CHECK(has("zoom_out", ALKeyChord{ '-', MASK_CONTROL })); + UNSCOPED_INFO("the size chosen"); + CHECK(has("zoom_reset", ALKeyChord{ '0', MASK_CONTROL })); + UNSCOPED_INFO("back not on Control-minus"); + CHECK_FALSE(has("back", ALKeyChord{ '-', MASK_CONTROL })); #if LL_DARWIN - ensure("back on the Mac's Control-minus", has("back", ALKeyChord{ '-', MASK_MAC_CONTROL })); + UNSCOPED_INFO("back on the Mac's Control-minus"); + CHECK(has("back", ALKeyChord{ '-', MASK_MAC_CONTROL })); #else - ensure("back on Alt-Left", has("back", ALKeyChord{ KEY_LEFT, MASK_ALT }) && has("forward", ALKeyChord{ KEY_RIGHT, MASK_ALT })); + { UNSCOPED_INFO("back on Alt-Left"); REQUIRE((has("back", ALKeyChord{ KEY_LEFT, MASK_ALT }) && has("forward", ALKeyChord{ KEY_RIGHT, MASK_ALT }))); } #endif } - template<> template<> - void alscriptkeymap_object::test<7>() + TEST_CASE_METHOD(alscriptkeymap_data, "alscriptkeymap: every preset binds studio commands once and editor ones to single keys", "[alscriptkeymap]") { - set_test_name("every preset names the studio's commands, each once, an editor's command with keys of one key each"); - ensure("the studio's own first, changing nothing", ALScriptKeyPresets::all().front().id == ALScriptKeyPresets::STANDARD && - ALScriptKeyPresets::all().front().bindings.empty()); - ensure("four", ALScriptKeyPresets::all().size() == 4); + { + INFO("the studio's own first, changing nothing"); + CHECK(ALScriptKeyPresets::all().front().id == ALScriptKeyPresets::STANDARD); + REQUIRE(ALScriptKeyPresets::all().front().bindings.empty()); + } + UNSCOPED_INFO("four"); + REQUIRE(ALScriptKeyPresets::all().size() == 4); for (const ALScriptKeyPresets::Preset& preset : ALScriptKeyPresets::all()) { std::set named; for (const ALScriptKeyPresets::Binding& binding : preset.bindings) { const std::string what = preset.id + ": " + binding.id; - ensure("once: " + what, named.insert(binding.id).second); - ensure("keys: " + what, !binding.keys.empty()); + UNSCOPED_INFO("once: " + what); + REQUIRE(named.insert(binding.id).second); + UNSCOPED_INFO("keys: " + what); + REQUIRE_FALSE(binding.keys.empty()); const bool editor = alEditorCommandFromName(binding.id).has_value(); - ensure("a command: " + what, editor || ALScriptKeymap::isMenuCommand(binding.id)); + UNSCOPED_INFO("a command: " + what); + REQUIRE((editor || ALScriptKeymap::isMenuCommand(binding.id))); for (const ALKeyChord& chord : binding.keys) { - ensure("one key at a time for an editor's: " + what, !editor || !chord.twoKeys()); + UNSCOPED_INFO("one key at a time for an editor's: " + what); + REQUIRE((!editor || !chord.twoKeys())); } } } } - template<> template<> - void alscriptkeymap_object::test<8>() + TEST_CASE_METHOD(alscriptkeymap_data, "alscriptkeymap: under each preset every key reaches its command and none is shared", "[alscriptkeymap]") { - set_test_name("with each preset in force, every key it gives is its command's, and no key is two commands'"); for (const ALScriptKeyPresets::Preset& preset : ALScriptKeyPresets::all()) { ALScriptKeymap::setPreset(preset.id); - ensure_equals("in force", ALScriptKeymap::preset(), preset.id); + UNSCOPED_INFO("in force"); + REQUIRE(ALScriptKeymap::preset() == preset.id); const ALKeymap& map = ALScriptKeymap::current(); for (const ALScriptKeyPresets::Binding& binding : preset.bindings) { @@ -297,13 +382,14 @@ namespace tut { for (const ALKeyChord& chord : binding.keys) { - ensure("the editor's key: " + what + " " + chord.describe(), map.lookup(chord.key, chord.mask) == *command); + UNSCOPED_INFO("the editor's key: " + what + " " + chord.describe()); + REQUIRE(map.lookup(chord.key, chord.mask) == *command); } } else { - ensure("the menu's keys: " + what + " " + ALScriptKeymap::describe(ALScriptKeymap::menuKeys(binding.id)), - ALScriptKeymap::menuKeys(binding.id) == binding.keys); + UNSCOPED_INFO("the menu's keys: " + what + " " + ALScriptKeymap::describe(ALScriptKeymap::menuKeys(binding.id))); + REQUIRE(ALScriptKeymap::menuKeys(binding.id) == binding.keys); } } // No menu's key the first key of an editor's command, nor @@ -315,7 +401,8 @@ namespace tut const std::string what = preset.id + ": " + id + " " + chord.describe(); const KEY first_key = chord.twoKeys() ? chord.leadKey : chord.key; const MASK first_mask = chord.twoKeys() ? chord.leadMask : chord.mask; - ensure("not an editor's key: " + what, map.lookup(first_key, first_mask) == ALEditorCommand::None); + UNSCOPED_INFO("not an editor's key: " + what); + REQUIRE(map.lookup(first_key, first_mask) == ALEditorCommand::None); for (const std::string& other : ALScriptKeymap::menuIds()) { if (other == id) @@ -326,7 +413,8 @@ namespace tut { const bool clash = theirs == chord || (!chord.twoKeys() && theirs.ledBy(chord.key, chord.mask)) || (chord.twoKeys() && !theirs.twoKeys() && theirs.key == chord.leadKey && theirs.mask == chord.leadMask); - ensure("not " + other + "'s too: " + what, !clash); + UNSCOPED_INFO("not " + other + "'s too: " + what); + REQUIRE_FALSE(clash); } } } @@ -334,36 +422,45 @@ namespace tut } } - template<> template<> - void alscriptkeymap_object::test<9>() + TEST_CASE_METHOD(alscriptkeymap_data, "alscriptkeymap: a person's keys win over any preset and restoring keeps the preset", "[alscriptkeymap]") { - set_test_name("a person's own keys stay over another preset and win; restoring one goes back to the preset's, and all keeps the preset"); #if LL_DARWIN const std::string other_preset = "xcode"; #else const std::string other_preset = "visual_studio"; #endif ALScriptKeymap::setPreset("jetbrains"); - ensure("JetBrains' Control-D duplicates", ALScriptKeymap::current().lookup('D', MASK_CONTROL) == C::DuplicateLine); + UNSCOPED_INFO("JetBrains' Control-D duplicates"); + CHECK(ALScriptKeymap::current().lookup('D', MASK_CONTROL) == C::DuplicateLine); ALScriptKeymap::takeKeys(ALScriptKeymap::Owner{ C::JoinLines, "" }, ALKeyChord{ 'D', MASK_CONTROL }, true); ALScriptKeymap::rebind(C::JoinLines, { { 'D', MASK_CONTROL } }); - ensure("taken", ALScriptKeymap::current().lookup('D', MASK_CONTROL) == C::JoinLines && ALScriptKeymap::isRebound(C::JoinLines)); + { + INFO("taken"); + CHECK(ALScriptKeymap::current().lookup('D', MASK_CONTROL) == C::JoinLines); + CHECK(ALScriptKeymap::isRebound(C::JoinLines)); + } ALScriptKeymap::setPreset(other_preset); - ensure("kept over another preset", ALScriptKeymap::current().lookup('D', MASK_CONTROL) == C::JoinLines); - ensure("and the person's still", ALScriptKeymap::anyRebound()); + UNSCOPED_INFO("kept over another preset"); + CHECK(ALScriptKeymap::current().lookup('D', MASK_CONTROL) == C::JoinLines); + UNSCOPED_INFO("and the person's still"); + CHECK(ALScriptKeymap::anyRebound()); ALScriptKeymap::restore(C::JoinLines); ALScriptKeymap::restore(C::DuplicateLine); - ensure("restored: the preset's own", ALScriptKeymap::current().lookup('D', MASK_CONTROL) == C::DuplicateLine); + UNSCOPED_INFO("restored: the preset's own"); + CHECK(ALScriptKeymap::current().lookup('D', MASK_CONTROL) == C::DuplicateLine); ALScriptKeymap::restoreAll(); - ensure("all restored, the preset kept", ALScriptKeymap::preset() == other_preset && !ALScriptKeymap::anyRebound()); + { + INFO("all restored, the preset kept"); + CHECK(ALScriptKeymap::preset() == other_preset); + CHECK_FALSE(ALScriptKeymap::anyRebound()); + } ALScriptKeymap::setPreset("nothing of the kind"); - ensure("one not offered: the standard", ALScriptKeymap::preset() == ALScriptKeyPresets::STANDARD); + UNSCOPED_INFO("one not offered: the standard"); + CHECK(ALScriptKeymap::preset() == ALScriptKeyPresets::STANDARD); } - template<> template<> - void alscriptkeymap_object::test<10>() + TEST_CASE_METHOD(alscriptkeymap_data, "alscriptkeymap: comparison bar commands are Alt with a first letter and peeking is Alt-F3", "[alscriptkeymap]") { - set_test_name("what the comparison's bar does has keys too, the first letter of each word; peeking at a change on Alt-F3, beside Alt-F5's step"); const std::pair keys[] = { { "compare_settle_theirs", ALKeyChord{ 'T', MASK_ALT } }, { "compare_settle_mine", ALKeyChord{ 'M', MASK_ALT } }, { "compare_settle_both", ALKeyChord{ 'B', MASK_ALT } }, { "compare_fold", ALKeyChord{ 'F', MASK_ALT } }, @@ -372,24 +469,30 @@ namespace tut }; for (const auto& [id, chord] : keys) { - ensure(std::string("a menu command: ") + id, ALScriptKeymap::isMenuCommand(id)); - ensure(std::string("its key: ") + id + " " + chord.describe(), ALScriptKeymap::menuKey(id) == chord); - ensure(std::string("no editor's: ") + id, ALScriptKeymap::current().lookup(chord.key, chord.mask) == C::None); + UNSCOPED_INFO(std::string("a menu command: ") + id); + REQUIRE(ALScriptKeymap::isMenuCommand(id)); + UNSCOPED_INFO(std::string("its key: ") + id + " " + chord.describe()); + REQUIRE(ALScriptKeymap::menuKey(id) == chord); + UNSCOPED_INFO(std::string("no editor's: ") + id); + REQUIRE(ALScriptKeymap::current().lookup(chord.key, chord.mask) == C::None); } - ensure("the step beside it", ALScriptKeymap::menuKey("next_difference") == (ALKeyChord{ KEY_F5, MASK_ALT })); + UNSCOPED_INFO("the step beside it"); + CHECK(ALScriptKeymap::menuKey("next_difference") == (ALKeyChord{ KEY_F5, MASK_ALT })); } - template<> template<> - void alscriptkeymap_object::test<11>() + TEST_CASE_METHOD(alscriptkeymap_data, "alscriptkeymap: keys kept for a menu command now gone take nothing from others", "[alscriptkeymap]") { - set_test_name("keys kept for a menu's command the table no longer has, renamed or gone, take nothing from the commands that have them"); // Go > Next Change was next_change until it was told from Next Edit // Location, the editor's command of that name. - ensure("no menu command now", !ALScriptKeymap::isMenuCommand("next_change")); + UNSCOPED_INFO("no menu command now"); + CHECK_FALSE(ALScriptKeymap::isMenuCommand("next_change")); ALScriptKeymap::rebindMenu("next_change", { ALKeyChord{ KEY_F5, MASK_ALT }, ALKeyChord{ KEY_F8, MASK_NONE } }); - ensure("the step's key its own still", ALScriptKeymap::menuKey("next_difference") == (ALKeyChord{ KEY_F5, MASK_ALT })); - ensure("and a problem's", has(ALScriptKeymap::menuKeys("next_problem"), ALKeyChord{ KEY_F8, MASK_NONE })); - ensure("the editor's command of that name untouched", ALScriptKeymap::keysOf(ALScriptKeymap::current(), C::NextChange).empty() == + UNSCOPED_INFO("the step's key its own still"); + CHECK(ALScriptKeymap::menuKey("next_difference") == (ALKeyChord{ KEY_F5, MASK_ALT })); + UNSCOPED_INFO("and a problem's"); + CHECK(has(ALScriptKeymap::menuKeys("next_problem"), ALKeyChord{ KEY_F8, MASK_NONE })); + UNSCOPED_INFO("the editor's command of that name untouched"); + REQUIRE(ALScriptKeymap::keysOf(ALScriptKeymap::current(), C::NextChange).empty() == ALScriptKeymap::keysOf(ALKeymap::standard(), C::NextChange).empty()); ALScriptKeymap::restoreAll(); } diff --git a/indra/newview/tests/alscriptlookup_test.cpp b/indra/newview/tests/alscriptlookup_test.cpp index 9f4ca1c5fc..7d41ecbff0 100644 --- a/indra/newview/tests/alscriptlookup_test.cpp +++ b/indra/newview/tests/alscriptlookup_test.cpp @@ -39,7 +39,7 @@ #include "llfocusmgr.h" #include "newview_test_fakes.h" -#include "../test/lltut.h" +#include #include #include @@ -319,7 +319,7 @@ namespace bool has(const std::string& text, const std::string& part) { return text.find(part) != std::string::npos; } } -namespace tut +namespace { struct alscriptlookup_data { @@ -358,7 +358,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } navigation = std::make_unique(services); unit = std::make_unique(services, studio, studio, navigation->unit, studio); @@ -393,19 +393,14 @@ namespace tut } }; - typedef test_group alscriptlookup_group; - typedef alscriptlookup_group::object alscriptlookup_object; - alscriptlookup_group alscriptlookup_instance("alscriptlookup"); - - template<> template<> - void alscriptlookup_object::test<1>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: places kept once and sorted own first and language words reserved", "[alscriptlookup]") { - set_test_name("places once each, the script's own first then each other's by name; the language's own words reserved"); Doc::Lookup lookup; ALScriptLookup::addPlace(lookup, place("", 1, 2)); ALScriptLookup::addPlace(lookup, place("", 1, 2, 7)); ALScriptLookup::addPlace(lookup, place("x", 1, 2)); - ensure_equals("once a file and a start", lookup.places.size(), size_t(2)); + UNSCOPED_INFO("once a file and a start"); + REQUIRE(lookup.places.size() == size_t(2)); std::vector places = { place("object:z", 0, 0, 5, "Beta"), place("", 3, 0, 5, "Zeta"), place("object:y", 2, 0, 5, "Alpha"), place("object:x", 0, 0, 5, "Beta"), @@ -416,82 +411,148 @@ namespace tut { order.push_back(each.file + ":" + std::to_string(each.span.line)); } - ensure_equals("own whatever it is called, then by name, file and place", joined(order), + UNSCOPED_INFO("own whatever it is called, then by name, file and place"); + CHECK(joined(order) == joined(Names{ ":1", ":3", "object:y:1", "object:y:2", "object:x:0", "object:z:0" })); - ensure("an LSL keyword", ALScriptLookup::reserved(false, "state") && !ALScriptLookup::reserved(true, "state")); - ensure("a Luau keyword", ALScriptLookup::reserved(true, "local") && !ALScriptLookup::reserved(false, "local")); - ensure("the preprocessor's, in LSL", ALScriptLookup::reserved(false, "switch") && !ALScriptLookup::reserved(true, "switch")); - ensure("the definitions'", ALScriptLookup::reserved(false, "llSay") && ALScriptLookup::reserved(true, "ll.Say")); - ensure("a name of the script's", !ALScriptLookup::reserved(false, "count") && !ALScriptLookup::reserved(true, "count")); + { + INFO("an LSL keyword"); + CHECK(ALScriptLookup::reserved(false, "state")); + CHECK_FALSE(ALScriptLookup::reserved(true, "state")); + } + { + INFO("a Luau keyword"); + CHECK(ALScriptLookup::reserved(true, "local")); + CHECK_FALSE(ALScriptLookup::reserved(false, "local")); + } + { + INFO("the preprocessor's, in LSL"); + CHECK(ALScriptLookup::reserved(false, "switch")); + CHECK_FALSE(ALScriptLookup::reserved(true, "switch")); + } + { + INFO("the definitions'"); + CHECK(ALScriptLookup::reserved(false, "llSay")); + CHECK(ALScriptLookup::reserved(true, "ll.Say")); + } + { + INFO("a name of the script's"); + CHECK_FALSE(ALScriptLookup::reserved(false, "count")); + CHECK_FALSE(ALScriptLookup::reserved(true, "count")); + } } - template<> template<> - void alscriptlookup_object::test<2>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: a name declared nowhere shared is found in the script alone at once", "[alscriptlookup]") { - set_test_name("a name declared nowhere shared looked up in the script alone, answered at once and shown, the preview held"); make(); studio.others = { { b, "B" } }; tab("a", a, A_TEXT, "A").preview = true; Doc& doc = lookUp(ALEditorCommand::FindReferences, false); - ensure("the preview held", !doc.preview); - ensure("nothing else asked", studio.asked.empty() && studio.loads.empty()); - ensure_equals("shown", studio.shows, 1); - ensure_equals("in its tab", studio.shownIn, std::string("a")); - ensure_equals("from", studio.shown.from, std::string("a")); - ensure_equals("named", studio.shown.fromName, std::string("A")); - ensure_equals("the name", studio.shown.name, std::string("count")); - ensure("in order", studio.shown.places.size() == 2 && studio.shown.places[0].span.line == 0); - ensure("not declared", !studio.shown.hasDefinition); - ensure("said", !services.statuses.empty() && has(services.statuses.back(), "ReferencesFound [COUNT]=2")); - ensure("done with", doc.lookup->command == ALEditorCommand::None && doc.lookup->pending == 0); + UNSCOPED_INFO("the preview held"); + CHECK_FALSE(doc.preview); + { + INFO("nothing else asked"); + REQUIRE(studio.asked.empty()); + REQUIRE(studio.loads.empty()); + } + UNSCOPED_INFO("shown"); + CHECK(studio.shows == 1); + UNSCOPED_INFO("in its tab"); + CHECK(studio.shownIn == std::string("a")); + UNSCOPED_INFO("from"); + CHECK(studio.shown.from == std::string("a")); + UNSCOPED_INFO("named"); + CHECK(studio.shown.fromName == std::string("A")); + UNSCOPED_INFO("the name"); + CHECK(studio.shown.name == std::string("count")); + { + INFO("in order"); + REQUIRE(studio.shown.places.size() == 2); + CHECK(studio.shown.places[0].span.line == 0); + } + UNSCOPED_INFO("not declared"); + CHECK_FALSE(studio.shown.hasDefinition); + { + INFO("said"); + REQUIRE_FALSE(services.statuses.empty()); + CHECK(has(services.statuses.back(), "ReferencesFound [COUNT]=2")); + } + { + INFO("done with"); + REQUIRE(doc.lookup->command == ALEditorCommand::None); + CHECK(doc.lookup->pending == 0); + } } - template<> template<> - void alscriptlookup_object::test<3>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: the object's other scripts are read and expanded and asked for places", "[alscriptlookup]") { - set_test_name("the object's others: one open without the name passed over, one read, expanded, asked, and its place added"); make(); tab("c", c, "default { touch_start(integer n) { } }\n", "C"); studio.others = { { c, "C" }, { b, "B" } }; Doc& doc = lookUp(ALEditorCommand::FindReferences); - ensure("candidates asked for", studio.asked == Names{ "a" }); - ensure_equals("one to read", studio.loads.size(), size_t(1)); - ensure("the open one passed over", studio.expands.empty()); - ensure("waiting said", has(services.statuses.back(), "LookingAcross [COUNT]=1 [NAME]=count")); - ensure_equals("nothing shown yet", studio.shows, 0); + UNSCOPED_INFO("candidates asked for"); + CHECK(studio.asked == Names{ "a" }); + UNSCOPED_INFO("one to read"); + REQUIRE(studio.loads.size() == size_t(1)); + UNSCOPED_INFO("the open one passed over"); + REQUIRE(studio.expands.empty()); + UNSCOPED_INFO("waiting said"); + CHECK(has(services.statuses.back(), "LookingAcross [COUNT]=1 [NAME]=count")); + UNSCOPED_INFO("nothing shown yet"); + CHECK(studio.shows == 0); const LLUUID asset("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee"); studio.loads[0].loaded(asset, B_TEXT); - ensure_equals("expanded", studio.expands.size(), size_t(1)); + UNSCOPED_INFO("expanded"); + REQUIRE(studio.expands.size() == size_t(1)); const ALScriptPreprocessor::Request& request = studio.expands[0].request; - ensure("as the compiler sees it, not optimized", - request.ref == b && request.name == "B" && request.assetId == asset && request.sourceText() == B_TEXT && !request.optimize); + { + INFO("as the compiler sees it, not optimized"); + CHECK(request.ref == b); + CHECK(request.name == "B"); + CHECK(request.assetId == asset); + CHECK(request.sourceText() == B_TEXT); + CHECK_FALSE(request.optimize); + } studio.expands[0].expanded( expansion("B", ALScriptPreprocessor::pathOf(b), B_TEXT, "A", ALScriptPreprocessor::pathOf(a), "integer count;\n")); - ensure_equals("asked", studio.asks.size(), size_t(1)); + UNSCOPED_INFO("asked"); + REQUIRE(studio.asks.size() == size_t(1)); const ALScriptAnalysis::Request& asked = studio.asks[0].request; - ensure("where the declaration went", asked.kind == ALScriptAnalysis::Kind::References && asked.line == 0 && asked.column == 8); - ensure_equals("by who asked and the script", asked.id, "lookup:" + doc.id + ":" + b.id()); - ensure_equals("of this lookup", asked.version, doc.lookup->generation); + { + INFO("where the declaration went"); + CHECK(asked.kind == ALScriptAnalysis::Kind::References); + CHECK(asked.line == 0); + CHECK(asked.column == 8); + } + UNSCOPED_INFO("by who asked and the script"); + CHECK(asked.id == "lookup:" + doc.id + ":" + b.id()); + UNSCOPED_INFO("of this lookup"); + CHECK(asked.version == doc.lookup->generation); studio.asks[0].answered(answer({ span(0, 8, 5), span(1, 8, 5) })); - ensure_equals("shown", studio.shows, 1); - ensure_equals("its own through the other's expansion left out", studio.shown.places.size(), size_t(3)); + UNSCOPED_INFO("shown"); + CHECK(studio.shows == 1); + UNSCOPED_INFO("its own through the other's expansion left out"); + REQUIRE(studio.shown.places.size() == size_t(3)); const Doc::Place& other = studio.shown.places[2]; - ensure_equals("in B", other.file, ALScriptPreprocessor::pathOf(b)); - ensure_equals("named", other.fileName, std::string("B")); - ensure_equals("as written", other.text, std::string("foo() { count = 2; }")); - ensure_equals("the name in it", other.at, 8); - ensure("declared", studio.shown.hasDefinition); - ensure("across scripts", has(services.statuses.back(), "ReferencesFoundAcross [COUNT]=3 [FILES]=2")); + UNSCOPED_INFO("in B"); + CHECK(other.file == ALScriptPreprocessor::pathOf(b)); + UNSCOPED_INFO("named"); + CHECK(other.fileName == std::string("B")); + UNSCOPED_INFO("as written"); + CHECK(other.text == std::string("foo() { count = 2; }")); + UNSCOPED_INFO("the name in it"); + CHECK(other.at == 8); + UNSCOPED_INFO("declared"); + CHECK(studio.shown.hasDefinition); + UNSCOPED_INFO("across scripts"); + CHECK(has(services.statuses.back(), "ReferencesFoundAcross [COUNT]=3 [FILES]=2")); } - template<> template<> - void alscriptlookup_object::test<4>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: an open script is expanded from its tab and an include's line read once", "[alscriptlookup]") { - set_test_name("an open script with the name answered on the spot, the others still counted; an include's line where it is had"); make(); Doc& open = tab("b", b, B_TEXT, "B"); studio.others = { { b, "B" }, { c, "C" } }; @@ -499,53 +560,89 @@ namespace tut studio.lines[inc + "#0"] = " integer count; // kept"; Doc& doc = services.findDoc("a") ? *services.findDoc("a") : tab("a", a, A_TEXT, "A"); unit->start(doc, ALEditorCommand::FindReferences, refsOf("count"), true, inc, span(0, 8, 5), {}, doc.editor->document().version()); - ensure("the open one expanded at once", studio.expands.size() == 1 && studio.expands[0].request.sourceText() == open.editor->text()); - ensure("from its tab's own copy, not another", studio.expands[0].request.source == open.snapshot()); - ensure_equals("the other read", studio.loads.size(), size_t(1)); - ensure("both waited for", doc.lookup->pending == 2 && studio.shows == 0); + { + INFO("the open one expanded at once"); + REQUIRE(studio.expands.size() == 1); + CHECK(studio.expands[0].request.sourceText() == open.editor->text()); + } + UNSCOPED_INFO("from its tab's own copy, not another"); + CHECK(studio.expands[0].request.source == open.snapshot()); + UNSCOPED_INFO("the other read"); + REQUIRE(studio.loads.size() == size_t(1)); + { + INFO("both waited for"); + CHECK(doc.lookup->pending == 2); + CHECK(studio.shows == 0); + } studio.expands[0].expanded(expansion("B", ALScriptPreprocessor::pathOf(b), B_TEXT, "inc.lsl", inc, "integer count;\n")); studio.asks[0].answered(answer({ span(0, 8, 5) })); - ensure("still one to come", studio.shows == 0 && doc.lookup->pending == 1); + { + INFO("still one to come"); + CHECK(studio.shows == 0); + CHECK(doc.lookup->pending == 1); + } studio.loads[0].loaded(LLUUID::null, ""); - ensure_equals("an empty one passed over", studio.shows, 1); - ensure_equals("one place", studio.shown.places.size(), size_t(1)); + UNSCOPED_INFO("an empty one passed over"); + CHECK(studio.shows == 1); + UNSCOPED_INFO("one place"); + REQUIRE(studio.shown.places.size() == size_t(1)); const Doc::Place& found = studio.shown.places[0]; - ensure("in the include", found.file == inc && found.fileName == "inc.lsl"); - ensure("as the include reads", found.text == "integer count; // kept" && found.at == 5); - ensure_equals("its lines asked for once", studio.linesAsked[inc], 1); + { + INFO("in the include"); + CHECK(found.file == inc); + CHECK(found.fileName == "inc.lsl"); + } + { + INFO("as the include reads"); + CHECK(found.text == "integer count; // kept"); + CHECK(found.at == 5); + } + UNSCOPED_INFO("its lines asked for once"); + CHECK(studio.linesAsked[inc] == 1); studio.lines.clear(); unit->start(doc, ALEditorCommand::FindReferences, refsOf("count"), true, inc, span(0, 8, 5), {}, doc.editor->document().version()); studio.expands.back().expanded(expansion("B", ALScriptPreprocessor::pathOf(b), B_TEXT, "inc.lsl", inc, "integer count;\n")); studio.asks.back().answered(answer({ span(0, 8, 5) })); studio.loads.back().loaded(LLUUID::null, "default { }\n"); - ensure_equals("shown again", studio.shows, 2); - ensure("the expansion's line, the name not placed in it", - studio.shown.places.size() == 1 && studio.shown.places[0].text == "integer count;" && studio.shown.places[0].at == -1); + UNSCOPED_INFO("shown again"); + CHECK(studio.shows == 2); + { + INFO("the expansion's line, the name not placed in it"); + REQUIRE(studio.shown.places.size() == 1); + CHECK(studio.shown.places[0].text == "integer count;"); + CHECK(studio.shown.places[0].at == -1); + } } - template<> template<> - void alscriptlookup_object::test<5>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: answers to an earlier lookup or after the unit is gone are dropped", "[alscriptlookup]") { - set_test_name("answers to an earlier lookup, or after the lookups are gone, dropped; a script not naming the home passed over"); make(); studio.others = { { b, "B" } }; Doc& doc = lookUp(ALEditorCommand::FindReferences); lookUp(ALEditorCommand::FindReferences, false); - ensure_equals("the second shown", studio.shows, 1); + UNSCOPED_INFO("the second shown"); + CHECK(studio.shows == 1); studio.loads[0].loaded(LLUUID::null, B_TEXT); - ensure("the first's answer dropped", studio.expands.empty() && studio.shows == 1); + { + INFO("the first's answer dropped"); + REQUIRE(studio.expands.empty()); + CHECK(studio.shows == 1); + } lookUp(ALEditorCommand::FindReferences); studio.loads.back().loaded(LLUUID::null, B_TEXT); studio.expands.back().expanded(expansion("B", ALScriptPreprocessor::pathOf(b), B_TEXT)); - ensure("no declaration in it: nothing asked", studio.asks.empty()); - ensure_equals("shown without it", studio.shows, 2); + UNSCOPED_INFO("no declaration in it: nothing asked"); + REQUIRE(studio.asks.empty()); + UNSCOPED_INFO("shown without it"); + CHECK(studio.shows == 2); const U32 generation = doc.lookup->generation; lookUp(ALEditorCommand::FindReferences); - ensure("a new generation", doc.lookup->generation != generation); + UNSCOPED_INFO("a new generation"); + CHECK(doc.lookup->generation != generation); studio.loads.back().loaded(LLUUID::null, B_TEXT); // A lookup of another tab's, still waiting on its read, as this // one waits on its expansion: both current, and both gone with it. @@ -556,38 +653,57 @@ namespace tut unit.reset(); studio.expands.back().expanded( expansion("B", ALScriptPreprocessor::pathOf(b), B_TEXT, "A", ALScriptPreprocessor::pathOf(a), "integer count;\n")); - ensure("nothing asked once gone", studio.asks.empty() && studio.shows == 2); + { + INFO("nothing asked once gone"); + REQUIRE(studio.asks.empty()); + CHECK(studio.shows == 2); + } studio.loads.back().loaded(LLUUID::null, B_TEXT); - ensure("nothing read once gone", studio.expands.size() == expands); + UNSCOPED_INFO("nothing read once gone"); + REQUIRE(studio.expands.size() == expands); } - template<> template<> - void alscriptlookup_object::test<6>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: Rename says what is not renamable and hints at what return will do", "[alscriptlookup]") { - set_test_name("Rename: one that may not be said so; else the new name asked, the row under it saying what return will do"); make(); lookUp(ALEditorCommand::Rename, false, false); - ensure("not renamable", has(services.statuses.back(), "NotRenamable") && studio.askedName.empty()); + { + INFO("not renamable"); + CHECK(has(services.statuses.back(), "NotRenamable")); + REQUIRE(studio.askedName.empty()); + } Doc& doc = lookUp(ALEditorCommand::Rename, false); - ensure_equals("asked in its tab", studio.askedName, std::string("a")); + UNSCOPED_INFO("asked in its tab"); + CHECK(studio.askedName == std::string("a")); ALScriptOutlineEntry entry; entry.name = "total"; doc.outline.push_back(entry); - ensure("nothing typed", has(studio.hint(""), "RenameHint [COUNT]=2 [FILES]=1 [NAME]=count")); - ensure("no name", has(studio.hint("9lives"), "RenameBadName") && has(studio.hint("9lives"), "[NAME]=9lives")); - ensure("reserved", has(studio.hint("state"), "RenameReserved [NAME]=state")); - ensure("the same", has(studio.hint(" count "), "RenameSame")); - ensure("a clash said, allowed", has(studio.hint("total"), "RenameClash")); - ensure("what it will do", has(studio.hint("sum"), "RenameTo [COUNT]=2") && has(studio.hint("sum"), "[NEW]=sum")); + UNSCOPED_INFO("nothing typed"); + CHECK(has(studio.hint(""), "RenameHint [COUNT]=2 [FILES]=1 [NAME]=count")); + { + INFO("no name"); + CHECK(has(studio.hint("9lives"), "RenameBadName")); + CHECK(has(studio.hint("9lives"), "[NAME]=9lives")); + } + UNSCOPED_INFO("reserved"); + CHECK(has(studio.hint("state"), "RenameReserved [NAME]=state")); + UNSCOPED_INFO("the same"); + CHECK(has(studio.hint(" count "), "RenameSame")); + UNSCOPED_INFO("a clash said, allowed"); + CHECK(has(studio.hint("total"), "RenameClash")); + { + INFO("what it will do"); + CHECK(has(studio.hint("sum"), "RenameTo [COUNT]=2")); + CHECK(has(studio.hint("sum"), "[NEW]=sum")); + } services.docs.clear(); - ensure("its tab gone: nothing said", studio.hint("sum").empty()); + UNSCOPED_INFO("its tab gone: nothing said"); + REQUIRE(studio.hint("sum").empty()); } - template<> template<> - void alscriptlookup_object::test<7>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: a rename across scripts edits open tabs and opens others with it pending", "[alscriptlookup]") { - set_test_name("a rename across scripts: here as one step, open ones unchanged since, others opened with it waiting, the rest left"); make(); Doc& doc = tab("a", a, A_TEXT, "A"); Doc& open = tab("b", b, "foo() { count = 2; }\nbar() { total = count; }\n", "B"); @@ -605,135 +721,220 @@ namespace tut place(pc, 0, 8, 5, "C"), place(pd, 2, 4, 5, "D"), place("disk:/e.lsl", 0, 8, 5, "e.lsl"), place("weird:x", 0, 0) }, doc.editor->document().version()); moved.editor->insertText("// "); - ensure("asked", (bool)studio.chosen); - ensure("across scripts", has(studio.hint("sum"), "RenameToAcross [COUNT]=9 [FILES]=6")); + UNSCOPED_INFO("asked"); + REQUIRE((bool)studio.chosen); + UNSCOPED_INFO("across scripts"); + CHECK(has(studio.hint("sum"), "RenameToAcross [COUNT]=9 [FILES]=6")); studio.chosen("9lives"); - ensure("no name", has(services.statuses.back(), "RenameBadName") && doc.editor->text() == A_TEXT); + { + INFO("no name"); + CHECK(has(services.statuses.back(), "RenameBadName")); + CHECK(doc.editor->text() == A_TEXT); + } studio.chosen("state"); - ensure("reserved", has(services.statuses.back(), "RenameReserved")); + UNSCOPED_INFO("reserved"); + CHECK(has(services.statuses.back(), "RenameReserved")); studio.chosen("count"); - ensure("the same: nothing", services.reports.empty() && doc.editor->text() == A_TEXT); + { + INFO("the same: nothing"); + REQUIRE(services.reports.empty()); + CHECK(doc.editor->text() == A_TEXT); + } studio.chosen(" total "); - ensure_equals("here", doc.editor->text(), std::string("integer total;\ndefault { state_entry() { total = 1; } }\n")); - ensure_equals("one step", doc.editor->undoJournal().undoLabel(), std::string("rename")); - ensure_equals("open and unchanged: where it still stands", open.editor->text(), + UNSCOPED_INFO("here"); + CHECK(doc.editor->text() == std::string("integer total;\ndefault { state_entry() { total = 1; } }\n")); + UNSCOPED_INFO("one step"); + CHECK(doc.editor->undoJournal().undoLabel() == std::string("rename")); + UNSCOPED_INFO("open and unchanged: where it still stands"); + CHECK(open.editor->text() == std::string("foo() { total = 2; }\nbar() { total = total; }\n")); - ensure_equals("there as one step too", open.editor->undoJournal().undoLabel(), std::string("rename")); - ensure("moved on since: left", has(moved.editor->text(), "count") && !has(moved.editor->text(), "total")); - ensure("not open: opened", services.opened.size() == 1 && services.opened[0].ref == d && services.opened[0].name == "D"); + UNSCOPED_INFO("there as one step too"); + CHECK(open.editor->undoJournal().undoLabel() == std::string("rename")); + { + INFO("moved on since: left"); + REQUIRE(has(moved.editor->text(), "count")); + CHECK_FALSE(has(moved.editor->text(), "total")); + } + { + INFO("not open: opened"); + REQUIRE(services.opened.size() == 1); + CHECK(services.opened[0].ref == d); + CHECK(services.opened[0].name == "D"); + } Doc* waiting = services.findDoc("d"); - ensure("the change waiting", waiting && waiting->pendingEdits.size() == 1 && waiting->pendingEdits[0].now == "total"); - ensure("a file opened", studio.filesOpened == Names{ "/e.lsl" }); - ensure_equals("and changed", services.findDoc("disk:/e.lsl")->editor->text(), std::string("integer total = 4;\n")); - ensure_equals("said once", services.reports.size(), size_t(1)); + { + INFO("the change waiting"); + REQUIRE(waiting); + REQUIRE(waiting->pendingEdits.size() == 1); + CHECK(waiting->pendingEdits[0].now == "total"); + } + UNSCOPED_INFO("a file opened"); + CHECK(studio.filesOpened == Names{ "/e.lsl" }); + UNSCOPED_INFO("and changed"); + CHECK(services.findDoc("disk:/e.lsl")->editor->text() == std::string("integer total = 4;\n")); + UNSCOPED_INFO("said once"); + REQUIRE(services.reports.size() == size_t(1)); const al_studio_test::FakeServices::Said& said = services.reports[0]; - ensure("the counts", has(said.text, "RenamedIn [NAME]=total [PLACES]=Places [COUNT]=6 [SCRIPTS]=Scripts [COUNT]=4")); - ensure("opened, a clause joined on", has(said.text, "[SECOND]=RenamedOpened [NAME]=total [PLACES]=Places [COUNT]=6 [SCRIPTS]=Scripts [COUNT]=2")); - ensure("left, another", has(said.text, "[SECOND]=RenamedLeft [NAME]=total [PLACES]=Places [COUNT]=6 [SCRIPTS]=Scripts [COUNT]=2")); - ensure("as the language joins clauses and ends a sentence", has(said.text, "Sentence [TEXT]=JoinClauses [FIRST]=JoinClauses")); - ensure("a failure where any was left", said.failure); - ensure("its tab brought forward", studio.activated == Names{ "a" }); + UNSCOPED_INFO("the counts"); + CHECK(has(said.text, "RenamedIn [NAME]=total [PLACES]=Places [COUNT]=6 [SCRIPTS]=Scripts [COUNT]=4")); + UNSCOPED_INFO("opened, a clause joined on"); + CHECK(has(said.text, "[SECOND]=RenamedOpened [NAME]=total [PLACES]=Places [COUNT]=6 [SCRIPTS]=Scripts [COUNT]=2")); + UNSCOPED_INFO("left, another"); + CHECK(has(said.text, "[SECOND]=RenamedLeft [NAME]=total [PLACES]=Places [COUNT]=6 [SCRIPTS]=Scripts [COUNT]=2")); + UNSCOPED_INFO("as the language joins clauses and ends a sentence"); + CHECK(has(said.text, "Sentence [TEXT]=JoinClauses [FIRST]=JoinClauses")); + UNSCOPED_INFO("a failure where any was left"); + CHECK(said.failure); + UNSCOPED_INFO("its tab brought forward"); + CHECK(studio.activated == Names{ "a" }); } - template<> template<> - void alscriptlookup_object::test<8>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: a stale rename is refused and one in this script alone is said as here", "[alscriptlookup]") { - set_test_name("a rename of a script that has moved on since the lookup refused, and one in only this script said as here"); make(); Doc& doc = lookUp(ALEditorCommand::Rename, false); doc.editor->insertText(" "); studio.chosen("total"); - ensure("stale", has(services.statuses.back(), "RenameStale [NAME]=total") && services.reports.empty()); + { + INFO("stale"); + CHECK(has(services.statuses.back(), "RenameStale [NAME]=total")); + REQUIRE(services.reports.empty()); + } lookUp(ALEditorCommand::Rename, false); studio.chosen("total"); - ensure_equals("said", services.reports.size(), size_t(1)); - ensure("here", has(services.reports[0].text, "RenamedHere") && !has(services.reports[0].text, ";")); - ensure("not a failure", !services.reports[0].failure); + UNSCOPED_INFO("said"); + REQUIRE(services.reports.size() == size_t(1)); + { + INFO("here"); + CHECK(has(services.reports[0].text, "RenamedHere")); + CHECK_FALSE(has(services.reports[0].text, ";")); + } + UNSCOPED_INFO("not a failure"); + CHECK_FALSE(services.reports[0].failure); Doc& open = tab("b", b, "foo() { count = 2; }\n", "B"); doc.editor->setText(A_TEXT); unit->start(doc, ALEditorCommand::Rename, refsOf("count"), false, std::string(), span(0, 8, 5), { place("", 0, 8), place(ALScriptPreprocessor::pathOf(b), 0, 8, 5, "B") }, doc.editor->document().version()); studio.chosen("sum"); - ensure("in both, none opened", has(services.reports.back().text, "RenamedIn") && !has(services.reports.back().text, ";")); - ensure_equals("B too", open.editor->text(), std::string("foo() { sum = 2; }\n")); + { + INFO("in both, none opened"); + CHECK(has(services.reports.back().text, "RenamedIn")); + CHECK_FALSE(has(services.reports.back().text, ";")); + } + UNSCOPED_INFO("B too"); + CHECK(open.editor->text() == std::string("foo() { sum = 2; }\n")); } - template<> template<> - void alscriptlookup_object::test<9>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: pending edits are made where the old name stands and the rest said missed", "[alscriptlookup]") { - set_test_name("edits waiting for a text made where the old name stands, the rest said missed; none where nothing may change"); make(); Doc& doc = tab("d", d, "integer count;\nx = count;\n", "D"); doc.loaded = false; doc.pendingEdits = { { span(0, 8, 5), "count", "total" }, { span(1, 0, 5), "count", "total" } }; unit->applyPendingEdits(doc); - ensure("not loaded: kept", doc.pendingEdits.size() == 2 && doc.editor->text() == "integer count;\nx = count;\n"); + { + INFO("not loaded: kept"); + REQUIRE(doc.pendingEdits.size() == 2); + CHECK(doc.editor->text() == "integer count;\nx = count;\n"); + } doc.loaded = true; doc.editor->setReadOnly(true); unit->applyPendingEdits(doc); - ensure("made", doc.pendingEdits.empty() && doc.editor->text() == "integer total;\nx = count;\n"); - ensure_equals("one step", doc.editor->undoJournal().undoLabel(), std::string("rename")); - ensure("the one missed said", services.reports.size() == 1 && has(services.reports[0].text, "RenameMissed [COUNT]=1 [NAME]=D")); - ensure("of the tab, a failure", services.reports[0].doc == "d" && services.reports[0].failure); + { + INFO("made"); + REQUIRE(doc.pendingEdits.empty()); + CHECK(doc.editor->text() == "integer total;\nx = count;\n"); + } + UNSCOPED_INFO("one step"); + CHECK(doc.editor->undoJournal().undoLabel() == std::string("rename")); + { + INFO("the one missed said"); + REQUIRE(services.reports.size() == 1); + CHECK(has(services.reports[0].text, "RenameMissed [COUNT]=1 [NAME]=D")); + } + { + INFO("of the tab, a failure"); + CHECK(services.reports[0].doc == "d"); + CHECK(services.reports[0].failure); + } Doc::PendingEdit replace{ span(0, 8, 5), "total", "sum", true }; doc.pendingEdits = { replace }; unit->applyPendingEdits(doc); - ensure("a replace", doc.editor->text() == "integer sum;\nx = count;\n" && doc.editor->undoJournal().undoLabel() == "replace"); - ensure("nothing missed", services.reports.size() == 1); + { + INFO("a replace"); + REQUIRE(doc.editor->text() == "integer sum;\nx = count;\n"); + CHECK(doc.editor->undoJournal().undoLabel() == "replace"); + } + UNSCOPED_INFO("nothing missed"); + REQUIRE(services.reports.size() == 1); doc.modifiable = false; doc.pendingEdits = { { span(0, 8, 3), "sum", "total", true } }; unit->applyPendingEdits(doc); - ensure("none made", doc.editor->text() == "integer sum;\nx = count;\n"); - ensure("every one missed", services.reports.size() == 2 && has(services.reports[1].text, "ReplaceMissed [COUNT]=1")); + UNSCOPED_INFO("none made"); + CHECK(doc.editor->text() == "integer sum;\nx = count;\n"); + { + INFO("every one missed"); + REQUIRE(services.reports.size() == 2); + CHECK(has(services.reports[1].text, "ReplaceMissed [COUNT]=1")); + } } - template<> template<> - void alscriptlookup_object::test<10>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: other scripts are read a few at a time and a new lookup drops the rest", "[alscriptlookup]") { - set_test_name("the other scripts read a few at a time, the next begun as one is done with; a lookup begun again lets the rest go"); make(); const ALScriptRef e{ object, LLUUID("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee") }; const ALScriptRef f{ object, LLUUID("ffffffff-ffff-ffff-ffff-ffffffffffff") }; studio.others = { { b, "B" }, { c, "C" }, { d, "D" }, { e, "E" }, { f, "F" } }; Doc& doc = lookUp(ALEditorCommand::FindReferences); - ensure_equals("no more than so many read at once", studio.loads.size(), size_t(ALScriptLookup::AT_ONCE)); - ensure_equals("every one waited for", doc.lookup->pending, S32(5)); + UNSCOPED_INFO("no more than so many read at once"); + REQUIRE(studio.loads.size() == size_t(ALScriptLookup::AT_ONCE)); + UNSCOPED_INFO("every one waited for"); + CHECK(doc.lookup->pending == S32(5)); // One that does not name it: passed over, and the next read. studio.loads[0].loaded(LLUUID::null, "default { }\n"); - ensure_equals("the next begun", studio.loads.size(), size_t(ALScriptLookup::AT_ONCE + 1)); - ensure_equals("one fewer waited for", doc.lookup->pending, S32(4)); + UNSCOPED_INFO("the next begun"); + REQUIRE(studio.loads.size() == size_t(ALScriptLookup::AT_ONCE + 1)); + UNSCOPED_INFO("one fewer waited for"); + CHECK(doc.lookup->pending == S32(4)); studio.loads[1].loaded(LLUUID::null, ""); studio.loads[2].loaded(LLUUID::null, ""); - ensure_equals("and on", studio.loads.size(), size_t(5)); + UNSCOPED_INFO("and on"); + REQUIRE(studio.loads.size() == size_t(5)); studio.loads[3].loaded(LLUUID::null, ""); studio.loads[4].loaded(LLUUID::null, ""); - ensure("all done with: shown", doc.lookup->pending == 0 && studio.shows == 1); + { + INFO("all done with: shown"); + CHECK(doc.lookup->pending == 0); + CHECK(studio.shows == 1); + } // Begun again with some still to read: what the first had not // begun is let go of, and its answers dropped. studio.loads.clear(); lookUp(ALEditorCommand::FindReferences); - ensure_equals("two read", studio.loads.size(), size_t(2)); + UNSCOPED_INFO("two read"); + REQUIRE(studio.loads.size() == size_t(2)); lookUp(ALEditorCommand::FindReferences); - ensure_equals("two more, for the new one", studio.loads.size(), size_t(4)); + UNSCOPED_INFO("two more, for the new one"); + REQUIRE(studio.loads.size() == size_t(4)); studio.loads[0].loaded(LLUUID::null, ""); studio.loads[1].loaded(LLUUID::null, ""); - ensure_equals("the first's answers begin nothing", studio.loads.size(), size_t(4)); + UNSCOPED_INFO("the first's answers begin nothing"); + REQUIRE(studio.loads.size() == size_t(4)); studio.loads[2].loaded(LLUUID::null, ""); - ensure_equals("the new one's go on", studio.loads.size(), size_t(5)); + UNSCOPED_INFO("the new one's go on"); + REQUIRE(studio.loads.size() == size_t(5)); } - template<> template<> - void alscriptlookup_object::test<11>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: folderCandidates are the folder's other scripts in the same language", "[alscriptlookup]") { - set_test_name("an inventory script's lookups reach the others of its folder in its language: SLua by subtype or runtime, not notecards, not itself"); const auto made = [](const char* name, LLAssetType::EType type, U32 subtype, const char* runtime) { LLPointer item = new LLInventoryItem(); item->setUUID(LLUUID::generateNewID()); @@ -751,106 +952,177 @@ namespace tut const std::vector folder = { own.get(), lib.get(), lua.get(), onluau.get(), readme.get() }; const std::vector lsl = ALScriptLookup::folderCandidates(folder, own->getUUID(), false); - ensure("LSL: the other LSL script", lsl.size() == 1 && lsl[0].name == "lib.lsl" && lsl[0].ref.inInventory() && lsl[0].ref.item == lib->getUUID()); + { + INFO("LSL: the other LSL script"); + REQUIRE(lsl.size() == 1); + CHECK(lsl[0].name == "lib.lsl"); + CHECK(lsl[0].ref.inInventory()); + CHECK(lsl[0].ref.item == lib->getUUID()); + } const std::vector slua = ALScriptLookup::folderCandidates(folder, lua->getUUID(), true); - ensure("SLua: by runtime too", slua.size() == 1 && slua[0].name == "port.luau"); + { + INFO("SLua: by runtime too"); + REQUIRE(slua.size() == 1); + CHECK(slua[0].name == "port.luau"); + } } - template<> template<> - void alscriptlookup_object::test<12>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: a previewed rename is made at the places kept and clashes only with code", "[alscriptlookup]") { - set_test_name("Rename previewed: Shift-Return shows each place, made at those kept; a name anywhere in what it changes is a clash; an include's other scripts said out of reach"); make(); lookUp(ALEditorCommand::Rename, false); - ensure("previewing offered", (bool)studio.previewed); - ensure("the prompt says Shift-Return shows it first", has(studio.hint("sum"), "RenamePreviewHint")); + UNSCOPED_INFO("previewing offered"); + REQUIRE((bool)studio.previewed); + UNSCOPED_INFO("the prompt says Shift-Return shows it first"); + CHECK(has(studio.hint("sum"), "RenamePreviewHint")); studio.previewed("9lives"); - ensure("no name: nothing shown", has(services.statuses.back(), "RenameBadName") && !studio.apply); + { + INFO("no name: nothing shown"); + CHECK(has(services.statuses.back(), "RenameBadName")); + REQUIRE_FALSE(studio.apply); + } studio.previewed("sum"); - ensure("shown from its tab", studio.previewIn == "a" && studio.previewName == "sum" && studio.previewOf.places.size() == 2); - ensure("what it will do said over them", has(studio.previewSaid, "RenameTo [COUNT]=2") && !has(studio.previewSaid, "RenamePreviewHint")); + { + INFO("shown from its tab"); + CHECK(studio.previewIn == "a"); + CHECK(studio.previewName == "sum"); + REQUIRE(studio.previewOf.places.size() == 2); + } + { + INFO("what it will do said over them"); + CHECK(has(studio.previewSaid, "RenameTo [COUNT]=2")); + CHECK_FALSE(has(studio.previewSaid, "RenamePreviewHint")); + } studio.apply({ 1 }); Doc& doc = *services.findDoc("a"); - ensure_equals("made at the one kept", doc.editor->text(), std::string("integer count;\ndefault { state_entry() { sum = 1; } }\n")); + UNSCOPED_INFO("made at the one kept"); + CHECK(doc.editor->text() == std::string("integer count;\ndefault { state_entry() { sum = 1; } }\n")); // A local of the same name -- in no outline -- is a clash; a name in // a comment or a string is not. doc.editor->setText("integer count;\ndefault { state_entry() { integer total = count; llSay(0, \"hidden\"); } } // gone\n"); lookUp(ALEditorCommand::Rename, false); - ensure("a local's name", has(studio.hint("total"), "RenameClash") && has(studio.hint("total"), "[SCRIPT]=A")); - ensure("not a string's", !has(studio.hint("hidden"), "RenameClash")); - ensure("nor a comment's", !has(studio.hint("gone"), "RenameClash")); + { + INFO("a local's name"); + CHECK(has(studio.hint("total"), "RenameClash")); + CHECK(has(studio.hint("total"), "[SCRIPT]=A")); + } + UNSCOPED_INFO("not a string's"); + CHECK_FALSE(has(studio.hint("hidden"), "RenameClash")); + UNSCOPED_INFO("nor a comment's"); + CHECK_FALSE(has(studio.hint("gone"), "RenameClash")); // A place in an include: the scripts elsewhere that include it are // not reached, and said to be so. unit->start(doc, ALEditorCommand::Rename, refsOf("count"), true, "disk:/lib.lsl", span(0, 8, 5), { place("", 1, 26), place("disk:/lib.lsl", 0, 8, 5, "lib.lsl") }, doc.editor->document().version()); - ensure("out of reach said", has(studio.hint("sum"), "RenameUnreached [NAMES]=lib.lsl")); - - ensure("SLua: a comment is not a mention", !ALScriptLookup::mentions("local a = 1 -- total\n", "total", true)); - ensure("nor a long comment", !ALScriptLookup::mentions("--[[ total ]] local b = 2", "total", true)); - ensure("nor a long string", !ALScriptLookup::mentions("local s = [==[ total ]==]", "total", true)); - ensure("a local is", ALScriptLookup::mentions("local total = 1", "total", true)); - ensure("not part of a longer name", !ALScriptLookup::mentions("integer totals;", "total", false)); - ensure("LSL: nor in a block comment", !ALScriptLookup::mentions("/* total */ integer x;", "total", false)); + UNSCOPED_INFO("out of reach said"); + CHECK(has(studio.hint("sum"), "RenameUnreached [NAMES]=lib.lsl")); + + UNSCOPED_INFO("SLua: a comment is not a mention"); + CHECK_FALSE(ALScriptLookup::mentions("local a = 1 -- total\n", "total", true)); + UNSCOPED_INFO("nor a long comment"); + CHECK_FALSE(ALScriptLookup::mentions("--[[ total ]] local b = 2", "total", true)); + UNSCOPED_INFO("nor a long string"); + CHECK_FALSE(ALScriptLookup::mentions("local s = [==[ total ]==]", "total", true)); + UNSCOPED_INFO("a local is"); + CHECK(ALScriptLookup::mentions("local total = 1", "total", true)); + UNSCOPED_INFO("not part of a longer name"); + CHECK_FALSE(ALScriptLookup::mentions("integer totals;", "total", false)); + UNSCOPED_INFO("LSL: nor in a block comment"); + CHECK_FALSE(ALScriptLookup::mentions("/* total */ integer x;", "total", false)); } - template<> template<> - void alscriptlookup_object::test<13>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: the object's scripts wait on its prims and what was missed is said", "[alscriptlookup]") { - set_test_name("an object's others taken once its prims have said what they hold; the prims that did not, and a script not read, said with what was found"); make(); studio.others = { { b, "B" }, { c, "C" } }; studio.unlisted = 2; studio.holdCandidates = true; lookUp(ALEditorCommand::FindReferences); - ensure("asked", studio.asked == Names{ "a" }); - ensure("nothing read while the prims are asked", studio.loads.empty()); - ensure_equals("nothing shown", studio.shows, 0); + UNSCOPED_INFO("asked"); + CHECK(studio.asked == Names{ "a" }); + UNSCOPED_INFO("nothing read while the prims are asked"); + REQUIRE(studio.loads.empty()); + UNSCOPED_INFO("nothing shown"); + CHECK(studio.shows == 0); studio.heldCandidates(); - ensure_equals("both read", studio.loads.size(), size_t(2)); + UNSCOPED_INFO("both read"); + REQUIRE(studio.loads.size() == size_t(2)); studio.loads[0].loaded(LLUUID::null, std::nullopt); - ensure_equals("one still out", studio.shows, 0); + UNSCOPED_INFO("one still out"); + CHECK(studio.shows == 0); studio.loads[1].loaded(LLUUID::null, std::string("default { }\n")); - ensure_equals("shown", studio.shows, 1); + UNSCOPED_INFO("shown"); + CHECK(studio.shows == 1); const std::string said = services.statuses.back(); - ensure("found, then what was passed over: " + said, - has(said, "ReferencesFound") && has(said, "LookupUnlisted [COUNT]=2") && has(said, "LookupUnread [COUNT]=1 [NAMES]=B")); + { + INFO("found, then what was passed over: " + said); + CHECK(has(said, "ReferencesFound")); + CHECK(has(said, "LookupUnlisted [COUNT]=2")); + CHECK(has(said, "LookupUnread [COUNT]=1 [NAMES]=B")); + } // A rename says it under the prompt, all prims listed this time. studio.holdCandidates = false; studio.unlisted = 0; studio.loads.clear(); lookUp(ALEditorCommand::Rename); - ensure_equals("read again", studio.loads.size(), size_t(2)); + UNSCOPED_INFO("read again"); + REQUIRE(studio.loads.size() == size_t(2)); studio.loads[0].loaded(LLUUID::null, std::nullopt); studio.loads[1].loaded(LLUUID::null, std::string("default { }\n")); - ensure("a new name asked", static_cast(studio.hint)); + UNSCOPED_INFO("a new name asked"); + REQUIRE(static_cast(studio.hint)); const std::string hint = studio.hint("total"); - ensure("the hint says it: " + hint, has(hint, "LookupUnread [COUNT]=1 [NAMES]=B") && !has(hint, "LookupUnlisted")); + { + INFO("the hint says it: " + hint); + CHECK(has(hint, "LookupUnread [COUNT]=1 [NAMES]=B")); + CHECK_FALSE(has(hint, "LookupUnlisted")); + } } - template<> template<> - void alscriptlookup_object::test<14>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: ALScriptPlaces::Lines gives lines without returns and none past the end", "[alscriptlookup]") { - set_test_name("a text's lines found once: held, read where it is, or open in a tab; none past the end; a line's return left off"); const ALScriptPlaces::Lines held(std::make_shared("one\r\ntwo\n\nfour")); - ensure("four lines", held.has(0) && held.has(3) && !held.has(4) && !held.has(-1)); - ensure("each as it is", held.line(0) == "one" && held.line(1) == "two" && held.line(2).empty() && held.line(3) == "four"); - ensure("none past the end", held.line(9).empty()); + { + INFO("four lines"); + REQUIRE(held.has(0)); + REQUIRE(held.has(3)); + REQUIRE_FALSE(held.has(4)); + REQUIRE_FALSE(held.has(-1)); + } + { + INFO("each as it is"); + CHECK(held.line(0) == "one"); + CHECK(held.line(1) == "two"); + REQUIRE(held.line(2).empty()); + CHECK(held.line(3) == "four"); + } + UNSCOPED_INFO("none past the end"); + REQUIRE(held.line(9).empty()); const std::string text = "a\nb\n"; const ALScriptPlaces::Lines here(text); - ensure("read where it is, the last line empty", here.line(1) == "b" && here.has(2) && here.line(2).empty() && !here.has(3)); + { + INFO("read where it is, the last line empty"); + CHECK(here.line(1) == "b"); + REQUIRE(here.has(2)); + REQUIRE(here.line(2).empty()); + REQUIRE_FALSE(here.has(3)); + } const ALTextDocument open("x\ny"); const ALScriptPlaces::Lines tab(&open); - ensure("a tab's", tab.line(1) == "y" && !tab.has(2)); - ensure("nothing: no lines", !ALScriptPlaces::Lines().has(0)); + { + INFO("a tab's"); + CHECK(tab.line(1) == "y"); + REQUIRE_FALSE(tab.has(2)); + } + UNSCOPED_INFO("nothing: no lines"); + REQUIRE_FALSE(ALScriptPlaces::Lines().has(0)); } - template<> template<> - void alscriptlookup_object::test<15>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: a rename preview compares an open unchanged file with its renamed text", "[alscriptlookup]") { - set_test_name("a rename previewed shows what it makes of a file, at the places kept: here, or in another open and unchanged; not in one that is not"); make(); Doc& doc = tab("a", a, A_TEXT, "A"); Doc& open = tab("b", b, "foo() { count = 2; }\nbar() { total = count; }\n", "B"); @@ -859,33 +1131,46 @@ namespace tut { place("", 0, 8), place("", 1, 26), place(pb, 0, 8, 5, "B"), place(pb, 1, 16, 5, "B"), place(pd, 2, 4, 5, "D") }, doc.editor->document().version()); studio.previewed("sum"); - ensure("offered", (bool)studio.changes); + UNSCOPED_INFO("offered"); + REQUIRE((bool)studio.changes); studio.changes("", { 1, 2, 3 }); - ensure_equals("here, at the one of its own kept", studio.compared.size(), 1U); - ensure_equals("beside it as it is", studio.compared.back(), + UNSCOPED_INFO("here, at the one of its own kept"); + REQUIRE(studio.compared.size() == 1U); + UNSCOPED_INFO("beside it as it is"); + CHECK(studio.compared.back() == "a: " + std::string(A_TEXT) + " | integer count;\ndefault { state_entry() { sum = 1; } }\n (CompareNow | RenameAfter [NAME]=sum [SCRIPT]=A)"); - ensure("in its tab, brought forward", studio.activated.back() == "a"); - ensure("nothing changed", doc.editor->text() == A_TEXT); + UNSCOPED_INFO("in its tab, brought forward"); + CHECK(studio.activated.back() == "a"); + UNSCOPED_INFO("nothing changed"); + CHECK(doc.editor->text() == A_TEXT); studio.changes(pb, { 2, 3 }); - ensure_equals("another open", studio.compared.back(), + UNSCOPED_INFO("another open"); + CHECK(studio.compared.back() == "b: foo() { count = 2; }\nbar() { total = count; }\n | foo() { sum = 2; }\nbar() { total = sum; }\n (CompareNow | RenameAfter [NAME]=sum [SCRIPT]=B)"); - ensure("in its tab", studio.activated.back() == "b"); + UNSCOPED_INFO("in its tab"); + CHECK(studio.activated.back() == "b"); const size_t before = studio.compared.size(); studio.changes(pd, { 4 }); - ensure("not open: said, not shown", studio.compared.size() == before && has(services.statuses.back(), "RenameChangesNotHere [NAME]=sum [SCRIPT]=D") && - services.statusFailures.back()); + { + INFO("not open: said, not shown"); + REQUIRE(studio.compared.size() == before); + CHECK(has(services.statuses.back(), "RenameChangesNotHere [NAME]=sum [SCRIPT]=D")); + REQUIRE(services.statusFailures.back()); + } open.editor->insertText("// "); studio.changes(pb, { 2, 3 }); - ensure("changed since: said", studio.compared.size() == before && has(services.statuses.back(), "RenameChangesNotHere")); + { + INFO("changed since: said"); + REQUIRE(studio.compared.size() == before); + CHECK(has(services.statuses.back(), "RenameChangesNotHere")); + } } - template<> template<> - void alscriptlookup_object::test<16>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: open files on disk are looked through and renamed with the script", "[alscriptlookup]") { - set_test_name("files on disk open here are looked through too, which no object lists: a module's field renamed in the script, the module and another script requiring it"); make(); const std::string LIB = "disk:/s/lib.luau"; const std::string OTHER = "disk:/s/b.luau"; @@ -905,40 +1190,68 @@ namespace tut // module's declaration. unit->start(doc, ALEditorCommand::Rename, refsOf("twice"), true, LIB, span(1, 11, 5), { place("", 1, 10), place(LIB, 1, 11, 5, "lib.luau") }, doc.editor->document().version()); - ensure_equals("each open file of the language, as it stands in its tab", studio.expands.size(), size_t(2)); + UNSCOPED_INFO("each open file of the language, as it stands in its tab"); + REQUIRE(studio.expands.size() == size_t(2)); const ALScriptPreprocessor::Request& module = studio.expands[0].request; - ensure("the module, by its path, no item", module.path == LIB && module.ref.isNull() && module.name == "lib.luau" && - module.sourceText() == LIB_TEXT); - ensure("the other script", studio.expands[1].request.path == OTHER && studio.expands[1].request.sourceText() == B_LUA); + { + INFO("the module, by its path, no item"); + CHECK(module.path == LIB); + CHECK(module.ref.isNull()); + CHECK(module.name == "lib.luau"); + CHECK(module.sourceText() == LIB_TEXT); + } + { + INFO("the other script"); + CHECK(studio.expands[1].request.path == OTHER); + CHECK(studio.expands[1].request.sourceText() == B_LUA); + } // The module read alone is the home itself; the other script has it // ahead of its own lines. studio.expands[0].expanded(expansion("lib.luau", LIB, LIB_TEXT)); studio.expands[1].expanded(expansion("b.luau", OTHER, B_LUA, "lib.luau", LIB, LIB_TEXT)); - ensure_equals("both asked", studio.asks.size(), size_t(2)); - ensure("the module at its declaration", studio.asks[0].request.line == 1 && studio.asks[0].request.column == 11 && - studio.asks[0].request.id == "lookup:a:" + LIB); - ensure("the other where the module's declaration went", studio.asks[1].request.line == 1 && studio.asks[1].request.column == 11); + UNSCOPED_INFO("both asked"); + REQUIRE(studio.asks.size() == size_t(2)); + { + INFO("the module at its declaration"); + CHECK(studio.asks[0].request.line == 1); + CHECK(studio.asks[0].request.column == 11); + CHECK(studio.asks[0].request.id == "lookup:a:" + LIB); + } + { + INFO("the other where the module's declaration went"); + CHECK(studio.asks[1].request.line == 1); + CHECK(studio.asks[1].request.column == 11); + } studio.asks[0].answered(answer({ span(1, 11, 5) })); studio.asks[1].answered(answer({ span(1, 11, 5), span(4, 10, 5) })); - ensure("asked for the new name", (bool)studio.chosen); - ensure_equals("each place once: the script's, the module's, the other's", doc.lookup->places.size(), size_t(3)); - ensure("the other's, by its path", std::any_of(doc.lookup->places.begin(), doc.lookup->places.end(), [&](const Doc::Place& place) { + UNSCOPED_INFO("asked for the new name"); + REQUIRE((bool)studio.chosen); + UNSCOPED_INFO("each place once: the script's, the module's, the other's"); + REQUIRE(doc.lookup->places.size() == size_t(3)); + UNSCOPED_INFO("the other's, by its path"); + CHECK(std::any_of(doc.lookup->places.begin(), doc.lookup->places.end(), [&](const Doc::Place& place) { return place.file == OTHER && place.fileName == "b.luau" && place.span.line == 1 && place.span.column == 10; })); studio.chosen("double"); - ensure_equals("here", doc.editor->text(), std::string("local lib = require(\"./lib\")\nprint(lib.double(2))\n")); - ensure_equals("in the module", lib.editor->text(), std::string("local M = {}\nfunction M.double(n) return n * 2 end\nreturn M\n")); - ensure_equals("in the other script", other.editor->text(), std::string("local lib = require(\"./lib\")\nprint(lib.double(4))\n")); - ensure("each its own step", lib.editor->undoJournal().undoLabel() == "rename" && other.editor->undoJournal().undoLabel() == "rename"); - ensure_equals("another language's file left alone", lsl.editor->text(), std::string("integer twice;\n")); + UNSCOPED_INFO("here"); + CHECK(doc.editor->text() == std::string("local lib = require(\"./lib\")\nprint(lib.double(2))\n")); + UNSCOPED_INFO("in the module"); + CHECK(lib.editor->text() == std::string("local M = {}\nfunction M.double(n) return n * 2 end\nreturn M\n")); + UNSCOPED_INFO("in the other script"); + CHECK(other.editor->text() == std::string("local lib = require(\"./lib\")\nprint(lib.double(4))\n")); + { + INFO("each its own step"); + REQUIRE(lib.editor->undoJournal().undoLabel() == "rename"); + CHECK(other.editor->undoJournal().undoLabel() == "rename"); + } + UNSCOPED_INFO("another language's file left alone"); + CHECK(lsl.editor->text() == std::string("integer twice;\n")); } - template<> template<> - void alscriptlookup_object::test<17>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: scripts on disk in the script's folders are read and opened to be renamed", "[alscriptlookup]") { - set_test_name("scripts on disk under the folders a script reads from are looked through, open or not: one not open read as it is on disk, and opened to be renamed"); make(); // A folder of the scripter's, as the window lists it, where it // stands: what the walk names each file by. @@ -965,15 +1278,25 @@ namespace tut doc.language.lua = true; unit->start(doc, ALEditorCommand::Rename, refsOf("twice"), true, LIB, span(1, 11, 5), { place("", 1, 10), place(LIB, 1, 11, 5, "lib.luau") }, doc.editor->document().version()); - ensure_equals("the module open here once, the other read from disk, and the one not naming it passed over", studio.expands.size(), size_t(2)); - ensure("the module, as its tab has it", studio.expands[0].request.path == LIB && studio.expands[0].request.sourceText() == LIB_TEXT); - ensure("the other, as it is on disk", studio.expands[1].request.path == B && studio.expands[1].request.name == "b.luau" && - studio.expands[1].request.sourceText() == B_LUA); + UNSCOPED_INFO("the module open here once, the other read from disk, and the one not naming it passed over"); + REQUIRE(studio.expands.size() == size_t(2)); + { + INFO("the module, as its tab has it"); + CHECK(studio.expands[0].request.path == LIB); + CHECK(studio.expands[0].request.sourceText() == LIB_TEXT); + } + { + INFO("the other, as it is on disk"); + CHECK(studio.expands[1].request.path == B); + CHECK(studio.expands[1].request.name == "b.luau"); + CHECK(studio.expands[1].request.sourceText() == B_LUA); + } studio.expands[0].expanded(expansion("lib.luau", LIB, LIB_TEXT)); studio.expands[1].expanded(expansion("b.luau", B, B_LUA, "lib.luau", LIB, LIB_TEXT)); studio.asks[0].answered(answer({ span(1, 11, 5) })); studio.asks[1].answered(answer({ span(1, 11, 5), span(4, 10, 5) })); - ensure("the other's place, by its path", std::any_of(doc.lookup->places.begin(), doc.lookup->places.end(), [&](const Doc::Place& place) { + UNSCOPED_INFO("the other's place, by its path"); + CHECK(std::any_of(doc.lookup->places.begin(), doc.lookup->places.end(), [&](const Doc::Place& place) { return place.file == B && place.span.line == 1 && place.span.column == 10; })); @@ -985,17 +1308,20 @@ namespace tut return &opened; }; studio.chosen("double"); - ensure("opened to be renamed", studio.filesOpened == Names{ b_file }); + UNSCOPED_INFO("opened to be renamed"); + CHECK(studio.filesOpened == Names{ b_file }); const Doc* other = services.findDoc(B); - ensure("renamed there", other && other->editor->text() == "local lib = require(\"./lib\")\nprint(lib.double(4))\n"); + { + INFO("renamed there"); + REQUIRE(other); + CHECK(other->editor->text() == "local lib = require(\"./lib\")\nprint(lib.double(4))\n"); + } std::error_code ec; fs::remove_all(root, ec); } - template<> template<> - void alscriptlookup_object::test<18>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: SLua read apart asks in the module and maps places back through the piece", "[alscriptlookup]") { - set_test_name("SLua read apart, as the checker reads it: another script asked at the module's declaration in the module, with its modules, and each place read back through its own piece"); make(); const std::string LIB = "disk:/s/lib.luau"; const std::string OTHER = "disk:/s/b.luau"; @@ -1008,29 +1334,47 @@ namespace tut doc.language.lua = true; unit->start(doc, ALEditorCommand::FindReferences, refsOf("twice"), true, LIB, span(1, 11, 5), { place("", 1, 10), place(LIB, 1, 11, 5, "lib.luau") }, doc.editor->document().version()); - ensure_equals("the other expanded", studio.expands.size(), size_t(1)); - ensure("apart asked for", studio.expands[0].request.apart); + UNSCOPED_INFO("the other expanded"); + REQUIRE(studio.expands.size() == size_t(1)); + UNSCOPED_INFO("apart asked for"); + CHECK(studio.expands[0].request.apart); studio.expands[0].expanded(apartExpansion("b.luau", OTHER, B_LUA, "./lib", "lib.luau", LIB, LIB_TEXT)); - ensure_equals("asked", studio.asks.size(), size_t(1)); + UNSCOPED_INFO("asked"); + REQUIRE(studio.asks.size() == size_t(1)); const ALScriptAnalysis::Request& asked = studio.asks[0].request; - ensure("the script alone, its require a call", asked.text && *asked.text == B_LUA); - ensure("in the module, at its declaration in its own lines", asked.module == LIB && asked.line == 1 && asked.column == 11); - ensure("with its modules", asked.modules && asked.modules->modules.size() == 1 && asked.modules->modules[0].key == LIB && - asked.modules->reaches.size() == 1 && asked.modules->reaches[0].name == "./lib"); + { + INFO("the script alone, its require a call"); + REQUIRE(asked.text); + CHECK(*asked.text == B_LUA); + } + { + INFO("in the module, at its declaration in its own lines"); + CHECK(asked.module == LIB); + CHECK(asked.line == 1); + CHECK(asked.column == 11); + } + { + INFO("with its modules"); + REQUIRE(asked.modules); + REQUIRE(asked.modules->modules.size() == 1); + REQUIRE(asked.modules->modules[0].key == LIB); + REQUIRE(asked.modules->reaches.size() == 1); + CHECK(asked.modules->reaches[0].name == "./lib"); + } ALScriptAnalysis::Result result = answer({ span(1, 10, 5) }); result.references.elsewhere.push_back({ LIB, span(1, 11, 5) }); studio.asks[0].answered(result); - ensure("the other's place, through its piece", std::any_of(doc.lookup->places.begin(), doc.lookup->places.end(), [&](const Doc::Place& place) { + UNSCOPED_INFO("the other's place, through its piece"); + CHECK(std::any_of(doc.lookup->places.begin(), doc.lookup->places.end(), [&](const Doc::Place& place) { return place.file == OTHER && place.fileName == "b.luau" && place.span.line == 1 && place.span.column == 10; })); - ensure_equals("each once: the script's, the module's, the other's", doc.lookup->places.size(), size_t(3)); + UNSCOPED_INFO("each once: the script's, the module's, the other's"); + REQUIRE(doc.lookup->places.size() == size_t(3)); } - template<> template<> - void alscriptlookup_object::test<19>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: a file open under another path to it is read once as its tab has it", "[alscriptlookup]") { - set_test_name("a file open here by another way to its path is the one file: looked through once, as its tab has it, and found to be where the name is declared"); make(); namespace fs = std::filesystem; const fs::path made = fs::temp_directory_path() / ("alscriptlookup_" + LLUUID::generateNewID().asString()); @@ -1054,20 +1398,29 @@ namespace tut doc.language.lua = true; unit->start(doc, ALEditorCommand::FindReferences, refsOf("twice"), true, LIB, span(1, 11, 5), { place("", 1, 10), place(LIB, 1, 11, 5, "lib.luau") }, doc.editor->document().version()); - ensure_equals("the module once, and the other", studio.expands.size(), size_t(2)); - ensure("the module as its tab has it", studio.expands[0].request.path == LIB_TAB && studio.expands[0].request.sourceText() == TYPED); - ensure("the other from disk", studio.expands[1].request.sourceText() == B_LUA); + UNSCOPED_INFO("the module once, and the other"); + REQUIRE(studio.expands.size() == size_t(2)); + { + INFO("the module as its tab has it"); + CHECK(studio.expands[0].request.path == LIB_TAB); + CHECK(studio.expands[0].request.sourceText() == TYPED); + } + UNSCOPED_INFO("the other from disk"); + CHECK(studio.expands[1].request.sourceText() == B_LUA); studio.expands[0].expanded(expansion("lib.luau", LIB_TAB, TYPED)); - ensure_equals("the home itself, asked at its declaration", studio.asks.size(), size_t(1)); - ensure("there", studio.asks[0].request.line == 1 && studio.asks[0].request.column == 11); + UNSCOPED_INFO("the home itself, asked at its declaration"); + REQUIRE(studio.asks.size() == size_t(1)); + { + INFO("there"); + CHECK(studio.asks[0].request.line == 1); + CHECK(studio.asks[0].request.column == 11); + } std::error_code ec; fs::remove_all(root, ec); } - template<> template<> - void alscriptlookup_object::test<20>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: folders on disk are walked off the main thread and stale walks dropped", "[alscriptlookup]") { - set_test_name("with a main loop to hand them back to, the folders on disk are walked and read off the main thread, the lookup held open for them; nothing comes of a walk once the lookups are gone"); make(); namespace fs = std::filesystem; const fs::path made = fs::temp_directory_path() / ("alscriptlookup_" + LLUUID::generateNewID().asString()); @@ -1099,12 +1452,23 @@ namespace tut const std::string LIB = "disk:/s/lib.luau"; unit->start(doc, ALEditorCommand::FindReferences, refsOf("twice"), true, LIB, span(1, 11, 5), { place("", 1, 10) }, doc.editor->document().version()); - ensure("nothing read here", studio.expands.empty()); - ensure("held open for the walk", doc.lookup->pending == 1 && studio.shows == 0); - ensure("what it read handed back", pumped([&] { return !studio.expands.empty(); }, std::chrono::seconds(5))); - ensure("the one naming it, as it is on disk", studio.expands.size() == 1 && studio.expands[0].request.sourceText() == B_LUA); + UNSCOPED_INFO("nothing read here"); + REQUIRE(studio.expands.empty()); + { + INFO("held open for the walk"); + CHECK(doc.lookup->pending == 1); + CHECK(studio.shows == 0); + } + UNSCOPED_INFO("what it read handed back"); + REQUIRE(pumped([&] { return !studio.expands.empty(); }, std::chrono::seconds(5))); + { + INFO("the one naming it, as it is on disk"); + REQUIRE(studio.expands.size() == 1); + CHECK(studio.expands[0].request.sourceText() == B_LUA); + } studio.expands[0].expanded(expansion("b.luau", studio.expands[0].request.path, B_LUA)); - ensure_equals("shown once it is done with", studio.shows, 1); + UNSCOPED_INFO("shown once it is done with"); + CHECK(studio.shows == 1); // Begun again while its walk is under way: the walk let go of, and // only the new lookup's read looked through. @@ -1112,37 +1476,56 @@ namespace tut doc.editor->document().version()); unit->start(doc, ALEditorCommand::FindReferences, refsOf("twice"), true, LIB, span(1, 11, 5), { place("", 1, 10) }, doc.editor->document().version()); - ensure("the new one's handed back", pumped([&] { return studio.expands.size() > 1; }, std::chrono::seconds(5))); + UNSCOPED_INFO("the new one's handed back"); + REQUIRE(pumped([&] { return studio.expands.size() > 1; }, std::chrono::seconds(5))); pumped([] { return false; }, std::chrono::milliseconds(300)); - ensure_equals("and nothing of the old one's", studio.expands.size(), size_t(2)); + UNSCOPED_INFO("and nothing of the old one's"); + REQUIRE(studio.expands.size() == size_t(2)); studio.expands[1].expanded(expansion("b.luau", studio.expands[1].request.path, B_LUA)); - ensure_equals("shown once", studio.shows, 2); + UNSCOPED_INFO("shown once"); + CHECK(studio.shows == 2); // Begun again, and the lookups gone before what it read is back. unit->start(doc, ALEditorCommand::FindReferences, refsOf("twice"), true, LIB, span(1, 11, 5), { place("", 1, 10) }, doc.editor->document().version()); unit.reset(); pumped([] { return false; }, std::chrono::milliseconds(300)); - ensure_equals("nothing comes of it", studio.expands.size(), size_t(2)); + UNSCOPED_INFO("nothing comes of it"); + REQUIRE(studio.expands.size() == size_t(2)); std::error_code ec; fs::remove_all(root, ec); } - template<> template<> - void alscriptlookup_object::test<21>() + TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: held lines match a tab's with a lone CR a break and CRLF one", "[alscriptlookup]") { - set_test_name("a text's lines held apart are the lines its tab would have: a lone CR a break, CRLF one"); const std::string text = "one\rtwo\r\nthree\n\rfive"; const ALScriptPlaces::Lines held(std::make_shared(text)); const ALTextDocument open(text); const ALScriptPlaces::Lines tab(&open); - ensure("as many as the tab's", held.has(4) && !held.has(5) && tab.has(4) && !tab.has(5)); + { + INFO("as many as the tab's"); + REQUIRE(held.has(4)); + REQUIRE_FALSE(held.has(5)); + REQUIRE(tab.has(4)); + REQUIRE_FALSE(tab.has(5)); + } for (S32 line = 0; line < 5; ++line) { - ensure_equals("line " + std::to_string(line) + " the tab's", held.line(line), tab.line(line)); + UNSCOPED_INFO("line " + std::to_string(line) + " the tab's"); + REQUIRE(held.line(line) == tab.line(line)); + } + { + INFO("each as it is"); + CHECK(held.line(1) == "two"); + REQUIRE(held.line(3).empty()); + CHECK(held.line(4) == "five"); } - ensure("each as it is", held.line(1) == "two" && held.line(3).empty() && held.line(4) == "five"); const ALScriptPlaces::Lines here(text); - ensure("read where it is, the same", here.line(2) == "three" && here.has(4) && !here.has(5)); + { + INFO("read where it is, the same"); + CHECK(here.line(2) == "three"); + REQUIRE(here.has(4)); + REQUIRE_FALSE(here.has(5)); + } } } diff --git a/indra/newview/tests/alscriptnavigation_test.cpp b/indra/newview/tests/alscriptnavigation_test.cpp index 0e799362a8..683440d2fc 100644 --- a/indra/newview/tests/alscriptnavigation_test.cpp +++ b/indra/newview/tests/alscriptnavigation_test.cpp @@ -30,7 +30,7 @@ #include "alscriptstudio_fixture.h" #include "llfocusmgr.h" -#include "../test/lltut.h" +#include #include #include @@ -79,7 +79,7 @@ namespace std::string lines(const std::optional& place) { return place ? place->doc + ":" + std::to_string(place->at.line) : "none"; } } -namespace tut +namespace { struct alscriptnavigation_data { @@ -93,7 +93,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } unit = std::make_unique(services, studio, studio); studio.navigation = unit.get(); @@ -130,23 +130,26 @@ namespace tut static void waitToSettle() { std::this_thread::sleep_for(std::chrono::milliseconds(400)); } }; - typedef test_group alscriptnavigation_group; - typedef alscriptnavigation_group::object alscriptnavigation_object; - alscriptnavigation_group alscriptnavigation_instance("alscriptnavigation"); - - template<> template<> - void alscriptnavigation_object::test<1>() + TEST_CASE_METHOD(alscriptnavigation_data, "alscriptnavigation: the history notes a line once and keeps the fifty latest places", "[alscriptnavigation]") { - set_test_name("the history: once a line, a view its own place, the fifty latest, and the way forward gone once a place is noted"); ALNavHistory history; const auto open = [](const std::string&) { return true; }; history.note(at("a", 1)); history.note(at("a", 1)); - ensure("once a line", lines(history.take(false, std::nullopt, open)) == "a:1" && !history.canGo(false)); + { + INFO("once a line"); + CHECK(lines(history.take(false, std::nullopt, open)) == "a:1"); + CHECK_FALSE(history.canGo(false)); + } history.note(at("a", 1)); history.note(at("a", 1, Doc::View::Expanded)); std::optional expanded = history.take(false, std::nullopt, open); - ensure("the expansion's line its own place", expanded && expanded->view == Doc::View::Expanded && history.canGo(false)); + { + INFO("the expansion's line its own place"); + REQUIRE(expanded); + CHECK(expanded->view == Doc::View::Expanded); + CHECK(history.canGo(false)); + } history.take(false, std::nullopt, open); for (S32 i = 0; i < 60; ++i) { @@ -159,18 +162,22 @@ namespace tut oldest = history.take(false, std::nullopt, open); ++count; } - ensure("fifty, the oldest dropped", count == 50 && lines(oldest) == "a:10"); + { + INFO("fifty, the oldest dropped"); + CHECK(count == 50); + CHECK(lines(oldest) == "a:10"); + } history.note(at("a", 1)); history.take(false, at("b", 2), open); - ensure("where it went from, forward", history.canGo(true)); + UNSCOPED_INFO("where it went from, forward"); + CHECK(history.canGo(true)); history.note(at("c", 3)); - ensure("a place noted: the way forward gone", !history.canGo(true)); + UNSCOPED_INFO("a place noted: the way forward gone"); + CHECK_FALSE(history.canGo(true)); } - template<> template<> - void alscriptnavigation_object::test<2>() + TEST_CASE_METHOD(alscriptnavigation_data, "alscriptnavigation: back and forward pass closed tabs over and follow renamed ones", "[alscriptnavigation]") { - set_test_name("back and forward: where it goes from put on the other way, a closed tab passed over, a tab renamed followed"); ALNavHistory history; std::set closed; const auto open = [&closed](const std::string& id) { return closed.count(id) == 0; }; @@ -178,96 +185,134 @@ namespace tut history.note(at("gone", 2)); history.note(at("b", 3)); closed.insert("gone"); - ensure("back", lines(history.take(false, at("c", 4), open)) == "b:3"); - ensure("back past the closed one", lines(history.take(false, at("b", 3), open)) == "a:1" && !history.canGo(false)); - ensure("forward again", lines(history.take(true, at("a", 1), open)) == "b:3"); + UNSCOPED_INFO("back"); + CHECK(lines(history.take(false, at("c", 4), open)) == "b:3"); + { + INFO("back past the closed one"); + CHECK(lines(history.take(false, at("b", 3), open)) == "a:1"); + CHECK_FALSE(history.canGo(false)); + } + UNSCOPED_INFO("forward again"); + CHECK(lines(history.take(true, at("a", 1), open)) == "b:3"); history.rekey("c", "renamed"); - ensure("followed", lines(history.take(true, std::nullopt, open)) == "renamed:4"); - ensure("nowhere left", !history.take(true, std::nullopt, open)); + UNSCOPED_INFO("followed"); + CHECK(lines(history.take(true, std::nullopt, open)) == "renamed:4"); + UNSCOPED_INFO("nowhere left"); + REQUIRE_FALSE(history.take(true, std::nullopt, open)); } - template<> template<> - void alscriptnavigation_object::test<3>() + TEST_CASE_METHOD(alscriptnavigation_data, "alscriptnavigation: a walk is noted as one jump and back and forward are shown by the window", "[alscriptnavigation]") { - set_test_name("a jump from the tab in front, a walk one jump until it ends; back and forward shown by the window"); ALScriptNavigation& unit = make(); Doc& a = tab("a", 1); services.front = 0; unit.noteJump(true); a.editor->setCaret(ALTextPos(3, 0)); unit.noteJump(true); - ensure("a walk: one jump", unit.walking()); + UNSCOPED_INFO("a walk: one jump"); + CHECK(unit.walking()); unit.goBack(false); - ensure("back where the walk began", studio.shown == Names{ "a:1" } && !unit.walking() && !unit.canGo(false)); + { + INFO("back where the walk began"); + CHECK(studio.shown == Names{ "a:1" }); + CHECK_FALSE(unit.walking()); + CHECK_FALSE(unit.canGo(false)); + } unit.goBack(true); - ensure("and forward to where it was then", studio.shown == Names{ "a:1", "a:3" }); + UNSCOPED_INFO("and forward to where it was then"); + CHECK(studio.shown == Names{ "a:1", "a:3" }); unit.noteJump(true); unit.walked(); a.editor->setCaret(ALTextPos(2, 0)); unit.noteJump(true); unit.goBack(false); - ensure("a walk ended: the next is a jump of its own", studio.shown.back() == "a:2"); + UNSCOPED_INFO("a walk ended: the next is a jump of its own"); + CHECK(studio.shown.back() == "a:2"); a.loaded = false; unit.noteJump(); - ensure("a tab not loaded: nothing noted", !unit.canGo(false) || studio.shown.size() == 3); + UNSCOPED_INFO("a tab not loaded: nothing noted"); + REQUIRE((!unit.canGo(false) || studio.shown.size() == 3)); } - template<> template<> - void alscriptnavigation_object::test<4>() + TEST_CASE_METHOD(alscriptnavigation_data, "alscriptnavigation: a row stayed on opens as a preview unless already open or passed or left", "[alscriptnavigation]") { - set_test_name("a row stayed on a moment opened as a preview; one open already, walked past, or left, not"); ALScriptNavigation& unit = make(); ALPaneList* l = list(); studio.open.insert("open path"); - ensure("open already: at once", !unit.deferOpen(l, "open path")); - ensure("nowhere: at once", !unit.deferOpen(l, "")); - ensure("put off", unit.deferOpen(l, "a path")); + UNSCOPED_INFO("open already: at once"); + CHECK_FALSE(unit.deferOpen(l, "open path")); + UNSCOPED_INFO("nowhere: at once"); + CHECK_FALSE(unit.deferOpen(l, "")); + UNSCOPED_INFO("put off"); + CHECK(unit.deferOpen(l, "a path")); unit.pumpSettle(); - ensure("not yet", studio.chosen == 0); + UNSCOPED_INFO("not yet"); + CHECK(studio.chosen == 0); waitToSettle(); unit.pumpSettle(); - ensure("stayed on: opened, as a preview", studio.chosen == 1 && studio.previewing && !unit.openingPreview()); + { + INFO("stayed on: opened, as a preview"); + CHECK(studio.chosen == 1); + CHECK(studio.previewing); + CHECK_FALSE(unit.openingPreview()); + } unit.pumpSettle(); - ensure("once", studio.chosen == 1); + UNSCOPED_INFO("once"); + CHECK(studio.chosen == 1); unit.deferOpen(l, "a path"); l->selectByValue(LLSD("b")); waitToSettle(); unit.pumpSettle(); - ensure("walked past: not", studio.chosen == 1); + UNSCOPED_INFO("walked past: not"); + CHECK(studio.chosen == 1); unit.deferOpen(l, "a path"); gFocusMgr.setKeyboardFocus(nullptr); waitToSettle(); unit.pumpSettle(); - ensure("left: not", studio.chosen == 1); + UNSCOPED_INFO("left: not"); + CHECK(studio.chosen == 1); } - template<> template<> - void alscriptnavigation_object::test<5>() + TEST_CASE_METHOD(alscriptnavigation_data, "alscriptnavigation: the preview is let go of unless typed in or worked from or revealed", "[alscriptnavigation]") { - set_test_name("the preview let go of for the next, held where anything was done in it or it is worked from; to the editor, held"); ALScriptNavigation& unit = make(); Doc& a = tab("a"); a.preview = true; unit.closePreview(); - ensure("let go of", studio.letGo == Names{ "a" }); + UNSCOPED_INFO("let go of"); + CHECK(studio.letGo == Names{ "a" }); Doc& b = tab("b"); b.preview = true; b.editor->insertText("typed"); unit.closePreview(); - ensure("typed in: held", !b.preview && studio.tabs == 1 && studio.letGo.size() == 1); + { + INFO("typed in: held"); + CHECK_FALSE(b.preview); + CHECK(studio.tabs == 1); + REQUIRE(studio.letGo.size() == 1); + } Doc& c = tab("c"); c.preview = true; studio.worked = "c"; unit.closePreview(); - ensure("worked from: held", !c.preview && studio.letGo.size() == 1); + { + INFO("worked from: held"); + CHECK_FALSE(c.preview); + REQUIRE(studio.letGo.size() == 1); + } Doc& d = tab("d"); d.preview = true; services.front = 3; unit.revealed(nullptr, true); - ensure("taken to the editor: held, and given the keyboard", !d.preview && studio.focused == Names{ "d" }); + { + INFO("taken to the editor: held, and given the keyboard"); + CHECK_FALSE(d.preview); + CHECK(studio.focused == Names{ "d" }); + } ALPaneList* l = list(); gFocusMgr.setKeyboardFocus(nullptr); unit.revealed(l, false); - ensure("back to the list", l->hasFocus()); + UNSCOPED_INFO("back to the list"); + CHECK(l->hasFocus()); } } diff --git a/indra/newview/tests/alscriptobjectcheck_test.cpp b/indra/newview/tests/alscriptobjectcheck_test.cpp index 3a6ebb765c..b97ad27148 100644 --- a/indra/newview/tests/alscriptobjectcheck_test.cpp +++ b/indra/newview/tests/alscriptobjectcheck_test.cpp @@ -34,7 +34,7 @@ #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include #include #include @@ -144,7 +144,7 @@ namespace } } -namespace tut +namespace { struct alscriptobjectcheck_data { @@ -166,54 +166,96 @@ namespace tut window.texts = { { id(11), "default {}\n" }, { id(12), "default {}\n" } }; } }; - typedef test_group alscriptobjectcheck_group; - typedef alscriptobjectcheck_group::object alscriptobjectcheck_object; - alscriptobjectcheck_group alscriptobjectcheck_instance("alscriptobjectcheck"); - template<> template<> - void alscriptobjectcheck_object::test<1>() + TEST_CASE_METHOD(alscriptobjectcheck_data, "alscriptobjectcheck: a check reads scripts two at a time and reports open and unread ones", "[alscriptobjectcheck]") { - set_test_name("an object's scripts checked a few at a time, the open ones left to their tabs; one not read and the prims that did not answer said when done"); house(); check.check(root, "House"); - ensure("listed", window.listedFor == std::vector{ root }); - ensure("running", check.running()); - ensure_equals("two at once", window.asks.size(), size_t(2)); - ensure("the open one not read", window.reads.size() == 2 && window.reads[0].item == id(11) && window.reads[1].item == id(12)); - ensure("a check of what was read", window.asks[0].request.kind == ALScriptAnalysis::Kind::Check && *window.asks[0].request.text == "default {}\n"); - ensure("for its problems alone", !window.asks[0].request.semantics && !window.asks[0].request.hintTypes); - ensure("not expanded, the preprocessor off", window.expands.empty()); + UNSCOPED_INFO("listed"); + CHECK(window.listedFor == std::vector{ root }); + UNSCOPED_INFO("running"); + CHECK(check.running()); + UNSCOPED_INFO("two at once"); + REQUIRE(window.asks.size() == size_t(2)); + { + INFO("the open one not read"); + REQUIRE(window.reads.size() == 2); + CHECK(window.reads[0].item == id(11)); + CHECK(window.reads[1].item == id(12)); + } + { + INFO("a check of what was read"); + REQUIRE(window.asks[0].request.kind == ALScriptAnalysis::Kind::Check); + CHECK(*window.asks[0].request.text == "default {}\n"); + } + { + INFO("for its problems alone"); + CHECK_FALSE(window.asks[0].request.semantics); + CHECK_FALSE(window.asks[0].request.hintTypes); + } + UNSCOPED_INFO("not expanded, the preprocessor off"); + REQUIRE(window.expands.empty()); window.asks[0].answered(answer({ problem(0, "wrong"), problem(1, "unwanted", ALScriptProblem::Severity::Warning, "off") })); - ensure_equals("B checked", window.checked.size(), size_t(1)); + UNSCOPED_INFO("B checked"); + REQUIRE(window.checked.size() == size_t(1)); const Check::Script& b = window.checked[0]; - ensure("by its name", b.name == "B" && b.ref.item == id(11)); - ensure_equals("the lints as chosen applied", b.rows.size(), size_t(1)); - ensure("said as a tab's row", b.rows[0].message == "wrong" && b.rows[0].level == ALScriptStudioDoc::Level::Error && b.rows[0].line == 0); - ensure("the next begun, which could not be read", window.reads.size() == 3 && window.reads[2].item == id(13)); - ensure("not done while C is out", window.done.empty()); + { + INFO("by its name"); + CHECK(b.name == "B"); + CHECK(b.ref.item == id(11)); + } + UNSCOPED_INFO("the lints as chosen applied"); + REQUIRE(b.rows.size() == size_t(1)); + { + INFO("said as a tab's row"); + CHECK(b.rows[0].message == "wrong"); + CHECK(b.rows[0].level == ALScriptStudioDoc::Level::Error); + CHECK(b.rows[0].line == 0); + } + { + INFO("the next begun, which could not be read"); + REQUIRE(window.reads.size() == 3); + CHECK(window.reads[2].item == id(13)); + } + UNSCOPED_INFO("not done while C is out"); + REQUIRE(window.done.empty()); window.asks[1].answered(answer({})); - ensure_equals("done", window.done.size(), size_t(1)); + UNSCOPED_INFO("done"); + REQUIRE(window.done.size() == size_t(1)); const Check::Done& done = window.done[0]; - ensure("of the house", done.root == root && done.name == "House" && done.present); - ensure_equals("checked", done.checked, 2); - ensure_equals("left to its tab", done.open, 1); - ensure_equals("prims that did not answer", done.unlisted, 1); - ensure("the one not read, by name", done.unread == std::vector{ "D" }); - ensure("no longer running", !check.running()); + { + INFO("of the house"); + CHECK(done.root == root); + CHECK(done.name == "House"); + CHECK(done.present); + } + UNSCOPED_INFO("checked"); + CHECK(done.checked == 2); + UNSCOPED_INFO("left to its tab"); + CHECK(done.open == 1); + UNSCOPED_INFO("prims that did not answer"); + CHECK(done.unlisted == 1); + UNSCOPED_INFO("the one not read, by name"); + CHECK(done.unread == std::vector{ "D" }); + UNSCOPED_INFO("no longer running"); + CHECK_FALSE(check.running()); } - template<> template<> - void alscriptobjectcheck_object::test<2>() + TEST_CASE_METHOD(alscriptobjectcheck_data, "alscriptobjectcheck: a preprocessed script's problems map back to it or its include", "[alscriptobjectcheck]") { - set_test_name("with the preprocessor on, each script expanded first and its problems read back through the expansion to the script or its include"); window.preprocess = true; window.listing.scripts.push_back({ ALScriptRef(root, id(20)), "Main" }); window.texts = { { id(20), "#include \"lib\"\ndefault {}\n" } }; check.check(root, "Shed"); - ensure_equals("expanded", window.expands.size(), size_t(1)); - ensure("apart, as a tab's check", window.expands[0].request.apart && window.expands[0].request.sourceText() == "#include \"lib\"\ndefault {}\n"); + UNSCOPED_INFO("expanded"); + REQUIRE(window.expands.size() == size_t(1)); + { + INFO("apart, as a tab's check"); + CHECK(window.expands[0].request.apart); + CHECK(window.expands[0].request.sourceText() == "#include \"lib\"\ndefault {}\n"); + } // The include's line, then the script's own. ALPreprocessor::Result result; @@ -239,23 +281,39 @@ namespace tut said.message = "from the preprocessor"; result.problems.push_back(said); window.expands[0].expanded(result); - ensure_equals("asked", window.asks.size(), size_t(1)); - ensure_equals("about the expansion", *window.asks[0].request.text, std::string("integer x;\ndefault {}\n")); + UNSCOPED_INFO("asked"); + REQUIRE(window.asks.size() == size_t(1)); + UNSCOPED_INFO("about the expansion"); + CHECK(*window.asks[0].request.text == std::string("integer x;\ndefault {}\n")); window.asks[0].answered(answer({ problem(0, "in the library"), problem(1, "in the script") })); - ensure_equals("checked", window.checked.size(), size_t(1)); + UNSCOPED_INFO("checked"); + REQUIRE(window.checked.size() == size_t(1)); const std::vector& rows = window.checked[0].rows; - ensure_equals("the preprocessor's and the analyzers'", rows.size(), size_t(3)); - ensure("the preprocessor's first", rows[0].message == "from the preprocessor" && rows[0].origin == "OriginPreprocessor"); - ensure("the include's, under its name", rows[1].file == "disk:/lib.lsl" && rows[1].fileName == "lib" && rows[1].line == 0); - ensure("the script's own, at its line", rows[2].file.empty() && rows[2].line == 1); - ensure_equals("done", window.done.size(), size_t(1)); + UNSCOPED_INFO("the preprocessor's and the analyzers'"); + REQUIRE(rows.size() == size_t(3)); + { + INFO("the preprocessor's first"); + CHECK(rows[0].message == "from the preprocessor"); + CHECK(rows[0].origin == "OriginPreprocessor"); + } + { + INFO("the include's, under its name"); + CHECK(rows[1].file == "disk:/lib.lsl"); + CHECK(rows[1].fileName == "lib"); + CHECK(rows[1].line == 0); + } + { + INFO("the script's own, at its line"); + REQUIRE(rows[2].file.empty()); + CHECK(rows[2].line == 1); + } + UNSCOPED_INFO("done"); + REQUIRE(window.done.size() == size_t(1)); } - template<> template<> - void alscriptobjectcheck_object::test<3>() + TEST_CASE_METHOD(alscriptobjectcheck_data, "alscriptobjectcheck: a restarted check drops stale answers and an absent object ends at once", "[alscriptobjectcheck]") { - set_test_name("a check begun again lets the last one's answers go; an object out of sight is said so at once"); house(); check.check(root, "House"); std::function stale = std::move(window.asks[0].answered); @@ -263,13 +321,20 @@ namespace tut window.checked.clear(); check.check(root, "House"); stale(answer({ problem(0, "old") })); - ensure("the earlier answer dropped", window.checked.empty()); - ensure_equals("the new one's asked", window.asks.size(), size_t(2)); + UNSCOPED_INFO("the earlier answer dropped"); + REQUIRE(window.checked.empty()); + UNSCOPED_INFO("the new one's asked"); + REQUIRE(window.asks.size() == size_t(2)); FakeWindow away; away.listing.present = false; Check gone(services, away, away); gone.check(id(99), "Gone"); - ensure("said at once, as not in sight", away.done.size() == 1 && !away.done[0].present && away.done[0].checked == 0); + { + INFO("said at once, as not in sight"); + REQUIRE(away.done.size() == 1); + CHECK_FALSE(away.done[0].present); + CHECK(away.done[0].checked == 0); + } } } diff --git a/indra/newview/tests/alscriptoutlinepane_test.cpp b/indra/newview/tests/alscriptoutlinepane_test.cpp index 6acb2b0fe9..729feed77a 100644 --- a/indra/newview/tests/alscriptoutlinepane_test.cpp +++ b/indra/newview/tests/alscriptoutlinepane_test.cpp @@ -38,7 +38,7 @@ #include "llscrolllistitem.h" #include "lltextbox.h" -#include "../test/lltut.h" +#include #include @@ -104,7 +104,7 @@ namespace } } -namespace tut +namespace { struct alscriptoutlinepane_data { @@ -116,7 +116,7 @@ namespace tut ALScriptOutlinePane* found = window.find("outline_pane"); if (!found) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } return found; } @@ -159,171 +159,225 @@ namespace tut std::string comment() { return pane()->list()->saysEmpty() ? pane()->list()->emptyWords() : std::string(); } }; - typedef test_group alscriptoutlinepane_group; - typedef alscriptoutlinepane_group::object alscriptoutlinepane_object; - alscriptoutlinepane_group alscriptoutlinepane_instance("alscriptoutlinepane"); - - template<> template<> - void alscriptoutlinepane_object::test<1>() + TEST_CASE_METHOD(alscriptoutlinepane_data, "alscriptoutlinepane: only the front tab's symbols show as a tree and the window is told", "[alscriptoutlinepane]") { - set_test_name("the tab in front's symbols as a tree, marked and explained, the window told; another tab's, or none, not"); ALScriptOutlinePane* outline = pane(); Doc& doc = tab("a"); Doc& other = tab("b"); outline->show(other); - ensure("not in front: nothing", outline->list()->getItemCount() == 0 && told().shown.empty()); + { + INFO("not in front: nothing"); + CHECK(outline->list()->getItemCount() == 0); + REQUIRE(told().shown.empty()); + } outline->show(doc); - ensure_equals("the tree", rows(), std::string("count, ^default, .touch_start, .state_entry, alpha")); - ensure_equals("told", joined(told().shown), std::string("a")); + UNSCOPED_INFO("the tree"); + CHECK(rows() == std::string("count, ^default, .touch_start, .state_entry, alpha")); + UNSCOPED_INFO("told"); + CHECK(joined(told().shown) == std::string("a")); const std::vector items = outline->list()->getAllData(); - ensure_equals("what it is", items[1]->getColumn(0)->getToolTip(), std::string("state")); - ensure_equals("and its declaration", items[0]->getColumn(1)->getToolTip(), std::string("variable\ninteger")); - ensure_equals("by its index", items[4]->getValue().asInteger(), 4); - ensure("nothing said over it", comment().empty()); + UNSCOPED_INFO("what it is"); + CHECK(items[1]->getColumn(0)->getToolTip() == std::string("state")); + UNSCOPED_INFO("and its declaration"); + CHECK(items[0]->getColumn(1)->getToolTip() == std::string("variable\ninteger")); + UNSCOPED_INFO("by its index"); + CHECK(items[4]->getValue().asInteger() == 4); + UNSCOPED_INFO("nothing said over it"); + REQUIRE(comment().empty()); doc.outline.clear(); outline->show(doc); - ensure_equals("nothing to outline", comment(), std::string("Nothing in this script to outline yet.")); + UNSCOPED_INFO("nothing to outline"); + CHECK(comment() == std::string("Nothing in this script to outline yet.")); doc.loaded = false; outline->show(doc); - ensure_equals("not loaded yet", comment(), std::string("Still loading.")); + UNSCOPED_INFO("not loaded yet"); + CHECK(comment() == std::string("Still loading.")); } - template<> template<> - void alscriptoutlinepane_object::test<2>() + TEST_CASE_METHOD(alscriptoutlinepane_data, "alscriptoutlinepane: folds are kept by name through renumbering and left goes to the holder", "[alscriptoutlinepane]") { - set_test_name("folded shut and opened by the names down to it, which a check that numbers them anew keeps; left from a leaf to its holder"); ALScriptOutlinePane* outline = pane(); Doc& doc = tab("a"); outline->show(doc); outline->fold(1); - ensure_equals("shut", rows(), std::string("count, >default, alpha")); - ensure("kept by name", doc.outlineFolded.contains("default")); - ensure_equals("the row it was", chosen(), 1); + UNSCOPED_INFO("shut"); + CHECK(rows() == std::string("count, >default, alpha")); + UNSCOPED_INFO("kept by name"); + CHECK(doc.outlineFolded.contains("default")); + UNSCOPED_INFO("the row it was"); + CHECK(chosen() == 1); outline->fold(1); - ensure_equals("open", rows(), std::string("count, ^default, .touch_start, .state_entry, alpha")); + UNSCOPED_INFO("open"); + CHECK(rows() == std::string("count, ^default, .touch_start, .state_entry, alpha")); outline->fold(1, false); - ensure("already open: left so", !doc.outlineFolded.contains("default")); + UNSCOPED_INFO("already open: left so"); + CHECK_FALSE(doc.outlineFolded.contains("default")); outline->fold(1, true); doc.outline.insert(doc.outline.begin(), entry("before", ALScriptSymbolKind::Variable, 0, 0)); outline->show(doc); - ensure_equals("numbered anew, still shut", rows(), std::string("before, count, >default, alpha")); + UNSCOPED_INFO("numbered anew, still shut"); + CHECK(rows() == std::string("before, count, >default, alpha")); outline->fold(2); outline->fold(4, true); - ensure_equals("from a leaf to what holds it", chosen(), 2); - ensure_equals("gone to as a row walked to is", joined(told().chosen), std::string("default")); - ensure("the list kept", !window.services().reveals.empty() && !window.services().reveals.back()); + UNSCOPED_INFO("from a leaf to what holds it"); + CHECK(chosen() == 2); + UNSCOPED_INFO("gone to as a row walked to is"); + CHECK(joined(told().chosen) == std::string("default")); + { + INFO("the list kept"); + REQUIRE_FALSE(window.services().reveals.empty()); + REQUIRE_FALSE(window.services().reveals.back()); + } outline->fold(0, true); - ensure_equals("a leaf at the top: nowhere", joined(told().chosen), std::string("default")); + UNSCOPED_INFO("a leaf at the top: nowhere"); + CHECK(joined(told().chosen) == std::string("default")); outline->fold(4, false); - ensure_equals("right on a leaf: nothing", joined(told().chosen), std::string("default")); + UNSCOPED_INFO("right on a leaf: nothing"); + CHECK(joined(told().chosen) == std::string("default")); } - template<> template<> - void alscriptoutlinepane_object::test<3>() + TEST_CASE_METHOD(alscriptoutlinepane_data, "alscriptoutlinepane: the filter flattens the tree and the sort by name or kind is kept", "[alscriptoutlinepane]") { - set_test_name("through the filter, flat and unfoldable; sorted by name or kind under each holder, the window told"); ALScriptOutlinePane* outline = pane(); Doc& doc = tab("a"); LLFilterEditor* filter = window.find("outline_filter"); filter->setText(std::string("ST")); filter->onCommit(); - ensure_equals("each with the letters", rows(), std::string("touch_start, state_entry")); + UNSCOPED_INFO("each with the letters"); + CHECK(rows() == std::string("touch_start, state_entry")); filter->setText(std::string("zz")); outline->show(doc); - ensure_equals("none", comment(), std::string("No symbol names match what you typed.")); + UNSCOPED_INFO("none"); + CHECK(comment() == std::string("No symbol names match what you typed.")); filter->setText(std::string()); outline->setSortOrder("name"); outline->show(doc); - ensure_equals("by name", rows(), std::string("alpha, count, ^default, .state_entry, .touch_start")); - ensure_equals("kept", outline->sortOrder(), std::string("name")); + UNSCOPED_INFO("by name"); + CHECK(rows() == std::string("alpha, count, ^default, .state_entry, .touch_start")); + UNSCOPED_INFO("kept"); + CHECK(outline->sortOrder() == std::string("name")); LLComboBox* sort = window.find("outline_sort"); sort->selectByValue(LLSD("kind")); sort->onCommit(); - ensure_equals("by kind, then name", rows(), std::string("count, alpha, ^default, .state_entry, .touch_start")); - ensure_equals("the window told", told().sorts, 1); + UNSCOPED_INFO("by kind, then name"); + CHECK(rows() == std::string("count, alpha, ^default, .state_entry, .touch_start")); + UNSCOPED_INFO("the window told"); + CHECK(told().sorts == 1); filter->setText(std::string("t")); outline->show(doc); - ensure_equals("sorted through the filter too", rows(), std::string("count, state_entry, touch_start, default")); + UNSCOPED_INFO("sorted through the filter too"); + CHECK(rows() == std::string("count, state_entry, touch_start, default")); } - template<> template<> - void alscriptoutlinepane_object::test<4>() + TEST_CASE_METHOD(alscriptoutlinepane_data, "alscriptoutlinepane: the caret's symbol or its nearest shown holder is chosen", "[alscriptoutlinepane]") { - set_test_name("the symbol the caret is in chosen, or the nearest shown that holds it; none where it is in none"); ALScriptOutlinePane* outline = pane(); Doc& doc = tab("a"); outline->show(doc); doc.caret->crumbPath = { 1, 3 }; outline->followCaret(doc); - ensure_equals("the innermost", chosen(), 3); + UNSCOPED_INFO("the innermost"); + CHECK(chosen() == 3); outline->fold(1); outline->list()->deselectAllItems(true); doc.caret->crumbPath = { 1, 3 }; outline->followCaret(doc); - ensure_equals("folded away: its holder", chosen(), 1); + UNSCOPED_INFO("folded away: its holder"); + CHECK(chosen() == 1); doc.caret->crumbPath.clear(); outline->followCaret(doc); - ensure_equals("in none", chosen(), -1); + UNSCOPED_INFO("in none"); + CHECK(chosen() == -1); outline->list()->selectByValue(LLSD(0)); doc.caret->crumbPath = { 9 }; outline->followCaret(doc); - ensure_equals("not listed", chosen(), -1); + UNSCOPED_INFO("not listed"); + CHECK(chosen() == -1); outline->fold(1); doc.caret->crumbPath = { 1, 2 }; doc.outline[0].detail = "float"; outline->show(doc); - ensure_equals("followed as it is shown", chosen(), 2); - ensure("going nowhere", told().chosen.empty()); + UNSCOPED_INFO("followed as it is shown"); + CHECK(chosen() == 2); + UNSCOPED_INFO("going nowhere"); + REQUIRE(told().chosen.empty()); } - template<> template<> - void alscriptoutlinepane_object::test<5>() + TEST_CASE_METHOD(alscriptoutlinepane_data, "alscriptoutlinepane: the list is made again only when what it shows changes", "[alscriptoutlinepane]") { - set_test_name("a check that changes nothing shown leaves the list; a change makes it again; no tab, and it is made again whatever"); ALScriptOutlinePane* outline = pane(); Doc& doc = tab("a"); outline->show(doc); // A mark left on the first row, which a list made again does not have. outline->list()->getFirstData()->getColumn(1)->setValue(LLSD("marked")); outline->show(doc); - ensure_equals("the same rows", cell(outline->list()->getFirstData(), 1), std::string("marked")); + UNSCOPED_INFO("the same rows"); + CHECK(cell(outline->list()->getFirstData(), 1) == std::string("marked")); doc.outline[0].detail = "float"; outline->show(doc); - ensure("a detail changed: made again", cell(outline->list()->getFirstData(), 1) != "marked"); + UNSCOPED_INFO("a detail changed: made again"); + CHECK(cell(outline->list()->getFirstData(), 1) != "marked"); outline->list()->getFirstData()->getColumn(1)->setValue(LLSD("marked")); Doc& other = tab("b"); other.outline[0].detail = "float"; window.services().front = 1; outline->show(other); - ensure("another tab's, the same rows: made again", cell(outline->list()->getFirstData(), 1) != "marked"); + UNSCOPED_INFO("another tab's, the same rows: made again"); + CHECK(cell(outline->list()->getFirstData(), 1) != "marked"); window.services().front = 0; outline->forget(); - ensure("nothing listed", outline->list()->getItemCount() == 0); + UNSCOPED_INFO("nothing listed"); + CHECK(outline->list()->getItemCount() == 0); outline->show(doc); - ensure_equals("the same rows back", outline->list()->getItemCount(), 5); + UNSCOPED_INFO("the same rows back"); + CHECK(outline->list()->getItemCount() == 5); } - template<> template<> - void alscriptoutlinepane_object::test<6>() + TEST_CASE_METHOD(alscriptoutlinepane_data, "alscriptoutlinepane: choosing a row goes there and keys and arrow clicks fold", "[alscriptoutlinepane]") { - set_test_name("a row chosen gone to; return to type there, escape back without going; left and right fold; an arrow clicked folds"); ALScriptOutlinePane* outline = pane(); Doc& doc = tab("a"); outline->show(doc); ALPaneList* list = outline->list(); list->selectByValue(LLSD(0)); list->onCommit(); - ensure("gone to", joined(told().chosen) == "count" && window.services().reveals.back() == false); - ensure("return", list->handleKeyHere(KEY_RETURN, MASK_NONE) && told().chosen.back() == "count editor"); - ensure("the keyboard taken", window.services().reveals.back()); - ensure("escape", list->handleKeyHere(KEY_ESCAPE, MASK_NONE) && told().chosen.size() == 2 && window.services().reveals.size() == 3); - ensure("with a key held: the list's", !list->handleKeyHere(KEY_RETURN, MASK_CONTROL) && told().chosen.size() == 2); + { + INFO("gone to"); + CHECK(joined(told().chosen) == "count"); + REQUIRE(window.services().reveals.back() == false); + } + { + INFO("return"); + CHECK(list->handleKeyHere(KEY_RETURN, MASK_NONE)); + CHECK(told().chosen.back() == "count editor"); + } + UNSCOPED_INFO("the keyboard taken"); + REQUIRE(window.services().reveals.back()); + { + INFO("escape"); + CHECK(list->handleKeyHere(KEY_ESCAPE, MASK_NONE)); + REQUIRE(told().chosen.size() == 2); + REQUIRE(window.services().reveals.size() == 3); + } + { + INFO("with a key held: the list's"); + CHECK_FALSE(list->handleKeyHere(KEY_RETURN, MASK_CONTROL)); + REQUIRE(told().chosen.size() == 2); + } list->selectByValue(LLSD(1)); - ensure("left", list->handleKeyHere(KEY_LEFT, MASK_NONE) && doc.outlineFolded.contains("default")); - ensure("right", list->handleKeyHere(KEY_RIGHT, MASK_NONE) && !doc.outlineFolded.contains("default")); + { + INFO("left"); + CHECK(list->handleKeyHere(KEY_LEFT, MASK_NONE)); + CHECK(doc.outlineFolded.contains("default")); + } + { + INFO("right"); + CHECK(list->handleKeyHere(KEY_RIGHT, MASK_NONE)); + CHECK_FALSE(doc.outlineFolded.contains("default")); + } // The mouse only reaches what is shown. window.floater->setVisible(true); @@ -341,78 +395,100 @@ namespace tut --row_y; } row_y -= 2; - ensure_equals("row 1 found", row(row_y), 1); + UNSCOPED_INFO("row 1 found"); + CHECK(row(row_y) == 1); list->localPointToOtherView(rect.mLeft + icon->getWidth() + list->getColumnPadding() + 2, row_y, &x, &y, outline); - ensure("an arrow clicked", outline->handleMouseDown(x, y, MASK_NONE)); - ensure("folds", doc.outlineFolded.contains("default")); + UNSCOPED_INFO("an arrow clicked"); + CHECK(outline->handleMouseDown(x, y, MASK_NONE)); + UNSCOPED_INFO("folds"); + CHECK(doc.outlineFolded.contains("default")); list->localPointToOtherView(rect.mRight - 4, row_y, &x, &y, outline); outline->handleMouseDown(x, y, MASK_NONE); - ensure("past it: not", doc.outlineFolded.contains("default")); + UNSCOPED_INFO("past it: not"); + CHECK(doc.outlineFolded.contains("default")); // Row 0, a leaf, where an arrow would be: the list's, which chooses it. list->deselectAllItems(true); const S32 leaf_y = row_y + (rect.mTop - row_y) / 2 + 1; list->localPointToOtherView(rect.mLeft + icon->getWidth() + list->getColumnPadding() + 2, leaf_y, &x, &y, outline); - ensure_equals("a leaf row there", row(leaf_y), 0); + UNSCOPED_INFO("a leaf row there"); + CHECK(row(leaf_y) == 0); outline->handleMouseDown(x, y, MASK_NONE); - ensure_equals("chosen by the list", chosen(), 0); + UNSCOPED_INFO("chosen by the list"); + CHECK(chosen() == 0); } - template<> template<> - void alscriptoutlinepane_object::test<7>() + TEST_CASE_METHOD(alscriptoutlinepane_data, "alscriptoutlinepane: out of sight it only tells the window and lists once seen", "[alscriptoutlinepane]") { - set_test_name("out of sight, only the window told; listed, and the caret followed, once it is seen"); ALScriptOutlinePane* outline = pane(); Doc& doc = tab("a"); window.floater->setVisible(false); outline->show(doc); - ensure("told", joined(told().shown) == "a"); - ensure("not listed", outline->list()->getItemCount() == 0); + UNSCOPED_INFO("told"); + CHECK(joined(told().shown) == "a"); + UNSCOPED_INFO("not listed"); + CHECK(outline->list()->getItemCount() == 0); outline->pump(); - ensure("nor while unseen", outline->list()->getItemCount() == 0); + UNSCOPED_INFO("nor while unseen"); + CHECK(outline->list()->getItemCount() == 0); window.floater->setVisible(true); outline->pump(); - ensure_equals("seen: listed", rows(), std::string("count, ^default, .touch_start, .state_entry, alpha")); + UNSCOPED_INFO("seen: listed"); + CHECK(rows() == std::string("count, ^default, .touch_start, .state_entry, alpha")); window.floater->setVisible(false); doc.caret->crumbPath = { 1, 3 }; outline->followCaret(doc); - ensure_equals("not followed unseen", chosen(), -1); + UNSCOPED_INFO("not followed unseen"); + CHECK(chosen() == -1); window.floater->setVisible(true); outline->pump(); - ensure_equals("followed once seen", chosen(), 3); + UNSCOPED_INFO("followed once seen"); + CHECK(chosen() == 3); outline->pump(); - ensure_equals("and then left be", joined(told().shown), std::string("a, a, a")); + UNSCOPED_INFO("and then left be"); + CHECK(joined(told().shown) == std::string("a, a, a")); } - template<> template<> - void alscriptoutlinepane_object::test<8>() + TEST_CASE_METHOD(alscriptoutlinepane_data, "alscriptoutlinepane: a symbol added keeps the other rows and the choice", "[alscriptoutlinepane]") { - set_test_name("a symbol added among the others: its row made, the others the same rows where they were, the row chosen kept"); ALScriptOutlinePane* outline = pane(); Doc& doc = tab("a"); outline->show(doc); const std::vector before = outline->list()->getAllData(); doc.caret->crumbPath = { 4 }; outline->followCaret(doc); - ensure_equals("alpha chosen", chosen(), 4); + UNSCOPED_INFO("alpha chosen"); + CHECK(chosen() == 4); doc.outline.insert(doc.outline.begin() + 1, entry("beta", ALScriptSymbolKind::Function, 0, 1)); doc.caret->crumbPath = { 5 }; outline->show(doc); - ensure_equals("in its place", rows(), std::string("count, beta, ^default, .touch_start, .state_entry, alpha")); + UNSCOPED_INFO("in its place"); + CHECK(rows() == std::string("count, beta, ^default, .touch_start, .state_entry, alpha")); const std::vector after = outline->list()->getAllData(); - ensure("the others the same rows", after.size() == 6 && after[0] == before[0] && after[2] == before[1] && after[5] == before[4]); - ensure_equals("alpha still chosen, by its new place", chosen(), 5); + { + INFO("the others the same rows"); + REQUIRE(after.size() == 6); + CHECK(after[0] == before[0]); + CHECK(after[2] == before[1]); + CHECK(after[5] == before[4]); + } + UNSCOPED_INFO("alpha still chosen, by its new place"); + CHECK(chosen() == 5); } - template<> template<> - void alscriptoutlinepane_object::test<9>() + TEST_CASE_METHOD(alscriptoutlinepane_data, "alscriptoutlinepane: the heading fits its word with the sort and filter after it", "[alscriptoutlinepane]") { - set_test_name("the heading as wide as its word, the sort and the filter after it in turn"); ALScriptOutlinePane* outline = pane(); const LLRect head = outline->getChild("outline_head")->getRect(); const LLRect sort = outline->getChild("outline_sort")->getRect(); const LLRect filter = outline->getChild("outline_filter")->getRect(); - ensure("the word fits", head.getWidth() >= outline->getChild("outline_head")->getTextPixelWidth()); - ensure("in turn, apart", head.mRight < sort.mLeft && sort.mRight < filter.mLeft && filter.getWidth() >= 40); + UNSCOPED_INFO("the word fits"); + CHECK(head.getWidth() >= outline->getChild("outline_head")->getTextPixelWidth()); + { + INFO("in turn, apart"); + CHECK(head.mRight < sort.mLeft); + CHECK(sort.mRight < filter.mLeft); + CHECK(filter.getWidth() >= 40); + } } } diff --git a/indra/newview/tests/alscriptoutputpane_test.cpp b/indra/newview/tests/alscriptoutputpane_test.cpp index b5acd12c61..a4a0fc5ab6 100644 --- a/indra/newview/tests/alscriptoutputpane_test.cpp +++ b/indra/newview/tests/alscriptoutputpane_test.cpp @@ -32,7 +32,7 @@ #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include #include #include @@ -88,7 +88,7 @@ namespace } } -namespace tut +namespace { struct alscriptoutputpane_data { @@ -102,11 +102,12 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } // The tab as the skin built it. pane = window.find("output_tab"); - ensure("the skin builds the tab as the pane", pane != nullptr); + UNSCOPED_INFO("the skin builds the tab as the pane"); + REQUIRE(pane != nullptr); return *pane; } @@ -160,7 +161,8 @@ namespace tut void whose(const std::string& value) { LLComboBox* combo = window.find("output_filter"); - ensure("offered: " + value, combo->selectByValue(LLSD(value))); + UNSCOPED_INFO("offered: " + value); + REQUIRE(combo->selectByValue(LLSD(value))); combo->onCommit(); } void find(const std::string& words) @@ -171,40 +173,38 @@ namespace tut } const ALOutputView::Entry& last() const { return pane->view()->entries().back(); } }; - typedef test_group alscriptoutputpane_group; - typedef alscriptoutputpane_group::object alscriptoutputpane_object; - alscriptoutputpane_group alscriptoutputpane_instance("ALScriptOutputPane"); - template <> - template <> - void alscriptoutputpane_object::test<1>() + TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: the kind filter picks errors or owner words or debug or the studio's", "[ALScriptOutputPane]") { - set_test_name("by kind: errors, what owners were told, the debug channel, the studio's own words"); ALScriptOutputPane& out = make(); const LLUUID door = fresh(); out.heard(said(door, "Door", "opening", Event::Channel::OwnerSay)); out.heard(said(door, "Door", "tick\n")); out.heard(failed(door, fresh(), "door.lsl", "Stack-Heap Collision", -1)); out.said("Saved.", false, nullptr, {}); - ensure_equals("everything, a trailing newline gone", shown(), std::string("|opening|tick|Stack-Heap Collision|Saved.")); + UNSCOPED_INFO("everything, a trailing newline gone"); + CHECK(shown() == std::string("|opening|tick|Stack-Heap Collision|Saved.")); out.showKind("error"); - ensure_equals("the error", shown(), std::string("|Stack-Heap Collision")); - ensure_equals("kept as chosen", out.kind(), std::string("error")); + UNSCOPED_INFO("the error"); + CHECK(shown() == std::string("|Stack-Heap Collision")); + UNSCOPED_INFO("kept as chosen"); + CHECK(out.kind() == std::string("error")); out.showKind("owner"); - ensure_equals("what the owner was told", shown(), std::string("|opening")); + UNSCOPED_INFO("what the owner was told"); + CHECK(shown() == std::string("|opening")); out.showKind("debug"); - ensure_equals("the debug channel", shown(), std::string("|tick")); + UNSCOPED_INFO("the debug channel"); + CHECK(shown() == std::string("|tick")); out.showKind("studio"); - ensure_equals("the studio", shown(), std::string("|Saved.")); + UNSCOPED_INFO("the studio"); + CHECK(shown() == std::string("|Saved.")); out.showKind(""); - ensure_equals("everything again", shownTexts().size(), size_t(4)); + UNSCOPED_INFO("everything again"); + REQUIRE(shownTexts().size() == size_t(4)); } - template <> - template <> - void alscriptoutputpane_object::test<2>() + TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: filters by whose it is and by words in either case", "[ALScriptOutputPane]") { - set_test_name("by whose: one object's alone, the scripts open here, the agent's own; and by the words, in either case"); ALScriptOutputPane& out = make(); const LLUUID door = fresh(); const LLUUID lamp = fresh(); @@ -219,33 +219,37 @@ namespace tut out.said("Saved door.lsl.", false, nullptr, {}); whose(lamp.asString()); - ensure_equals("one object's alone, not the studio's", shown(), std::string("|lamp speaks")); + UNSCOPED_INFO("one object's alone, not the studio's"); + CHECK(shown() == std::string("|lamp speaks")); whose("open"); - ensure_equals("the open script's, and the studio's", shown(), std::string("|door speaks|Saved door.lsl.")); + UNSCOPED_INFO("the open script's, and the studio's"); + CHECK(shown() == std::string("|door speaks|Saved door.lsl.")); whose("mine"); - ensure_equals("the agent's object's, what an owner was told, and the studio's", shown(), + UNSCOPED_INFO("the agent's object's, what an owner was told, and the studio's"); + CHECK(shown() == std::string("|lamp speaks|crate tells its owner|Saved door.lsl.")); whose(""); find("DOOR"); - ensure_equals("the words, in the text or whose it is", shown(), std::string("|door speaks|Saved door.lsl.")); + UNSCOPED_INFO("the words, in the text or whose it is"); + CHECK(shown() == std::string("|door speaks|Saved door.lsl.")); find(" lamp "); - ensure_equals("trimmed", shown(), std::string("|lamp speaks")); + UNSCOPED_INFO("trimmed"); + CHECK(shown() == std::string("|lamp speaks")); find(""); - ensure_equals("everything", shownTexts().size(), size_t(4)); + UNSCOPED_INFO("everything"); + REQUIRE(shownTexts().size() == size_t(4)); // The script closed: the filter by open scripts follows. whose("open"); services.docs.clear(); out.openChanged(); - ensure_equals("the studio's alone", shown(), std::string("|Saved door.lsl.")); + UNSCOPED_INFO("the studio's alone"); + CHECK(shown() == std::string("|Saved door.lsl.")); } - template <> - template <> - void alscriptoutputpane_object::test<3>() + TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: the objects offered stop at forty dropping the stalest but the chosen", "[ALScriptOutputPane]") { - set_test_name("the objects offered stop at forty, the one least lately heard from going first, unless it is the one chosen"); ALScriptOutputPane& out = make(); std::vector roots; for (S32 i = 0; i < 45; ++i) @@ -253,68 +257,87 @@ namespace tut roots.push_back(fresh()); out.heard(said(roots.back(), llformat("Object %02d", i), "hello")); } - ensure_equals("forty", out.objects().size(), size_t(40)); - ensure("the first five gone", out.objects().front().first == roots[5]); + UNSCOPED_INFO("forty"); + REQUIRE(out.objects().size() == size_t(40)); + UNSCOPED_INFO("the first five gone"); + CHECK(out.objects().front().first == roots[5]); // Heard from again: the last to go. out.heard(said(roots[5], "Object 05", "again")); - ensure("heard again, last", out.objects().back().first == roots[5]); - ensure_equals("still forty", out.objects().size(), size_t(40)); + UNSCOPED_INFO("heard again, last"); + CHECK(out.objects().back().first == roots[5]); + UNSCOPED_INFO("still forty"); + REQUIRE(out.objects().size() == size_t(40)); // Renamed, and heard from under its new name. out.heard(said(roots[9], "Renamed", "again")); - ensure_equals("its new name", out.objects().back().second, std::string("Renamed")); + UNSCOPED_INFO("its new name"); + CHECK(out.objects().back().second == std::string("Renamed")); // The one chosen stays, least lately heard from as it is. whose(roots[6].asString()); out.heard(said(fresh(), "Newcomer", "hello")); - ensure_equals("forty still", out.objects().size(), size_t(40)); - ensure("the one chosen stayed", out.objects().front().first == roots[6]); - ensure("the next went", std::none_of(out.objects().begin(), out.objects().end(), [&](const auto& one) { return one.first == roots[7]; })); - ensure_equals("and is still chosen", window.find("output_filter")->getValue().asString(), roots[6].asString()); + UNSCOPED_INFO("forty still"); + REQUIRE(out.objects().size() == size_t(40)); + UNSCOPED_INFO("the one chosen stayed"); + CHECK(out.objects().front().first == roots[6]); + UNSCOPED_INFO("the next went"); + CHECK(std::none_of(out.objects().begin(), out.objects().end(), [&](const auto& one) { return one.first == roots[7]; })); + UNSCOPED_INFO("and is still chosen"); + CHECK(window.find("output_filter")->getValue().asString() == roots[6].asString()); } - template <> - template <> - void alscriptoutputpane_object::test<4>() + TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: an error or failure out of sight is unread until seen or cleared", "[ALScriptOutputPane]") { - set_test_name("an error or a failure said out of sight is unread until the tab is looked at, or cleared"); ALScriptOutputPane& out = make(); const LLUUID door = fresh(); out.heard(said(door, "Door", "tick")); out.said("Saved.", false, nullptr, {}); - ensure("words alone are not unread", !out.unread()); - ensure_equals("and nothing to say of it", studio.unreadChanges, 0); + UNSCOPED_INFO("words alone are not unread"); + CHECK_FALSE(out.unread()); + UNSCOPED_INFO("and nothing to say of it"); + CHECK(studio.unreadChanges == 0); out.heard(failed(door, fresh(), "door.lsl", "Math Error", -1)); - ensure("an error is", out.unread()); - ensure_equals("said on the title", studio.unreadChanges, 1); + UNSCOPED_INFO("an error is"); + CHECK(out.unread()); + UNSCOPED_INFO("said on the title"); + CHECK(studio.unreadChanges == 1); out.pump(); - ensure("still, out of sight", out.unread()); + UNSCOPED_INFO("still, out of sight"); + CHECK(out.unread()); studio.inSight = true; out.pump(); - ensure("looked at", !out.unread()); - ensure_equals("said again", studio.unreadChanges, 2); + UNSCOPED_INFO("looked at"); + CHECK_FALSE(out.unread()); + UNSCOPED_INFO("said again"); + CHECK(studio.unreadChanges == 2); out.said("Could not save.", true, nullptr, {}); - ensure("a failure in sight is read", !out.unread()); + UNSCOPED_INFO("a failure in sight is read"); + CHECK_FALSE(out.unread()); studio.inSight = false; out.said("Could not save.", true, nullptr, {}); - ensure("a failure out of sight is not", out.unread()); + UNSCOPED_INFO("a failure out of sight is not"); + CHECK(out.unread()); window.find("output_clear")->onCommit(); - ensure("cleared", !out.unread()); - ensure("with what was said", out.view()->entries().empty()); + UNSCOPED_INFO("cleared"); + CHECK_FALSE(out.unread()); + UNSCOPED_INFO("with what was said"); + REQUIRE(out.view()->entries().empty()); } - template <> - template <> - void alscriptoutputpane_object::test<5>() + TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: the studio's words link to the tab they name and to its actions", "[ALScriptOutputPane]") { - set_test_name("the studio's words link to the tab they name and to what can be done about it, each handed to the window"); ALScriptOutputPane& out = make(); ALScriptStudioDoc& doc = services.addDoc("door-script", ALScriptRef(fresh(), fresh()), "door.lsl"); out.said("Could not save door.lsl.", true, &doc, { "retry", "copy" }); const ALOutputView::Entry& entry = last(); - ensure_equals("the name and two things to do", entry.links.size(), size_t(3)); - ensure_equals("the name, where the words say it", entry.links[0].begin, 15); - ensure_equals("to its end", entry.links[0].end, 23); - ensure("each thing after the words", entry.text.find(services.words("ActionRetry")) > entry.text.find("door.lsl.")); - ensure_equals("where it is", entry.text.substr(entry.links[1].begin, entry.links[1].end - entry.links[1].begin), services.words("ActionRetry")); + UNSCOPED_INFO("the name and two things to do"); + REQUIRE(entry.links.size() == size_t(3)); + UNSCOPED_INFO("the name, where the words say it"); + CHECK(entry.links[0].begin == 15); + UNSCOPED_INFO("to its end"); + CHECK(entry.links[0].end == 23); + UNSCOPED_INFO("each thing after the words"); + CHECK(entry.text.find(services.words("ActionRetry")) > entry.text.find("door.lsl.")); + UNSCOPED_INFO("where it is"); + CHECK(entry.text.substr(entry.links[1].begin, entry.links[1].end - entry.links[1].begin) == services.words("ActionRetry")); ALOutputView::Entry chosen = entry; for (const ALOutputView::Entry::Link& link : entry.links) @@ -322,26 +345,30 @@ namespace tut chosen.value = link.value; out.choose(chosen); } - ensure_equals("the tab, with its problems", studio.shown.size(), size_t(1)); - ensure_equals("the tab named", studio.shown[0], std::string("door-script:problems")); - ensure_equals("what to do, by name", studio.actions.size(), size_t(2)); - ensure_equals("try again", studio.actions[0], std::string("door-script:retry")); - ensure_equals("a copy", studio.actions[1], std::string("door-script:copy")); + UNSCOPED_INFO("the tab, with its problems"); + REQUIRE(studio.shown.size() == size_t(1)); + UNSCOPED_INFO("the tab named"); + CHECK(studio.shown[0] == std::string("door-script:problems")); + UNSCOPED_INFO("what to do, by name"); + REQUIRE(studio.actions.size() == size_t(2)); + UNSCOPED_INFO("try again"); + CHECK(studio.actions[0] == std::string("door-script:retry")); + UNSCOPED_INFO("a copy"); + CHECK(studio.actions[1] == std::string("door-script:copy")); // Said of no tab: nothing to link. out.said("Nothing open.", false, nullptr, { "retry" }); - ensure("no links", last().links.empty()); + UNSCOPED_INFO("no links"); + REQUIRE(last().links.empty()); // The tab closed since: nothing asked of the window. services.docs.clear(); out.choose(chosen); - ensure_equals("nothing more", studio.actions.size(), size_t(2)); + UNSCOPED_INFO("nothing more"); + REQUIRE(studio.actions.size() == size_t(2)); } - template <> - template <> - void alscriptoutputpane_object::test<6>() + TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: a run's lines map back to the script or an include for each frame", "[ALScriptOutputPane]") { - set_test_name("a run's lines read back through the text it runs: the script's own, an include's, and the frames under an error"); ALScriptOutputPane& out = make(); const LLUUID object = fresh(); const LLUUID item = fresh(); @@ -367,41 +394,62 @@ namespace tut Event error = failed(object, item, "Counter", "attempt to index nil", 7); error.stack = { "lua_script:8: attempt to index nil", "lua_script:3 function helper", "lua_script:8", "[C] function error" }; const ALScriptOutputPane::Place at = out.heard(error); - ensure_equals("the error's line, the script's", at.line, 4); - ensure("in the script", at.file.empty()); + UNSCOPED_INFO("the error's line, the script's"); + CHECK(at.line == 4); + UNSCOPED_INFO("in the script"); + REQUIRE(at.file.empty()); const ALOutputView::Entry& entry = last(); - ensure("a link to it", entry.link); - ensure_equals("at that line", entry.value["line"].asInteger(), 4); - ensure_equals("a link for each frame of the script's", entry.links.size(), size_t(2)); - ensure_equals("the first in the include", entry.links[0].value["file"].asString(), std::string("disk:/scripts/lib.luau")); - ensure_equals("at its line", entry.links[0].value["line"].asInteger(), 2); - ensure_equals("the second in the script", entry.links[1].value["line"].asInteger(), 4); + UNSCOPED_INFO("a link to it"); + CHECK(entry.link); + UNSCOPED_INFO("at that line"); + CHECK(entry.value["line"].asInteger() == 4); + UNSCOPED_INFO("a link for each frame of the script's"); + REQUIRE(entry.links.size() == size_t(2)); + UNSCOPED_INFO("the first in the include"); + CHECK(entry.links[0].value["file"].asString() == std::string("disk:/scripts/lib.luau")); + UNSCOPED_INFO("at its line"); + CHECK(entry.links[0].value["line"].asInteger() == 2); + UNSCOPED_INFO("the second in the script"); + CHECK(entry.links[1].value["line"].asInteger() == 4); ALOutputView::Entry chosen = entry; out.choose(chosen); chosen.value = entry.links[0].value; out.choose(chosen); - ensure_equals("two places gone to", studio.went.size(), size_t(2)); - ensure("the script", studio.went[0].ref == ALScriptRef(object, item) && studio.went[0].file.empty()); - ensure_equals("at the error's line", studio.went[0].line, 4); - ensure("read back already", !studio.went[0].running); - ensure_equals("the include", studio.went[1].file, std::string("disk:/scripts/lib.luau")); - ensure_equals("by its name", studio.went[1].name, std::string("lib.luau")); - ensure_equals("at the frame's line", studio.went[1].line, 2); + UNSCOPED_INFO("two places gone to"); + REQUIRE(studio.went.size() == size_t(2)); + { + INFO("the script"); + CHECK(studio.went[0].ref == ALScriptRef(object, item)); + REQUIRE(studio.went[0].file.empty()); + } + UNSCOPED_INFO("at the error's line"); + CHECK(studio.went[0].line == 4); + UNSCOPED_INFO("read back already"); + CHECK_FALSE(studio.went[0].running); + UNSCOPED_INFO("the include"); + CHECK(studio.went[1].file == std::string("disk:/scripts/lib.luau")); + UNSCOPED_INFO("by its name"); + CHECK(studio.went[1].name == std::string("lib.luau")); + UNSCOPED_INFO("at the frame's line"); + CHECK(studio.went[1].line == 2); // Not open here: the line the run names, as it named it, and a // link that says so, for the window to read back once it can. services.docs.clear(); - ensure_equals("as said", out.heard(error).line, 7); + UNSCOPED_INFO("as said"); + CHECK(out.heard(error).line == 7); chosen = last(); out.choose(chosen); - ensure("gone to as the region counts it", studio.went.back().line == 7 && studio.went.back().running); + { + INFO("gone to as the region counts it"); + CHECK(studio.went.back().line == 7); + CHECK(studio.went.back().running); + } } - template<> template<> - void alscriptoutputpane_object::test<7>() + TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: a run's line past the envelope's lines maps back through the code", "[ALScriptOutputPane]") { - set_test_name("a run's line counted with the envelope's lines above the code, as the region counts it, read back through the code"); ALScriptOutputPane& out = make(); const LLUUID object = fresh(); const LLUUID item = fresh(); @@ -426,16 +474,16 @@ namespace tut envelope.compileTarget = "luau"; doc.envelope = envelope; const S32 under = envelope.codeLine(); - ensure("the envelope has lines of its own", under > 3); - ensure_equals("its code's third line, where the region names it", out.heard(failed(object, item, "Counter", "attempt to index nil", under + 2)).line, 102); - ensure_equals("a line in the envelope is none of the code's: as said", out.heard(failed(object, item, "Counter", "boom", 1)).line, 1); + UNSCOPED_INFO("the envelope has lines of its own"); + CHECK(under > 3); + UNSCOPED_INFO("its code's third line, where the region names it"); + CHECK(out.heard(failed(object, item, "Counter", "attempt to index nil", under + 2)).line == 102); + UNSCOPED_INFO("a line in the envelope is none of the code's: as said"); + CHECK(out.heard(failed(object, item, "Counter", "boom", 1)).line == 1); } - template <> - template <> - void alscriptoutputpane_object::test<8>() + TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: an error the filters hide is not unread", "[ALScriptOutputPane]") { - set_test_name("an error the filters hide is not unread: a stranger's, with one object's chosen; the chosen one's is"); ALScriptOutputPane& out = make(); const LLUUID lamp = fresh(); const LLUUID crate = fresh(); @@ -443,19 +491,22 @@ namespace tut out.heard(said(crate, "Crate", "crate speaks")); whose(lamp.asString()); out.heard(failed(crate, fresh(), "crate.lsl", "Math Error", -1)); - ensure("a stranger's, hidden: not unread", !out.unread() && studio.unreadChanges == 0); + { + INFO("a stranger's, hidden: not unread"); + CHECK_FALSE(out.unread()); + CHECK(studio.unreadChanges == 0); + } out.heard(failed(lamp, fresh(), "lamp.lsl", "Math Error", -1)); - ensure("the chosen one's is", out.unread()); + UNSCOPED_INFO("the chosen one's is"); + CHECK(out.unread()); const S32 said = studio.unreadChanges; out.heard(failed(lamp, fresh(), "lamp.lsl", "Another Error", -1)); - ensure_equals("unread already: not said again", studio.unreadChanges, said); + UNSCOPED_INFO("unread already: not said again"); + CHECK(studio.unreadChanges == said); } - template <> - template <> - void alscriptoutputpane_object::test<9>() + TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: what objects say aloud or to the agent or in IMs gets its own kind", "[ALScriptOutputPane]") { - set_test_name("what the agent's objects say aloud, to the agent, and in IMs: each its kind, the agent's own; the prim that spoke named"); ALScriptOutputPane& out = make(); const LLUUID lamp = fresh(); Event aloud = said(lamp, "Lamp", "hello", Event::Channel::Said); @@ -464,24 +515,30 @@ namespace tut out.heard(said(lamp, "Lamp", "just you", Event::Channel::SaidTo)); out.heard(said(lamp, "Lamp", "an IM", Event::Channel::Instant)); const auto& entries = out.view()->entries(); - ensure_equals("three", entries.size(), size_t(3)); - ensure_equals("the prim that spoke, after its object", entries[0].source, std::string("Lamp \xE2\x96\xB8 Bulb")); - ensure_equals("said", entries[0].kind, window.services().words("KindSaid")); - ensure_equals("said to the agent", entries[1].kind, window.services().words("KindSaidTo")); - ensure_equals("an IM", entries[2].kind, window.services().words("KindInstant")); + UNSCOPED_INFO("three"); + REQUIRE(entries.size() == size_t(3)); + UNSCOPED_INFO("the prim that spoke, after its object"); + CHECK(entries[0].source == std::string("Lamp \xE2\x96\xB8 Bulb")); + UNSCOPED_INFO("said"); + CHECK(entries[0].kind == window.services().words("KindSaid")); + UNSCOPED_INFO("said to the agent"); + CHECK(entries[1].kind == window.services().words("KindSaidTo")); + UNSCOPED_INFO("an IM"); + CHECK(entries[2].kind == window.services().words("KindInstant")); whose("mine"); - ensure_equals("the agent's own, all of them", shownTexts().size(), size_t(3)); + UNSCOPED_INFO("the agent's own, all of them"); + REQUIRE(shownTexts().size() == size_t(3)); whose(""); out.showKind("said"); - ensure_equals("aloud and to the agent", shown(), std::string("|hello|just you")); + UNSCOPED_INFO("aloud and to the agent"); + CHECK(shown() == std::string("|hello|just you")); out.showKind("im"); - ensure_equals("IMs", shown(), std::string("|an IM")); + UNSCOPED_INFO("IMs"); + CHECK(shown() == std::string("|an IM")); } - template<> template<> - void alscriptoutputpane_object::test<10>() + TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: the controls row keeps buttons right and narrows the lists first", "[ALScriptOutputPane]") { - set_test_name("the row over the log: the buttons against the right edge, the words' box the rest; narrow, the lists give way first, never overlapping"); ALScriptOutputPane& out = make(); const LLRect whose = out.getChild("output_filter")->getRect(); const LLRect kind = out.getChild("output_kind")->getRect(); @@ -505,21 +562,38 @@ namespace tut }; out.reshape(800, out.getRect().getHeight()); std::vector wide = row(); - ensure("wide: the lists as the skin made them", wide[0].getWidth() == whose.getWidth() && wide[1].getWidth() == kind.getWidth()); - ensure("the copy against the right edge, the box up to the clear", wide[4].mRight == 798 && wide[2].mRight + 6 == wide[3].mLeft); - ensure("in order, apart", apart(wide, 800)); + { + INFO("wide: the lists as the skin made them"); + CHECK(wide[0].getWidth() == whose.getWidth()); + CHECK(wide[1].getWidth() == kind.getWidth()); + } + { + INFO("the copy against the right edge, the box up to the clear"); + CHECK(wide[4].mRight == 798); + CHECK(wide[2].mRight + 6 == wide[3].mLeft); + } + UNSCOPED_INFO("in order, apart"); + CHECK(apart(wide, 800)); out.reshape(420, out.getRect().getHeight()); std::vector narrow = row(); - ensure("narrow: the lists narrower", narrow[0].getWidth() < whose.getWidth() && narrow[1].getWidth() <= kind.getWidth()); - ensure("the buttons as they were", narrow[3].getWidth() == wide[3].getWidth() && narrow[4].getWidth() == wide[4].getWidth()); - ensure("in order, apart", apart(narrow, 420)); - ensure("the box still there", narrow[2].getWidth() >= 60); + { + INFO("narrow: the lists narrower"); + CHECK(narrow[0].getWidth() < whose.getWidth()); + CHECK(narrow[1].getWidth() <= kind.getWidth()); + } + { + INFO("the buttons as they were"); + CHECK(narrow[3].getWidth() == wide[3].getWidth()); + CHECK(narrow[4].getWidth() == wide[4].getWidth()); + } + UNSCOPED_INFO("in order, apart"); + CHECK(apart(narrow, 420)); + UNSCOPED_INFO("the box still there"); + CHECK(narrow[2].getWidth() >= 60); } - template<> template<> - void alscriptoutputpane_object::test<11>() + TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: a lone CR breaks a line and links follow it to the shown line", "[ALScriptOutputPane]") { - set_test_name("an error that says a lone CR runs to a line more, and a frame under it links from the line the log shows it on; the studio's own words' links likewise"); ALScriptOutputPane& out = make(); const LLUUID object = fresh(); const LLUUID item = fresh(); @@ -527,19 +601,33 @@ namespace tut error.stack = { "lua_script:8: bad\rvalue", "lua_script:3 function helper" }; out.heard(error); const ALOutputView::Entry& entry = last(); - ensure_equals("its breaks as the log reads them", entry.text, std::string("bad\nvalue\nlua_script:3 function helper")); - ensure_equals("a link for the frame", entry.links.size(), size_t(1)); - ensure_equals("on the frame's line", entry.links[0].line, 2); + UNSCOPED_INFO("its breaks as the log reads them"); + CHECK(entry.text == std::string("bad\nvalue\nlua_script:3 function helper")); + UNSCOPED_INFO("a link for the frame"); + REQUIRE(entry.links.size() == size_t(1)); + UNSCOPED_INFO("on the frame's line"); + CHECK(entry.links[0].line == 2); const ALTextDocument& shown_text = out.view()->document(); - ensure_equals("the line the log shows it on", shown_text.line(shown_text.lineCount() - 1), std::string("lua_script:3 function helper")); + UNSCOPED_INFO("the line the log shows it on"); + CHECK(shown_text.line(shown_text.lineCount() - 1) == std::string("lua_script:3 function helper")); // The studio's own words likewise: a name after a lone CR linked on // the line it is shown on, and what to do after it. ALScriptStudioDoc& doc = services.addDoc("door-script", ALScriptRef(fresh(), fresh()), "door.lsl"); out.said("Could not save\rdoor.lsl.", true, &doc, { "retry" }); const ALOutputView::Entry& studio_said = last(); - ensure_equals("the name and what to do", studio_said.links.size(), size_t(2)); - ensure("the name at the start of the second line", studio_said.links[0].line == 1 && studio_said.links[0].begin == 0 && studio_said.links[0].end == 8); - ensure("what to do on it too", studio_said.links[1].line == 1 && studio_said.links[1].begin == 12); + UNSCOPED_INFO("the name and what to do"); + REQUIRE(studio_said.links.size() == size_t(2)); + { + INFO("the name at the start of the second line"); + CHECK(studio_said.links[0].line == 1); + CHECK(studio_said.links[0].begin == 0); + CHECK(studio_said.links[0].end == 8); + } + { + INFO("what to do on it too"); + CHECK(studio_said.links[1].line == 1); + CHECK(studio_said.links[1].begin == 12); + } } } diff --git a/indra/newview/tests/alscriptproblemspane_test.cpp b/indra/newview/tests/alscriptproblemspane_test.cpp index f41eed5fce..17199c9c2b 100644 --- a/indra/newview/tests/alscriptproblemspane_test.cpp +++ b/indra/newview/tests/alscriptproblemspane_test.cpp @@ -40,7 +40,7 @@ #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include #include #include @@ -135,7 +135,7 @@ namespace } } -namespace tut +namespace { struct alscriptproblemspane_data { @@ -149,11 +149,12 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } // The tab as the skin built it. pane = window.find("problems_tab"); - ensure("the skin builds the tab as the pane", pane != nullptr); + UNSCOPED_INFO("the skin builds the tab as the pane"); + REQUIRE(pane != nullptr); return *pane; } @@ -225,7 +226,7 @@ namespace tut return; } } - fail("no row says " + message); + FAIL("no row says " + message); } void tick(const char* box, bool on) { @@ -236,19 +237,14 @@ namespace tut void pick(const char* combo, const std::string& value) { LLComboBox* box = window.find(combo); - ensure("offered: " + value, box->selectByValue(LLSD(value))); + UNSCOPED_INFO("offered: " + value); + REQUIRE(box->selectByValue(LLSD(value))); box->onCommit(); } }; - typedef test_group alscriptproblemspane_group; - typedef alscriptproblemspane_group::object alscriptproblemspane_object; - alscriptproblemspane_group alscriptproblemspane_instance("ALScriptProblemsPane"); - template <> - template <> - void alscriptproblemspane_object::test<1>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: gathered problems come in order and fixes lapse once the text changes", "[ALScriptProblemsPane]") { - set_test_name("a tab's problems gathered: in order, each at its level, the compiler's under the analyzer's, and fixes only for the text they were made on"); make(); Doc& d = doc("door"); using S = ALScriptProblem::Source; @@ -282,16 +278,26 @@ namespace tut { messages.push_back(row.message); } - ensure_equals("six rows", made.rows.size(), size_t(6)); - ensure_equals("the weight first, at no line", made.rows[0].origin, services.words("OriginWeight")); - ensure("the weight a warning, the studio's reckoning", made.rows[0].level == Doc::Level::Warning); - ensure_equals("then the compiler's own", made.rows[1].message, std::string("the compiler's own")); - ensure_equals("the lint with its name", made.rows[2].message, std::string("a local shadows another [LocalShadow]")); - ensure_equals("the analyzer's error, the compiler's on its line said once", made.rows[3].message, std::string("syntax error, unexpected")); - ensure_equals("the run-time error, how many times", made.rows[4].message, "Math Error " + services.words("RepeatedTimes", { { "[COUNT]", "3" } })); - ensure("a run-time error is an error", made.rows[4].level == Doc::Level::Error); - ensure_equals("the include's last", made.rows[5].fileName, std::string("lib.lsl")); - ensure_equals("the squiggles: the script's own", made.decorations.size(), size_t(4)); + UNSCOPED_INFO("six rows"); + REQUIRE(made.rows.size() == size_t(6)); + UNSCOPED_INFO("the weight first, at no line"); + CHECK(made.rows[0].origin == services.words("OriginWeight")); + UNSCOPED_INFO("the weight a warning, the studio's reckoning"); + CHECK(made.rows[0].level == Doc::Level::Warning); + UNSCOPED_INFO("then the compiler's own"); + CHECK(made.rows[1].message == std::string("the compiler's own")); + UNSCOPED_INFO("the lint with its name"); + CHECK(made.rows[2].message == std::string("a local shadows another [LocalShadow]")); + UNSCOPED_INFO("the analyzer's error, the compiler's on its line said once"); + CHECK(made.rows[3].message == std::string("syntax error, unexpected")); + UNSCOPED_INFO("the run-time error, how many times"); + CHECK(made.rows[4].message == "Math Error " + services.words("RepeatedTimes", { { "[COUNT]", "3" } })); + UNSCOPED_INFO("a run-time error is an error"); + CHECK(made.rows[4].level == Doc::Level::Error); + UNSCOPED_INFO("the include's last"); + CHECK(made.rows[5].fileName == std::string("lib.lsl")); + UNSCOPED_INFO("the squiggles: the script's own"); + REQUIRE(made.decorations.size() == size_t(4)); const auto underline = [&](S32 line) { for (const ALCodeEditor::Decoration& each : made.decorations) { @@ -303,32 +309,40 @@ namespace tut return ALCodeEditor::Decoration::Style::Background; }; using Style = ALCodeEditor::Decoration::Style; - ensure("an error waved, a warning dashed, a run-time error waved", - underline(2) == Style::Squiggle && underline(4) == Style::Dashed && underline(8) == Style::Squiggle); - ensure("the run-time mark on its line", - std::find(made.marks.begin(), made.marks.end(), std::make_pair(S32(8), ALCodeEditor::Mark::Runtime)) != made.marks.end()); - ensure("each level's mark", ALScriptProblemsPane::markOf(Doc::Level::Error) == ALCodeEditor::Mark::Error && - ALScriptProblemsPane::markOf(Doc::Level::Warning) == ALCodeEditor::Mark::Warning && - ALScriptProblemsPane::markOf(Doc::Level::Note) == ALCodeEditor::Mark::Note); - ensure_equals("the lint's line offers its fix", made.fixable.size(), size_t(1)); - ensure("which changes the script", made.fixable[0] == std::make_pair(S32(4), true)); + { + INFO("an error waved, a warning dashed, a run-time error waved"); + CHECK(underline(2) == Style::Squiggle); + CHECK(underline(4) == Style::Dashed); + CHECK(underline(8) == Style::Squiggle); + } + UNSCOPED_INFO("the run-time mark on its line"); + REQUIRE(std::find(made.marks.begin(), made.marks.end(), std::make_pair(S32(8), ALCodeEditor::Mark::Runtime)) != made.marks.end()); + { + INFO("each level's mark"); + CHECK(ALScriptProblemsPane::markOf(Doc::Level::Error) == ALCodeEditor::Mark::Error); + CHECK(ALScriptProblemsPane::markOf(Doc::Level::Warning) == ALCodeEditor::Mark::Warning); + CHECK(ALScriptProblemsPane::markOf(Doc::Level::Note) == ALCodeEditor::Mark::Note); + } + UNSCOPED_INFO("the lint's line offers its fix"); + REQUIRE(made.fixable.size() == size_t(1)); + UNSCOPED_INFO("which changes the script"); + CHECK(made.fixable[0] == std::make_pair(S32(4), true)); // Typed in since the check: the fixes are of a text there is no // longer, and the compiler's error on the analyzer's line is its own // again. d.editor->setText("line 0\nline 1\n"); made = gather(d); - ensure("no fix offered", made.fixable.empty()); - ensure("the compiler's error said", std::any_of(made.rows.begin(), made.rows.end(), [](const Doc::Shown& row) { return row.message == "syntax error"; })); - ensure("nor the weight, weighed of the old text", - std::none_of(made.rows.begin(), made.rows.end(), [&](const Doc::Shown& row) { return row.origin == services.words("OriginWeight"); })); + UNSCOPED_INFO("no fix offered"); + REQUIRE(made.fixable.empty()); + UNSCOPED_INFO("the compiler's error said"); + CHECK(std::any_of(made.rows.begin(), made.rows.end(), [](const Doc::Shown& row) { return row.message == "syntax error"; })); + UNSCOPED_INFO("nor the weight, weighed of the old text"); + CHECK(std::none_of(made.rows.begin(), made.rows.end(), [&](const Doc::Shown& row) { return row.origin == services.words("OriginWeight"); })); } - template <> - template <> - void alscriptproblemspane_object::test<2>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: the list follows its filters and scope and the boxes say the counts", "[ALScriptProblemsPane]") { - set_test_name("the list through its filters -- levels, origin, words -- and its scope, with the counts the boxes and the tab say"); ALScriptProblemsPane& out = make(); using S = ALScriptProblem::Source; using V = ALScriptProblem::Severity; @@ -340,63 +354,79 @@ namespace tut gather(lamp); gather(door); out.fill(&door); - ensure_equals("the one in front's", shown(), std::string("|door error|door warning|door note")); - ensure_equals("three to list", out.held(), 3); - ensure("said on the tab", studio.counts > 0); - ensure_equals("counted on the box", window.find("problems_errors")->getLabel(), + UNSCOPED_INFO("the one in front's"); + CHECK(shown() == std::string("|door error|door warning|door note")); + UNSCOPED_INFO("three to list"); + CHECK(out.held() == 3); + UNSCOPED_INFO("said on the tab"); + CHECK(studio.counts > 0); + UNSCOPED_INFO("counted on the box"); + CHECK(window.find("problems_errors")->getLabel() == services.words("FilterErrorsCount", { { "[COUNT]", "1" } })); tick("problems_errors", false); - ensure("the filter kept", studio.filtersKept == 1); - ensure_equals("no errors, and what is hidden said", shown(), + UNSCOPED_INFO("the filter kept"); + CHECK(studio.filtersKept == 1); + UNSCOPED_INFO("no errors, and what is hidden said"); + CHECK(shown() == "|door warning|door note|#" + services.counted("ProblemsHidden", 1)); tick("problems_errors", true); pick("problems_origin", services.words("OriginLint")); - ensure_equals("the lint's alone", shown(), "|door warning|door note|#" + services.counted("ProblemsHidden", 1)); + UNSCOPED_INFO("the lint's alone"); + CHECK(shown() == "|door warning|door note|#" + services.counted("ProblemsHidden", 1)); pick("problems_origin", ""); window.find("problems_filter")->setText(std::string("NOTE")); window.find("problems_filter")->onCommit(); - ensure_equals("the words, in either case", shown(), "|door note|#" + services.counted("ProblemsHidden", 2)); - ensure("rows to show: nothing said over them", !out.list()->saysEmpty()); + UNSCOPED_INFO("the words, in either case"); + CHECK(shown() == "|door note|#" + services.counted("ProblemsHidden", 2)); + UNSCOPED_INFO("rows to show: nothing said over them"); + CHECK_FALSE(out.list()->saysEmpty()); window.find("problems_filter")->setText(std::string()); window.find("problems_filter")->onCommit(); pick("problems_scope", "all"); - ensure_equals("every script's, each under its name", shown(), + UNSCOPED_INFO("every script's, each under its name"); + CHECK(shown() == "|#door.lsl \xC2\xB7 " + services.counted("ProblemErrors", 1) + ", " + services.counted("ProblemWarnings", 1) + ", " + services.counted("ProblemNotes", 1) + "|door error|door warning|door note|#lamp.lsl \xC2\xB7 " + services.counted("ProblemErrors", 1) + "|lamp error"); - ensure_equals("four to list", out.held(), 4); + UNSCOPED_INFO("four to list"); + CHECK(out.held() == 4); // Another script's problems gathered again: listed, since every // one's are. lamp.check->analysis.push_back(problem(S::Lint, V::Warning, 7, "lamp warning")); gather(lamp); - ensure("the new one listed", shown().find("lamp warning") != std::string::npos); + UNSCOPED_INFO("the new one listed"); + REQUIRE(shown().find("lamp warning") != std::string::npos); pick("problems_scope", "this"); - ensure_equals("back to the one", shown(), std::string("|door error|door warning|door note")); + UNSCOPED_INFO("back to the one"); + CHECK(shown() == std::string("|door error|door warning|door note")); gather(lamp); - ensure("another's gathered leaves the list alone", shown().find("lamp") == std::string::npos); + UNSCOPED_INFO("another's gathered leaves the list alone"); + REQUIRE(shown().find("lamp") == std::string::npos); // Closed, it is let go of. out.closed("door"); - ensure("forgotten", out.listedId().empty()); + UNSCOPED_INFO("forgotten"); + REQUIRE(out.listedId().empty()); LLSD state; out.saveState(state); - ensure_equals("the scope kept", state["problem_scope"].asString(), std::string("this")); + UNSCOPED_INFO("the scope kept"); + CHECK(state["problem_scope"].asString() == std::string("this")); // A script with nothing wrong with it says so where the rows would be. Doc& clean = doc("clean"); gather(clean); out.fill(&clean); - ensure("nothing listed, said", out.list()->saysEmpty() - && out.list()->emptyWords() == services.words("NoProblemsIn", { { "[NAME]", "clean.lsl" } })); + { + INFO("nothing listed, said"); + REQUIRE(out.list()->saysEmpty()); + CHECK(out.list()->emptyWords() == services.words("NoProblemsIn", { { "[NAME]", "clean.lsl" } })); + } } - template <> - template <> - void alscriptproblemspane_object::test<3>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: selectFirstError and a chosen row go to the problem's place", "[ALScriptProblemsPane]") { - set_test_name("the first error chosen and gone to, passing over the compiler's where asked; a row chosen goes to its place"); ALScriptProblemsPane& out = make(); Doc& d = doc("door"); d.problems.push_back({ 1, 0, true, std::string(), "ERROR", "compiler first" }); @@ -405,30 +435,44 @@ namespace tut gather(d); out.fill(&d); out.selectFirstError(false); - ensure_equals("the first error, the compiler's", studio.chosen.back().line, 1); - ensure("taken to the script", studio.toEditor.back()); + UNSCOPED_INFO("the first error, the compiler's"); + CHECK(studio.chosen.back().line == 1); + UNSCOPED_INFO("taken to the script"); + REQUIRE(studio.toEditor.back()); out.selectFirstError(true); - ensure_equals("the checkers' own", studio.chosen.back().line, 5); - ensure_equals("its stretch", studio.chosen.back().endColumn, 6); + UNSCOPED_INFO("the checkers' own"); + CHECK(studio.chosen.back().line == 5); + UNSCOPED_INFO("its stretch"); + CHECK(studio.chosen.back().endColumn == 6); choose("a warning before"); out.choose(false); - ensure_equals("a row walked to", studio.chosen.back().line, 0); - ensure("the keyboard left in the list", !studio.toEditor.back()); - ensure_equals("whose it is", studio.chosen.back().doc, std::string("door")); + UNSCOPED_INFO("a row walked to"); + CHECK(studio.chosen.back().line == 0); + UNSCOPED_INFO("the keyboard left in the list"); + REQUIRE_FALSE(studio.toEditor.back()); + UNSCOPED_INFO("whose it is"); + CHECK(studio.chosen.back().doc == std::string("door")); // The list's keys: return goes there to type, escape back to the // script without going. - ensure("return", out.list()->handleKeyHere(KEY_RETURN, MASK_NONE) && studio.chosen.back().line == 0 && studio.toEditor.back()); + { + INFO("return"); + CHECK(out.list()->handleKeyHere(KEY_RETURN, MASK_NONE)); + CHECK(studio.chosen.back().line == 0); + REQUIRE(studio.toEditor.back()); + } const size_t gone = studio.chosen.size(); - ensure("escape", out.list()->handleKeyHere(KEY_ESCAPE, MASK_NONE) && services.reveals.back() && studio.chosen.size() == gone); + { + INFO("escape"); + CHECK(out.list()->handleKeyHere(KEY_ESCAPE, MASK_NONE)); + REQUIRE(services.reveals.back()); + REQUIRE(studio.chosen.size() == gone); + } } - template <> - template <> - void alscriptproblemspane_object::test<4>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: the menu offers only what the chosen problem allows and acts on it", "[ALScriptProblemsPane]") { - set_test_name("the menu offers what the chosen problem allows: its lint turned off or made an error, its fixes, every one of its kind"); ALScriptProblemsPane& out = make(); Doc& d = doc("door"); studio.lints.insert("LocalShadow"); @@ -447,51 +491,80 @@ namespace tut out.fill(&d); choose("no lint"); - ensure("no lint to turn off", !out.enabled("off") && !out.enabled("error")); - ensure("copying always", out.enabled("copy") && out.enabled("copy_all")); - ensure("no run-time errors to let go of", !out.enabled("clear_runtime")); - ensure("of no kind, none to fix along with it", !out.fixShown("kind")); + { + INFO("no lint to turn off"); + CHECK_FALSE(out.enabled("off")); + CHECK_FALSE(out.enabled("error")); + } + { + INFO("copying always"); + CHECK(out.enabled("copy")); + CHECK(out.enabled("copy_all")); + } + UNSCOPED_INFO("no run-time errors to let go of"); + CHECK_FALSE(out.enabled("clear_runtime")); + UNSCOPED_INFO("of no kind, none to fix along with it"); + CHECK_FALSE(out.fixShown("kind")); out.act("fix_kind"); - ensure("nor made", studio.kinds.empty()); - ensure("Fix All, over two", out.fixShown("all")); + UNSCOPED_INFO("nor made"); + REQUIRE(studio.kinds.empty()); + UNSCOPED_INFO("Fix All, over two"); + CHECK(out.fixShown("all")); choose("shadowed once [LocalShadow]"); - ensure("its lint", out.enabled("off") && out.enabled("error")); - ensure("a warning", !out.lintIsError()); + { + INFO("its lint"); + CHECK(out.enabled("off")); + CHECK(out.enabled("error")); + } + UNSCOPED_INFO("a warning"); + CHECK_FALSE(out.lintIsError()); out.act("error"); - ensure("made an error", out.lintIsError()); + UNSCOPED_INFO("made an error"); + CHECK(out.lintIsError()); out.act("error"); - ensure("and back", !out.lintIsError()); + UNSCOPED_INFO("and back"); + CHECK_FALSE(out.lintIsError()); out.act("off"); - ensure("turned off", studio.levels["LocalShadow"] == ALScriptLints::Level::Off); + UNSCOPED_INFO("turned off"); + CHECK(studio.levels["LocalShadow"] == ALScriptLints::Level::Off); out.act("settings"); - ensure_equals("the settings", studio.settings, 1); - ensure("every one of its kind", out.fixShown("kind")); + UNSCOPED_INFO("the settings"); + CHECK(studio.settings == 1); + UNSCOPED_INFO("every one of its kind"); + CHECK(out.fixShown("kind")); out.act("fix:0"); - ensure_equals("its fix made", studio.fixed.size(), size_t(1)); - ensure_equals("which", studio.fixed[0], std::string("door:Rename")); + UNSCOPED_INFO("its fix made"); + REQUIRE(studio.fixed.size() == size_t(1)); + UNSCOPED_INFO("which"); + CHECK(studio.fixed[0] == std::string("door:Rename")); out.act("fix_kind"); out.act("fix_all"); - ensure_equals("of its kind, then of all", studio.kinds.size(), size_t(2)); - ensure_equals("by its kind", studio.kinds[0], std::string("door:shadow")); - ensure_equals("then every kind", studio.kinds[1], std::string("door:")); + UNSCOPED_INFO("of its kind, then of all"); + REQUIRE(studio.kinds.size() == size_t(2)); + UNSCOPED_INFO("by its kind"); + CHECK(studio.kinds[0] == std::string("door:shadow")); + UNSCOPED_INFO("then every kind"); + CHECK(studio.kinds[1] == std::string("door:")); out.act("copy_all"); - ensure_equals("copied, and said", services.statuses.back(), services.counted("ProblemsCopied", 3)); + UNSCOPED_INFO("copied, and said"); + CHECK(services.statuses.back() == services.counted("ProblemsCopied", 3)); d.runtime.push_back({ 1, -1, std::string(), "Math Error", 1 }); - ensure("run-time errors to let go of", out.enabled("clear_runtime")); + UNSCOPED_INFO("run-time errors to let go of"); + CHECK(out.enabled("clear_runtime")); out.act("clear_runtime"); - ensure("let go of", d.runtime.empty()); - ensure("and not recalled when it is opened again", studio.cleared == std::vector{ d.id }); - ensure_equals("and the tab's problems gathered again", studio.refreshed.size(), size_t(1)); + UNSCOPED_INFO("let go of"); + REQUIRE(d.runtime.empty()); + UNSCOPED_INFO("and not recalled when it is opened again"); + CHECK(studio.cleared == std::vector{ d.id }); + UNSCOPED_INFO("and the tab's problems gathered again"); + REQUIRE(studio.refreshed.size() == size_t(1)); } - template <> - template <> - void alscriptproblemspane_object::test<5>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: a compiler error a line after the analyzer's is merged and dated after edits", "[ALScriptProblemsPane]") { - set_test_name("the compiler's error a line from the analyzer's is the same error said once; the compiler's said to be as of the last save once the text has changed"); make(); Doc& d = doc("door"); using S = ALScriptProblem::Source; @@ -507,8 +580,10 @@ namespace tut { messages.push_back(row.message); } - ensure("the one a line after said once", std::find(messages.begin(), messages.end(), "syntax error") == messages.end()); - ensure("one further off kept", std::find(messages.begin(), messages.end(), "far from any") != messages.end()); + UNSCOPED_INFO("the one a line after said once"); + REQUIRE(std::find(messages.begin(), messages.end(), "syntax error") == messages.end()); + UNSCOPED_INFO("one further off kept"); + REQUIRE(std::find(messages.begin(), messages.end(), "far from any") != messages.end()); // Typed in since the save: what the compiler said is of the text // as it was. d.editor->insertText("x"); @@ -518,14 +593,12 @@ namespace tut { marked |= row.message == "far from any " + services.words("CompilerAsSaved"); } - ensure("as of the last save", marked); + UNSCOPED_INFO("as of the last save"); + CHECK(marked); } - template <> - template <> - void alscriptproblemspane_object::test<6>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: an LSL lint shows its NOLINT name and an error no code number", "[ALScriptProblemsPane]") { - set_test_name("an LSL lint says its name, which a NOLINT comment turns it off by; an error says no number; the origins offer the weight"); make(); Doc& d = doc("door"); using S = ALScriptProblem::Source; @@ -544,17 +617,20 @@ namespace tut named |= row.message == "declared but never used [DeclaredButNotUsed]"; numbered |= row.message.find("10002") != std::string::npos; } - ensure("the lint named", named); - ensure("the error no number", !numbered); + UNSCOPED_INFO("the lint named"); + CHECK(named); + UNSCOPED_INFO("the error no number"); + CHECK_FALSE(numbered); LLComboBox* origins = window.find("problems_origin"); - ensure("the origins offer the weight", origins && origins->selectByValue(LLSD(services.words("OriginWeight")))); + { + INFO("the origins offer the weight"); + REQUIRE(origins); + CHECK(origins->selectByValue(LLSD(services.words("OriginWeight")))); + } } - template <> - template <> - void alscriptproblemspane_object::test<7>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: code past four fifths of its limit warns what is left once optimized", "[ALScriptProblemsPane]") { - set_test_name("code past four fifths of its target's limit is a warning that says what is left to run in; not before the optimizer, nor under"); make(); Doc& d = doc("door"); ALScriptWeight weight; @@ -570,39 +646,49 @@ namespace tut return rows; }; std::vector rows = weights(gather(d)); - ensure_equals("near: one row", rows.size(), size_t(1)); - ensure("a warning", rows[0].level == Doc::Level::Warning); - ensure("what is left", rows[0].message == services.words("WeightNear", { { "[SIZE]", "14.0" }, { "[LIMIT]", "16" }, { "[LEFT]", "2.0" }, { "[TARGET]", "LSL (LSO)" } })); + UNSCOPED_INFO("near: one row"); + REQUIRE(rows.size() == size_t(1)); + UNSCOPED_INFO("a warning"); + CHECK(rows[0].level == Doc::Level::Warning); + UNSCOPED_INFO("what is left"); + CHECK(rows[0].message == services.words("WeightNear", { { "[SIZE]", "14.0" }, { "[LIMIT]", "16" }, { "[LEFT]", "2.0" }, { "[TARGET]", "LSL (LSO)" } })); d.weighing->exact = false; - ensure("before the optimizer, nothing", weights(gather(d)).empty()); + UNSCOPED_INFO("before the optimizer, nothing"); + REQUIRE(weights(gather(d)).empty()); d.weighing->exact = true; d.weighing->weight->total = 12 * 1024; - ensure("at three quarters, nothing", weights(gather(d)).empty()); + UNSCOPED_INFO("at three quarters, nothing"); + REQUIRE(weights(gather(d)).empty()); d.weighing->weight->total = 17 * 1024; rows = weights(gather(d)); - ensure("over: the over row alone", rows.size() == 1 && rows[0].message.find("more than") != std::string::npos); + { + INFO("over: the over row alone"); + REQUIRE(rows.size() == 1); + REQUIRE(rows[0].message.find("more than") != std::string::npos); + } } - template <> - template <> - void alscriptproblemspane_object::test<8>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: a problem in generated code is listed as such and not marked in the source", "[ALScriptProblemsPane]") { - set_test_name("a problem in code the preprocessor made is listed under that name, not marked on the source's line of its number"); make(); Doc& d = doc("door"); ALScriptProblem made_here = problem(ALScriptProblem::Source::Parser, ALScriptProblem::Severity::Error, 1, "in a switch's jump table", Doc::GENERATED); d.check->analysis = { made_here }; d.check->analysisVersion = d.editor->document().version(); const ALScriptProblemsPane::Made made = gather(d); - ensure_equals("one row", made.rows.size(), size_t(1)); - ensure_equals("named so", made.rows[0].fileName, services.words("InGeneratedCode")); - ensure("no mark, no squiggle", made.marks.empty() && made.decorations.empty()); + UNSCOPED_INFO("one row"); + REQUIRE(made.rows.size() == size_t(1)); + UNSCOPED_INFO("named so"); + CHECK(made.rows[0].fileName == services.words("InGeneratedCode")); + { + INFO("no mark, no squiggle"); + REQUIRE(made.marks.empty()); + REQUIRE(made.decorations.empty()); + } } - template<> template<> - void alscriptproblemspane_object::test<9>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: a checked script with no tab is listed after open ones and chosen by its item", "[ALScriptProblemsPane]") { - set_test_name("a script no tab holds, which an object's check reached, is listed after the open ones under its name, chosen by its item, and gives way to its tab"); make(); Doc& d = doc("door"); d.check->analysis = { problem(ALScriptProblem::Source::Parser, ALScriptProblem::Severity::Error, 1, "in the open one") }; @@ -622,10 +708,14 @@ namespace tut pane->showEveryScript(); const std::string listed = shown(); const std::string heading = "#" + services.words("ProblemsChecked", { { "[NAME]", "hinge.lsl" }, { "[OBJECT]", "House" } }); - ensure("the open one's, then the closed one's under its name and object: " + listed, - listed.find("in the open one") < listed.find(heading) && listed.find(heading) < listed.find("in the closed one") && - listed.find("in the closed one") != std::string::npos); - ensure_equals("counted with the rest", pane->held(), 2); + { + INFO("the open one's, then the closed one's under its name and object: " + listed); + CHECK(listed.find("in the open one") < listed.find(heading)); + CHECK(listed.find(heading) < listed.find("in the closed one")); + REQUIRE(listed.find("in the closed one") != std::string::npos); + } + UNSCOPED_INFO("counted with the rest"); + CHECK(pane->held() == 2); // Chosen by its item and name, with no tab. const std::vector rows = list()->getAllData(); @@ -634,26 +724,41 @@ namespace tut { at = rows[i]->getValue()["owner"].asString().rfind("checked:", 0) == 0 ? static_cast(i) : at; } - ensure("a row of it", at >= 0); + UNSCOPED_INFO("a row of it"); + CHECK(at >= 0); list()->selectNthItem(at); pane->choose(false); - ensure("chosen", !studio.chosen.empty()); + UNSCOPED_INFO("chosen"); + REQUIRE_FALSE(studio.chosen.empty()); const ALScriptProblemsPane::Place& place = studio.chosen.back(); - ensure("by its item, with no tab", place.ref == closed && place.name == "hinge.lsl" && place.doc.empty() && place.line == 3); + { + INFO("by its item, with no tab"); + CHECK(place.ref == closed); + CHECK(place.name == "hinge.lsl"); + REQUIRE(place.doc.empty()); + CHECK(place.line == 3); + } // Opened, its tab says; a new check lets the last one's go. pane->forgetChecked(closed); - ensure("given way", shown().find("in the closed one") == std::string::npos && pane->held() == 1); + { + INFO("given way"); + REQUIRE(shown().find("in the closed one") == std::string::npos); + CHECK(pane->held() == 1); + } pane->checkedScript(closed, "hinge.lsl", false, { row }, "House"); - ensure_equals("back", pane->checkedCount(), size_t(1)); + UNSCOPED_INFO("back"); + CHECK(pane->checkedCount() == size_t(1)); pane->clearChecked(); - ensure("let go of", pane->checkedCount() == 0 && shown().find("in the closed one") == std::string::npos); + { + INFO("let go of"); + CHECK(pane->checkedCount() == 0); + REQUIRE(shown().find("in the closed one") == std::string::npos); + } } - template<> template<> - void alscriptproblemspane_object::test<10>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: a closed script's last recompile errors list beside its check until clean", "[ALScriptProblemsPane]") { - set_test_name("what a recompile's compiler said of a closed script is listed beside its check's rows, the last recompile's alone, and goes when it compiles clean"); make(); LLUUID object, item; object.generate(); @@ -669,33 +774,46 @@ namespace tut }; pane->showEveryScript(); pane->compiledScript(closed, "hinge.lsl", false, {}, "House"); - ensure("clean, and nothing listed of it: nothing to list", pane->checkedCount() == 0); + UNSCOPED_INFO("clean, and nothing listed of it: nothing to list"); + CHECK(pane->checkedCount() == 0); pane->checkedScript(closed, "hinge.lsl", false, { row("the check's", "Lint") }, "House"); pane->compiledScript(closed, "hinge.lsl", false, { row("the compiler's", "Compiler") }, "House"); - ensure("both listed", shown().find("the check's") != std::string::npos && shown().find("the compiler's") != std::string::npos); - ensure_equals("counted", pane->held(), 2); + { + INFO("both listed"); + REQUIRE(shown().find("the check's") != std::string::npos); + REQUIRE(shown().find("the compiler's") != std::string::npos); + } + UNSCOPED_INFO("counted"); + CHECK(pane->held() == 2); pane->compiledScript(closed, "hinge.lsl", false, { row("again", "Compiler") }, "House"); - ensure("the last recompile's alone", shown().find("the compiler's") == std::string::npos && shown().find("again") != std::string::npos); + { + INFO("the last recompile's alone"); + REQUIRE(shown().find("the compiler's") == std::string::npos); + REQUIRE(shown().find("again") != std::string::npos); + } pane->compiledScript(closed, "hinge.lsl", false, {}, "House"); - ensure("clean: the compiler's gone, the check's stay", shown().find("again") == std::string::npos && shown().find("the check's") != std::string::npos); + { + INFO("clean: the compiler's gone, the check's stay"); + REQUIRE(shown().find("again") == std::string::npos); + REQUIRE(shown().find("the check's") != std::string::npos); + } // Recompiled alone, with no check: gone with its rows. LLUUID other; other.generate(); const ALScriptRef lone(object, other); pane->compiledScript(lone, "latch.lsl", false, { row("latch", "Compiler") }, "House"); - ensure_equals("listed", pane->checkedCount(), size_t(2)); + UNSCOPED_INFO("listed"); + CHECK(pane->checkedCount() == size_t(2)); pane->compiledScript(lone, "latch.lsl", false, {}, "House"); - ensure_equals("gone", pane->checkedCount(), size_t(1)); + UNSCOPED_INFO("gone"); + CHECK(pane->checkedCount() == size_t(1)); } - template <> - template <> - void alscriptproblemspane_object::test<11>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: out of sight the pane counts at once but lists rows only when seen or chosen", "[ALScriptProblemsPane]") { - set_test_name("out of sight, the counts said at once and the rows listed once the list is seen, or once a row is to be chosen"); ALScriptProblemsPane& out = make(); using S = ALScriptProblem::Source; using V = ALScriptProblem::Severity; @@ -703,33 +821,47 @@ namespace tut Doc& door = doc("door"); door.check->analysis = { problem(S::Parser, V::Error, 1, "door error"), problem(S::Lint, V::Warning, 3, "door warning") }; tabs->selectTabByName("references_tab"); - ensure("out of sight", !ALPaneFolds::inSight(&out)); + UNSCOPED_INFO("out of sight"); + CHECK_FALSE(ALPaneFolds::inSight(&out)); const S32 said = studio.counts; gather(door); - ensure("counted, and said on the tab", out.held() == 2 && studio.counts > said); - ensure_equals("not listed", shown(), std::string()); + { + INFO("counted, and said on the tab"); + CHECK(out.held() == 2); + CHECK(studio.counts > said); + } + UNSCOPED_INFO("not listed"); + CHECK(shown() == std::string()); out.pump(); - ensure_equals("nor while unseen", shown(), std::string()); + UNSCOPED_INFO("nor while unseen"); + CHECK(shown() == std::string()); tabs->selectTabByName("problems_tab"); out.pump(); - ensure_equals("seen: listed", shown(), std::string("|door error|door warning")); + UNSCOPED_INFO("seen: listed"); + CHECK(shown() == std::string("|door error|door warning")); tabs->selectTabByName("references_tab"); door.check->analysis.push_back(problem(S::Parser, V::Error, 5, "a second error")); gather(door); - ensure("counted again, the rows as they were", out.held() == 3 && shown() == "|door error|door warning"); + { + INFO("counted again, the rows as they were"); + CHECK(out.held() == 3); + CHECK(shown() == "|door error|door warning"); + } const size_t chosen = studio.chosen.size(); out.selectFirstError(false); - ensure("a row to choose: listed first", shown().find("a second error") != std::string::npos); - ensure("and chosen", studio.chosen.size() == chosen + 1 && studio.chosen.back().line == 1); + UNSCOPED_INFO("a row to choose: listed first"); + REQUIRE(shown().find("a second error") != std::string::npos); + { + INFO("and chosen"); + REQUIRE(studio.chosen.size() == chosen + 1); + CHECK(studio.chosen.back().line == 1); + } tabs->selectTabByName("problems_tab"); } - template <> - template <> - void alscriptproblemspane_object::test<12>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: a refill keeps matching rows and the selection and lists at most a thousand", "[ALScriptProblemsPane]") { - set_test_name("a refill keeps the rows that say the same, moved or not, and the row chosen; no more than a thousand listed, the rest counted"); ALScriptProblemsPane& out = make(); using S = ALScriptProblem::Source; using V = ALScriptProblem::Severity; @@ -747,13 +879,20 @@ namespace tut door.check->analysis = { problem(S::Parser, V::Error, 1, "first"), problem(S::Lint, V::Warning, 3, "second") }; gather(door); LLScrollListItem* second = row_saying("second"); - ensure("listed", second != nullptr && second->getColumn(3)->getValue().asString().rfind("4:", 0) == 0); + { + INFO("listed"); + REQUIRE(second != nullptr); + CHECK(second->getColumn(3)->getValue().asString().rfind("4:", 0) == 0); + } choose("second"); door.check->analysis = { problem(S::Parser, V::Error, 2, "first"), problem(S::Lint, V::Warning, 4, "second") }; gather(door); - ensure("moved a line: the same row", row_saying("second") == second); - ensure("where it is now", second->getColumn(3)->getValue().asString().rfind("5:", 0) == 0); - ensure("still chosen", list()->getFirstSelected() == second); + UNSCOPED_INFO("moved a line: the same row"); + CHECK(row_saying("second") == second); + UNSCOPED_INFO("where it is now"); + CHECK(second->getColumn(3)->getValue().asString().rfind("5:", 0) == 0); + UNSCOPED_INFO("still chosen"); + CHECK(list()->getFirstSelected() == second); std::vector many; for (S32 i = 0; i < 1005; ++i) @@ -762,20 +901,21 @@ namespace tut } door.check->analysis = many; gather(door); - ensure_equals("all counted", out.held(), 1005); + UNSCOPED_INFO("all counted"); + CHECK(out.held() == 1005); S32 rows = 0; for (LLScrollListItem* item : list()->getAllData()) { rows += item->getValue().has("heading") ? 0 : 1; } - ensure_equals("a thousand listed", rows, 1000); - ensure("the rest said", shown().find(services.counted("ProblemsUnlisted", 5)) != std::string::npos); + UNSCOPED_INFO("a thousand listed"); + CHECK(rows == 1000); + UNSCOPED_INFO("the rest said"); + REQUIRE(shown().find(services.counted("ProblemsUnlisted", 5)) != std::string::npos); } - template<> template<> - void alscriptproblemspane_object::test<13>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: showObject lists that object's open and checked scripts and no other's", "[ALScriptProblemsPane]") { - set_test_name("an object's check lists that object's scripts: its open ones and those it read, none of another object's open beside them"); make(); const LLUUID house = LLUUID::generateNewID(); const LLUUID shed = LLUUID::generateNewID(); @@ -803,32 +943,41 @@ namespace tut pane->checkedScript(closed, "hinge.lsl", false, { row }, "House"); pane->showObject(house); std::string listed = shown(); - ensure("the house's open scripts: " + listed, listed.find("the door's") != std::string::npos && listed.find("the lamp's") != std::string::npos); - ensure("and the one it read: " + listed, listed.find("the hinge's") != std::string::npos); - ensure("not the shed's: " + listed, listed.find("the bench's") == std::string::npos); - ensure_equals("counted as the house's", pane->held(), 3); + { + INFO("the house's open scripts: " + listed); + REQUIRE(listed.find("the door's") != std::string::npos); + REQUIRE(listed.find("the lamp's") != std::string::npos); + } + UNSCOPED_INFO("and the one it read: " + listed); + REQUIRE(listed.find("the hinge's") != std::string::npos); + UNSCOPED_INFO("not the shed's: " + listed); + REQUIRE(listed.find("the bench's") == std::string::npos); + UNSCOPED_INFO("counted as the house's"); + CHECK(pane->held() == 3); // In front or not, the shed's script is not the house's. services.front = 2; pane->fill(&bench); - ensure("the shed's in front, still not listed", shown().find("the bench's") == std::string::npos); + UNSCOPED_INFO("the shed's in front, still not listed"); + REQUIRE(shown().find("the bench's") == std::string::npos); // Every open script's lists them all; and it is what is kept. pane->showEveryScript(); listed = shown(); - ensure("every open one's: " + listed, listed.find("the bench's") != std::string::npos && listed.find("the door's") != std::string::npos); + { + INFO("every open one's: " + listed); + REQUIRE(listed.find("the bench's") != std::string::npos); + REQUIRE(listed.find("the door's") != std::string::npos); + } pane->showObject(house); LLSD state; pane->saveState(state); - ensure_equals("one object's is not kept", state["problem_scope"].asString(), std::string("all")); + UNSCOPED_INFO("one object's is not kept"); + CHECK(state["problem_scope"].asString() == std::string("all")); } - template <> - template <> - void alscriptproblemspane_object::test<14>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: only LSL leftovers in a ported script are listed and counted as from LSL", "[ALScriptProblemsPane]") { - set_test_name("what a script moved from LSL is left with -- a converter's note, an LSL habit's lint, a call to llcompat -- listed as " - "from LSL, counted, and the origin that lists them alone; not a performance lint, nor ll's own deprecation"); make(); Doc& d = doc("door"); d.language.lua = true; @@ -856,23 +1005,27 @@ namespace tut { if (row.migration) { - ensure_equals("said to be from LSL", row.origin, services.words("OriginMigration")); + UNSCOPED_INFO("said to be from LSL"); + REQUIRE(row.origin == services.words("OriginMigration")); from_lsl += row.message.substr(0, 4) + ";"; } } - ensure_equals("the three", from_lsl, std::string("a no;a nu;llco;")); + UNSCOPED_INFO("the three"); + CHECK(from_lsl == std::string("a no;a nu;llco;")); d.setShown(made.rows); - ensure_equals("counted", d.shownMigration, 3); + UNSCOPED_INFO("counted"); + CHECK(d.shownMigration == 3); pane->showOrigin("OriginMigration"); LLComboBox* origins = window.find("problems_origin"); - ensure("listed alone", origins && origins->getValue().asString() == services.words("OriginMigration")); + { + INFO("listed alone"); + REQUIRE(origins); + CHECK(origins->getValue().asString() == services.words("OriginMigration")); + } } - template <> - template <> - void alscriptproblemspane_object::test<15>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: only an LSL leftover's menu offers and makes the from-LSL fix", "[ALScriptProblemsPane]") { - set_test_name("the menu of a problem left from LSL offers what is left from LSL fixed, and makes it; another problem's does not"); ALScriptProblemsPane& out = make(); Doc& d = doc("door"); d.language.lua = true; @@ -886,53 +1039,75 @@ namespace tut gather(d); out.fill(&d); choose("shadowed [LocalShadow]"); - ensure("not of another", !out.fixShown("migration")); + UNSCOPED_INFO("not of another"); + CHECK_FALSE(out.fixShown("migration")); choose("reads nothing at 0 [SlZeroIndex]"); - ensure("offered", out.fixShown("migration")); + UNSCOPED_INFO("offered"); + CHECK(out.fixShown("migration")); out.act("fix_migration"); - ensure("asked", !studio.kinds.empty() && studio.kinds.back() == "door:from LSL"); + { + INFO("asked"); + REQUIRE_FALSE(studio.kinds.empty()); + CHECK(studio.kinds.back() == "door:from LSL"); + } } - template <> - template <> - void alscriptproblemspane_object::test<16>() + TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: a problem naming no line is listed and chosen at none and marked nowhere", "[ALScriptProblemsPane]") { - set_test_name("what names no line -- a compiler's line of no form it has, a run-time error of no place -- is listed at none, marked " - "nowhere, and chosen at none, and gone to as the first error only where no error names a line; one that names a line, at it"); ALScriptProblemsPane& out = make(); Doc& d = doc("door"); d.problems.push_back({ -1, 0, false, std::string(), "ERROR", "the compiler's, nowhere" }); d.problems.push_back({ 3, 0, false, std::string(), "WARN", "the compiler's, at 3" }); d.runtime.push_back({ -1, -1, std::string(), "Stack-Heap Collision", 1 }); const ALScriptProblemsPane::Made made = gather(d); - ensure_equals("all three", made.rows.size(), size_t(3)); - ensure("at none, first", made.rows[0].line == -1 && made.rows[1].line == -1 && made.rows[2].line == 3); - ensure("a warning said WARN", made.rows[2].level == Doc::Level::Warning); - ensure("marked at its line alone", made.marks.size() == 1 && made.marks[0].first == 3); - ensure("waved at its line alone", made.decorations.size() == 1 && made.decorations[0].range.begin.line == 3); + UNSCOPED_INFO("all three"); + REQUIRE(made.rows.size() == size_t(3)); + { + INFO("at none, first"); + CHECK(made.rows[0].line == -1); + CHECK(made.rows[1].line == -1); + CHECK(made.rows[2].line == 3); + } + UNSCOPED_INFO("a warning said WARN"); + CHECK(made.rows[2].level == Doc::Level::Warning); + { + INFO("marked at its line alone"); + REQUIRE(made.marks.size() == 1); + CHECK(made.marks[0].first == 3); + } + { + INFO("waved at its line alone"); + REQUIRE(made.decorations.size() == 1); + CHECK(made.decorations[0].range.begin.line == 3); + } out.fill(&d); list()->updateSort(); for (const LLScrollListItem* item : list()->getAllData()) { const std::string message = item->getColumn(1)->getValue().asString(); const std::string where = item->getColumn(3)->getValue().asString(); - ensure("where: " + message + " " + where, message == "the compiler's, at 3" ? where == "4" : where.empty()); + UNSCOPED_INFO("where: " + message + " " + where); + REQUIRE((message == "the compiler's, at 3" ? where == "4" : where.empty())); } choose("the compiler's, nowhere"); out.choose(false); - ensure_equals("chosen at none", studio.chosen.back().line, -1); + UNSCOPED_INFO("chosen at none"); + CHECK(studio.chosen.back().line == -1); choose("the compiler's, at 3"); out.choose(false); - ensure_equals("chosen at its line", studio.chosen.back().line, 3); + UNSCOPED_INFO("chosen at its line"); + CHECK(studio.chosen.back().line == 3); // The first error gone to: one at none, listed first, only where no // error names a line. out.selectFirstError(false); - ensure_equals("one at none, where no error is at a line", studio.chosen.back().line, -1); + UNSCOPED_INFO("one at none, where no error is at a line"); + CHECK(studio.chosen.back().line == -1); d.problems.push_back({ 5, 0, false, std::string(), "ERROR", "the compiler's, at 5" }); gather(d); out.fill(&d); out.selectFirstError(false); - ensure_equals("one at a line, past those at none", studio.chosen.back().line, 5); + UNSCOPED_INFO("one at a line, past those at none"); + CHECK(studio.chosen.back().line == 5); } } diff --git a/indra/newview/tests/alscriptrecompile_test.cpp b/indra/newview/tests/alscriptrecompile_test.cpp index b2e39c738d..935afcbbac 100644 --- a/indra/newview/tests/alscriptrecompile_test.cpp +++ b/indra/newview/tests/alscriptrecompile_test.cpp @@ -33,7 +33,7 @@ #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include #include #include @@ -122,7 +122,7 @@ namespace } } -namespace tut +namespace { struct alscriptrecompile_data { @@ -148,76 +148,119 @@ namespace tut [&](const auto& one) { return one.text.find(word) == 0 && one.failure == failure; }); } }; - typedef test_group alscriptrecompile_group; - typedef alscriptrecompile_group::object alscriptrecompile_object; - alscriptrecompile_group alscriptrecompile_instance("alscriptrecompile"); - template<> template<> - void alscriptrecompile_object::test<1>() + TEST_CASE_METHOD(alscriptrecompile_data, "alscriptrecompile: a prim's scripts and one chosen go up a few at a time each once", "[alscriptrecompile]") { - set_test_name("a prim's scripts and a script chosen go up a few at a time, each once, for the target; SLua as SLua; what is known of running given"); house(); window.runs = { { id(11), false } }; run.recompile({ one(10, "A") }, { { prim, "House" } }, "mono"); - ensure("listed", window.listedFor.size() == 1 && window.listedFor[0].front().first == prim); - ensure("running", run.running()); - ensure_equals("four at once", window.asked.size(), size_t(Recompile::AT_ONCE)); - ensure("A once, chosen and in its prim", window.asked[0].ref.item == id(10) && window.asked[1].ref.item == id(11)); - ensure_equals("for the target", window.asked[0].target, std::string("mono")); - ensure_equals("the SLua one as it compiles", window.asked[2].target, std::string("auto")); - ensure("B known stopped, stays so", window.asked[1].running == false); - ensure("A not known: the save asks", !window.asked[0].running.has_value()); + { + INFO("listed"); + REQUIRE(window.listedFor.size() == 1); + CHECK(window.listedFor[0].front().first == prim); + } + UNSCOPED_INFO("running"); + CHECK(run.running()); + UNSCOPED_INFO("four at once"); + REQUIRE(window.asked.size() == size_t(Recompile::AT_ONCE)); + { + INFO("A once, chosen and in its prim"); + CHECK(window.asked[0].ref.item == id(10)); + CHECK(window.asked[1].ref.item == id(11)); + } + UNSCOPED_INFO("for the target"); + CHECK(window.asked[0].target == std::string("mono")); + UNSCOPED_INFO("the SLua one as it compiles"); + CHECK(window.asked[2].target == std::string("auto")); + UNSCOPED_INFO("B known stopped, stays so"); + CHECK(window.asked[1].running == false); + UNSCOPED_INFO("A not known: the save asks"); + REQUIRE_FALSE(window.asked[0].running.has_value()); for (size_t i = 0; i < 4; ++i) { window.asked[i].told(compiled()); } - ensure_equals("the rest begun", window.asked.size(), size_t(6)); + UNSCOPED_INFO("the rest begun"); + REQUIRE(window.asked.size() == size_t(6)); window.asked[4].told(compiled()); - ensure("not done yet", window.done.empty()); + UNSCOPED_INFO("not done yet"); + REQUIRE(window.done.empty()); window.asked[5].told(compiled()); - ensure_equals("done once", window.done.size(), size_t(1)); - ensure("all compiled", window.done[0].compiled == 6 && window.done[0].failed == 0 && window.done[0].target == "mono"); - ensure("no longer running", !run.running()); - ensure_equals("each said", window.scripts.size(), size_t(6)); + UNSCOPED_INFO("done once"); + REQUIRE(window.done.size() == size_t(1)); + { + INFO("all compiled"); + CHECK(window.done[0].compiled == 6); + CHECK(window.done[0].failed == 0); + CHECK(window.done[0].target == "mono"); + } + UNSCOPED_INFO("no longer running"); + CHECK_FALSE(run.running()); + UNSCOPED_INFO("each said"); + REQUIRE(window.scripts.size() == size_t(6)); } - template<> template<> - void alscriptrecompile_object::test<2>() + TEST_CASE_METHOD(alscriptrecompile_data, "alscriptrecompile: a script being saved is skipped and each result is said in Output", "[alscriptrecompile]") { - set_test_name("a save on its way is left alone and said, changes not saved are said, and each result said in Output with a closed one's rows"); house(); window.sending = { id(11) }; window.changed = { id(12) }; window.open = { id(14) }; run.recompile({}, { { prim, "House" } }, "auto"); - ensure("B left alone", std::none_of(window.asked.begin(), window.asked.end(), [](const auto& a) { return a.ref.item == id(11); })); - ensure("and said", said("RecompileSkippedSaving", true)); - ensure("C's unsaved changes said", said("RecompileUnsaved", true)); - ensure_equals("four begun past B", window.asked.size(), size_t(4)); + UNSCOPED_INFO("B left alone"); + CHECK(std::none_of(window.asked.begin(), window.asked.end(), [](const auto& a) { return a.ref.item == id(11); })); + UNSCOPED_INFO("and said"); + CHECK(said("RecompileSkippedSaving", true)); + UNSCOPED_INFO("C's unsaved changes said"); + CHECK(said("RecompileUnsaved", true)); + UNSCOPED_INFO("four begun past B"); + REQUIRE(window.asked.size() == size_t(4)); window.asked[0].told(compiled()); // A window.asked[1].told(failed(2, "syntax error")); // C window.asked[2].told(notSent("no such object")); // D window.asked[3].told(failed(0, "wrong")); // E, open - ensure("the last begun", window.asked.size() == 5 && window.asked[4].ref.item == id(15)); + { + INFO("the last begun"); + REQUIRE(window.asked.size() == 5); + CHECK(window.asked[4].ref.item == id(15)); + } window.asked[4].told(compiled()); // F - ensure("compiled said", said("Compiled", false)); - ensure("a failure said", said("CompileFailed", true)); - ensure("one not sent said with why", said("SaveFailed", true)); + UNSCOPED_INFO("compiled said"); + CHECK(said("Compiled", false)); + UNSCOPED_INFO("a failure said"); + CHECK(said("CompileFailed", true)); + UNSCOPED_INFO("one not sent said with why"); + CHECK(said("SaveFailed", true)); const Recompile::Script& c = window.scripts[1]; - ensure("C's rows, by the compiler", c.one.name == "C" && c.rows.size() == 1 && c.rows[0].line == 2 && c.rows[0].level == ALScriptStudioDoc::Level::Error); - ensure("E is open: its tab says it", window.scripts[3].open && window.scripts[3].rows.empty()); - ensure("D's why", window.scripts[2].error == "no such object"); + { + INFO("C's rows, by the compiler"); + CHECK(c.one.name == "C"); + REQUIRE(c.rows.size() == 1); + CHECK(c.rows[0].line == 2); + CHECK(c.rows[0].level == ALScriptStudioDoc::Level::Error); + } + { + INFO("E is open: its tab says it"); + CHECK(window.scripts[3].open); + REQUIRE(window.scripts[3].rows.empty()); + } + UNSCOPED_INFO("D's why"); + CHECK(window.scripts[2].error == "no such object"); const Recompile::Done& done = window.done.at(0); - ensure("counted", done.compiled == 2 && done.failed == 2 && done.notSent == 1 && done.skipped == 1); + { + INFO("counted"); + CHECK(done.compiled == 2); + CHECK(done.failed == 2); + CHECK(done.notSent == 1); + CHECK(done.skipped == 1); + } } - template<> template<> - void alscriptrecompile_object::test<3>() + TEST_CASE_METHOD(alscriptrecompile_data, "alscriptrecompile: rowsOf reads a compiler's lines back to the source and its includes", "[alscriptrecompile]") { - set_test_name("what the compiler said is read back through the expansion that went up, under the envelope's lines, to the source and its includes"); ALPreprocessor::Options options; options.fileName = "main.lsl"; options.resolve = [](const ALPreprocessor::Ask& ask, ALPreprocessor::Include& out) { @@ -226,7 +269,8 @@ namespace tut return ALPreprocessor::Found::Yes; }; const ALPreprocessor::Result expanded = ALPreprocessor::run("#include \"lib.lsl\"\ndefault\n{\nstate_entry() { x; }\n}\n", options); - ensure("expanded", expanded.problems.empty()); + UNSCOPED_INFO("expanded"); + REQUIRE(expanded.problems.empty()); // The lines of the expansion that hold each. S32 entry = -1, second = -1, line = 0; for (size_t at = 0, next; at < expanded.text.size(); at = next + 1, ++line) @@ -240,7 +284,11 @@ namespace tut break; } } - ensure("found in the expansion", entry >= 0 && second >= 0); + { + INFO("found in the expansion"); + CHECK(entry >= 0); + CHECK(second >= 0); + } Result result = failed(entry + 7, "undefined x"); result.codeLine = 7; @@ -248,41 +296,70 @@ namespace tut result.diagnostics.push_back(failed(second + 7, "b again").diagnostics[0]); result.diagnostics.push_back(failed(5000, "somewhere made").diagnostics[0]); const std::vector rows = Recompile::rowsOf(result, "Compiler", "made"); - ensure_equals("three", rows.size(), size_t(3)); - ensure("the script's own line", rows[0].line == 3 && rows[0].file.empty() && rows[0].origin == "Compiler"); - ensure("the include's, by its name", rows[1].line == 1 && rows[1].fileName == "lib.lsl"); - ensure("none: made by the preprocessor", rows[2].file == ALScriptStudioDoc::GENERATED && rows[2].fileName == "made"); + UNSCOPED_INFO("three"); + REQUIRE(rows.size() == size_t(3)); + { + INFO("the script's own line"); + CHECK(rows[0].line == 3); + REQUIRE(rows[0].file.empty()); + CHECK(rows[0].origin == "Compiler"); + } + { + INFO("the include's, by its name"); + CHECK(rows[1].line == 1); + CHECK(rows[1].fileName == "lib.lsl"); + } + { + INFO("none: made by the preprocessor"); + CHECK(rows[2].file == ALScriptStudioDoc::GENERATED); + CHECK(rows[2].fileName == "made"); + } // Nothing expanded: as the compiler said it. const std::vector plain = Recompile::rowsOf(failed(4, "as is"), "Compiler", "made"); - ensure("as said", plain.size() == 1 && plain[0].line == 4 && plain[0].file.empty()); + { + INFO("as said"); + REQUIRE(plain.size() == 1); + CHECK(plain[0].line == 4); + REQUIRE(plain[0].file.empty()); + } } - template<> template<> - void alscriptrecompile_object::test<4>() + TEST_CASE_METHOD(alscriptrecompile_data, "alscriptrecompile: a recompile begun again drops the last and an empty one is done at once", "[alscriptrecompile]") { - set_test_name("a recompile begun again lets the last go; one with nothing to do is done at once"); house(); run.recompile({}, { { prim, "House" } }, "auto"); const size_t first = window.asked.size(); window.listing.scripts.resize(1); run.recompile({}, { { prim, "House" } }, "lsl2"); - ensure_equals("the new one begun", window.asked.size(), first + 1); + UNSCOPED_INFO("the new one begun"); + REQUIRE(window.asked.size() == first + 1); window.asked[0].told(compiled()); - ensure("the old one's answer passed over", window.scripts.empty() && window.done.empty()); + { + INFO("the old one's answer passed over"); + REQUIRE(window.scripts.empty()); + REQUIRE(window.done.empty()); + } window.asked[first].told(compiled()); - ensure("the new one done", window.done.size() == 1 && window.done[0].target == "lsl2" && window.done[0].compiled == 1); + { + INFO("the new one done"); + REQUIRE(window.done.size() == 1); + CHECK(window.done[0].target == "lsl2"); + CHECK(window.done[0].compiled == 1); + } window.listing.scripts.clear(); run.recompile({}, {}, "auto"); - ensure("nothing: done at once", window.done.size() == 2 && window.done[1].compiled == 0 && !run.running()); + { + INFO("nothing: done at once"); + REQUIRE(window.done.size() == 2); + CHECK(window.done[1].compiled == 0); + CHECK_FALSE(run.running()); + } } - template<> template<> - void alscriptrecompile_object::test<5>() + TEST_CASE_METHOD(alscriptrecompile_data, "alscriptrecompile: places named in a compiler's message are read back as its line is", "[alscriptrecompile]") { - set_test_name("the places a compiler's words name are read back as its line is, the script's own or an include's by name; one " - "that names no line is at none"); ALPreprocessor::Options options; options.fileName = "main.lsl"; options.resolve = [](const ALPreprocessor::Ask& ask, ALPreprocessor::Include& out) { @@ -291,7 +368,8 @@ namespace tut return ALPreprocessor::Found::Yes; }; const ALPreprocessor::Result expanded = ALPreprocessor::run("#include \"lib.lsl\"\ndefault\n{\nstate_entry() { x; }\n}\n", options); - ensure("expanded", expanded.problems.empty()); + UNSCOPED_INFO("expanded"); + REQUIRE(expanded.problems.empty()); S32 entry = -1, second = -1, line = 0; for (size_t at = 0, next; at < expanded.text.size(); at = next + 1, ++line) { @@ -304,7 +382,11 @@ namespace tut break; } } - ensure("found in the expansion", entry >= 0 && second >= 0); + { + INFO("found in the expansion"); + CHECK(entry >= 0); + CHECK(second >= 0); + } // As Tailslide says it, one-based, under the envelope's seven lines. LLSD said; @@ -326,15 +408,33 @@ namespace tut result.diagnostics.push_back(one); } const std::vector rows = Recompile::rowsOf(result, "Compiler", "made"); - ensure_equals("three", rows.size(), size_t(3)); - ensure("the line, the source's", rows[0].line == 3 && rows[0].level == ALScriptStudioDoc::Level::Warning); - ensure_equals("the place named, the source's", rows[0].message, std::string("x shadows previous declaration at (4, 1)")); - ensure_equals("an include's, by its name; one made, as said", rows[1].message, + UNSCOPED_INFO("three"); + REQUIRE(rows.size() == size_t(3)); + { + INFO("the line, the source's"); + CHECK(rows[0].line == 3); + CHECK(rows[0].level == ALScriptStudioDoc::Level::Warning); + } + UNSCOPED_INFO("the place named, the source's"); + CHECK(rows[0].message == std::string("x shadows previous declaration at (4, 1)")); + UNSCOPED_INFO("an include's, by its name; one made, as said"); + CHECK(rows[1].message == std::string("b previously declared at (2, 9) in lib.lsl. Again at (5000, 1).")); - ensure("no line named, none", rows[2].line == -1 && rows[2].file.empty() && rows[2].message == "Math Error"); + { + INFO("no line named, none"); + CHECK(rows[2].line == -1); + REQUIRE(rows[2].file.empty()); + CHECK(rows[2].message == "Math Error"); + } // A tab's, the same. const std::vector tab = ALScriptStudioDoc::compiledOf(result.diagnostics, result.sourceMap.get(), 7); - ensure("a tab's", tab.size() == 3 && tab[0].line == 3 && tab[0].message == rows[0].message && tab[2].line == -1); + { + INFO("a tab's"); + REQUIRE(tab.size() == 3); + CHECK(tab[0].line == 3); + CHECK(tab[0].message == rows[0].message); + CHECK(tab[2].line == -1); + } } } diff --git a/indra/newview/tests/alscriptreferencespane_test.cpp b/indra/newview/tests/alscriptreferencespane_test.cpp index db9f569b9b..638bbae231 100644 --- a/indra/newview/tests/alscriptreferencespane_test.cpp +++ b/indra/newview/tests/alscriptreferencespane_test.cpp @@ -35,7 +35,7 @@ #include "llscrolllistitem.h" #include "lltextbox.h" -#include "../test/lltut.h" +#include namespace { @@ -90,7 +90,7 @@ namespace } } -namespace tut +namespace { struct alscriptreferencespane_data { @@ -103,7 +103,7 @@ namespace tut ALScriptReferencesPane* found = window.find("references_tab"); if (!found) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } // In sight, its tab the one chosen, as when it is worked in. window.find("bottom_tabs")->selectTabByName("references_tab"); @@ -147,43 +147,50 @@ namespace tut } }; - typedef test_group alscriptreferencespane_group; - typedef alscriptreferencespane_group::object alscriptreferencespane_object; - alscriptreferencespane_group alscriptreferencespane_instance("alscriptreferencespane"); - - template<> template<> - void alscriptreferencespane_object::test<1>() + TEST_CASE_METHOD(alscriptreferencespane_data, "alscriptreferencespane: show lists places and marks the declaration and forget clears them", "[alscriptreferencespane]") { - set_test_name("what was found listed under what was looked up, the declaration marked; nothing, with the question it answers"); ALScriptReferencesPane* refs = pane(); refs->show(found()); - ensure_equals("the head", head(), std::string("3 occurrences of count in 2 scripts.")); - ensure("the window told", window.pane().counts == 1); - ensure_equals("each place", lines(), joined(Names{ "A 1:9", "A 2:5", "B 1:9" })); + UNSCOPED_INFO("the head"); + CHECK(head() == std::string("3 occurrences of count in 2 scripts.")); + UNSCOPED_INFO("the window told"); + CHECK(window.pane().counts == 1); + UNSCOPED_INFO("each place"); + CHECK(lines() == joined(Names{ "A 1:9", "A 2:5", "B 1:9" })); const std::vector rows = refs->list()->getAllData(); - ensure_equals("the declaration", cell(rows[0], 2), std::string("declaration")); - ensure_equals("in the script it is declared in only", cell(rows[2], 2), std::string()); - ensure_equals("its text", cell(rows[1], 3), std::string("x = count;")); - ensure_equals("kept", refs->found().places.size(), size_t(3)); + UNSCOPED_INFO("the declaration"); + CHECK(cell(rows[0], 2) == std::string("declaration")); + UNSCOPED_INFO("in the script it is declared in only"); + CHECK(cell(rows[2], 2) == std::string()); + UNSCOPED_INFO("its text"); + CHECK(cell(rows[1], 3) == std::string("x = count;")); + UNSCOPED_INFO("kept"); + REQUIRE(refs->found().places.size() == size_t(3)); Found twice = found(); twice.places.push_back(place("", 0, 20, "integer count; count")); refs->show(twice); - ensure("on the declaration's line, not it", cell(refs->list()->getAllData()[3], 2).empty()); + UNSCOPED_INFO("on the declaration's line, not it"); + REQUIRE(cell(refs->list()->getAllData()[3], 2).empty()); Found in_b = found(); in_b.home = B; refs->show(in_b); - ensure("declared in B: A's first line not it", cell(refs->list()->getAllData()[0], 2).empty()); + UNSCOPED_INFO("declared in B: A's first line not it"); + REQUIRE(cell(refs->list()->getAllData()[0], 2).empty()); refs->forget(); - ensure_equals("nothing", head(), std::string("Nothing to show yet. Put the caret on a name and choose Find References.")); - ensure("no rows", refs->list()->getItemCount() == 0 && refs->found().from.empty()); - ensure("told each time", window.pane().counts == 4); + UNSCOPED_INFO("nothing"); + CHECK(head() == std::string("Nothing to show yet. Put the caret on a name and choose Find References.")); + { + INFO("no rows"); + REQUIRE(refs->list()->getItemCount() == 0); + REQUIRE(refs->found().from.empty()); + } + UNSCOPED_INFO("told each time"); + CHECK(window.pane().counts == 4); } - template<> template<> - void alscriptreferencespane_object::test<2>() + TEST_CASE_METHOD(alscriptreferencespane_data, "alscriptreferencespane: places slide with their script's edits and go where the name is edited", "[alscriptreferencespane]") { - set_test_name("places slid with the edits to what they are in, listed again once the frame is drawn; gone where the name was edited"); ALScriptReferencesPane* refs = pane(); Doc& a = tab("a", "integer count;\nx = count;\n"); Doc& b = tab("b", "foo() { count; }\n"); @@ -200,69 +207,93 @@ namespace tut c.editor->replaceAll({ { ALTextRange(ALTextPos(0, 0), ALTextPos(0, 0)), "// one\n" } }); a.editor->replaceAll({ { ALTextRange(ALTextPos(0, 0), ALTextPos(0, 0)), "// one\n" } }); - ensure_equals("not listed again yet", lines(), joined(Names{ "A 1:9", "A 2:5", "B 1:9" })); + UNSCOPED_INFO("not listed again yet"); + CHECK(lines() == joined(Names{ "A 1:9", "A 2:5", "B 1:9" })); refs->pump(); - ensure_equals("A's slid, B's not", lines(), joined(Names{ "A 2:9", "A 3:5", "B 1:9" })); - ensure("the row chosen kept", refs->list()->getFirstSelected() && refs->list()->getFirstSelected()->getValue().asInteger() == 1); - ensure_equals("the declaration too", refs->found().definition.line, 1); + UNSCOPED_INFO("A's slid, B's not"); + CHECK(lines() == joined(Names{ "A 2:9", "A 3:5", "B 1:9" })); + { + INFO("the row chosen kept"); + REQUIRE(refs->list()->getFirstSelected()); + CHECK(refs->list()->getFirstSelected()->getValue().asInteger() == 1); + } + UNSCOPED_INFO("the declaration too"); + CHECK(refs->found().definition.line == 1); b.editor->replaceAll({ { ALTextRange(ALTextPos(0, 0), ALTextPos(0, 0)), " " } }); refs->pump(); - ensure_equals("B's by its path", lines(), joined(Names{ "A 2:9", "A 3:5", "B 1:11" })); - ensure_equals("its line's words", refs->found().places[2].text, std::string("foo() { count; }")); + UNSCOPED_INFO("B's by its path"); + CHECK(lines() == joined(Names{ "A 2:9", "A 3:5", "B 1:11" })); + UNSCOPED_INFO("its line's words"); + CHECK(refs->found().places[2].text == std::string("foo() { count; }")); a.editor->replaceAll({ { ALTextRange(ALTextPos(1, 8), ALTextPos(1, 13)), "total" } }); refs->pump(); - ensure_equals("the declaration edited: gone", lines(), joined(Names{ "A 3:5", "B 1:11" })); - ensure("not declared any more", !refs->found().hasDefinition); + UNSCOPED_INFO("the declaration edited: gone"); + CHECK(lines() == joined(Names{ "A 3:5", "B 1:11" })); + UNSCOPED_INFO("not declared any more"); + CHECK_FALSE(refs->found().hasDefinition); a.editor->replaceAll({ { ALTextRange(ALTextPos(2, 0), ALTextPos(2, 1)), "yy" } }); refs->pump(); - ensure_equals("a place on the line edited", lines(), joined(Names{ "A 3:6", "B 1:11" })); - ensure_equals("its words again", refs->found().places[0].text, std::string("yy = count;")); + UNSCOPED_INFO("a place on the line edited"); + CHECK(lines() == joined(Names{ "A 3:6", "B 1:11" })); + UNSCOPED_INFO("its words again"); + CHECK(refs->found().places[0].text == std::string("yy = count;")); const S32 counts = window.pane().counts; refs->pump(); - ensure_equals("not listed again for nothing", window.pane().counts, counts); + UNSCOPED_INFO("not listed again for nothing"); + CHECK(window.pane().counts == counts); a.editor->replaceAll({ { ALTextRange(ALTextPos(0, 0), ALTextPos(0, 0)), "\n" } }); a.editor->replaceAll({ { ALTextRange(ALTextPos(4, 0), ALTextPos(4, 0)), "z" } }); refs->pump(); - ensure_equals("moved, not on a line edited; then an edit that moves nothing", lines(), joined(Names{ "A 4:6", "B 1:11" })); + UNSCOPED_INFO("moved, not on a line edited; then an edit that moves nothing"); + CHECK(lines() == joined(Names{ "A 4:6", "B 1:11" })); } - template<> template<> - void alscriptreferencespane_object::test<3>() + TEST_CASE_METHOD(alscriptreferencespane_data, "alscriptreferencespane: choosing a row goes to its place and follows its tab's new id", "[alscriptreferencespane]") { - set_test_name("a row chosen gone to, walked or taken to the editor; the tab it was looked up from followed to its new id"); ALScriptReferencesPane* refs = pane(); refs->show(found()); refs->choose(false); - ensure("nothing chosen, nothing gone to", window.pane().chosen.empty()); + UNSCOPED_INFO("nothing chosen, nothing gone to"); + REQUIRE(window.pane().chosen.empty()); // A row is known by its place's number, counted from one. refs->list()->selectByValue(LLSD(3)); refs->list()->onCommit(); refs->choose(true); - ensure_equals("gone to", joined(window.pane().chosen), joined(Names{ "a|" + B + "|0", "a|" + B + "|0 editor" })); + UNSCOPED_INFO("gone to"); + CHECK(joined(window.pane().chosen) == joined(Names{ "a|" + B + "|0", "a|" + B + "|0 editor" })); refs->rekey("elsewhere", "z"); - ensure_equals("another's id", refs->found().from, std::string("a")); + UNSCOPED_INFO("another's id"); + CHECK(refs->found().from == std::string("a")); refs->rekey("a", "a2"); refs->list()->selectByValue(LLSD(1)); refs->choose(false); - ensure_equals("followed", window.pane().chosen.back(), std::string("a2||0")); + UNSCOPED_INFO("followed"); + CHECK(window.pane().chosen.back() == std::string("a2||0")); // The list's keys: return goes to the place chosen, to type there, // escape back to the script; and the rows copy. - ensure("return", refs->list()->handleKeyHere(KEY_RETURN, MASK_NONE) && window.pane().chosen.back() == "a2||0 editor"); + { + INFO("return"); + CHECK(refs->list()->handleKeyHere(KEY_RETURN, MASK_NONE)); + CHECK(window.pane().chosen.back() == "a2||0 editor"); + } const size_t gone = window.pane().chosen.size(); - ensure("escape", refs->list()->handleKeyHere(KEY_ESCAPE, MASK_NONE) && window.services().reveals.back() - && window.pane().chosen.size() == gone); - ensure("copied", refs->list()->handleKeyHere('C', MASK_CONTROL)); + { + INFO("escape"); + CHECK(refs->list()->handleKeyHere(KEY_ESCAPE, MASK_NONE)); + REQUIRE(window.services().reveals.back()); + REQUIRE(window.pane().chosen.size() == gone); + } + UNSCOPED_INFO("copied"); + CHECK(refs->list()->handleKeyHere('C', MASK_CONTROL)); } - template<> template<> - void alscriptreferencespane_object::test<4>() + TEST_CASE_METHOD(alscriptreferencespane_data, "alscriptreferencespane: rows sort by a column and then by script and place", "[alscriptreferencespane]") { - set_test_name("sorted by a column, then by script and place: by text, by script the other way, the declaration first"); ALScriptReferencesPane* refs = pane(); Found many = found(); many.places.push_back(place("", 2, 0, "count = 0;")); @@ -270,24 +301,26 @@ namespace tut ALPaneList* list = refs->list(); list->sortByColumn("text", true); list->updateSort(); - ensure_equals("by text", lines(), joined(Names{ "A 3:1", "B 1:9", "A 1:9", "A 2:5" })); + UNSCOPED_INFO("by text"); + CHECK(lines() == joined(Names{ "A 3:1", "B 1:9", "A 1:9", "A 2:5" })); list->sortByColumn("where", false); list->updateSort(); - ensure_equals("by script, then place, the other way", lines(), joined(Names{ "B 1:9", "A 3:1", "A 2:5", "A 1:9" })); + UNSCOPED_INFO("by script, then place, the other way"); + CHECK(lines() == joined(Names{ "B 1:9", "A 3:1", "A 2:5", "A 1:9" })); list->sortByColumn("role", true); list->updateSort(); - ensure_equals("the declaration first, then by script", lines(), joined(Names{ "A 1:9", "A 2:5", "A 3:1", "B 1:9" })); + UNSCOPED_INFO("the declaration first, then by script"); + CHECK(lines() == joined(Names{ "A 1:9", "A 2:5", "A 3:1", "B 1:9" })); many.home = B; refs->show(many); list->sortByColumn("role", true); list->updateSort(); - ensure_equals("the declaration first, then by script", lines(), joined(Names{ "B 1:9", "A 1:9", "A 2:5", "A 3:1" })); + UNSCOPED_INFO("the declaration first, then by script"); + CHECK(lines() == joined(Names{ "B 1:9", "A 1:9", "A 2:5", "A 3:1" })); } - template<> template<> - void alscriptreferencespane_object::test<5>() + TEST_CASE_METHOD(alscriptreferencespane_data, "alscriptreferencespane: a row picked before relisting after a place is removed still goes to its place", "[alscriptreferencespane]") { - set_test_name("a row picked between an edit that took a place away and the listing again is still its own place"); ALScriptReferencesPane* refs = pane(); Doc& a = tab("a", "integer count;\nx = count;\n"); refs->show(found()); @@ -295,22 +328,24 @@ namespace tut [refs, &a](const ALTextDocument::Edit& edit) { refs->slide(a, "object:1:a", edit); })); refs->list()->selectFirstItem(); refs->list()->selectNextItem(false); - ensure_equals("A's second chosen", cell(refs->list()->getFirstSelected(), 1), std::string("2:5")); + UNSCOPED_INFO("A's second chosen"); + CHECK(cell(refs->list()->getFirstSelected(), 1) == std::string("2:5")); // The declaration's name edited: the first place goes, not listed // again until the frame is drawn. a.editor->replaceAll({ { ALTextRange(ALTextPos(0, 8), ALTextPos(0, 13)), "total" } }); - ensure_equals("one place fewer", refs->found().places.size(), size_t(2)); + UNSCOPED_INFO("one place fewer"); + REQUIRE(refs->found().places.size() == size_t(2)); window.pane().chosen.clear(); refs->choose(false); - ensure_equals("A's second, not what took its index", joined(window.pane().chosen), std::string("a||1")); + UNSCOPED_INFO("A's second, not what took its index"); + CHECK(joined(window.pane().chosen) == std::string("a||1")); refs->pump(); - ensure_equals("listed again, the row still chosen", cell(refs->list()->getFirstSelected(), 1), std::string("2:5")); + UNSCOPED_INFO("listed again, the row still chosen"); + CHECK(cell(refs->list()->getFirstSelected(), 1) == std::string("2:5")); } - template<> template<> - void alscriptreferencespane_object::test<6>() + TEST_CASE_METHOD(alscriptreferencespane_data, "alscriptreferencespane: a rename preview checks each place and renames only those kept", "[alscriptreferencespane]") { - set_test_name("a rename previewed: a box by each place and its line as renamed, Rename with the places kept, Space and a box leaving one out, Cancel listing them as found"); ALScriptReferencesPane* refs = pane(); std::vector made; bool applied = false; @@ -318,33 +353,61 @@ namespace tut made = kept; applied = true; }); - ensure("previewing", refs->previewing()); - ensure_equals("what it will do over them", head(), std::string("Rename 3 places")); + UNSCOPED_INFO("previewing"); + CHECK(refs->previewing()); + UNSCOPED_INFO("what it will do over them"); + CHECK(head() == std::string("Rename 3 places")); LLButton* rename = window.find("references_rename"); - ensure("its buttons shown", rename && rename->getVisible() && window.find("references_cancel")->getVisible()); + { + INFO("its buttons shown"); + REQUIRE(rename); + CHECK(rename->getVisible()); + CHECK(window.find("references_cancel")->getVisible()); + } const std::vector rows = refs->list()->getAllData(); - ensure("each checked", rows.size() == 3 && std::all_of(rows.begin(), rows.end(), [](const LLScrollListItem* row) { + { + INFO("each checked"); + REQUIRE(rows.size() == 3); + CHECK(std::all_of(rows.begin(), rows.end(), [](const LLScrollListItem* row) { return row->getColumn(2)->getValue().asBoolean(); })); - ensure_equals("the line as it would read", cell(rows[1], 3), std::string("x = total;")); + } + UNSCOPED_INFO("the line as it would read"); + CHECK(cell(rows[1], 3) == std::string("x = total;")); // Left out by Space on the row chosen: its box clear, its line as it is. refs->list()->selectNthItem(1); refs->list()->handleUnicodeCharHere(' '); - ensure("left out", !refs->list()->getAllData()[1]->getColumn(2)->getValue().asBoolean()); - ensure_equals("its line as it is", cell(refs->list()->getAllData()[1], 3), std::string("x = count;")); + UNSCOPED_INFO("left out"); + CHECK_FALSE(refs->list()->getAllData()[1]->getColumn(2)->getValue().asBoolean()); + UNSCOPED_INFO("its line as it is"); + CHECK(cell(refs->list()->getAllData()[1], 3) == std::string("x = count;")); refs->setKept(2, false); refs->setKept(2, true); rename->onCommit(); - ensure("made at the rest, by their order in what was found", applied && made == std::vector({ 0, 2 })); - ensure("done previewing", !refs->previewing() && !rename->getVisible()); - ensure_equals("listed as found again", head().find("total"), std::string::npos); + { + INFO("made at the rest, by their order in what was found"); + CHECK(applied); + CHECK(made == std::vector({ 0, 2 })); + } + { + INFO("done previewing"); + CHECK_FALSE(refs->previewing()); + CHECK_FALSE(rename->getVisible()); + } + UNSCOPED_INFO("listed as found again"); + CHECK(head().find("total") == std::string::npos); applied = false; refs->preview(found(), "total", "Rename 3 places", [&](const std::vector&) { applied = true; }); - ensure("no Show Changes where none is given", !window.find("references_changes")->getVisible()); + UNSCOPED_INFO("no Show Changes where none is given"); + CHECK_FALSE(window.find("references_changes")->getVisible()); window.find("references_cancel")->onCommit(); - ensure("Cancel makes nothing", !applied && !refs->previewing()); + { + INFO("Cancel makes nothing"); + CHECK_FALSE(applied); + CHECK_FALSE(refs->previewing()); + } // Show Changes: the chosen row's file, or the script's own with // none chosen, and the places kept. @@ -356,23 +419,32 @@ namespace tut shown = kept; }); LLButton* changes = window.find("references_changes"); - ensure("Show Changes shown", changes && changes->getVisible()); + { + INFO("Show Changes shown"); + REQUIRE(changes); + CHECK(changes->getVisible()); + } changes->onCommit(); refs->list()->selectNthItem(2); refs->setKept(1, false); refs->list()->selectNthItem(2); changes->onCommit(); - ensure("its own, then the chosen row's", files == std::vector({ std::string(), B })); - ensure("with the places kept", shown == std::vector({ 0, 2 })); + UNSCOPED_INFO("its own, then the chosen row's"); + CHECK(files == std::vector({ std::string(), B })); + UNSCOPED_INFO("with the places kept"); + CHECK(shown == std::vector({ 0, 2 })); window.find("references_cancel")->onCommit(); - ensure("gone with the preview", !changes->getVisible()); - ensure("each row as found", cell(refs->list()->getAllData()[0], 3) == "integer count;" && refs->list()->getAllData()[0]->getColumn(2)->getValue().asString() != "1"); + UNSCOPED_INFO("gone with the preview"); + CHECK_FALSE(changes->getVisible()); + { + INFO("each row as found"); + REQUIRE(cell(refs->list()->getAllData()[0], 3) == "integer count;"); + CHECK(refs->list()->getAllData()[0]->getColumn(2)->getValue().asString() != "1"); + } } - template<> template<> - void alscriptreferencespane_object::test<7>() + TEST_CASE_METHOD(alscriptreferencespane_data, "alscriptreferencespane: places slid out of sight are listed again once the list is seen", "[alscriptreferencespane]") { - set_test_name("places slid out of sight are listed again once the list is seen, not before"); ALScriptReferencesPane* refs = pane(); Doc& a = tab("a", "integer count;\nx = count;\n"); tab("b", "foo() { count; }\n"); @@ -383,17 +455,18 @@ namespace tut tabs->selectTabByName("problems_tab"); a.editor->replaceAll({ { ALTextRange(ALTextPos(0, 0), ALTextPos(0, 0)), "// one\n" } }); refs->pump(); - ensure_equals("slid, not listed again unseen", lines(), joined(Names{ "A 1:9", "A 2:5", "B 1:9" })); - ensure_equals("the places themselves slid", refs->found().places[0].span.line, 1); + UNSCOPED_INFO("slid, not listed again unseen"); + CHECK(lines() == joined(Names{ "A 1:9", "A 2:5", "B 1:9" })); + UNSCOPED_INFO("the places themselves slid"); + CHECK(refs->found().places[0].span.line == 1); tabs->selectTabByName("references_tab"); refs->pump(); - ensure_equals("seen: listed again", lines(), joined(Names{ "A 2:9", "A 3:5", "B 1:9" })); + UNSCOPED_INFO("seen: listed again"); + CHECK(lines() == joined(Names{ "A 2:9", "A 3:5", "B 1:9" })); } - template<> template<> - void alscriptreferencespane_object::test<8>() + TEST_CASE_METHOD(alscriptreferencespane_data, "alscriptreferencespane: a slid place keeps its row and at most a thousand places are listed", "[alscriptreferencespane]") { - set_test_name("a place slid is the same row, made again where it says something else; a thousand places listed at most, the rest counted"); ALScriptReferencesPane* refs = pane(); Doc& a = tab("a", "integer count;\nx = count;\n"); tab("b", "foo() { count; }\n"); @@ -406,10 +479,17 @@ namespace tut refs->list()->selectByValue(LLSD(2)); a.editor->replaceAll({ { ALTextRange(ALTextPos(0, 0), ALTextPos(0, 0)), "// one\n" } }); refs->pump(); - ensure_equals("slid", lines(), joined(Names{ "A 2:9", "A 3:5", "B 1:9" })); - ensure("the same rows", refs->list()->rowWithKey("2") == second && refs->list()->rowWithKey("3") == in_b); - ensure("one not moved, its cells as they were", in_b->getColumn(1) == b_line); - ensure("the row chosen kept", refs->list()->getFirstSelected() == second); + UNSCOPED_INFO("slid"); + CHECK(lines() == joined(Names{ "A 2:9", "A 3:5", "B 1:9" })); + { + INFO("the same rows"); + REQUIRE(refs->list()->rowWithKey("2") == second); + CHECK(refs->list()->rowWithKey("3") == in_b); + } + UNSCOPED_INFO("one not moved, its cells as they were"); + CHECK(in_b->getColumn(1) == b_line); + UNSCOPED_INFO("the row chosen kept"); + CHECK(refs->list()->getFirstSelected() == second); Found many; many.from = "a"; @@ -420,8 +500,11 @@ namespace tut many.places.push_back(place("", i, 0, "count;")); } refs->show(many); - ensure_equals("a thousand and one row saying the rest", refs->list()->getItemCount(), 1001); - ensure_equals("the rest", cell(refs->list()->getAllData().back(), 3), window.services().counted("ReferencesUnlisted", 3)); - ensure("all of them counted over the list", head().find("1003") != std::string::npos); + UNSCOPED_INFO("a thousand and one row saying the rest"); + CHECK(refs->list()->getItemCount() == 1001); + UNSCOPED_INFO("the rest"); + CHECK(cell(refs->list()->getAllData().back(), 3) == window.services().counted("ReferencesUnlisted", 3)); + UNSCOPED_INFO("all of them counted over the list"); + REQUIRE(head().find("1003") != std::string::npos); } } diff --git a/indra/newview/tests/alscriptregionusage_test.cpp b/indra/newview/tests/alscriptregionusage_test.cpp index cab391ef1e..30e38450eb 100644 --- a/indra/newview/tests/alscriptregionusage_test.cpp +++ b/indra/newview/tests/alscriptregionusage_test.cpp @@ -26,12 +26,12 @@ #include "../alscriptregionusage.h" -#include "../test/lltut.h" +#include #include #include -namespace tut +namespace { struct alscriptregionusage_data { @@ -97,14 +97,8 @@ namespace tut } }; - typedef test_group alscriptregionusage_group; - typedef alscriptregionusage_group::object alscriptregionusage_object; - tut::alscriptregionusage_group alscriptregionusage_test("ALScriptRegionUsage"); - - template<> template<> - void alscriptregionusage_object::test<1>() + TEST_CASE_METHOD(alscriptregionusage_data, "ALScriptRegionUsage: readAttachments and readDetails read each listed object's memory and URLs", "[ALScriptRegionUsage]") { - set_test_name("each object an answer lists, by id, with its memory and URLs: the attachments' by point, a parcel's details by parcel"); LLSD attachments; attachments["attachments"][0]["location"] = "Chest"; attachments["attachments"][0]["objects"].append(object(id(1), 65536, 1)); @@ -115,9 +109,19 @@ namespace tut const LLDate when(1.8e9); Usage::usages_t read; Usage::readAttachments(attachments, when, read); - ensure_equals("both", read.size(), 2U); - ensure("the chest's", read[id(1)].memory == 65536 && read[id(1)].urls == 1 && read[id(1)].when == when); - ensure("the HUD's", read[id(2)].memory == 131072 && read[id(2)].urls == 0); + UNSCOPED_INFO("both"); + REQUIRE(read.size() == 2U); + { + INFO("the chest's"); + CHECK(read[id(1)].memory == 65536); + CHECK(read[id(1)].urls == 1); + CHECK(read[id(1)].when == when); + } + { + INFO("the HUD's"); + CHECK(read[id(2)].memory == 131072); + CHECK(read[id(2)].urls == 0); + } LLSD details; details["parcels"][0]["name"] = "Home"; @@ -126,64 +130,92 @@ namespace tut details["parcels"][0]["objects"].append(object(LLUUID::null, 1, 1)); read.clear(); Usage::readDetails(details, when, read); - ensure("a parcel's, one without an id passed over", read.size() == 1 && read[id(3)].memory == 16384); + { + INFO("a parcel's, one without an id passed over"); + REQUIRE(read.size() == 1); + CHECK(read[id(3)].memory == 16384); + } read.clear(); Usage::readDetails(LLSD(), when, read); Usage::readAttachments(LLSD("nonsense"), when, read); - ensure("nothing from nothing", read.empty()); + UNSCOPED_INFO("nothing from nothing"); + REQUIRE(read.empty()); } - template<> template<> - void alscriptregionusage_object::test<2>() + TEST_CASE_METHOD(alscriptregionusage_data, "ALScriptRegionUsage: ask asks once for all attachments and once per object on land", "[ALScriptRegionUsage]") { - set_test_name("asked: the attachments once for all of them, each object on land by itself, none out of sight; heard and kept"); kinds[id(1)] = Kind::Attachment; kinds[id(2)] = Kind::Attachment; kinds[id(3)] = Kind::Land; kinds[id(4)] = Kind::Land; usage.ask({ id(1), id(2), id(3), id(4), id(5) }, 100.0); - ensure_equals("one asking for the attachments", attachmentAsks.size(), 1U); - ensure("each on land", landAsks.size() == 2 && landAsks[0].first == id(3) && landAsks[1].first == id(4)); - ensure("nothing known yet", !usage.usageOf(id(1)) && heard == 0); + UNSCOPED_INFO("one asking for the attachments"); + REQUIRE(attachmentAsks.size() == 1U); + { + INFO("each on land"); + REQUIRE(landAsks.size() == 2); + CHECK(landAsks[0].first == id(3)); + CHECK(landAsks[1].first == id(4)); + } + { + INFO("nothing known yet"); + REQUIRE_FALSE(usage.usageOf(id(1))); + CHECK(heard == 0); + } LLSD answer; answer["attachments"][0]["objects"].append(object(id(1), 65536, 2)); answer["attachments"][0]["objects"].append(object(id(2), 16384, 0)); attachmentAsks[0](answer); - ensure("heard", heard == 1 && usage.usageOf(id(1)) && usage.usageOf(id(1))->urls == 2 && usage.usageOf(id(2))->memory == 16384); + { + INFO("heard"); + CHECK(heard == 1); + REQUIRE(usage.usageOf(id(1))); + REQUIRE(usage.usageOf(id(1))->urls == 2); + CHECK(usage.usageOf(id(2))->memory == 16384); + } LLSD parcel; parcel["parcels"][0]["objects"].append(object(id(3), 131072, 0)); parcel["parcels"][0]["objects"].append(object(id(4), 65536, 0)); landAsks[0].second(parcel); - ensure("a parcel's answer is every object on it", heard == 2 && usage.usageOf(id(4)) && usage.usageOf(id(4))->memory == 65536); + { + INFO("a parcel's answer is every object on it"); + CHECK(heard == 2); + REQUIRE(usage.usageOf(id(4))); + CHECK(usage.usageOf(id(4))->memory == 65536); + } } - template<> template<> - void alscriptregionusage_object::test<3>() + TEST_CASE_METHOD(alscriptregionusage_data, "ALScriptRegionUsage: an object is asked about at most once a minute counted from the answer", "[ALScriptRegionUsage]") { - set_test_name("once a minute: an object asked again only after, one another answer named counted as asked, and none after it is gone"); kinds[id(3)] = Kind::Land; kinds[id(4)] = Kind::Land; usage.ask({ id(3) }, 100.0); - ensure_equals("asked", landAsks.size(), 1U); + UNSCOPED_INFO("asked"); + REQUIRE(landAsks.size() == 1U); usage.ask({ id(3) }, 130.0); - ensure_equals("not again within the minute", landAsks.size(), 1U); + UNSCOPED_INFO("not again within the minute"); + REQUIRE(landAsks.size() == 1U); LLSD parcel; parcel["parcels"][0]["objects"].append(object(id(3), 1, 0)); parcel["parcels"][0]["objects"].append(object(id(4), 2, 0)); landAsks[0].second(parcel); usage.ask({ id(4) }, 140.0); - ensure_equals("one the answer named is answered already", landAsks.size(), 1U); + UNSCOPED_INFO("one the answer named is answered already"); + REQUIRE(landAsks.size() == 1U); usage.ask({ id(3), id(4) }, 161.0); - ensure_equals("a minute from the answer, not the asking", landAsks.size(), 1U); + UNSCOPED_INFO("a minute from the answer, not the asking"); + REQUIRE(landAsks.size() == 1U); usage.ask({ id(3), id(4) }, 191.0); - ensure_equals("after the minute, each again", landAsks.size(), 3U); + UNSCOPED_INFO("after the minute, each again"); + REQUIRE(landAsks.size() == 3U); kinds[id(1)] = Kind::Attachment; kinds[id(2)] = Kind::Attachment; usage.ask({ id(1) }, 200.0); usage.ask({ id(2) }, 210.0); - ensure_equals("the attachments once a minute, whichever asks", attachmentAsks.size(), 1U); + UNSCOPED_INFO("the attachments once a minute, whichever asks"); + REQUIRE(attachmentAsks.size() == 1U); // An answer after it is gone goes nowhere. Told late = landAsks.back().second; @@ -197,13 +229,12 @@ namespace tut other.reset(); orphaned(parcel); late(parcel); - ensure("the one still here heard", usage.usageOf(id(3)) != nullptr); + UNSCOPED_INFO("the one still here heard"); + REQUIRE(usage.usageOf(id(3)) != nullptr); } - template<> template<> - void alscriptregionusage_object::test<4>() + TEST_CASE_METHOD(alscriptregionusage_data, "ALScriptRegionUsage: an estate manager asks each owner's script time once a minute", "[ALScriptRegionUsage]") { - set_test_name("time, of an estate manager only: each owner's objects asked for at once, once a minute, an owner unknown not at all; kept with what memory said, and memory kept with it"); kinds[id(1)] = Kind::Land; kinds[id(2)] = Kind::Land; kinds[id(3)] = Kind::Attachment; @@ -212,18 +243,29 @@ namespace tut owners[id(2)] = "Ann Resident"; owners[id(3)] = "Bo Smith"; usage.ask({ id(1), id(2), id(3), id(4) }, 100.0); - ensure("not an estate manager: not asked", timeAsks.empty()); + UNSCOPED_INFO("not an estate manager: not asked"); + REQUIRE(timeAsks.empty()); estateManager = true; attachmentAsks.clear(); landAsks.clear(); usage.ask({ id(1), id(2), id(3), id(4) }, 100.0); - ensure_equals("an asking an owner", timeAsks.size(), 2U); - ensure("each owner once, none for one unknown", timeAsks[0].first == "Ann Resident" && timeAsks[1].first == "Bo Smith"); + UNSCOPED_INFO("an asking an owner"); + REQUIRE(timeAsks.size() == 2U); + { + INFO("each owner once, none for one unknown"); + CHECK(timeAsks[0].first == "Ann Resident"); + CHECK(timeAsks[1].first == "Bo Smith"); + } usage.ask({ id(1) }, 130.0); - ensure("not again within a minute", timeAsks.size() == 2); + UNSCOPED_INFO("not again within a minute"); + REQUIRE(timeAsks.size() == 2); usage.ask({ id(1) }, 161.0); - ensure("again after it", timeAsks.size() == 3 && timeAsks[2].first == "Ann Resident"); + { + INFO("again after it"); + REQUIRE(timeAsks.size() == 3); + CHECK(timeAsks[2].first == "Ann Resident"); + } // Memory first, then time: both kept. LLSD details; @@ -234,13 +276,26 @@ namespace tut times[id(5)] = 2.0f; const S32 before = heard; timeAsks[0].second(times); - ensure("heard", heard == before + 1); + UNSCOPED_INFO("heard"); + CHECK(heard == before + 1); const ALScriptRegionUsage::Usage* one = usage.usageOf(id(1)); - ensure("its time and its memory", one && one->hasTime() && one->time == 0.125f && one->hasMemory() && one->memory == 65536); - ensure("an object not asked about kept too, time alone", usage.usageOf(id(5)) && !usage.usageOf(id(5))->hasMemory()); + { + INFO("its time and its memory"); + REQUIRE(one); + REQUIRE(one->hasTime()); + REQUIRE(one->time == 0.125f); + REQUIRE(one->hasMemory()); + CHECK(one->memory == 65536); + } + { + INFO("an object not asked about kept too, time alone"); + REQUIRE(usage.usageOf(id(5))); + CHECK_FALSE(usage.usageOf(id(5))->hasMemory()); + } // Memory again: the time stays. landAsks[0].second(details); - ensure("time kept through memory", usage.usageOf(id(1))->time == 0.125f); + UNSCOPED_INFO("time kept through memory"); + CHECK(usage.usageOf(id(1))->time == 0.125f); // A later answer for the owner that leaves one of theirs out: it // runs no scripts now. One as full as Top Scripts gives proves @@ -248,38 +303,53 @@ namespace tut Usage::times_t later; later[id(2)] = 0.5f; timeAsks[0].second(later); - ensure("left out: no time now, its memory kept", !usage.usageOf(id(1))->hasTime() && usage.usageOf(id(1))->hasMemory()); - ensure("named: its time", usage.usageOf(id(2))->time == 0.5f); + { + INFO("left out: no time now, its memory kept"); + REQUIRE_FALSE(usage.usageOf(id(1))->hasTime()); + CHECK(usage.usageOf(id(1))->hasMemory()); + } + UNSCOPED_INFO("named: its time"); + CHECK(usage.usageOf(id(2))->time == 0.5f); Usage::times_t full; for (U32 n = 0; n < ALScriptRegionUsage::TOP_SCRIPTS_MOST; ++n) { full[id(100 + n)] = 0.01f; } timeAsks[0].second(full); - ensure("a full answer leaving it out: its time stands", usage.usageOf(id(2))->time == 0.5f); + UNSCOPED_INFO("a full answer leaving it out: its time stands"); + CHECK(usage.usageOf(id(2))->time == 0.5f); } - template<> template<> - void alscriptregionusage_object::test<5>() + TEST_CASE_METHOD(alscriptregionusage_data, "ALScriptRegionUsage: ownerKey and answering match a Top Scripts answer to the right ask", "[ALScriptRegionUsage]") { - set_test_name("an answer of Top Scripts by owner: with Top Objects not waiting on one, the oldest ask's whose owner its rows name, else the oldest's; with it waiting, its own but for one naming an owner only the studio asked about"); typedef std::optional Whose; typedef std::optional Theirs; - ensure_equals("a name in either form, lowered", ALScriptRegionUsage::ownerKey("Ann Resident "), std::string("ann")); - ensure_equals("a last name kept", ALScriptRegionUsage::ownerKey("Bo Smith"), std::string("bo.smith")); - ensure_equals("a username as it is", ALScriptRegionUsage::ownerKey("Bo.Smith"), std::string("bo.smith")); + UNSCOPED_INFO("a name in either form, lowered"); + CHECK(ALScriptRegionUsage::ownerKey("Ann Resident ") == std::string("ann")); + UNSCOPED_INFO("a last name kept"); + CHECK(ALScriptRegionUsage::ownerKey("Bo Smith") == std::string("bo.smith")); + UNSCOPED_INFO("a username as it is"); + CHECK(ALScriptRegionUsage::ownerKey("Bo.Smith") == std::string("bo.smith")); const std::vector waiting = { "Ann Resident", "Bo Smith", "Ann Resident" }; const Theirs none; - ensure("the oldest it names", ALScriptRegionUsage::answering(waiting, { "ann ", "ann " }, none) == Whose(0)); - ensure("not the oldest where it names a later one", ALScriptRegionUsage::answering(waiting, { "Bo Smith" }, none) == Whose(1)); - ensure("no rows, Top Objects not waiting: the oldest's", ALScriptRegionUsage::answering(waiting, {}, none) == Whose(0)); - ensure("named otherwise, Top Objects not waiting: the oldest's still", ALScriptRegionUsage::answering(waiting, { "Cy Resident" }, none) == Whose(0)); - ensure("none waiting: none", !ALScriptRegionUsage::answering({}, { "Ann Resident" }, none)); + UNSCOPED_INFO("the oldest it names"); + CHECK(ALScriptRegionUsage::answering(waiting, { "ann ", "ann " }, none) == Whose(0)); + UNSCOPED_INFO("not the oldest where it names a later one"); + CHECK(ALScriptRegionUsage::answering(waiting, { "Bo Smith" }, none) == Whose(1)); + UNSCOPED_INFO("no rows, Top Objects not waiting: the oldest's"); + CHECK(ALScriptRegionUsage::answering(waiting, {}, none) == Whose(0)); + UNSCOPED_INFO("named otherwise, Top Objects not waiting: the oldest's still"); + CHECK(ALScriptRegionUsage::answering(waiting, { "Cy Resident" }, none) == Whose(0)); + UNSCOPED_INFO("none waiting: none"); + REQUIRE_FALSE(ALScriptRegionUsage::answering({}, { "Ann Resident" }, none)); const Theirs cy = std::string("cy"); - ensure("Top Objects waiting: one naming the studio's owner alone is the studio's", ALScriptRegionUsage::answering(waiting, { "Bo Smith" }, cy) == Whose(1)); - ensure("one naming its own owner: Top Objects'", !ALScriptRegionUsage::answering(waiting, { "Cy Resident" }, cy)); - ensure("no rows: Top Objects'", !ALScriptRegionUsage::answering(waiting, {}, cy)); - ensure("an owner both asked about: Top Objects', the studio's answer to come", - !ALScriptRegionUsage::answering(waiting, { "Bo Smith" }, Theirs(std::string("Bo Smith")))); + UNSCOPED_INFO("Top Objects waiting: one naming the studio's owner alone is the studio's"); + CHECK(ALScriptRegionUsage::answering(waiting, { "Bo Smith" }, cy) == Whose(1)); + UNSCOPED_INFO("one naming its own owner: Top Objects'"); + REQUIRE_FALSE(ALScriptRegionUsage::answering(waiting, { "Cy Resident" }, cy)); + UNSCOPED_INFO("no rows: Top Objects'"); + REQUIRE_FALSE(ALScriptRegionUsage::answering(waiting, {}, cy)); + UNSCOPED_INFO("an owner both asked about: Top Objects', the studio's answer to come"); + REQUIRE_FALSE(ALScriptRegionUsage::answering(waiting, { "Bo Smith" }, Theirs(std::string("Bo Smith")))); } } diff --git a/indra/newview/tests/alscriptsaveflow_test.cpp b/indra/newview/tests/alscriptsaveflow_test.cpp index da21490d6d..fd01f967f6 100644 --- a/indra/newview/tests/alscriptsaveflow_test.cpp +++ b/indra/newview/tests/alscriptsaveflow_test.cpp @@ -26,9 +26,9 @@ #include "../alscriptsaveflow.h" -#include "../test/lltut.h" +#include -namespace tut +namespace { struct alscriptsaveflow_data { @@ -71,195 +71,271 @@ namespace tut return flow.compiled(answer); } }; - typedef test_group alscriptsaveflow_group; - typedef alscriptsaveflow_group::object alscriptsaveflow_object; - alscriptsaveflow_group alscriptsaveflow_instance("ALScriptSaveFlow"); - template<> template<> - void alscriptsaveflow_object::test<1>() + TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: a Save asked during a send runs once after it however often it was asked", "[ALScriptSaveFlow]") { - set_test_name("a Save while one is sent follows it once it answers, and once however often it was asked"); - ensure("goes", flow.ask(false, false) == Flow::Start::Go); - ensure("straight up", flow.route(script(1)) == Route::Send); + UNSCOPED_INFO("goes"); + CHECK(flow.ask(false, false) == Flow::Start::Go); + UNSCOPED_INFO("straight up"); + CHECK(flow.route(script(1)) == Route::Send); send(); - ensure("sending", flow.sending()); - ensure("asked again: queued", flow.ask(false, false) == Flow::Start::Queued); - ensure("and again", flow.ask(false, false) == Flow::Start::Queued); + UNSCOPED_INFO("sending"); + CHECK(flow.sending()); + UNSCOPED_INFO("asked again: queued"); + CHECK(flow.ask(false, false) == Flow::Start::Queued); + UNSCOPED_INFO("and again"); + CHECK(flow.ask(false, false) == Flow::Start::Queued); const Flow::Landing landing = compile(true, true); - ensure("its own save, saved", landing.ours && landing.markSaved && !landing.stopped); - ensure("nothing on its way", !flow.underway()); - ensure("the one asked for meanwhile", flow.takeAgain()); - ensure("once", !flow.takeAgain()); + { + INFO("its own save, saved"); + CHECK(landing.ours); + CHECK(landing.markSaved); + CHECK_FALSE(landing.stopped); + } + UNSCOPED_INFO("nothing on its way"); + CHECK_FALSE(flow.underway()); + UNSCOPED_INFO("the one asked for meanwhile"); + CHECK(flow.takeAgain()); + UNSCOPED_INFO("once"); + CHECK_FALSE(flow.takeAgain()); const Flow::Landing recompile = compile(true, true); - ensure("a recompile from elsewhere is not this tab's save", !recompile.ours && !recompile.markSaved); + { + INFO("a recompile from elsewhere is not this tab's save"); + CHECK_FALSE(recompile.ours); + CHECK_FALSE(recompile.markSaved); + } } - template<> template<> - void alscriptsaveflow_object::test<2>() + TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: Save Anyway lets one text past the analyzers' errors (S3-D1)", "[ALScriptSaveFlow]") { - set_test_name("Save Anyway lets past the check that stopped the save, for that text (S3-D1); nothing the preprocessor finds stops one"); - ensure("the analyzers' errors stop it", flow.route(expanded(1, true, true, 2)) == Route::StoppedByAnalyzers); - ensure("and nothing waits", !flow.underway()); + UNSCOPED_INFO("the analyzers' errors stop it"); + CHECK(flow.route(expanded(1, true, true, 2)) == Route::StoppedByAnalyzers); + UNSCOPED_INFO("and nothing waits"); + CHECK_FALSE(flow.underway()); flow.letPast(1); - ensure("asked again: past the errors, on to the preprocessor", flow.route(expanded(1, true, true, 2)) == Route::Preprocess); - ensure("whatever it found, sent: the save keeps the work", flow.preprocessed(run(1, 1)) == Flow::Landed::Send); - ensure("the same text asked again: still past", flow.route(expanded(1, true, true, 2)) == Route::Preprocess); - ensure("a changed text asks afresh", flow.route(expanded(2, true, true, 2)) == Route::StoppedByAnalyzers); + UNSCOPED_INFO("asked again: past the errors, on to the preprocessor"); + CHECK(flow.route(expanded(1, true, true, 2)) == Route::Preprocess); + UNSCOPED_INFO("whatever it found, sent: the save keeps the work"); + CHECK(flow.preprocessed(run(1, 1)) == Flow::Landed::Send); + UNSCOPED_INFO("the same text asked again: still past"); + CHECK(flow.route(expanded(1, true, true, 2)) == Route::Preprocess); + UNSCOPED_INFO("a changed text asks afresh"); + CHECK(flow.route(expanded(2, true, true, 2)) == Route::StoppedByAnalyzers); flow.letPast(2); - ensure("let past", flow.route(expanded(2, true, true, 2)) == Route::Preprocess); + UNSCOPED_INFO("let past"); + CHECK(flow.route(expanded(2, true, true, 2)) == Route::Preprocess); flow.preprocessed(run(2, 2)); send(); compile(true, true); - ensure("and a save that went up leaves nothing let past", flow.route(expanded(2, true, true, 2)) == Route::StoppedByAnalyzers); + UNSCOPED_INFO("and a save that went up leaves nothing let past"); + CHECK(flow.route(expanded(2, true, true, 2)) == Route::StoppedByAnalyzers); } - template<> template<> - void alscriptsaveflow_object::test<3>() + TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: a save held on errors waits for a check of its text and is asked again", "[ALScriptSaveFlow]") { - set_test_name("a save held on errors waits for a check of its text, and is asked again when it comes"); - ensure("not checked yet", flow.route(script(4, true, false)) == Route::Check); - ensure("waiting", flow.stage() == Flow::Stage::Checking); - ensure("the check came: asked again", flow.checked()); - ensure("once", !flow.checked()); - ensure("checked, and clean: sent", flow.route(script(4, true, true, 0)) == Route::Send); + UNSCOPED_INFO("not checked yet"); + CHECK(flow.route(script(4, true, false)) == Route::Check); + UNSCOPED_INFO("waiting"); + CHECK(flow.stage() == Flow::Stage::Checking); + UNSCOPED_INFO("the check came: asked again"); + CHECK(flow.checked()); + UNSCOPED_INFO("once"); + CHECK_FALSE(flow.checked()); + UNSCOPED_INFO("checked, and clean: sent"); + CHECK(flow.route(script(4, true, true, 0)) == Route::Send); } - template<> template<> - void alscriptsaveflow_object::test<4>() + TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: a text changed while preprocessed starts over and a running pass is joined", "[ALScriptSaveFlow]") { - set_test_name("a text changed while it is preprocessed starts the save over; a run already on its way is joined; a run nobody saves with is left alone"); - ensure("run", flow.route(expanded(1)) == Route::Preprocess); - ensure("typed in meanwhile: from the start", flow.preprocessed(run(1, 2)) == Flow::Landed::MovedOn); - ensure("nothing on its way", !flow.underway()); - ensure("a view's run, nobody saving", flow.preprocessed(run(2, 2)) == Flow::Landed::NotForSave); - ensure("a run on its way already: joined", flow.route(expanded(2, false, true, 0, true)) == Route::JoinPreprocessor); - ensure("waiting on it", flow.stage() == Flow::Stage::Preprocessing); - ensure("and sent when it comes", flow.preprocessed(run(2, 2)) == Flow::Landed::Send); + UNSCOPED_INFO("run"); + CHECK(flow.route(expanded(1)) == Route::Preprocess); + UNSCOPED_INFO("typed in meanwhile: from the start"); + CHECK(flow.preprocessed(run(1, 2)) == Flow::Landed::MovedOn); + UNSCOPED_INFO("nothing on its way"); + CHECK_FALSE(flow.underway()); + UNSCOPED_INFO("a view's run, nobody saving"); + CHECK(flow.preprocessed(run(2, 2)) == Flow::Landed::NotForSave); + UNSCOPED_INFO("a run on its way already: joined"); + CHECK(flow.route(expanded(2, false, true, 0, true)) == Route::JoinPreprocessor); + UNSCOPED_INFO("waiting on it"); + CHECK(flow.stage() == Flow::Stage::Preprocessing); + UNSCOPED_INFO("and sent when it comes"); + CHECK(flow.preprocessed(run(2, 2)) == Flow::Landed::Send); } - template<> template<> - void alscriptsaveflow_object::test<5>() + TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: a close waiting on a save is dropped when the save stops unless quitting", "[ALScriptSaveFlow]") { - set_test_name("a close waiting on a save goes where the save stops, and not where the viewer is quitting over a failed compile"); flow.setCloseAfter(true); flow.route(script(1)); flow.stopped(); - ensure("refused as it was sent", !flow.closeAfter() && !flow.underway()); + { + INFO("refused as it was sent"); + CHECK_FALSE(flow.closeAfter()); + CHECK_FALSE(flow.underway()); + } flow.setCloseAfter(true); send(); flow.ask(false, false); - ensure("the text did not go up: stopped", compile(false, false).stopped); - ensure("the close with it", !flow.closeAfter()); - ensure("and what was asked meanwhile", !flow.takeAgain()); + UNSCOPED_INFO("the text did not go up: stopped"); + CHECK(compile(false, false).stopped); + UNSCOPED_INFO("the close with it"); + CHECK_FALSE(flow.closeAfter()); + UNSCOPED_INFO("and what was asked meanwhile"); + CHECK_FALSE(flow.takeAgain()); flow.setCloseAfter(true); send(); - ensure("up, and did not compile: stopped", compile(true, false).stopped && !flow.closeAfter()); + { + INFO("up, and did not compile: stopped"); + CHECK(compile(true, false).stopped); + CHECK_FALSE(flow.closeAfter()); + } flow.setCloseAfter(true); send(); const Flow::Landing quitting = compile(true, false, true); - ensure("unless quitting: saved, and closed", !quitting.stopped && quitting.markSaved && flow.closeAfter()); + { + INFO("unless quitting: saved, and closed"); + CHECK_FALSE(quitting.stopped); + CHECK(quitting.markSaved); + CHECK(flow.closeAfter()); + } flow.setCloseAfter(true); send(); compile(true, true); - ensure("compiled: closed", flow.closeAfter()); + UNSCOPED_INFO("compiled: closed"); + CHECK(flow.closeAfter()); } - template<> template<> - void alscriptsaveflow_object::test<6>() + TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: an external editor's save skips every check and out of reach nothing goes", "[ALScriptSaveFlow]") { - set_test_name("an external editor's save goes past every check and is the editor's until it lands; out of reach, or detached, nothing goes"); flow.fromExternal(3); - ensure("the editor's", flow.external()); - ensure("past the errors", flow.route(expanded(3, true, true, 5)) == Route::Preprocess); - ensure("and sent", flow.preprocessed(run(3, 3)) == Flow::Landed::Send); + UNSCOPED_INFO("the editor's"); + CHECK(flow.external()); + UNSCOPED_INFO("past the errors"); + CHECK(flow.route(expanded(3, true, true, 5)) == Route::Preprocess); + UNSCOPED_INFO("and sent"); + CHECK(flow.preprocessed(run(3, 3)) == Flow::Landed::Send); flow.endExternal(); - ensure("ended", !flow.external()); + UNSCOPED_INFO("ended"); + CHECK_FALSE(flow.external()); flow.setCloseAfter(true); - ensure("out of reach", flow.ask(true, false) == Flow::Start::OutOfReach && !flow.closeAfter()); + { + INFO("out of reach"); + CHECK(flow.ask(true, false) == Flow::Start::OutOfReach); + CHECK_FALSE(flow.closeAfter()); + } flow.setCloseAfter(true); - ensure("detached", flow.ask(false, true) == Flow::Start::Detached && !flow.closeAfter()); + { + INFO("detached"); + CHECK(flow.ask(false, true) == Flow::Start::Detached); + CHECK_FALSE(flow.closeAfter()); + } } - template<> template<> - void alscriptsaveflow_object::test<7>() + TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: files and notecards go as they stand and errors stop only a held save", "[ALScriptSaveFlow]") { - set_test_name("a file is written and a notecard sent as they stand, never checked or preprocessed; not held, errors stop nothing"); Flow::Tab file = expanded(1, true, false, 3); file.file = true; - ensure("a file", flow.route(file) == Route::File); + UNSCOPED_INFO("a file"); + CHECK(flow.route(file) == Route::File); Flow::Tab card = expanded(1, true, false, 3); card.notecard = true; - ensure("a notecard", flow.route(card) == Route::Notecard); - ensure("not held: sent over errors", flow.route(script(1, false, true, 3)) == Route::Send); - ensure("or expanded first", flow.route(expanded(1, false, true, 3)) == Route::Preprocess); + UNSCOPED_INFO("a notecard"); + CHECK(flow.route(card) == Route::Notecard); + UNSCOPED_INFO("not held: sent over errors"); + CHECK(flow.route(script(1, false, true, 3)) == Route::Send); + UNSCOPED_INFO("or expanded first"); + CHECK(flow.route(expanded(1, false, true, 3)) == Route::Preprocess); } - template<> template<> - void alscriptsaveflow_object::test<8>() + TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: fixOnce is true once a save and again for the next", "[ALScriptSaveFlow]") { - set_test_name("the safe fixes are made once a save, however many checks it waits on, and afresh for the next"); - ensure("once", flow.fixOnce()); + UNSCOPED_INFO("once"); + CHECK(flow.fixOnce()); flow.route(script(1, true, false)); flow.checked(); - ensure("not again while the same save waits", !flow.fixOnce()); + UNSCOPED_INFO("not again while the same save waits"); + CHECK_FALSE(flow.fixOnce()); send(); - ensure("afresh once it went", flow.fixOnce()); + UNSCOPED_INFO("afresh once it went"); + CHECK(flow.fixOnce()); flow.stopped(); - ensure("or stopped", flow.fixOnce()); + UNSCOPED_INFO("or stopped"); + CHECK(flow.fixOnce()); flow.done(); - ensure("or a file was written", flow.fixOnce()); + UNSCOPED_INFO("or a file was written"); + CHECK(flow.fixOnce()); } - template<> template<> - void alscriptsaveflow_object::test<9>() + TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: sent keeps the save point and source map and a notecard's items", "[ALScriptSaveFlow]") { - set_test_name("what went up is kept: where the journal stood, the map the compiler's lines are read through, a notecard's items"); ALTextUndo::SavePoint at; at.serial = 7; LLUUID item; item.generate(); flow.sent(at, ALSourceMap(), { item }); - ensure("the save point", flow.savePoint().serial == 7); - ensure("the map", flow.sentMap().has_value()); - ensure("the items", flow.sentItems().size() == 1 && flow.sentItems().front() == item); + UNSCOPED_INFO("the save point"); + CHECK(flow.savePoint().serial == 7); + UNSCOPED_INFO("the map"); + REQUIRE(flow.sentMap().has_value()); + { + INFO("the items"); + REQUIRE(flow.sentItems().size() == 1); + CHECK(flow.sentItems().front() == item); + } flow.forgetSentItems(); - ensure("let go of", flow.sentItems().empty()); + UNSCOPED_INFO("let go of"); + REQUIRE(flow.sentItems().empty()); compile(true, true); - ensure("the map stays after, for what the script says as it runs", flow.sentMap().has_value()); + UNSCOPED_INFO("the map stays after, for what the script says as it runs"); + REQUIRE(flow.sentMap().has_value()); flow.setWarnWeightFor(9); - ensure("the weight to warn of", flow.warnWeightFor() == 9); + UNSCOPED_INFO("the weight to warn of"); + CHECK(flow.warnWeightFor() == 9); } - template<> template<> - void alscriptsaveflow_object::test<10>() + TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: the world is asked once a text and a moved item stops the save", "[ALScriptSaveFlow]") { - set_test_name("the world asked once a text what the item holds; moved, the save stops until asked again; a save asked meanwhile waits on the answer"); Flow::Tab tab = script(1); tab.askWorld = true; - ensure("asked first", flow.route(tab) == Route::AskWorld && flow.stage() == Flow::Stage::Asking); - ensure("a save asked meanwhile waits on the answer", flow.ask(false, false) == Flow::Start::Queued); + { + INFO("asked first"); + CHECK(flow.route(tab) == Route::AskWorld); + CHECK(flow.stage() == Flow::Stage::Asking); + } + UNSCOPED_INFO("a save asked meanwhile waits on the answer"); + CHECK(flow.ask(false, false) == Flow::Start::Queued); flow.worldAnswered(1, false); - ensure("answered, nothing moved: sent", flow.route(tab) == Route::Send); + UNSCOPED_INFO("answered, nothing moved: sent"); + CHECK(flow.route(tab) == Route::Send); tab.version = 2; - ensure("a new text asks again", flow.route(tab) == Route::AskWorld); + UNSCOPED_INFO("a new text asks again"); + CHECK(flow.route(tab) == Route::AskWorld); flow.worldAnswered(2, true); - ensure("moved: stopped", flow.route(tab) == Route::StoppedByWorld && !flow.underway()); - ensure("and again", flow.route(tab) == Route::StoppedByWorld); + { + INFO("moved: stopped"); + CHECK(flow.route(tab) == Route::StoppedByWorld); + CHECK_FALSE(flow.underway()); + } + UNSCOPED_INFO("and again"); + CHECK(flow.route(tab) == Route::StoppedByWorld); flow.letPast(2); - ensure("asked again: saved over it", flow.route(tab) == Route::Send); + UNSCOPED_INFO("asked again: saved over it"); + CHECK(flow.route(tab) == Route::Send); Flow::Tab file = tab; file.file = true; - ensure("a file asks nothing of the world", flow.route(file) == Route::File); + UNSCOPED_INFO("a file asks nothing of the world"); + CHECK(flow.route(file) == Route::File); Flow::Tab card = script(3); card.notecard = true; card.askWorld = true; - ensure("a notecard is asked about too", flow.route(card) == Route::AskWorld); + UNSCOPED_INFO("a notecard is asked about too"); + CHECK(flow.route(card) == Route::AskWorld); } } diff --git a/indra/newview/tests/alscriptsearchpane_test.cpp b/indra/newview/tests/alscriptsearchpane_test.cpp index ce393de489..4c81e61afc 100644 --- a/indra/newview/tests/alscriptsearchpane_test.cpp +++ b/indra/newview/tests/alscriptsearchpane_test.cpp @@ -35,7 +35,7 @@ #include "alscriptstudio_fixture.h" #include "lltabcontainer.h" -#include "../test/lltut.h" +#include #include #include @@ -151,7 +151,7 @@ namespace } } -namespace tut +namespace { struct alscriptsearchpane_data { @@ -165,11 +165,12 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } // The tab as the skin built it. pane = window.find("search_tab"); - ensure("the skin builds the tab as the pane", pane != nullptr); + UNSCOPED_INFO("the skin builds the tab as the pane"); + REQUIRE(pane != nullptr); // In sight, its tab the one chosen, as when it is worked in. window.find("bottom_tabs")->selectTabByName("search_tab"); return *pane; @@ -216,29 +217,38 @@ namespace tut } std::string counted() const { return pane->count()->getText(); } }; - typedef test_group alscriptsearchpane_group; - typedef alscriptsearchpane_group::object alscriptsearchpane_object; - alscriptsearchpane_group alscriptsearchpane_instance("ALScriptSearchPane"); - template <> - template <> - void alscriptsearchpane_object::test<1>() + TEST_CASE_METHOD(alscriptsearchpane_data, "ALScriptSearchPane: open scripts are searched as they stand and an object's are fetched", "[ALScriptSearchPane]") { - set_test_name("places found in the scripts open as they stand, and in an object's as fetched, a script open elsewhere as it stands there"); ALScriptSearchPane& out = make(); Doc& door = doc("door", "timer one\nnothing\n timer two\n"); find("timer"); - ensure_equals("one script", out.search().found().size(), size_t(1)); - ensure_equals("two places", out.search().found()[0].places.size(), size_t(2)); - ensure_equals("a row each", out.list()->getItemCount(), 2); + UNSCOPED_INFO("one script"); + REQUIRE(out.search().found().size() == size_t(1)); + UNSCOPED_INFO("two places"); + REQUIRE(out.search().found()[0].places.size() == size_t(2)); + UNSCOPED_INFO("a row each"); + CHECK(out.list()->getItemCount() == 2); // The list's keys: return goes to the place chosen, to type there, // escape back to the script; and the rows copy. out.list()->selectFirstItem(); - ensure("return", out.list()->handleKeyHere(KEY_RETURN, MASK_NONE) && !studio.chosen.empty() && studio.chosen.back().toEditor); - ensure("escape", out.list()->handleKeyHere(KEY_ESCAPE, MASK_NONE) && services.reveals.back()); - ensure("copied", out.list()->handleKeyHere('C', MASK_CONTROL)); - ensure_equals("the line as listed, trimmed", out.search().found()[0].lines[1], std::string("timer two")); - ensure_equals("counted", counted(), services.words("SearchCount", { { "[HITS]", services.counted("Matches", 2) }, + { + INFO("return"); + CHECK(out.list()->handleKeyHere(KEY_RETURN, MASK_NONE)); + REQUIRE_FALSE(studio.chosen.empty()); + CHECK(studio.chosen.back().toEditor); + } + { + INFO("escape"); + CHECK(out.list()->handleKeyHere(KEY_ESCAPE, MASK_NONE)); + REQUIRE(services.reveals.back()); + } + UNSCOPED_INFO("copied"); + CHECK(out.list()->handleKeyHere('C', MASK_CONTROL)); + UNSCOPED_INFO("the line as listed, trimmed"); + CHECK(out.search().found()[0].lines[1] == std::string("timer two")); + UNSCOPED_INFO("counted"); + CHECK(counted() == services.words("SearchCount", { { "[HITS]", services.counted("Matches", 2) }, { "[FILES]", services.counted("Files", 1) }, { "[SHOWN]", "2000" } })); @@ -251,57 +261,70 @@ namespace tut studio.objects = { { root, "Thing", { door.ref, there.ref, away } } }; studio.inHand = root; find("timer", "object"); - ensure_equals("the open one and the one elsewhere", out.search().found().size(), size_t(2)); - ensure_equals("where it is elsewhere, said", out.search().found()[1].where, std::string("Thing: there.lsl")); - ensure_equals("the rest fetched", studio.fetches.size(), size_t(1)); - ensure("the one asked", studio.fetches[0].ref == away); - ensure_equals("counting while it comes", counted(), services.words("SearchCounting", { { "[HITS]", services.counted("Matches", 3) }, + UNSCOPED_INFO("the open one and the one elsewhere"); + REQUIRE(out.search().found().size() == size_t(2)); + UNSCOPED_INFO("where it is elsewhere, said"); + CHECK(out.search().found()[1].where == std::string("Thing: there.lsl")); + UNSCOPED_INFO("the rest fetched"); + REQUIRE(studio.fetches.size() == size_t(1)); + UNSCOPED_INFO("the one asked"); + CHECK(studio.fetches[0].ref == away); + UNSCOPED_INFO("counting while it comes"); + CHECK(counted() == services.words("SearchCounting", { { "[HITS]", services.counted("Matches", 3) }, { "[FILES]", services.counted("Files", 2) }, { "[SHOWN]", "2000" } })); out.fetched(studio.fetches[0].generation, "Thing", away, "away.lsl", std::make_shared("x\ntimer fetched\n"), false); - ensure_equals("fetched, found", out.search().found().size(), size_t(3)); - ensure_equals("its text kept, for a replace", out.search().found()[2].text, std::string("x\ntimer fetched\n")); - ensure_equals("none to wait for", out.search().pending(), 0); + UNSCOPED_INFO("fetched, found"); + REQUIRE(out.search().found().size() == size_t(3)); + UNSCOPED_INFO("its text kept, for a replace"); + CHECK(out.search().found()[2].text == std::string("x\ntimer fetched\n")); + UNSCOPED_INFO("none to wait for"); + CHECK(out.search().pending() == 0); // No object in hand: none guessed at. studio.inHand.setNull(); find("timer", "object"); - ensure_equals("said", counted(), services.words("SearchNoObject")); + UNSCOPED_INFO("said"); + CHECK(counted() == services.words("SearchNoObject")); } - template <> - template <> - void alscriptsearchpane_object::test<2>() + TEST_CASE_METHOD(alscriptsearchpane_data, "ALScriptSearchPane: a later search drops the answers to an earlier one", "[ALScriptSearchPane]") { - set_test_name("a later search drops what an earlier one is answered"); ALScriptSearchPane& out = make(); const ALScriptRef away(fresh(), fresh()); const LLUUID root = fresh(); studio.objects = { { root, "Thing", { away } } }; find("timer", "listed"); find("other", "listed"); - ensure_equals("asked twice", studio.fetches.size(), size_t(2)); + UNSCOPED_INFO("asked twice"); + REQUIRE(studio.fetches.size() == size_t(2)); out.fetched(studio.fetches[0].generation, "Thing", away, "away.lsl", std::make_shared("timer\nother\n"), false); - ensure("the first search's answer dropped", out.search().found().empty()); - ensure_equals("still waiting on the second's", out.search().pending(), 1); + UNSCOPED_INFO("the first search's answer dropped"); + REQUIRE(out.search().found().empty()); + UNSCOPED_INFO("still waiting on the second's"); + CHECK(out.search().pending() == 1); out.fetched(studio.fetches[1].generation, "Thing", away, "away.lsl", std::make_shared("timer\nother\n"), false); - ensure_equals("the second's kept", out.search().found().size(), size_t(1)); - ensure_equals("for what it looked for", out.search().found()[0].places[0].begin.line, 1); + UNSCOPED_INFO("the second's kept"); + REQUIRE(out.search().found().size() == size_t(1)); + UNSCOPED_INFO("for what it looked for"); + CHECK(out.search().found()[0].places[0].begin.line == 1); } - template <> - template <> - void alscriptsearchpane_object::test<3>() + TEST_CASE_METHOD(alscriptsearchpane_data, "ALScriptSearchPane: a script typed in since the search is left alone and searched again", "[ALScriptSearchPane]") { - set_test_name("a script typed in since the search is not replaced over, and is searched again a moment later"); ALScriptSearchPane& out = make(); Doc& door = doc("door", "timer one\ntimer two\n"); find("timer"); door.editor->setCaret(ALTextPos(0, 0)); door.editor->insertText("x"); out.replaceAll(); - ensure_equals("left alone", door.editor->text(), std::string("xtimer one\ntimer two\n")); - ensure("said so", !services.reports.empty() && services.reports.back().failure); + UNSCOPED_INFO("left alone"); + CHECK(door.editor->text() == std::string("xtimer one\ntimer two\n")); + { + INFO("said so"); + REQUIRE_FALSE(services.reports.empty()); + CHECK(services.reports.back().failure); + } // Searched again once the typing has rested: its places are where // they are now. @@ -310,26 +333,28 @@ namespace tut door.editor->insertText("yy"); out.typedIn(door); out.pump(); - ensure_equals("not at once", out.search().found()[0].places[0].begin.column, 1); + UNSCOPED_INFO("not at once"); + CHECK(out.search().found()[0].places[0].begin.column == 1); std::this_thread::sleep_for(std::chrono::milliseconds(700)); LLTabContainer* tabs = window.find("bottom_tabs"); tabs->selectTabByName("problems_tab"); out.pump(); - ensure_equals("due, but out of sight: waiting", out.search().found()[0].places[0].begin.column, 1); + UNSCOPED_INFO("due, but out of sight: waiting"); + CHECK(out.search().found()[0].places[0].begin.column == 1); tabs->selectTabByName("search_tab"); out.pump(); - ensure_equals("then, seen, where it is now", out.search().found()[0].places[0].begin.column, 3); + UNSCOPED_INFO("then, seen, where it is now"); + CHECK(out.search().found()[0].places[0].begin.column == 3); out.replaceAll(); - ensure_equals("and replaced", door.editor->text(), std::string("yyx one\n two\n")); + UNSCOPED_INFO("and replaced"); + CHECK(door.editor->text() == std::string("yyx one\n two\n")); door.editor->undo(); - ensure_equals("as one step", door.editor->text(), std::string("yyxtimer one\ntimer two\n")); + UNSCOPED_INFO("as one step"); + CHECK(door.editor->text() == std::string("yyxtimer one\ntimer two\n")); } - template <> - template <> - void alscriptsearchpane_object::test<4>() + TEST_CASE_METHOD(alscriptsearchpane_data, "ALScriptSearchPane: Replace All asks then edits open scripts and opens the rest unsaved", "[ALScriptSearchPane]") { - set_test_name("Replace All, asked first: an open script's places as one step, a script or a notecard not open opened with the change unsaved"); ALScriptSearchPane& out = make(); Doc& door = doc("door", "llSay(0, \"timer\");\n"); const ALScriptRef away(fresh(), fresh()); @@ -340,7 +365,8 @@ namespace tut find("timer", "object"); out.fetched(studio.fetches[0].generation, "Thing", away, "away.lsl", std::make_shared("timer\n"), false); out.fetched(studio.fetches[1].generation, "Thing", card, "card", std::make_shared("a timer\n"), true); - ensure_equals("three found", out.search().found().size(), size_t(3)); + UNSCOPED_INFO("three found"); + REQUIRE(out.search().found().size() == size_t(3)); services.whenOpened = [this, card](const ALScriptRef& ref, const std::string&) { Doc& opened = ref == card ? doc("card", "a timer\n", true) : doc("away", "timer\n"); opened.ref = ref; @@ -348,19 +374,37 @@ namespace tut window.find("search_replacement")->setText(std::string("clock")); out.askReplaceAll(); - ensure_equals("asked", studio.asked.size(), size_t(1)); - ensure_equals("of the scripts and the notecard", studio.asked[0]["SCRIPTS"].asString(), services.counted("ScriptsNotecards", 3)); - ensure_equals("the open one, replaced", door.editor->text(), std::string("llSay(0, \"clock\");\n")); - ensure_equals("the two not open, opened", services.opened.size(), size_t(2)); - ensure("by their items", services.opened[0].ref == away && services.opened[1].ref == card); + UNSCOPED_INFO("asked"); + REQUIRE(studio.asked.size() == size_t(1)); + UNSCOPED_INFO("of the scripts and the notecard"); + CHECK(studio.asked[0]["SCRIPTS"].asString() == services.counted("ScriptsNotecards", 3)); + UNSCOPED_INFO("the open one, replaced"); + CHECK(door.editor->text() == std::string("llSay(0, \"clock\");\n")); + UNSCOPED_INFO("the two not open, opened"); + REQUIRE(services.opened.size() == size_t(2)); + { + INFO("by their items"); + CHECK(services.opened[0].ref == away); + CHECK(services.opened[1].ref == card); + } const Doc* opened = services.findDoc(away); - ensure("a tab for it", opened != nullptr); - ensure_equals("its change waiting on its text", opened->pendingEdits.size(), size_t(1)); - ensure_equals("which it replaces", opened->pendingEdits[0].now, std::string("clock")); + UNSCOPED_INFO("a tab for it"); + REQUIRE(opened != nullptr); + UNSCOPED_INFO("its change waiting on its text"); + REQUIRE(opened->pendingEdits.size() == size_t(1)); + UNSCOPED_INFO("which it replaces"); + CHECK(opened->pendingEdits[0].now == std::string("clock")); const Doc* notecard = services.findDoc(card); - ensure("the notecard's too", notecard && notecard->pendingEdits.size() == 1 && notecard->pendingEdits[0].now == "clock"); - ensure_equals("and each is made", studio.applied.size(), size_t(2)); - ensure_equals("said", services.reports.back().text, + { + INFO("the notecard's too"); + REQUIRE(notecard); + REQUIRE(notecard->pendingEdits.size() == 1); + CHECK(notecard->pendingEdits[0].now == "clock"); + } + UNSCOPED_INFO("and each is made"); + REQUIRE(studio.applied.size() == size_t(2)); + UNSCOPED_INFO("said"); + CHECK(services.reports.back().text == services.words("SearchReplaced", { { "[PLACES]", services.counted("Places", 3) }, { "[SCRIPTS]", services.counted("ScriptsNotecards", 3) } }) + "; " + services.words("SearchReplacedOpened", @@ -368,11 +412,8 @@ namespace tut "."); } - template <> - template <> - void alscriptsearchpane_object::test<5>() + TEST_CASE_METHOD(alscriptsearchpane_data, "ALScriptSearchPane: Replace All's step for a found script follows where it is now", "[ALScriptSearchPane]") { - set_test_name("what Replace All does with a script found, by where it is now"); using Step = ALScriptSearch::Step; using At = ALScriptSearch::Now::At; ALScriptSearch::Found one; @@ -382,49 +423,58 @@ namespace tut ALTextDocument text("timer\n"); ALScriptSearch::Now now; - ensure("closed, with no text kept: left", ALScriptSearch::step(one, now) == Step::Leave); + UNSCOPED_INFO("closed, with no text kept: left"); + CHECK(ALScriptSearch::step(one, now) == Step::Leave); one.text = "timer\n"; - ensure("closed, with its text: opened", ALScriptSearch::step(one, now) == Step::Open); + UNSCOPED_INFO("closed, with its text: opened"); + CHECK(ALScriptSearch::step(one, now) == Step::Open); ALScriptSearch::Found file = one; file.ref = ALScriptRef(); - ensure("a file closed since: left", ALScriptSearch::step(file, now) == Step::Leave); + UNSCOPED_INFO("a file closed since: left"); + CHECK(ALScriptSearch::step(file, now) == Step::Leave); now.at = At::Here; now.loaded = true; now.modifiable = true; now.text = &text; - ensure("here, at another version: left", ALScriptSearch::step(one, now) == Step::Leave); + UNSCOPED_INFO("here, at another version: left"); + CHECK(ALScriptSearch::step(one, now) == Step::Leave); one.version = text.version(); - ensure("here, as searched: replaced", ALScriptSearch::step(one, now) == Step::Replace); + UNSCOPED_INFO("here, as searched: replaced"); + CHECK(ALScriptSearch::step(one, now) == Step::Replace); now.modifiable = false; - ensure("here, not to be changed: left", ALScriptSearch::step(one, now) == Step::Leave); + UNSCOPED_INFO("here, not to be changed: left"); + CHECK(ALScriptSearch::step(one, now) == Step::Leave); now.modifiable = true; now.plainText = true; - ensure("here, a text file: skipped", ALScriptSearch::step(one, now) == Step::Skip); + UNSCOPED_INFO("here, a text file: skipped"); + CHECK(ALScriptSearch::step(one, now) == Step::Skip); now.plainText = false; now.at = At::Elsewhere; - ensure("elsewhere, reading as it did: replaced", ALScriptSearch::step(one, now) == Step::Replace); + UNSCOPED_INFO("elsewhere, reading as it did: replaced"); + CHECK(ALScriptSearch::step(one, now) == Step::Replace); ALTextDocument typed("timer!\n"); now.text = &typed; - ensure("elsewhere, typed in since: left", ALScriptSearch::step(one, now) == Step::Leave); + UNSCOPED_INFO("elsewhere, typed in since: left"); + CHECK(ALScriptSearch::step(one, now) == Step::Leave); one.notecard = true; now.text = &text; - ensure("found in a notecard in the world: replaced as a script is", ALScriptSearch::step(one, now) == Step::Replace); + UNSCOPED_INFO("found in a notecard in the world: replaced as a script is"); + CHECK(ALScriptSearch::step(one, now) == Step::Replace); ALScriptSearch::Found text_file = one; text_file.ref = ALScriptRef(); - ensure("found in a text file: skipped", ALScriptSearch::step(text_file, now) == Step::Skip); + UNSCOPED_INFO("found in a text file: skipped"); + CHECK(ALScriptSearch::step(text_file, now) == Step::Skip); one.notecard = false; one.places.clear(); - ensure("nothing found: skipped", ALScriptSearch::step(one, now) == Step::Skip); + UNSCOPED_INFO("nothing found: skipped"); + CHECK(ALScriptSearch::step(one, now) == Step::Skip); } - template <> - template <> - void alscriptsearchpane_object::test<6>() + TEST_CASE_METHOD(alscriptsearchpane_data, "ALScriptSearchPane: included files are searched once each on request and left by Replace All", "[ALScriptSearchPane]") { - set_test_name("what the scripts include searched too where asked: each file once, as its own, left alone by Replace All"); ALScriptSearchPane& out = make(); doc("door", "#include \"lib\"\ntimer\n"); doc("gate", "#include \"lib\"\n"); @@ -432,25 +482,36 @@ namespace tut studio.includes["door.lsl"] = lib; studio.includes["gate.lsl"] = lib; find("timer"); - ensure_equals("alone: the script's own", out.search().found().size(), size_t(1)); - ensure("nothing asked of what it includes", studio.askedIncludes.empty()); + UNSCOPED_INFO("alone: the script's own"); + REQUIRE(out.search().found().size() == size_t(1)); + UNSCOPED_INFO("nothing asked of what it includes"); + REQUIRE(studio.askedIncludes.empty()); out.bar()->setValue("includes", "yes"); const S32 before = studio.apart; find("timer"); - ensure_equals("and the file it includes, once for the two", out.search().found().size(), size_t(2)); - ensure("sought apart, once, and back", studio.apart == before + 1 && out.search().pending() == 0); + UNSCOPED_INFO("and the file it includes, once for the two"); + REQUIRE(out.search().found().size() == size_t(2)); + { + INFO("sought apart, once, and back"); + CHECK(studio.apart == before + 1); + CHECK(out.search().pending() == 0); + } const ALScriptSearch::Found& found = out.search().found()[1]; - ensure_equals("by its identity", found.file, std::string("disk:/scripts/lib.lsl")); - ensure("said to be included", found.where.find(services.words("SearchIncluded")) != std::string::npos && found.where.find("lib.lsl") != std::string::npos); - ensure_equals("a row for its place", out.list()->getItemCount(), 2); - ensure("Replace All leaves it", ALScriptSearch::step(found, ALScriptSearch::Now()) == ALScriptSearch::Step::Leave); + UNSCOPED_INFO("by its identity"); + CHECK(found.file == std::string("disk:/scripts/lib.lsl")); + { + INFO("said to be included"); + REQUIRE(found.where.find(services.words("SearchIncluded")) != std::string::npos); + REQUIRE(found.where.find("lib.lsl") != std::string::npos); + } + UNSCOPED_INFO("a row for its place"); + CHECK(out.list()->getItemCount() == 2); + UNSCOPED_INFO("Replace All leaves it"); + CHECK(ALScriptSearch::step(found, ALScriptSearch::Now()) == ALScriptSearch::Step::Leave); } - template <> - template <> - void alscriptsearchpane_object::test<7>() + TEST_CASE_METHOD(alscriptsearchpane_data, "ALScriptSearchPane: an object is searched once listed and the count says what was passed over", "[ALScriptSearchPane]") { - set_test_name("an object's scripts searched once its prims have said what they hold; the prims that did not, and a script not read, said with the count"); ALScriptSearchPane& out = make(); const ALScriptRef one(fresh(), fresh()); const ALScriptRef two(fresh(), fresh()); @@ -464,20 +525,26 @@ namespace tut studio.inHand = root; studio.holdListing = true; find("timer", "object"); - ensure("nothing fetched while its prims are asked", studio.fetches.empty()); - ensure_equals("waited for", out.search().pending(), 1); + UNSCOPED_INFO("nothing fetched while its prims are asked"); + REQUIRE(studio.fetches.empty()); + UNSCOPED_INFO("waited for"); + CHECK(out.search().pending() == 1); studio.heldListing(); - ensure_equals("both fetched", studio.fetches.size(), size_t(2)); + UNSCOPED_INFO("both fetched"); + REQUIRE(studio.fetches.size() == size_t(2)); out.fetched(studio.fetches[0].generation, "Thing", one, "one.lsl", std::make_shared("timer\n"), false); out.fetched(studio.fetches[1].generation, "Thing", two, "two.lsl", nullptr, false); - ensure_equals("none to wait for", out.search().pending(), 0); - ensure_equals("one read", out.search().found().size(), size_t(1)); + UNSCOPED_INFO("none to wait for"); + CHECK(out.search().pending() == 0); + UNSCOPED_INFO("one read"); + REQUIRE(out.search().found().size() == size_t(1)); const std::string said = services.words("SearchCount", { { "[HITS]", services.counted("Matches", 1) }, { "[FILES]", services.counted("Files", 1) }, { "[SHOWN]", "2000" } }); const std::string missed = services.words("SearchBoth", { { "[FIRST]", services.counted("SearchUnlisted", 3) }, { "[SECOND]", services.counted("SearchUnread", 1) } }); - ensure_equals("what was passed over, after what was found", counted(), + UNSCOPED_INFO("what was passed over, after what was found"); + CHECK(counted() == services.words("SearchPassedOver", { { "[SAID]", said }, { "[MISSED]", missed } })); // A search begun again lets the held listing go: its answer is an @@ -487,28 +554,41 @@ namespace tut std::function first = std::move(studio.heldListing); find("other", "object"); first(); - ensure("the earlier listing dropped", studio.fetches.empty()); + UNSCOPED_INFO("the earlier listing dropped"); + REQUIRE(studio.fetches.empty()); studio.heldListing(); - ensure_equals("the later one searched", studio.fetches.size(), size_t(2)); + UNSCOPED_INFO("the later one searched"); + REQUIRE(studio.fetches.size() == size_t(2)); } - template <> - template <> - void alscriptsearchpane_object::test<8>() + TEST_CASE_METHOD(alscriptsearchpane_data, "ALScriptSearchPane: Sources keeps a script by its text and drops the oldest past the limit", "[ALScriptSearchPane]") { - set_test_name("a script read for a search kept by which text it is: found again only for that text; no more than the most kept, the oldest going"); ALScriptSearch::Sources& sources = ALScriptSearch::Sources::instance(); sources.clear(); const ALScriptRef one(LLUUID::generateNewID(), LLUUID::generateNewID()); const LLUUID asset = LLUUID::generateNewID(); sources.keep(one, LLUUID::null, { std::make_shared("timer"), "one.lsl", false }); - ensure("which text unknown: not kept", sources.bytes() == 0); + UNSCOPED_INFO("which text unknown: not kept"); + CHECK(sources.bytes() == 0); sources.keep(one, asset, { std::make_shared("timer"), "one.lsl", false }); const ALScriptSearch::Sources::Source* kept = sources.find(one, asset); - ensure("found by its text", kept && *kept->text == "timer" && kept->name == "one.lsl"); - ensure("not for another", !sources.find(one, LLUUID::generateNewID()) && !sources.find(one, LLUUID::null)); + { + INFO("found by its text"); + REQUIRE(kept); + REQUIRE(*kept->text == "timer"); + CHECK(kept->name == "one.lsl"); + } + { + INFO("not for another"); + REQUIRE_FALSE(sources.find(one, LLUUID::generateNewID())); + REQUIRE_FALSE(sources.find(one, LLUUID::null)); + } sources.keep(one, LLUUID::generateNewID(), { std::make_shared("saved since"), "one.lsl", false }); - ensure("saved since: in its place", !sources.find(one, asset) && sources.bytes() == std::string("saved since").size()); + { + INFO("saved since: in its place"); + REQUIRE_FALSE(sources.find(one, asset)); + REQUIRE(sources.bytes() == std::string("saved since").size()); + } sources.clear(); const size_t big = ALScriptSearch::Sources::MOST / 3 + 1; @@ -520,53 +600,75 @@ namespace tut assets.push_back(LLUUID::generateNewID()); if (i == 2) { - ensure("the first used again", sources.find(refs[0], assets[0]) != nullptr); + UNSCOPED_INFO("the first used again"); + REQUIRE(sources.find(refs[0], assets[0]) != nullptr); } sources.keep(refs[i], assets[i], { std::make_shared(big, 'x'), "big", false }); } - ensure("within the most", sources.bytes() <= ALScriptSearch::Sources::MOST); - ensure("the one used longest ago gone", !sources.find(refs[1], assets[1]) && sources.find(refs[0], assets[0]) && sources.find(refs[2], assets[2])); + UNSCOPED_INFO("within the most"); + CHECK(sources.bytes() <= ALScriptSearch::Sources::MOST); + { + INFO("the one used longest ago gone"); + REQUIRE_FALSE(sources.find(refs[1], assets[1])); + REQUIRE(sources.find(refs[0], assets[0])); + REQUIRE(sources.find(refs[2], assets[2])); + } sources.clear(); } - template <> - template <> - void alscriptsearchpane_object::test<9>() + TEST_CASE_METHOD(alscriptsearchpane_data, "ALScriptSearchPane: a fetched script is sought apart and an earlier search's is dropped", "[ALScriptSearchPane]") { - set_test_name("a fetched script sought apart, still to come until the answer is back; one of an earlier search dropped"); ALScriptSearchPane& out = make(); const ALScriptRef away(LLUUID::generateNewID(), LLUUID::generateNewID()); studio.objects = { { LLUUID::generateNewID(), "Thing", { away } } }; find("timer", "listed"); - ensure_equals("fetched", studio.fetches.size(), size_t(1)); + UNSCOPED_INFO("fetched"); + REQUIRE(studio.fetches.size() == size_t(1)); out.fetched(studio.fetches[0].generation, "Thing", away, "away.lsl", std::make_shared("timer\n"), false); - ensure("sought apart", studio.apart == 1 && out.search().found().size() == 1 && out.search().pending() == 0); + { + INFO("sought apart"); + CHECK(studio.apart == 1); + REQUIRE(out.search().found().size() == 1); + CHECK(out.search().pending() == 0); + } const S32 before = studio.apart; out.fetched(studio.fetches[0].generation + 7, "Thing", away, "away.lsl", std::make_shared("timer\n"), false); - ensure("another search's: not sought", studio.apart == before); + UNSCOPED_INFO("another search's: not sought"); + CHECK(studio.apart == before); } - template <> - template <> - void alscriptsearchpane_object::test<10>() + TEST_CASE_METHOD(alscriptsearchpane_data, "ALScriptSearchPane: inventory search reads open scripts as they stand and fetches the rest", "[ALScriptSearchPane]") { - set_test_name("the inventory searched: a script open here as it stands, the rest fetched; typing in an inventory script searches it again"); ALScriptSearchPane& out = make(); Doc& door = doc("door", "timer here\n"); door.ref = ALScriptRef(LLUUID::null, fresh()); const ALScriptRef away(LLUUID::null, fresh()); studio.inventory = { { door.ref, "door" }, { away, "away.lsl" } }; find("timer", "inventory"); - ensure("the open one as it stands", out.search().found().size() == 1 && out.search().found()[0].doc == door.id); - ensure_equals("the other fetched", studio.fetches.size(), size_t(1)); - ensure("from the inventory", studio.fetches[0].ref == away && studio.fetches[0].where == window.services().words("SearchInventoryWhere")); + { + INFO("the open one as it stands"); + REQUIRE(out.search().found().size() == 1); + CHECK(out.search().found()[0].doc == door.id); + } + UNSCOPED_INFO("the other fetched"); + REQUIRE(studio.fetches.size() == size_t(1)); + { + INFO("from the inventory"); + CHECK(studio.fetches[0].ref == away); + CHECK(studio.fetches[0].where == window.services().words("SearchInventoryWhere")); + } out.fetched(studio.fetches[0].generation, studio.fetches[0].where, away, "away.lsl", std::make_shared("a timer\n"), false); - ensure("both found", out.search().found().size() == 2 && out.search().pending() == 0); + { + INFO("both found"); + REQUIRE(out.search().found().size() == 2); + CHECK(out.search().pending() == 0); + } door.editor->setCaret(ALTextPos(0, 0)); door.editor->insertText("x"); out.typedIn(door); std::this_thread::sleep_for(std::chrono::milliseconds(700)); out.pump(); - ensure_equals("typed in: searched again", out.search().found()[0].places[0].begin.column, 1); + UNSCOPED_INFO("typed in: searched again"); + CHECK(out.search().found()[0].places[0].begin.column == 1); } } diff --git a/indra/newview/tests/alscriptsnippets_test.cpp b/indra/newview/tests/alscriptsnippets_test.cpp index a16945a00a..b699988f23 100644 --- a/indra/newview/tests/alscriptsnippets_test.cpp +++ b/indra/newview/tests/alscriptsnippets_test.cpp @@ -33,7 +33,7 @@ #include "llfile.h" #include "lluuid.h" -#include "../test/lltut.h" +#include #include #include @@ -44,7 +44,7 @@ #include #endif -namespace tut +namespace { struct alscriptsnippets_data { @@ -103,27 +103,30 @@ namespace tut } }; - typedef test_group alscriptsnippets_group; - typedef alscriptsnippets_group::object alscriptsnippets_object; - alscriptsnippets_group alscriptsnippets_instance("alscriptsnippets"); - - template<> template<> - void alscriptsnippets_object::test<1>() + TEST_CASE_METHOD(alscriptsnippets_data, "alscriptsnippets: snippets read back as written and one with no body yet stays out", "[alscriptsnippets]") { - set_test_name("written and read back; one being written, with no body yet, stays out of the file"); const std::string file = folder + "/lsl.xml"; std::vector none; - ensure("no file is no snippets, and nothing wrong", ALScriptSnippets::readFrom(file, false, none) && none.empty()); - ensure("written", ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"$1\");"), snippet("half", "") })); + { + INFO("no file is no snippets, and nothing wrong"); + CHECK(ALScriptSnippets::readFrom(file, false, none)); + REQUIRE(none.empty()); + } + UNSCOPED_INFO("written"); + CHECK(ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"$1\");"), snippet("half", "") })); std::vector back; - ensure("read", ALScriptSnippets::readFrom(file, false, back)); - ensure("the one with a body", back.size() == 1 && back[0].name == "say" && back[0].body == "llSay(0, \"$1\");"); + UNSCOPED_INFO("read"); + REQUIRE(ALScriptSnippets::readFrom(file, false, back)); + { + INFO("the one with a body"); + REQUIRE(back.size() == 1); + CHECK(back[0].name == "say"); + CHECK(back[0].body == "llSay(0, \"$1\");"); + } } - template<> template<> - void alscriptsnippets_object::test<2>() + TEST_CASE_METHOD(alscriptsnippets_data, "alscriptsnippets: a file that does not read is kept beside and not written over", "[alscriptsnippets]") { - set_test_name("a file that does not read as snippets is kept beside, not written over"); const std::string file = folder + "/lsl.xml"; const std::string broken = "namemine "; { @@ -131,32 +134,50 @@ namespace tut out << broken; } std::vector held; - ensure("it does not read", !ALScriptSnippets::readFrom(file, false, held)); - ensure("written all the same", ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"hi\");") })); - ensure("what it held kept, as it was", LLFile::isfile(file + ".unreadable") && read(file + ".unreadable") == broken); + UNSCOPED_INFO("it does not read"); + CHECK_FALSE(ALScriptSnippets::readFrom(file, false, held)); + UNSCOPED_INFO("written all the same"); + CHECK(ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"hi\");") })); + { + INFO("what it held kept, as it was"); + CHECK(LLFile::isfile(file + ".unreadable")); + CHECK(read(file + ".unreadable") == broken); + } std::vector back; - ensure("the new file reads", ALScriptSnippets::readFrom(file, false, back) && back.size() == 1); + { + INFO("the new file reads"); + CHECK(ALScriptSnippets::readFrom(file, false, back)); + REQUIRE(back.size() == 1); + } // Broken again: kept beside the first, which is not written over. { llofstream out(file, std::ios::binary); out << "again"; } - ensure("written", ALScriptSnippets::writeTo(file, { snippet("say", "x") })); - ensure("the first kept still", read(file + ".unreadable") == broken); - ensure("the second beside it", read(file + ".unreadable.1") == "again"); + UNSCOPED_INFO("written"); + CHECK(ALScriptSnippets::writeTo(file, { snippet("say", "x") })); + UNSCOPED_INFO("the first kept still"); + CHECK(read(file + ".unreadable") == broken); + UNSCOPED_INFO("the second beside it"); + CHECK(read(file + ".unreadable.1") == "again"); } - template<> template<> - void alscriptsnippets_object::test<3>() + TEST_CASE_METHOD(alscriptsnippets_data, "alscriptsnippets: a write replaces the file whole and a failed one leaves it as it was", "[alscriptsnippets]") { - set_test_name("written whole in the file's place: nothing is left beside it, and a write that fails leaves the file as it was"); const std::string file = folder + "/lsl.xml"; - ensure("written", ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"one\");") })); + UNSCOPED_INFO("written"); + CHECK(ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"one\");") })); const std::string first = read(file); - ensure("written again, over it", ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"two\");") })); - ensure("replaced", read(file) != first && read(file).find("two") != std::string::npos); - ensure("and nothing half-written beside it", !LLFile::isfile(ALFileWrite::besideOf(file))); + UNSCOPED_INFO("written again, over it"); + CHECK(ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"two\");") })); + { + INFO("replaced"); + CHECK(read(file) != first); + REQUIRE(read(file).find("two") != std::string::npos); + } + UNSCOPED_INFO("and nothing half-written beside it"); + CHECK_FALSE(LLFile::isfile(ALFileWrite::besideOf(file))); // A file that cannot be written is not touched: never opened for // writing and left cut short. Root writes what it likes. @@ -169,18 +190,19 @@ namespace tut const std::string written = read(file); std::error_code ec; std::filesystem::permissions(fsyspath(file), std::filesystem::perms::owner_read, std::filesystem::perm_options::replace, ec); - ensure("a file nothing can be written in", !ec); + UNSCOPED_INFO("a file nothing can be written in"); + REQUIRE_FALSE(ec); const bool wrote = ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"three\");") }); std::filesystem::permissions(fsyspath(file), std::filesystem::perms::owner_read | std::filesystem::perms::owner_write, std::filesystem::perm_options::replace, ec); - ensure("not written", !wrote); - ensure("and the file as it was", read(file) == written); + UNSCOPED_INFO("not written"); + CHECK_FALSE(wrote); + UNSCOPED_INFO("and the file as it was"); + CHECK(read(file) == written); } - template<> template<> - void alscriptsnippets_object::test<4>() + TEST_CASE_METHOD(alscriptsnippets_data, "alscriptsnippets: a notecard carries both languages and passes over keys it does not know", "[alscriptsnippets]") { - set_test_name("a notecard carries both languages and reads back into each; keys it does not know are passed over"); ALScriptSnippets::Snippet say = snippet("say", "llSay(0, \"${1:hello}\");"); say.prefix = "say"; say.detail = "Say something"; @@ -189,15 +211,24 @@ namespace tut const std::string text = ALScriptSnippets::notecardText({ say, builtin, snippet("", "no name") }, { snippet("print", "print(${1})") }); std::vector lsl; std::vector slua; - ensure("read", ALScriptSnippets::readNotecard(text, false, lsl, slua)); - ensure_equals("the LSL one, and not the viewer's or the unnamed", lsl.size(), 1U); - ensure_equals("its name", lsl[0].name, std::string("say")); - ensure_equals("its prefix", lsl[0].prefix, std::string("say")); - ensure_equals("its detail", lsl[0].detail, std::string("Say something")); - ensure_equals("its body", lsl[0].body, say.body); - ensure("not the viewer's", !lsl[0].builtin); - ensure_equals("the SLua one in SLua's", slua.size(), 1U); - ensure_equals("its body", slua[0].body, std::string("print(${1})")); + UNSCOPED_INFO("read"); + REQUIRE(ALScriptSnippets::readNotecard(text, false, lsl, slua)); + UNSCOPED_INFO("the LSL one, and not the viewer's or the unnamed"); + REQUIRE(lsl.size() == 1U); + UNSCOPED_INFO("its name"); + CHECK(lsl[0].name == std::string("say")); + UNSCOPED_INFO("its prefix"); + CHECK(lsl[0].prefix == std::string("say")); + UNSCOPED_INFO("its detail"); + CHECK(lsl[0].detail == std::string("Say something")); + UNSCOPED_INFO("its body"); + CHECK(lsl[0].body == say.body); + UNSCOPED_INFO("not the viewer's"); + CHECK_FALSE(lsl[0].builtin); + UNSCOPED_INFO("the SLua one in SLua's"); + REQUIRE(slua.size() == 1U); + UNSCOPED_INFO("its body"); + CHECK(slua[0].body == std::string("print(${1})")); // Written by hand or by an older viewer: no language, and a key // this one does not know. @@ -205,105 +236,162 @@ namespace tut "colourred"; lsl.clear(); slua.clear(); - ensure("read", ALScriptSnippets::readNotecard(plain, true, lsl, slua)); - ensure("into the language shown", lsl.empty() && slua.size() == 1 && slua[0].name == "loop"); + UNSCOPED_INFO("read"); + CHECK(ALScriptSnippets::readNotecard(plain, true, lsl, slua)); + { + INFO("into the language shown"); + REQUIRE(lsl.empty()); + REQUIRE(slua.size() == 1); + CHECK(slua[0].name == "loop"); + } } - template<> template<> - void alscriptsnippets_object::test<5>() + TEST_CASE_METHOD(alscriptsnippets_data, "alscriptsnippets: a notecard that is not snippets reads as nothing and says so", "[alscriptsnippets]") { - set_test_name("a notecard that is not snippets reads as nothing, and says so"); std::vector lsl; std::vector slua; for (const char* text : { "Dear diary, today I scripted a door.", "namex", "titlex", "", "" }) { - ensure(std::string("not snippets: ") + text, !ALScriptSnippets::readNotecard(text, false, lsl, slua)); - ensure("and nothing added", lsl.empty() && slua.empty()); + UNSCOPED_INFO(std::string("not snippets: ") + text); + REQUIRE_FALSE(ALScriptSnippets::readNotecard(text, false, lsl, slua)); + { + INFO("and nothing added"); + REQUIRE(lsl.empty()); + REQUIRE(slua.empty()); + } } } - template<> template<> - void alscriptsnippets_object::test<6>() + TEST_CASE_METHOD(alscriptsnippets_data, "alscriptsnippets: merge leaves out the same snippet and numbers one whose name is taken", "[alscriptsnippets]") { - set_test_name("brought in beside one's own: the same left out, a name taken by another body numbered, and again left out"); std::vector own = { snippet("say", "llSay(0, \"a\");"), snippet("loop", "for") }; const std::vector incoming = { snippet("say", "llSay(0, \"b\");"), snippet("loop", "for"), snippet("new", "x") }; ALScriptSnippets::Merged merged = ALScriptSnippets::merge(own, incoming); - ensure_equals("one added under its own name", merged.added, 1U); - ensure_equals("one under a number", merged.renamed, 1U); - ensure_equals("one the same", merged.skipped, 1U); - ensure_equals("four now", own.size(), 4U); - ensure_equals("numbered", own[2].name, std::string("say (2)")); - ensure_equals("with its body", own[2].body, std::string("llSay(0, \"b\");")); - ensure_equals("and the new one", own[3].name, std::string("new")); + UNSCOPED_INFO("one added under its own name"); + CHECK(merged.added == 1U); + UNSCOPED_INFO("one under a number"); + CHECK(merged.renamed == 1U); + UNSCOPED_INFO("one the same"); + CHECK(merged.skipped == 1U); + UNSCOPED_INFO("four now"); + REQUIRE(own.size() == 4U); + UNSCOPED_INFO("numbered"); + CHECK(own[2].name == std::string("say (2)")); + UNSCOPED_INFO("with its body"); + CHECK(own[2].body == std::string("llSay(0, \"b\");")); + UNSCOPED_INFO("and the new one"); + CHECK(own[3].name == std::string("new")); // The same notecard again brings nothing in. merged = ALScriptSnippets::merge(own, incoming); - ensure("nothing again", merged.added == 0 && merged.renamed == 0 && merged.skipped == 3); - ensure_equals("still four", own.size(), 4U); + { + INFO("nothing again"); + CHECK(merged.added == 0); + CHECK(merged.renamed == 0); + CHECK(merged.skipped == 3); + } + UNSCOPED_INFO("still four"); + REQUIRE(own.size() == 4U); // A third body takes the next number free. merged = ALScriptSnippets::merge(own, { snippet("say", "llSay(0, \"c\");") }); - ensure_equals("numbered past the taken", own.back().name, std::string("say (3)")); + UNSCOPED_INFO("numbered past the taken"); + CHECK(own.back().name == std::string("say (3)")); } - template<> template<> - void alscriptsnippets_object::test<7>() + TEST_CASE_METHOD(alscriptsnippets_data, "alscriptsnippets: a followed notecard's snippets go to their languages and are never saved", "[alscriptsnippets]") { - set_test_name("a followed notecard's snippets: each in its language, one saying none in both, taken in place of those before; text that is not snippets taken as nothing; never written as one's own"); const std::string text = "" "namesaybodyllSay(0, \"\");languagelsl" "nameloopbodyforlanguageslua" "namebannerbodyx" ""; - ensure("followed", ALScriptSnippets::follow(text)); + UNSCOPED_INFO("followed"); + CHECK(ALScriptSnippets::follow(text)); const std::vector& lsl = ALScriptSnippets::followed(false); const std::vector& slua = ALScriptSnippets::followed(true); - ensure("LSL's and the one saying none", lsl.size() == 2 && lsl[0].name == "say" && lsl[1].name == "banner"); - ensure("SLua's and the one saying none", slua.size() == 2 && slua[0].name == "loop" && slua[1].name == "banner"); - ensure("each the notecard's", lsl[0].followed && lsl[1].followed && slua[0].followed && !lsl[0].builtin); + { + INFO("LSL's and the one saying none"); + REQUIRE(lsl.size() == 2); + CHECK(lsl[0].name == "say"); + CHECK(lsl[1].name == "banner"); + } + { + INFO("SLua's and the one saying none"); + REQUIRE(slua.size() == 2); + CHECK(slua[0].name == "loop"); + CHECK(slua[1].name == "banner"); + } + { + INFO("each the notecard's"); + CHECK(lsl[0].followed); + CHECK(lsl[1].followed); + CHECK(slua[0].followed); + CHECK_FALSE(lsl[0].builtin); + } - ensure("not snippets: not taken", !ALScriptSnippets::follow("Dear diary")); - ensure("those before stay", ALScriptSnippets::followed(false).size() == 2); + UNSCOPED_INFO("not snippets: not taken"); + CHECK_FALSE(ALScriptSnippets::follow("Dear diary")); + UNSCOPED_INFO("those before stay"); + REQUIRE(ALScriptSnippets::followed(false).size() == 2); // Never written where the scripter's own are, nor carried by their // notecard; copied in, one's own. const std::string file = folder + "/lsl.xml"; - ensure("written", ALScriptSnippets::writeTo(file, { snippet("mine", "y"), lsl[0] })); + UNSCOPED_INFO("written"); + CHECK(ALScriptSnippets::writeTo(file, { snippet("mine", "y"), lsl[0] })); std::vector back; - ensure("read", ALScriptSnippets::readFrom(file, false, back)); - ensure("one's own alone", back.size() == 1 && back[0].name == "mine"); - ensure("not on one's notecard", ALScriptSnippets::notecardText(lsl, {}).find("banner") == std::string::npos); + UNSCOPED_INFO("read"); + REQUIRE(ALScriptSnippets::readFrom(file, false, back)); + { + INFO("one's own alone"); + REQUIRE(back.size() == 1); + CHECK(back[0].name == "mine"); + } + UNSCOPED_INFO("not on one's notecard"); + REQUIRE(ALScriptSnippets::notecardText(lsl, {}).find("banner") == std::string::npos); std::vector own; ALScriptSnippets::merge(own, { lsl[1] }); - ensure("copied in: one's own", own.size() == 1 && !own[0].followed); + { + INFO("copied in: one's own"); + REQUIRE(own.size() == 1); + CHECK_FALSE(own[0].followed); + } - ensure("none followed", ALScriptSnippets::follow(std::string())); - ensure("none left", ALScriptSnippets::followed(false).empty() && ALScriptSnippets::followed(true).empty()); + UNSCOPED_INFO("none followed"); + CHECK(ALScriptSnippets::follow(std::string())); + { + INFO("none left"); + REQUIRE(ALScriptSnippets::followed(false).empty()); + REQUIRE(ALScriptSnippets::followed(true).empty()); + } } - template<> template<> - void alscriptsnippets_object::test<8>() + TEST_CASE_METHOD(alscriptsnippets_data, "alscriptsnippets: every shipped snippet expands with whole stops and no placeholder left", "[alscriptsnippets]") { - set_test_name("every snippet the viewer ships expands whole: each stop over all of what its placeholder holds, no bracket of it left " - "outside, and nothing of a placeholder left in the text"); for (const char* language : { "lsl.xml", "slua.xml" }) { const std::string file = std::string(LLUI_TEST_APP_DIR) + "/app_settings/snippets/" + language; std::vector shipped; - ensure(std::string("read: ") + file, ALScriptSnippets::readFrom(file, true, shipped) && !shipped.empty()); + { + INFO(std::string("read: ") + file); + REQUIRE(ALScriptSnippets::readFrom(file, true, shipped)); + REQUIRE_FALSE(shipped.empty()); + } for (const ALScriptSnippets::Snippet& one : shipped) { const std::string named = std::string(language) + ", " + one.name; const ALSnippetSession::Expansion expanded = ALSnippetSession::expand(one.body, ALTextPos(0, 0), std::string()); const ALTextDocument text(expanded.text); - ensure(named + ": no placeholder left in " + expanded.text, expanded.text.find("${") == std::string::npos); + UNSCOPED_INFO(named + ": no placeholder left in " + expanded.text); + REQUIRE(expanded.text.find("${") == std::string::npos); for (size_t i = 0; i < expanded.stops.size(); ++i) { const std::string held = text.text(expanded.stops[i]); - ensure(named + ": stop " + std::to_string(i + 1) + " holds the whole of its text, not \"" + held + "\"", whole(held)); + UNSCOPED_INFO(named + ": stop " + std::to_string(i + 1) + " holds the whole of its text, not \"" + held + "\""); + REQUIRE(whole(held)); } } } diff --git a/indra/newview/tests/alscriptstudioaccount_test.cpp b/indra/newview/tests/alscriptstudioaccount_test.cpp index 06d4bec17e..84521e3ad8 100644 --- a/indra/newview/tests/alscriptstudioaccount_test.cpp +++ b/indra/newview/tests/alscriptstudioaccount_test.cpp @@ -27,21 +27,12 @@ #include "../alscriptstudioaccount.h" -#include "../test/lltut.h" +#include -namespace tut +namespace { - struct alscriptstudioaccount_data + TEST_CASE("alscriptstudioaccount: split takes the account's own out of the state and drops what it lost", "[alscriptstudioaccount]") { - }; - typedef test_group alscriptstudioaccount_group; - typedef alscriptstudioaccount_group::object alscriptstudioaccount_object; - alscriptstudioaccount_group alscriptstudioaccount_instance("alscriptstudioaccount"); - - template<> template<> - void alscriptstudioaccount_object::test<1>() - { - set_test_name("the account's own taken out of a state written whole, the shape and switches left shared; a key it no longer has taken out of the account's too"); LLSD state; state["rect"] = LLSD().with(0, 1).with(1, 2); state["open"]["tabs"] = LLSD::emptyArray(); @@ -51,27 +42,47 @@ namespace tut LLSD mine; mine["windows"] = LLSD().with(0, "w"); ALScriptStudioAccount::split(state, mine); - ensure("out of the shared", !state.has("open") && !state.has("pinned") && !state.has("recent_scripts")); - ensure("the shape, the switches and the files left", state.has("rect") && state.has("recent_files")); - ensure("into the account's", mine.has("open") && mine["pinned"][0].asString() == "a" && mine["recent_scripts"][0].asString() == "s"); - ensure("what the state no longer has, gone from the account's", !mine.has("windows")); + { + INFO("out of the shared"); + REQUIRE_FALSE(state.has("open")); + REQUIRE_FALSE(state.has("pinned")); + REQUIRE_FALSE(state.has("recent_scripts")); + } + { + INFO("the shape, the switches and the files left"); + REQUIRE(state.has("rect")); + REQUIRE(state.has("recent_files")); + } + { + INFO("into the account's"); + REQUIRE(mine.has("open")); + CHECK(mine["pinned"][0].asString() == "a"); + CHECK(mine["recent_scripts"][0].asString() == "s"); + } + UNSCOPED_INFO("what the state no longer has, gone from the account's"); + REQUIRE_FALSE(mine.has("windows")); } - template<> template<> - void alscriptstudioaccount_object::test<2>() + TEST_CASE("alscriptstudioaccount: merged lays the account's own over the shared once it has kept any", "[alscriptstudioaccount]") { - set_test_name("read: the account's own over the shared where it has kept any, a key it has not taken out; the shared as it was where it has kept none"); LLSD shared; shared["rect"] = 1; shared["open"] = "old tabs"; shared["pinned"] = "old pins"; const LLSD first = ALScriptStudioAccount::merged(shared, LLSD()); - ensure("none kept yet: the shared taken over", first["open"].asString() == "old tabs" && first["pinned"].asString() == "old pins"); + { + INFO("none kept yet: the shared taken over"); + CHECK(first["open"].asString() == "old tabs"); + CHECK(first["pinned"].asString() == "old pins"); + } LLSD mine; mine["open"] = "my tabs"; const LLSD read = ALScriptStudioAccount::merged(shared, mine); - ensure("its own", read["open"].asString() == "my tabs"); - ensure("another account's pins not seen", !read.has("pinned")); - ensure("the shape shared", read["rect"].asInteger() == 1); + UNSCOPED_INFO("its own"); + CHECK(read["open"].asString() == "my tabs"); + UNSCOPED_INFO("another account's pins not seen"); + REQUIRE_FALSE(read.has("pinned")); + UNSCOPED_INFO("the shape shared"); + CHECK(read["rect"].asInteger() == 1); } } diff --git a/indra/newview/tests/alscriptstudiocaret_test.cpp b/indra/newview/tests/alscriptstudiocaret_test.cpp index d2cf37b7db..f2f91fb4e5 100644 --- a/indra/newview/tests/alscriptstudiocaret_test.cpp +++ b/indra/newview/tests/alscriptstudiocaret_test.cpp @@ -32,7 +32,7 @@ #include "alscriptstudio_fixture.h" #include "llfocusmgr.h" -#include "../test/lltut.h" +#include #include @@ -134,7 +134,7 @@ namespace const std::string SCRIPT = "integer count;\ndefault { state_entry() { count = 1; llSay(0, \"x\"); } }\n"; } -namespace tut +namespace { struct alscriptstudiocaret_data { @@ -166,7 +166,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } navigation = std::make_unique(services); lookup = std::make_unique(services, navigation->unit); @@ -199,50 +199,62 @@ namespace tut } }; - typedef test_group alscriptstudiocaret_group; - typedef alscriptstudiocaret_group::object alscriptstudiocaret_object; - alscriptstudiocaret_group alscriptstudiocaret_instance("alscriptstudiocaret"); - - template<> template<> - void alscriptstudiocaret_object::test<1>() + TEST_CASE_METHOD(alscriptstudiocaret_data, "alscriptstudiocaret: go to definition jumps or says there is none and drops stale answers", "[alscriptstudiocaret]") { - set_test_name("a definition asked for: gone to in the script, said where there is none, and an answer to another question dropped"); ALScriptStudioCaret& caret = make(); Doc& doc = tab("a"); const U32 v = ask(doc, ALEditorCommand::GoToDefinition); - ensure_equals("asked", joined(studio.asked), std::string("references 0:8")); - ensure("remembered", doc.caret->symbolCommand == ALEditorCommand::GoToDefinition && doc.caret->symbolVersion == v); + UNSCOPED_INFO("asked"); + CHECK(joined(studio.asked) == std::string("references 0:8")); + { + INFO("remembered"); + REQUIRE(doc.caret->symbolCommand == ALEditorCommand::GoToDefinition); + CHECK(doc.caret->symbolVersion == v); + } caret.answered(doc, references(v + 1), ALTextPos(0, 8)); caret.answered(doc, references(v), ALTextPos(0, 9)); - ensure("of another text or place: nothing", studio.said.empty()); + UNSCOPED_INFO("of another text or place: nothing"); + REQUIRE(studio.said.empty()); caret.answered(doc, references(v), ALTextPos(0, 8)); - ensure_equals("gone", joined(studio.said), std::string("go a 0:8-0:13")); - ensure_equals("a jump noted, for Back", navigation->unit.places(false), size_t(1)); + UNSCOPED_INFO("gone"); + CHECK(joined(studio.said) == std::string("go a 0:8-0:13")); + UNSCOPED_INFO("a jump noted, for Back"); + CHECK(navigation->unit.places(false) == size_t(1)); caret.answered(doc, references(v), ALTextPos(0, 8)); - ensure("answered once", studio.said.size() == 1 && navigation->unit.places(false) == 1); + { + INFO("answered once"); + REQUIRE(studio.said.size() == 1); + CHECK(navigation->unit.places(false) == 1); + } ask(doc, ALEditorCommand::GoToDefinition); caret.answered(doc, references(v, false), ALTextPos(0, 8)); - ensure("none: said, no jump", studio.said.size() == 1 && navigation->unit.places(false) == 1 && - services.statuses.back().find("NoDefinition [NAME]=count") == 0); + { + INFO("none: said, no jump"); + REQUIRE(studio.said.size() == 1); + CHECK(navigation->unit.places(false) == 1); + CHECK(services.statuses.back().find("NoDefinition [NAME]=count") == 0); + } ask(doc, ALEditorCommand::GoToDefinition); ALScriptAnalysis::Result none; none.version = v; none.understood = true; caret.answered(doc, none, ALTextPos(0, 8)); - ensure_equals("nothing known of it", services.statuses.back(), std::string("NothingKnown [NAME]=count")); - ensure("not a failure", !services.statusFailures.back()); + UNSCOPED_INFO("nothing known of it"); + CHECK(services.statuses.back() == std::string("NothingKnown [NAME]=count")); + UNSCOPED_INFO("not a failure"); + REQUIRE_FALSE(services.statusFailures.back()); ask(doc, ALEditorCommand::FindReferences); none.understood = false; caret.answered(doc, none, ALTextPos(0, 8)); - ensure_equals("nothing read", services.statuses.back(), std::string("NothingKnownBroken [NAME]=count")); - ensure("a failure", services.statusFailures.back()); + UNSCOPED_INFO("nothing read"); + CHECK(services.statuses.back() == std::string("NothingKnownBroken [NAME]=count")); + UNSCOPED_INFO("a failure"); + REQUIRE(services.statusFailures.back()); } - template<> template<> - void alscriptstudiocaret_object::test<2>() + TEST_CASE_METHOD(alscriptstudiocaret_data, "alscriptstudiocaret: a language word shows its reference unless the script defines it", "[alscriptstudiocaret]") { - set_test_name("a word of the language with no definition of the script's: its reference; one the script defines, gone to"); ALScriptStudioCaret& caret = make(); Doc& doc = tab("a"); const U32 v = doc.editor->document().version(); @@ -251,21 +263,25 @@ namespace tut result.version = v; result.understood = true; caret.answered(doc, result, ALTextPos(1, 37)); - ensure_equals("the reference", joined(studio.said), std::string("reference llSay")); + UNSCOPED_INFO("the reference"); + CHECK(joined(studio.said) == std::string("reference llSay")); caret.ask(doc, ALEditorCommand::FindReferences, ALTextRange(ALTextPos(1, 37), ALTextPos(1, 42))); caret.answered(doc, result, ALTextPos(1, 37)); - ensure("finding it: not", studio.said.size() == 1 && services.statuses.back().find("NothingKnown") == 0); + { + INFO("finding it: not"); + REQUIRE(studio.said.size() == 1); + CHECK(services.statuses.back().find("NothingKnown") == 0); + } caret.ask(doc, ALEditorCommand::GoToDefinition, ALTextRange(ALTextPos(1, 37), ALTextPos(1, 42))); ALScriptAnalysis::Result own = references(v); own.references.name = "llSay"; caret.answered(doc, own, ALTextPos(1, 37)); - ensure_equals("the script's own", studio.said.back(), std::string("go a 0:8-0:13")); + UNSCOPED_INFO("the script's own"); + CHECK(studio.said.back() == std::string("go a 0:8-0:13")); } - template<> template<> - void alscriptstudiocaret_object::test<3>() + TEST_CASE_METHOD(alscriptstudiocaret_data, "alscriptstudiocaret: through the expansion an include's definition and places map back", "[alscriptstudiocaret]") { - set_test_name("through the expansion: declared in an include, opened there; each place read back, in the script or the include"); ALScriptStudioCaret& caret = make(); Doc& doc = tab("a"); studio.expanded = true; @@ -289,85 +305,135 @@ namespace tut doc.expanded.version = v; ALScriptAnalysis::Result result = references(v); caret.answered(doc, result, ALTextPos(0, 8)); - ensure_equals("opened in the include", joined(studio.said), std::string("open disk:/inc.lsl inc.lsl 4:8+5")); - ensure_equals("a jump noted", navigation->unit.places(false), size_t(1)); + UNSCOPED_INFO("opened in the include"); + CHECK(joined(studio.said) == std::string("open disk:/inc.lsl inc.lsl 4:8+5")); + UNSCOPED_INFO("a jump noted"); + CHECK(navigation->unit.places(false) == size_t(1)); ask(doc, ALEditorCommand::FindReferences); result.references.references = { span(0, 8, 5), span(2, 26, 5), span(7, 0, 5) }; caret.answered(doc, result, ALTextPos(0, 8)); - ensure_equals("the lookup started", started(doc), "find in a declared disk:/inc.lsl@4 v" + std::to_string(v)); - ensure_equals("the places that map", doc.lookup->places.size(), size_t(2)); + UNSCOPED_INFO("the lookup started"); + CHECK(started(doc) == "find in a declared disk:/inc.lsl@4 v" + std::to_string(v)); + UNSCOPED_INFO("the places that map"); + REQUIRE(doc.lookup->places.size() == size_t(2)); const Doc::Place* included = placeIn(doc, "disk:/inc.lsl"); - ensure("the include's, as held", included && included->fileName == "inc.lsl" && included->text == "integer count; // held" && included->at == 6); + { + INFO("the include's, as held"); + REQUIRE(included); + REQUIRE(included->fileName == "inc.lsl"); + REQUIRE(included->text == "integer count; // held"); + CHECK(included->at == 6); + } const Doc::Place* own = placeIn(doc, std::string()); - ensure("the script's own, as typed", own && own->span.line == 1 && own->at == 26); + { + INFO("the script's own, as typed"); + REQUIRE(own); + REQUIRE(own->span.line == 1); + CHECK(own->at == 26); + } studio.held.clear(); ask(doc, ALEditorCommand::Rename); caret.answered(doc, result, ALTextPos(0, 8)); included = placeIn(doc, "disk:/inc.lsl"); - ensure("the include not held: the expansion's line", included && included->text == "integer count;" && included->at == -1); - ensure_equals("where the include has it", included->span.line, 4); - ensure("to rename", started(doc).find("rename in a") == 0); + { + INFO("the include not held: the expansion's line"); + REQUIRE(included); + REQUIRE(included->text == "integer count;"); + CHECK(included->at == -1); + } + UNSCOPED_INFO("where the include has it"); + CHECK(included->span.line == 4); + UNSCOPED_INFO("to rename"); + CHECK(started(doc).find("rename in a") == 0); doc.expanded.version = v + 7; ask(doc, ALEditorCommand::FindReferences); caret.answered(doc, result, ALTextPos(0, 8)); - ensure_equals("an expansion of another text: not read through", started(doc), "find in a declared @0 v" + std::to_string(v)); - ensure("its places as they are", doc.lookup->places.size() == 3 && placeIn(doc, std::string(), 7)); + UNSCOPED_INFO("an expansion of another text: not read through"); + CHECK(started(doc) == "find in a declared @0 v" + std::to_string(v)); + { + INFO("its places as they are"); + REQUIRE(doc.lookup->places.size() == 3); + REQUIRE(placeIn(doc, std::string(), 7)); + } doc.expanded.version = v; ask(doc, ALEditorCommand::GoToDefinition); result.references.definition = span(7, 0, 5); const size_t said = studio.said.size(); caret.answered(doc, result, ALTextPos(0, 8)); - ensure("declared where no source is: none", studio.said.size() == said && services.statuses.back().find("NoDefinition") == 0); + { + INFO("declared where no source is: none"); + REQUIRE(studio.said.size() == said); + CHECK(services.statuses.back().find("NoDefinition") == 0); + } } - template<> template<> - void alscriptstudiocaret_object::test<4>() + TEST_CASE_METHOD(alscriptstudiocaret_data, "alscriptstudiocaret: the watched caret tells its path and asks the inspector once settled", "[alscriptstudiocaret]") { - set_test_name("the caret watched: the path told as it moves, the lit places put out once it leaves them, the inspector once it settles"); ALScriptStudioCaret& caret = make(); caret.pump(10.0); Doc& doc = tab("a"); doc.editor->setCaret(ALTextPos(0, 10)); doc.editor->setHighlights(ALCodeEditor::Highlight::References, { ALTextRange(ALTextPos(0, 8), ALTextPos(0, 13)), ALTextRange(ALTextPos(1, 26), ALTextPos(1, 31)) }); caret.pump(10.0); - ensure_equals("told", joined(studio.said), std::string("path 0:10")); - ensure("the places kept while it is on one", doc.editor->highlights().size() == 2); + UNSCOPED_INFO("told"); + CHECK(joined(studio.said) == std::string("path 0:10")); + UNSCOPED_INFO("the places kept while it is on one"); + REQUIRE(doc.editor->highlights().size() == 2); caret.pump(10.2); - ensure("not yet settled", studio.asked.empty() && studio.said.size() == 1); + { + INFO("not yet settled"); + REQUIRE(studio.asked.empty()); + REQUIRE(studio.said.size() == 1); + } caret.pump(10.0 + ALScriptStudioCaret::SETTLE); - ensure_equals("settled: asked", joined(studio.asked), std::string("inspect 0:8")); - ensure("remembered", doc.caret->inspectAt == ALTextPos(0, 8) && doc.caret->inspectVersion == doc.editor->document().version()); + UNSCOPED_INFO("settled: asked"); + CHECK(joined(studio.asked) == std::string("inspect 0:8")); + { + INFO("remembered"); + REQUIRE(doc.caret->inspectAt == ALTextPos(0, 8)); + CHECK(doc.caret->inspectVersion == doc.editor->document().version()); + } doc.editor->setCaret(ALTextPos(0, 12)); caret.pump(20.0); caret.pump(21.0); - ensure("the same name: not again", studio.asked.size() == 1 && studio.said.size() == 2); + { + INFO("the same name: not again"); + REQUIRE(studio.asked.size() == 1); + REQUIRE(studio.said.size() == 2); + } doc.editor->insertText("s"); caret.pump(30.0); caret.pump(31.0); - ensure_equals("typed in: again", studio.asked.size(), size_t(2)); + UNSCOPED_INFO("typed in: again"); + REQUIRE(studio.asked.size() == size_t(2)); doc.editor->setCaret(ALTextPos(1, 9)); caret.pump(40.0); - ensure("left the lit places: put out", doc.editor->highlights().empty()); + UNSCOPED_INFO("left the lit places: put out"); + REQUIRE(doc.editor->highlights().empty()); caret.pump(41.0); - ensure("on no name: the problems", studio.said.back() == "problems 1:9" && doc.caret->inspectAt == ALTextPos(0, 8)); + { + INFO("on no name: the problems"); + CHECK(studio.said.back() == "problems 1:9"); + CHECK(doc.caret->inspectAt == ALTextPos(0, 8)); + } const size_t said = studio.said.size(); caret.pump(42.0); - ensure_equals("told once, not every frame", studio.said.size(), said); + UNSCOPED_INFO("told once, not every frame"); + REQUIRE(studio.said.size() == said); studio.problems = true; doc.editor->setCaret(ALTextPos(1, 8)); caret.pump(50.0); caret.pump(51.0); - ensure("some shown: the name forgotten", doc.caret->inspectAt == ALTextPos(-1, -1)); + UNSCOPED_INFO("some shown: the name forgotten"); + CHECK(doc.caret->inspectAt == ALTextPos(-1, -1)); } - template<> template<> - void alscriptstudiocaret_object::test<5>() + TEST_CASE_METHOD(alscriptstudiocaret_data, "alscriptstudiocaret: unloaded tabs and notecards are skipped and the expansion not inspected", "[alscriptstudiocaret]") { - set_test_name("not watched with no tab, one not loaded or a notecard; the expansion in front told nothing; the keyboard in the text told"); ALScriptStudioCaret& caret = make(); Doc& doc = tab("a"); doc.loaded = false; @@ -375,47 +441,55 @@ namespace tut doc.loaded = true; doc.notecard = true; caret.pump(1.0); - ensure("nothing", studio.said.empty()); + UNSCOPED_INFO("nothing"); + REQUIRE(studio.said.empty()); doc.notecard = false; doc.expandedEditor = editor("expanded_a", "integer count;\n"); doc.view = Doc::View::Expanded; doc.expandedEditor->setCaret(ALTextPos(0, 3)); caret.pump(1.0); caret.pump(9.0); - ensure_equals("the expansion's caret, the path told", joined(studio.said), std::string("path 0:0")); - ensure("the inspector not", studio.asked.empty() && doc.caret->inspectDue == 0.0); + UNSCOPED_INFO("the expansion's caret, the path told"); + CHECK(joined(studio.said) == std::string("path 0:0")); + { + INFO("the inspector not"); + REQUIRE(studio.asked.empty()); + CHECK(doc.caret->inspectDue == 0.0); + } navigation->unit.noteJump(true); caret.pump(9.2); - ensure("a walk down a list goes on while the text has no keyboard", navigation->unit.walking()); + UNSCOPED_INFO("a walk down a list goes on while the text has no keyboard"); + CHECK(navigation->unit.walking()); doc.expandedEditor->setFocus(true); caret.pump(9.5); - ensure("and ends once it has", !navigation->unit.walking()); + UNSCOPED_INFO("and ends once it has"); + CHECK_FALSE(navigation->unit.walking()); } - template<> template<> - void alscriptstudiocaret_object::test<6>() + TEST_CASE_METHOD(alscriptstudiocaret_data, "alscriptstudiocaret: a folded inspector is asked nothing until it is brought out", "[alscriptstudiocaret]") { - set_test_name("with the inspector folded away nothing is asked as the caret settles; brought out, what is at the caret is asked"); ALScriptStudioCaret& caret = make(); Doc& doc = tab("a"); studio.inspector = false; doc.editor->setCaret(ALTextPos(0, 10)); caret.pump(10.0); caret.pump(10.0 + ALScriptStudioCaret::SETTLE); - ensure("folded: nothing asked", studio.asked.empty()); + UNSCOPED_INFO("folded: nothing asked"); + REQUIRE(studio.asked.empty()); caret.pump(20.0); - ensure("still nothing", studio.asked.empty()); + UNSCOPED_INFO("still nothing"); + REQUIRE(studio.asked.empty()); studio.inspector = true; caret.pump(21.0); - ensure_equals("brought out: asked", joined(studio.asked), std::string("inspect 0:8")); + UNSCOPED_INFO("brought out: asked"); + CHECK(joined(studio.asked) == std::string("inspect 0:8")); caret.pump(22.0); - ensure_equals("once", studio.asked.size(), size_t(1)); + UNSCOPED_INFO("once"); + REQUIRE(studio.asked.size() == size_t(1)); } - template<> template<> - void alscriptstudiocaret_object::test<7>() + TEST_CASE_METHOD(alscriptstudiocaret_data, "alscriptstudiocaret: the caret's path changes on a new symbol or a new outline", "[alscriptstudiocaret]") { - set_test_name("the caret's path found once for both panes: changed where it moves into another symbol, or the outline is made again"); ALScriptStudioCaret& caret = make(); Doc& doc = tab("a"); ALScriptOutlineEntry state; @@ -429,52 +503,74 @@ namespace tut doc.outline = { state, event }; doc.editor->setCaret(ALTextPos(1, 12)); caret.placePath(doc); - ensure("in both", doc.caret->crumbPath == std::vector({ 0, 1 }) && studio.said.back() == "path 1:12 changed"); + { + INFO("in both"); + CHECK(doc.caret->crumbPath == std::vector({ 0, 1 })); + CHECK(studio.said.back() == "path 1:12 changed"); + } doc.editor->setCaret(ALTextPos(1, 14)); caret.placePath(doc); - ensure_equals("the same symbols: shown, not changed", studio.said.back(), std::string("path 1:14")); + UNSCOPED_INFO("the same symbols: shown, not changed"); + CHECK(studio.said.back() == std::string("path 1:14")); doc.editor->setCaret(ALTextPos(1, 2)); caret.placePath(doc); - ensure("out of the event: changed", doc.caret->crumbPath == std::vector({ 0 }) && studio.said.back() == "path 1:2 changed"); + { + INFO("out of the event: changed"); + CHECK(doc.caret->crumbPath == std::vector({ 0 })); + CHECK(studio.said.back() == "path 1:2 changed"); + } ++doc.check->analysisVersion; caret.placePath(doc); - ensure_equals("a new outline: changed", studio.said.back(), std::string("path 1:2 changed")); + UNSCOPED_INFO("a new outline: changed"); + CHECK(studio.said.back() == std::string("path 1:2 changed")); doc.expandedEditor = editor("expanded_a", "integer count;\n"); doc.view = Doc::View::Expanded; caret.placePath(doc); - ensure("the expansion in front: no path", doc.caret->crumbPath.empty()); + UNSCOPED_INFO("the expansion in front: no path"); + REQUIRE(doc.caret->crumbPath.empty()); } - template<> template<> - void alscriptstudiocaret_object::test<8>() + TEST_CASE_METHOD(alscriptstudiocaret_data, "alscriptstudiocaret: seeAfresh and inspectAfresh and inspect tell the window again", "[alscriptstudiocaret]") { - set_test_name("the caret as the window asks: seen afresh and told again where it has not moved; the inspector told again, or now"); ALScriptStudioCaret& caret = make(); Doc& doc = tab("a"); doc.editor->setCaret(ALTextPos(0, 10)); caret.pump(10.0); caret.pump(10.0 + ALScriptStudioCaret::SETTLE); - ensure("told, and asked", studio.said.size() == 1 && studio.asked.size() == 1); + { + INFO("told, and asked"); + REQUIRE(studio.said.size() == 1); + REQUIRE(studio.asked.size() == 1); + } caret.pump(20.0); - ensure("not again where it stands", studio.said.size() == 1); + UNSCOPED_INFO("not again where it stands"); + REQUIRE(studio.said.size() == 1); ALScriptStudioCaret::seeAfresh(doc); caret.pump(30.0); caret.pump(30.0 + ALScriptStudioCaret::SETTLE); - ensure("seen afresh: told again, the inspector not, of the same word", studio.said.size() == 2 && studio.asked.size() == 1); + { + INFO("seen afresh: told again, the inspector not, of the same word"); + REQUIRE(studio.said.size() == 2); + REQUIRE(studio.asked.size() == 1); + } ALScriptStudioCaret::seeAfresh(doc); ALScriptStudioCaret::inspectAfresh(doc); caret.pump(40.0); caret.pump(40.0 + ALScriptStudioCaret::SETTLE); - ensure_equals("the inspector told again", joined(studio.asked), std::string("inspect 0:8, inspect 0:8")); + UNSCOPED_INFO("the inspector told again"); + CHECK(joined(studio.asked) == std::string("inspect 0:8, inspect 0:8")); caret.inspect(doc, ALTextPos(1, 26)); - ensure_equals("told now of a word", studio.asked.back(), std::string("inspect 1:26")); - ensure("which is what it was last told", doc.caret->inspectAt == ALTextPos(1, 26) && doc.caret->inspectDue == 0.0); + UNSCOPED_INFO("told now of a word"); + CHECK(studio.asked.back() == std::string("inspect 1:26")); + { + INFO("which is what it was last told"); + REQUIRE(doc.caret->inspectAt == ALTextPos(1, 26)); + CHECK(doc.caret->inspectDue == 0.0); + } } - template<> template<> - void alscriptstudiocaret_object::test<9>() + TEST_CASE_METHOD(alscriptstudiocaret_data, "alscriptstudiocaret: a definition in a required module opens through the module's map", "[alscriptstudiocaret]") { - set_test_name("declared in a module the script requires, which the analyzers read apart: opened there, through the module's own map"); ALScriptStudioCaret& caret = make(); Doc& doc = tab("a"); studio.expanded = true; @@ -507,25 +603,33 @@ namespace tut result.references.definitionFile = "disk:/lib/util.luau"; result.references.references = { span(1, 8, 5) }; caret.answered(doc, result, ALTextPos(0, 8)); - ensure_equals("opened in the module", joined(studio.said), std::string("open disk:/lib/util.luau util.luau 3:11+5")); - ensure_equals("a jump noted", navigation->unit.places(false), size_t(1)); + UNSCOPED_INFO("opened in the module"); + CHECK(joined(studio.said) == std::string("open disk:/lib/util.luau util.luau 3:11+5")); + UNSCOPED_INFO("a jump noted"); + CHECK(navigation->unit.places(false) == size_t(1)); ask(doc, ALEditorCommand::GoToDefinition); result.references.definitionFile = "disk:/lib/gone.luau"; caret.answered(doc, result, ALTextPos(0, 8)); - ensure("a module the expansion has not: none", studio.said.size() == 1 && services.statuses.back().find("NoDefinition") == 0); + { + INFO("a module the expansion has not: none"); + REQUIRE(studio.said.size() == 1); + CHECK(services.statuses.back().find("NoDefinition") == 0); + } ask(doc, ALEditorCommand::GoToDefinition); result.references.definitionFile = "disk:/lib/util.luau"; doc.expanded.version = v + 3; caret.answered(doc, result, ALTextPos(0, 8)); - ensure("an expansion of another text: none", studio.said.size() == 1 && services.statuses.back().find("NoDefinition") == 0); + { + INFO("an expansion of another text: none"); + REQUIRE(studio.said.size() == 1); + CHECK(services.statuses.back().find("NoDefinition") == 0); + } } - template<> template<> - void alscriptstudiocaret_object::test<10>() + TEST_CASE_METHOD(alscriptstudiocaret_data, "alscriptstudiocaret: a name's places in required modules map back to each module's file", "[alscriptstudiocaret]") { - set_test_name("a name's places in the modules the script requires, read apart: each back in its file, as the file reads where it is held, else as the module's text"); ALScriptStudioCaret& caret = make(); Doc& doc = tab("a"); studio.expanded = true; @@ -568,18 +672,36 @@ namespace tut result.references.references = { span(1, 26, 5) }; result.references.elsewhere = { { "held", span(4, 8, 5) }, { "other", span(1, 12, 5) }, { "gone", span(0, 0, 5) } }; caret.answered(doc, result, ALTextPos(0, 8)); - ensure_equals("declared in the held module", started(doc), "find in a declared disk:/held.luau@4 v" + std::to_string(v)); - ensure_equals("the script's, each module's; none of a module not had", doc.lookup->places.size(), size_t(3)); + UNSCOPED_INFO("declared in the held module"); + CHECK(started(doc) == "find in a declared disk:/held.luau@4 v" + std::to_string(v)); + UNSCOPED_INFO("the script's, each module's; none of a module not had"); + REQUIRE(doc.lookup->places.size() == size_t(3)); const Doc::Place* held = placeIn(doc, "disk:/held.luau"); - ensure("as the file reads", held && held->fileName == "held.luau" && held->text == "integer count; // held" && held->at == 6); + { + INFO("as the file reads"); + REQUIRE(held); + REQUIRE(held->fileName == "held.luau"); + REQUIRE(held->text == "integer count; // held"); + CHECK(held->at == 6); + } const Doc::Place* other = placeIn(doc, "disk:/other.luau"); - ensure("as the module's text read, the name not placed", other && other->fileName == "other.luau" && - other->text == "return util.count" && other->at == -1); - ensure("in the module's lines", other->span.line == 1 && other->span.column == 12); + { + INFO("as the module's text read, the name not placed"); + REQUIRE(other); + REQUIRE(other->fileName == "other.luau"); + REQUIRE(other->text == "return util.count"); + CHECK(other->at == -1); + } + { + INFO("in the module's lines"); + REQUIRE(other->span.line == 1); + CHECK(other->span.column == 12); + } doc.expanded.version = v + 1; ask(doc, ALEditorCommand::FindReferences); caret.answered(doc, result, ALTextPos(0, 8)); - ensure_equals("an expansion of another text: the script's alone", doc.lookup->places.size(), size_t(1)); + UNSCOPED_INFO("an expansion of another text: the script's alone"); + REQUIRE(doc.lookup->places.size() == size_t(1)); } } diff --git a/indra/newview/tests/alscriptstudiochecking_test.cpp b/indra/newview/tests/alscriptstudiochecking_test.cpp index 3f07e83499..4e052971c2 100644 --- a/indra/newview/tests/alscriptstudiochecking_test.cpp +++ b/indra/newview/tests/alscriptstudiochecking_test.cpp @@ -40,7 +40,7 @@ #include "alscriptstudio_fixture.h" #include "llfocusmgr.h" -#include "../test/lltut.h" +#include #include #include @@ -231,7 +231,7 @@ namespace }; } -namespace tut +namespace { struct alscriptstudiochecking_data { @@ -286,7 +286,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } weighing = std::make_unique(services); unit = std::make_unique(services, studio, studio, weighing->unit, studio); @@ -356,37 +356,50 @@ namespace tut } }; - typedef test_group alscriptstudiochecking_group; - typedef alscriptstudiochecking_group::object alscriptstudiochecking_object; - alscriptstudiochecking_group alscriptstudiochecking_instance("alscriptstudiochecking"); - - template<> template<> - void alscriptstudiochecking_object::test<1>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: a check waits for typing to rest then asks of the text as it stands", "[alscriptstudiochecking]") { - set_test_name("a check waits while typing goes on and is asked once it rests, of the text as it stands, with the window's settings"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); checking.schedule(doc); const F64 due = doc.check->analysisDue; - ensure("due a moment on", due > 1.0); + UNSCOPED_INFO("due a moment on"); + CHECK(due > 1.0); checking.pump(due - 0.1); - ensure("not yet", studio.asks.empty()); + UNSCOPED_INFO("not yet"); + REQUIRE(studio.asks.empty()); doc.editor->insertText("x"); checking.schedule(doc); checking.pump(due); - ensure("typed again: waits again", studio.asks.empty() && doc.check->analysisDue > due); + { + INFO("typed again: waits again"); + REQUIRE(studio.asks.empty()); + CHECK(doc.check->analysisDue > due); + } checking.pump(doc.check->analysisDue); - ensure_equals("asked once", studio.asks.size(), size_t(1)); + UNSCOPED_INFO("asked once"); + REQUIRE(studio.asks.size() == size_t(1)); const ALScriptAnalysis::Request& asked = studio.asks[0].request; - ensure("a check of the text as it stands", - asked.kind == Kind::Check && asked.id == "a" && asked.version == version(doc) && *asked.text == doc.editor->text()); - ensure("with the window's settings", asked.hintTypes); - ensure("remembered", doc.check->requestedVersion == version(doc) && doc.check->analysisDue == 0.0); + { + INFO("a check of the text as it stands"); + REQUIRE(asked.kind == Kind::Check); + REQUIRE(asked.id == "a"); + REQUIRE(asked.version == version(doc)); + CHECK(*asked.text == doc.editor->text()); + } + UNSCOPED_INFO("with the window's settings"); + CHECK(asked.hintTypes); + { + INFO("remembered"); + REQUIRE(doc.check->requestedVersion == version(doc)); + CHECK(doc.check->analysisDue == 0.0); + } checking.pump(1e9); - ensure_equals("once", studio.asks.size(), size_t(1)); + UNSCOPED_INFO("once"); + REQUIRE(studio.asks.size() == size_t(1)); checking.schedule(doc, true); checking.pump(1.0); - ensure_equals("at once", studio.asks.size(), size_t(2)); + UNSCOPED_INFO("at once"); + REQUIRE(studio.asks.size() == size_t(2)); // A notecard is checked here, as scripts read it (test 20). doc.notecard = true; checking.schedule(doc, true); @@ -396,14 +409,18 @@ namespace tut checking.schedule(doc, true); doc.loaded = true; checking.pump(1e9); - ensure_equals("a notecard, or a tab not loaded: never asked of the analyzers", studio.asks.size(), size_t(2)); + UNSCOPED_INFO("a notecard, or a tab not loaded: never asked of the analyzers"); + REQUIRE(studio.asks.size() == size_t(2)); doc.notecard = true; checking.ask(doc, Kind::Hover, ALTextPos(0, 8), ALTextPos(0, 8)); - ensure_equals("a notecard not asked about", studio.asks.size(), size_t(2)); + UNSCOPED_INFO("a notecard not asked about"); + REQUIRE(studio.asks.size() == size_t(2)); preprocessing = true; - ensure("nor preprocessed", !checking.preprocessed(doc)); + UNSCOPED_INFO("nor preprocessed"); + CHECK_FALSE(checking.preprocessed(doc)); doc.notecard = false; - ensure("a script is", checking.preprocessed(doc)); + UNSCOPED_INFO("a script is"); + CHECK(checking.preprocessed(doc)); // A question of the text as it stands shares the one copy every // other question of that text holds; one of a text typed in since // has its own. @@ -412,17 +429,22 @@ namespace tut studio.asks.clear(); checking.ask(doc, Kind::Hover, ALTextPos(0, 1), ALTextPos(0, 1)); checking.ask(doc, Kind::Signature, ALTextPos(0, 1), ALTextPos(0, 1)); - ensure("the same text shared, not copied", studio.asks.size() == 2 && studio.asks[1].request.text == studio.asks[0].request.text); + { + INFO("the same text shared, not copied"); + REQUIRE(studio.asks.size() == 2); + CHECK(studio.asks[1].request.text == studio.asks[0].request.text); + } doc.editor->insertText("x"); checking.ask(doc, Kind::Hover, ALTextPos(0, 1), ALTextPos(0, 1)); - ensure("a newer text its own", studio.asks.back().request.text != studio.asks[0].request.text && - *studio.asks.back().request.text == doc.editor->text()); + { + INFO("a newer text its own"); + REQUIRE(studio.asks.back().request.text != studio.asks[0].request.text); + CHECK(*studio.asks.back().request.text == doc.editor->text()); + } } - template<> template<> - void alscriptstudiochecking_object::test<2>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: a check's answer is taken and one for a text since typed in dropped", "[alscriptstudiochecking]") { - set_test_name("a check's answer taken -- problems, outline, the window told -- one of a text since typed in dropped"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); checking.schedule(doc, true); @@ -433,50 +455,88 @@ namespace tut result.outline = { entry }; doc.editor->insertText("x"); studio.asks[0].answered(result); - ensure("of another text: dropped", doc.check->analysis.empty() && studio.told.empty()); + { + INFO("of another text: dropped"); + REQUIRE(doc.check->analysis.empty()); + REQUIRE(studio.told.empty()); + } result.version = version(doc); studio.asks[0].answered(result); - ensure("taken", doc.check->analysis.size() == 1 && doc.check->analysisVersion == version(doc) && doc.outline.size() == 1); - ensure_equals("LSL's lints as chosen", gLintsApplied, 1); - ensure_equals("told", joined(studio.told), std::string("problems a, outline a")); + { + INFO("taken"); + REQUIRE(doc.check->analysis.size() == 1); + CHECK(doc.check->analysisVersion == version(doc)); + REQUIRE(doc.outline.size() == 1); + } + UNSCOPED_INFO("LSL's lints as chosen"); + CHECK(gLintsApplied == 1); + UNSCOPED_INFO("told"); + CHECK(joined(studio.told) == std::string("problems a, outline a")); result.understood = false; result.outline.clear(); result.problems.clear(); studio.asks[0].answered(result); - ensure("past mending: the outline kept", doc.check->analysis.empty() && doc.outline.size() == 1); + { + INFO("past mending: the outline kept"); + REQUIRE(doc.check->analysis.empty()); + REQUIRE(doc.outline.size() == 1); + } doc.language.lua = true; studio.asks[0].answered(result); - ensure_equals("Luau's chosen by its configuration", gLintsApplied, 2); + UNSCOPED_INFO("Luau's chosen by its configuration"); + CHECK(gLintsApplied == 2); unit.reset(); result.problems = { problem(1, "late") }; studio.asks[0].answered(result); - ensure("gone: nothing taken", doc.check->analysis.empty()); + UNSCOPED_INFO("gone: nothing taken"); + REQUIRE(doc.check->analysis.empty()); } - template<> template<> - void alscriptstudiochecking_object::test<3>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: a preprocessed question waits on the expansion and maps back to source", "[alscriptstudiochecking]") { - set_test_name("preprocessed: the question waits on the expansion, one of a kind replacing the last; the answer read back to the source"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); preprocessing = true; checking.ask(doc, Kind::Inspect, ALTextPos(0, 8), ALTextPos(0, 8)); checking.ask(doc, Kind::Inspect, ALTextPos(3, 20), ALTextPos(3, 20)); checking.ask(doc, Kind::Check, ALTextPos(), ALTextPos()); - ensure("expanded once", expansions.size() == 1 && studio.asks.empty() && doc.check->waiting.size() == 2); - ensure("the last of a kind", doc.check->waiting[0].at == ALTextPos(3, 20)); + { + INFO("expanded once"); + REQUIRE(expansions.size() == 1); + REQUIRE(studio.asks.empty()); + REQUIRE(doc.check->waiting.size() == 2); + } + UNSCOPED_INFO("the last of a kind"); + CHECK(doc.check->waiting[0].at == ALTextPos(3, 20)); doc.editor->insertText("//"); expansions[0].second(expansion(SCRIPT)); - ensure("of another text: the questions go", doc.check->waiting.empty() && studio.asks.empty() && !doc.expanded.valid); + { + INFO("of another text: the questions go"); + REQUIRE(doc.check->waiting.empty()); + REQUIRE(studio.asks.empty()); + CHECK_FALSE(doc.expanded.valid); + } doc.editor->undoJournal().undo(); doc.editor->setText(SCRIPT); checking.ask(doc, Kind::Inspect, ALTextPos(3, 20), ALTextPos(3, 20)); expansions.back().second(expansion(SCRIPT)); - ensure("taken", doc.expanded.valid && doc.expanded.version == version(doc) && doc.check->expansions == 1); - ensure_equals("then asked", studio.asks.size(), size_t(1)); - ensure("of the expansion, at its place", *studio.asks[0].request.text == *doc.expanded.text && studio.asks[0].request.line == 4); - ensure("the include's line passed over", studio.asks[0].request.passedOver == (std::vector>{ { 0, 0 } })); - ensure_equals("the problems shown with it", joined(studio.told), std::string("problems a")); + { + INFO("taken"); + REQUIRE(doc.expanded.valid); + REQUIRE(doc.expanded.version == version(doc)); + CHECK(doc.check->expansions == 1); + } + UNSCOPED_INFO("then asked"); + REQUIRE(studio.asks.size() == size_t(1)); + { + INFO("of the expansion, at its place"); + CHECK(*studio.asks[0].request.text == *doc.expanded.text); + CHECK(studio.asks[0].request.line == 4); + } + UNSCOPED_INFO("the include's line passed over"); + CHECK(studio.asks[0].request.passedOver == (std::vector>{ { 0, 0 } })); + UNSCOPED_INFO("the problems shown with it"); + CHECK(joined(studio.told) == std::string("problems a")); ALScriptAnalysis::Result result; result.kind = Kind::Inspect; result.id = "a"; @@ -484,26 +544,33 @@ namespace tut result.line = 4; result.column = 20; studio.asks[0].answered(result); - ensure_equals("at the source's place", studio.told.back(), std::string("inspect a 3:20")); + UNSCOPED_INFO("at the source's place"); + CHECK(studio.told.back() == std::string("inspect a 3:20")); result.line = 0; const size_t told = studio.told.size(); studio.asks[0].answered(result); - ensure("in the include: nowhere of the script's", studio.told.size() == told); + UNSCOPED_INFO("in the include: nowhere of the script's"); + REQUIRE(studio.told.size() == told); checking.ask(doc, Kind::Inspect, ALTextPos(0, 0), ALTextPos(0, 0)); checking.ask(doc, Kind::Check, ALTextPos(), ALTextPos()); doc.check->expansions += 1; doc.expanded.generation += 1; studio.asks[2].answered(answer(doc)); - ensure("an answer of an expansion since replaced: the check asked again", doc.check->analysisDue == 1.0 && - doc.check->analysis.empty()); + { + INFO("an answer of an expansion since replaced: the check asked again"); + REQUIRE(doc.check->analysisDue == 1.0); + REQUIRE(doc.check->analysis.empty()); + } preprocessing = false; studio.asks[1].answered(result); - ensure("read plain now: dropped", studio.told.size() == told); + UNSCOPED_INFO("read plain now: dropped"); + REQUIRE(studio.told.size() == told); checking.ask(doc, Kind::Inspect, ALTextPos(3, 20), ALTextPos(3, 20)); preprocessing = true; result.line = 3; studio.asks.back().answered(result); - ensure("asked plain, read expanded now: dropped", studio.told.size() == told); + UNSCOPED_INFO("asked plain, read expanded now: dropped"); + REQUIRE(studio.told.size() == told); // An expansion of an older text is expanded again; a place a // directive holds is asked nothing; a stretch it carries as it @@ -511,12 +578,15 @@ namespace tut const size_t expanded = expansions.size(); doc.editor->insertText(" "); checking.ask(doc, Kind::Inspect, ALTextPos(3, 20), ALTextPos(3, 20)); - ensure("an older expansion: expanded again", expansions.size() == expanded + 1); + UNSCOPED_INFO("an older expansion: expanded again"); + REQUIRE(expansions.size() == expanded + 1); doc.editor->setText("#define X\n" + SCRIPT); checking.ask(doc, Kind::Check, ALTextPos(), ALTextPos()); - ensure("one still out: not another yet", expansions.size() == expanded + 1); + UNSCOPED_INFO("one still out: not another yet"); + REQUIRE(expansions.size() == expanded + 1); expansions.back().second(expansion(SCRIPT)); - ensure("it answered of an older text: the next, for the text as it is", expansions.size() == expanded + 2); + UNSCOPED_INFO("it answered of an older text: the next, for the text as it is"); + REQUIRE(expansions.size() == expanded + 2); ALPreprocessor::Result directive = expansion(SCRIPT); directive.map = ALSourceMap(); directive.map.addFile("a", "object:a"); @@ -533,10 +603,15 @@ namespace tut expansions.back().second(directive); const size_t asks = studio.asks.size(); checking.ask(doc, Kind::Hover, ALTextPos(0, 3), ALTextPos(0, 3)); - ensure("on the directive: nothing asked", studio.asks.size() == asks); + UNSCOPED_INFO("on the directive: nothing asked"); + REQUIRE(studio.asks.size() == asks); checking.ask(doc, Kind::Actions, ALTextPos(1, 8), ALTextPos(1, 13)); - ensure("a stretch kept", studio.asks.size() == asks + 1 && studio.asks.back().request.line == 0 && - studio.asks.back().request.endColumn == 13); + { + INFO("a stretch kept"); + REQUIRE(studio.asks.size() == asks + 1); + CHECK(studio.asks.back().request.line == 0); + CHECK(studio.asks.back().request.endColumn == 13); + } unit.reset(); doc.editor->insertText(" "); make(); @@ -545,13 +620,15 @@ namespace tut ALScriptStudioChecking* gone = unit.release(); delete gone; expansions.back().second(expansion(SCRIPT)); - ensure("gone before its expansion came: nothing", expansions.size() == stale_expansions + 1 && studio.asks.size() == asks + 1); + { + INFO("gone before its expansion came: nothing"); + REQUIRE(expansions.size() == stale_expansions + 1); + REQUIRE(studio.asks.size() == asks + 1); + } } - template<> template<> - void alscriptstudiochecking_object::test<4>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: an expansion's problems map back to the source or the include's file", "[alscriptstudiochecking]") { - set_test_name("a check of an expansion: problems back in the source, an include's kept by its file without fixes, its unused not said, one in generated code said so"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); preprocessing = true; @@ -578,52 +655,82 @@ namespace tut result.outline = { mine, theirs }; studio.asks[0].answered(result); const ALScriptProblems& got = doc.check->analysis; - ensure_equals("the include's unused dropped", got.size(), size_t(4)); - ensure("not an error of that code", got[2].message == "an error with that code"); - ensure("own: in the source, its fix too", got[0].line == 3 && got[0].file.empty() && got[0].fixes.size() == 1 && - got[0].fixes[0].edits[0].line == 3); - ensure("the include's: by its file, no fixes", got[1].file == "disk:/lib.lsl" && got[1].line == 2 && got[1].fixes.empty()); - ensure("nowhere: no fixes", got[3].fixes.empty()); - ensure("and said to be in code the preprocessor made, at the expansion's line", got[3].file == Doc::GENERATED && got[3].line == 9); - ensure("the include's symbol not outlined", doc.outline.size() == 1 && doc.outline[0].name == "count" && - doc.outline[0].nameSpan.line == 0); + UNSCOPED_INFO("the include's unused dropped"); + REQUIRE(got.size() == size_t(4)); + UNSCOPED_INFO("not an error of that code"); + CHECK(got[2].message == "an error with that code"); + { + INFO("own: in the source, its fix too"); + CHECK(got[0].line == 3); + REQUIRE(got[0].file.empty()); + REQUIRE(got[0].fixes.size() == 1); + CHECK(got[0].fixes[0].edits[0].line == 3); + } + { + INFO("the include's: by its file, no fixes"); + CHECK(got[1].file == "disk:/lib.lsl"); + CHECK(got[1].line == 2); + REQUIRE(got[1].fixes.empty()); + } + UNSCOPED_INFO("nowhere: no fixes"); + REQUIRE(got[3].fixes.empty()); + { + INFO("and said to be in code the preprocessor made, at the expansion's line"); + CHECK(got[3].file == Doc::GENERATED); + CHECK(got[3].line == 9); + } + { + INFO("the include's symbol not outlined"); + REQUIRE(doc.outline.size() == 1); + CHECK(doc.outline[0].name == "count"); + CHECK(doc.outline[0].nameSpan.line == 0); + } } - template<> template<> - void alscriptstudiochecking_object::test<5>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: an include's file checked with a state after it keeps only its problems", "[alscriptstudiochecking]") { - set_test_name("an include's file, checked with a state after it: what is said of the state, and of its unused, not the include's"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("disk:/lib.lsl", "integer helper;\nhelp() { }\n"); doc.file = "/lib.lsl"; doc.editor->setSyntax("lsl"); - ensure("a fragment", checking.lslFragment(doc)); - ensure("kept for the text it was asked of", doc.check->fragment && doc.check->fragment->first == doc.editor->document().version() && - doc.check->fragment->second); + UNSCOPED_INFO("a fragment"); + CHECK(checking.lslFragment(doc)); + { + INFO("kept for the text it was asked of"); + REQUIRE(doc.check->fragment); + REQUIRE(doc.check->fragment->first == doc.editor->document().version()); + CHECK(doc.check->fragment->second); + } checking.ask(doc, Kind::Check, ALTextPos(), ALTextPos()); - ensure("a state put after it", *studio.asks[0].request.text == doc.editor->text() + "\ndefault{state_entry(){}}\n"); + UNSCOPED_INFO("a state put after it"); + CHECK(*studio.asks[0].request.text == doc.editor->text() + "\ndefault{state_entry(){}}\n"); ALScriptProblem unused = problem(0, "helper unused", ALScriptProblem::Severity::Warning); unused.code = "LocalUnused"; ALScriptOutlineEntry state; state.name = "default"; state.nameSpan.line = 4; studio.asks[0].answered(answer(doc, { problem(1, "own"), problem(4, "in the state"), unused })); - ensure("only its own", doc.check->analysis.size() == 1 && doc.check->analysis[0].message == "own"); + { + INFO("only its own"); + REQUIRE(doc.check->analysis.size() == 1); + CHECK(doc.check->analysis[0].message == "own"); + } ALScriptAnalysis::Result outlined = answer(doc); outlined.outline = { state }; studio.asks[0].answered(outlined); - ensure("nor the state outlined", doc.outline.empty()); + UNSCOPED_INFO("nor the state outlined"); + REQUIRE(doc.outline.empty()); doc.editor->setText("integer helper;\ndefault\n{\n}\n"); - ensure("with a state: a script", !checking.lslFragment(doc)); + UNSCOPED_INFO("with a state: a script"); + CHECK_FALSE(checking.lslFragment(doc)); doc.file.clear(); doc.editor->setText("integer helper;\n"); - ensure("not a file: a script", !checking.lslFragment(doc)); + UNSCOPED_INFO("not a file: a script"); + CHECK_FALSE(checking.lslFragment(doc)); } - template<> template<> - void alscriptstudiochecking_object::test<6>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: an undeclared name is offered an include or what is near is fetched", "[alscriptstudiochecking]") { - set_test_name("a name nothing declares offered an include that declares it; one nothing in hand gives fetched from what is near"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); preprocessing = true; @@ -648,42 +755,58 @@ namespace tut result.problems[1].line = 4; studio.asks[0].answered(result); const ALScriptProblem& given = doc.check->analysis[0]; - ensure_equals("offered", given.fixes.size(), size_t(1)); - ensure("the include put in, preferred", given.fixes[0].preferred && - given.fixes[0].edits[0].text.find("#include \"lib.lsl\"") != std::string::npos); - ensure("nothing gives the other", doc.check->analysis[1].fixes.empty()); - ensure_equals("what is near fetched", nearby.size(), size_t(1)); + UNSCOPED_INFO("offered"); + REQUIRE(given.fixes.size() == size_t(1)); + { + INFO("the include put in, preferred"); + CHECK(given.fixes[0].preferred); + REQUIRE(given.fixes[0].edits[0].text.find("#include \"lib.lsl\"") != std::string::npos); + } + UNSCOPED_INFO("nothing gives the other"); + REQUIRE(doc.check->analysis[1].fixes.empty()); + UNSCOPED_INFO("what is near fetched"); + REQUIRE(nearby.size() == size_t(1)); const size_t asks = studio.asks.size(); nearby[0](); checking.pump(1.0); - ensure_equals("and checked again once it is in", studio.asks.size(), asks + 1); + UNSCOPED_INFO("and checked again once it is in"); + REQUIRE(studio.asks.size() == asks + 1); preprocessing = false; doc.check->analysisDue = 0.0; checking.ask(doc, Kind::Check, ALTextPos(), ALTextPos()); studio.asks.back().answered(answer(doc, { undeclared })); - ensure("not preprocessed: nothing to include with", doc.check->analysis[0].fixes.empty() && nearby.size() == 1); + { + INFO("not preprocessed: nothing to include with"); + REQUIRE(doc.check->analysis[0].fixes.empty()); + REQUIRE(nearby.size() == 1); + } preprocessing = true; checking.ask(doc, Kind::Check, ALTextPos(), ALTextPos()); ALScriptAnalysis::Result given_all = answer(doc, { undeclared }); given_all.problems[0].line = 4; studio.asks.back().answered(given_all); - ensure("all given: nothing fetched", !doc.check->analysis[0].fixes.empty() && nearby.size() == 1); + { + INFO("all given: nothing fetched"); + REQUIRE_FALSE(doc.check->analysis[0].fixes.empty()); + REQUIRE(nearby.size() == 1); + } // What is in reach found anew on the index's thread: the script // checked again. doc.check->analysisDue = 0.0; - ensure("a reach new to it told", (bool)modulesReady); + UNSCOPED_INFO("a reach new to it told"); + REQUIRE((bool)modulesReady); modulesReady(); - ensure("checked again", doc.check->analysisDue > 0.0); + UNSCOPED_INFO("checked again"); + CHECK(doc.check->analysisDue > 0.0); doc.check->analysisDue = 0.0; unit.reset(); nearby[0](); - ensure("gone: nothing asked", doc.check->analysisDue == 0.0); + UNSCOPED_INFO("gone: nothing asked"); + CHECK(doc.check->analysisDue == 0.0); } - template<> template<> - void alscriptstudiochecking_object::test<7>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: a NOLINT comment drops a problem and preprocessor words are explained", "[alscriptstudiochecking]") { - set_test_name("what a comment says is not wanted dropped, a comment offered for the rest; the preprocessor's words and a require explained"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a", "integer a; // NOLINT\ninteger b;\nswitch (a) { }\n"); ALScriptProblem quiet = problem(0, "a unused", ALScriptProblem::Severity::Warning); @@ -697,11 +820,17 @@ namespace tut theirs.file = "disk:/lib.lsl"; checking.ask(doc, Kind::Check, ALTextPos(), ALTextPos()); studio.asks[0].answered(answer(doc, { quiet, said, parse, theirs })); - ensure_equals("the one a comment quiets dropped", doc.check->analysis.size(), size_t(3)); - ensure_equals("an include's not explained here", doc.check->analysis[2].message, std::string("syntax error")); - ensure("the other offered a comment", doc.check->analysis[0].fixes.size() == 1 && - doc.check->analysis[0].fixes[0].kind == ALScriptFix::Kind::Suppress); - ensure("the switch explained", doc.check->analysis[1].message.find("syntax error PreprocHintSwitch [WORD]=switch") == 0); + UNSCOPED_INFO("the one a comment quiets dropped"); + REQUIRE(doc.check->analysis.size() == size_t(3)); + UNSCOPED_INFO("an include's not explained here"); + CHECK(doc.check->analysis[2].message == std::string("syntax error")); + { + INFO("the other offered a comment"); + REQUIRE(doc.check->analysis[0].fixes.size() == 1); + CHECK(doc.check->analysis[0].fixes[0].kind == ALScriptFix::Kind::Suppress); + } + UNSCOPED_INFO("the switch explained"); + CHECK(doc.check->analysis[1].message.find("syntax error PreprocHintSwitch [WORD]=switch") == 0); preprocessing = true; switches = true; doc.expanded.valid = false; @@ -712,20 +841,25 @@ namespace tut plain.map.finish(); expansions.back().second(plain); studio.asks.back().answered(answer(doc, { parse })); - ensure_equals("its transform on: not", doc.check->analysis[0].message, std::string("syntax error")); + UNSCOPED_INFO("its transform on: not"); + CHECK(doc.check->analysis[0].message == std::string("syntax error")); preprocessing = false; Doc& lua = tab("b", "local x = require(\"lib\")\n"); lua.language.lua = true; checking.ask(lua, Kind::Check, ALTextPos(), ALTextPos()); studio.asks.back().answered(answer(lua)); - ensure("a require the preprocessor does not run over, warned of", - lua.check->analysis.size() == 1 && lua.check->analysis[0].message == "RequireNotPreprocessed [NAME]=lib"); + { + INFO("a require the preprocessor does not run over, warned of"); + REQUIRE(lua.check->analysis.size() == 1); + CHECK(lua.check->analysis[0].message == "RequireNotPreprocessed [NAME]=lib"); + } preprocessing = true; checking.ask(lua, Kind::Check, ALTextPos(), ALTextPos()); expansions.back().second(plain); studio.asks.back().answered(answer(lua)); - ensure("preprocessed: not", lua.check->analysis.empty()); + UNSCOPED_INFO("preprocessed: not"); + REQUIRE(lua.check->analysis.empty()); // `inline` is taken off whenever the preprocessor runs, the // extensions on or not: said as the preprocessor's alone. @@ -733,7 +867,8 @@ namespace tut Doc& marked = tab("m", "integer f() inline { return 1; }\n"); checking.ask(marked, Kind::Check, ALTextPos(), ALTextPos()); studio.asks.back().answered(answer(marked, { problem(0, "syntax error") })); - ensure("inline explained: " + marked.check->analysis[0].message, marked.check->analysis[0].message.find("syntax error PreprocHintInline [WORD]=inline") == 0); + UNSCOPED_INFO("inline explained: " + marked.check->analysis[0].message); + CHECK(marked.check->analysis[0].message.find("syntax error PreprocHintInline [WORD]=inline") == 0); preprocessing = true; marked.expanded.valid = false; checking.ask(marked, Kind::Check, ALTextPos(), ALTextPos()); @@ -743,25 +878,31 @@ namespace tut stripped.map.finish(); expansions.back().second(stripped); studio.asks.back().answered(answer(marked, { problem(0, "syntax error") })); - ensure_equals("preprocessing, the extensions off: not", marked.check->analysis[0].message, std::string("syntax error")); + UNSCOPED_INFO("preprocessing, the extensions off: not"); + CHECK(marked.check->analysis[0].message == std::string("syntax error")); // And so is `const`, before a type anywhere on the line. preprocessing = false; Doc& constant = tab("c", "f(const integer n) { }\n"); checking.ask(constant, Kind::Check, ALTextPos(), ALTextPos()); studio.asks.back().answered(answer(constant, { problem(0, "syntax error") })); - ensure("const explained: " + constant.check->analysis[0].message, - constant.check->analysis[0].message.find("syntax error PreprocHintConst [WORD]=const") == 0); + UNSCOPED_INFO("const explained: " + constant.check->analysis[0].message); + CHECK(constant.check->analysis[0].message.find("syntax error PreprocHintConst [WORD]=const") == 0); // A script with a directive is preprocessed, the setting off or // on: the grid could compile it no other way. Doc& directive = tab("d", " #define MAX 15\ndefault { state_entry() { } }\n"); const size_t expanded = expansions.size(); - ensure("preprocessed for its directive", checking.preprocessed(directive) && - checking.preprocessedWhy(directive) == ALPreprocessor::Wanted::Directives); + { + INFO("preprocessed for its directive"); + CHECK(checking.preprocessed(directive)); + CHECK(checking.preprocessedWhy(directive) == ALPreprocessor::Wanted::Directives); + } checking.ask(directive, Kind::Check, ALTextPos(), ALTextPos()); - ensure("expanded, not read as code", expansions.size() == expanded + 1); - ensure("an envelope first", [&] { + UNSCOPED_INFO("expanded, not read as code"); + REQUIRE(expansions.size() == expanded + 1); + UNSCOPED_INFO("an envelope first"); + CHECK([&] { directive.envelope = ALScriptEnvelope(); const bool first = checking.preprocessedWhy(directive) == ALPreprocessor::Wanted::Enveloped; directive.envelope.reset(); @@ -772,54 +913,81 @@ namespace tut // preprocessor's to explain, and nothing put in where the parser // stopped. Doc& stray = tab("e", "# 15\ndefault { state_entry() { } }\n"); - ensure("not preprocessed", !checking.preprocessed(stray)); + UNSCOPED_INFO("not preprocessed"); + CHECK_FALSE(checking.preprocessed(stray)); checking.ask(stray, Kind::Check, ALTextPos(), ALTextPos()); ALScriptProblem missing = problem(0, "Missing '('."); missing.fixes.push_back(fix("Insert '('", 0, 2, 2, "(")); studio.asks.back().answered(answer(stray, { missing, problem(1, "syntax error") })); - ensure("the line explained: " + (stray.check->analysis.empty() ? std::string() : stray.check->analysis[0].message), - stray.check->analysis.size() == 2 && stray.check->analysis[0].message == "Missing '('. PreprocHintDirective" && - stray.check->analysis[0].fixes.empty()); - ensure_equals("a line of code: as the parser said", stray.check->analysis[1].message, std::string("syntax error")); + { + INFO("the line explained: " + (stray.check->analysis.empty() ? std::string() : stray.check->analysis[0].message)); + REQUIRE(stray.check->analysis.size() == 2); + REQUIRE(stray.check->analysis[0].message == "Missing '('. PreprocHintDirective"); + REQUIRE(stray.check->analysis[0].fixes.empty()); + } + UNSCOPED_INFO("a line of code: as the parser said"); + CHECK(stray.check->analysis[1].message == std::string("syntax error")); preprocessing = true; } - template<> template<> - void alscriptstudiochecking_object::test<8>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: a fix is made as one undo step or refused where the text moved on", "[alscriptstudiochecking]") { - set_test_name("a fix made as one step and checked again; refused where the text has moved on or its places are past the end"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); const U32 v = version(doc); - ensure("made", checking.applyFix(doc, fix("Rename it", 0, 8, 13, "total"), v)); - ensure_equals("in the text", doc.editor->document().line(0), std::string("integer total;")); - ensure_equals("one step", doc.editor->undoJournal().undoLabel(), std::string("fix")); - ensure("said, checked again", services.statuses.back() == "Rename it" && doc.check->analysisDue == 1.0); + UNSCOPED_INFO("made"); + CHECK(checking.applyFix(doc, fix("Rename it", 0, 8, 13, "total"), v)); + UNSCOPED_INFO("in the text"); + CHECK(doc.editor->document().line(0) == std::string("integer total;")); + UNSCOPED_INFO("one step"); + CHECK(doc.editor->undoJournal().undoLabel() == std::string("fix")); + { + INFO("said, checked again"); + CHECK(services.statuses.back() == "Rename it"); + CHECK(doc.check->analysisDue == 1.0); + } doc.check->analysisDue = 0.0; - ensure("moved on: refused", !checking.applyFix(doc, fix("Again", 0, 8, 13, "sum"), v)); - ensure("said, checked again", services.statuses.back() == "FixStale" && services.statusFailures.back() && - doc.check->analysisDue == 1.0); - ensure("past the end: refused", !checking.applyFix(doc, fix("Far", 40, 0, 1, "x"), version(doc))); + UNSCOPED_INFO("moved on: refused"); + CHECK_FALSE(checking.applyFix(doc, fix("Again", 0, 8, 13, "sum"), v)); + { + INFO("said, checked again"); + CHECK(services.statuses.back() == "FixStale"); + REQUIRE(services.statusFailures.back()); + CHECK(doc.check->analysisDue == 1.0); + } + UNSCOPED_INFO("past the end: refused"); + CHECK_FALSE(checking.applyFix(doc, fix("Far", 40, 0, 1, "x"), version(doc))); ALScriptFix refactor = fix("Extract", 0, 0, 7, "float"); refactor.kind = ALScriptFix::Kind::Refactor; - ensure("a refactor", checking.applyFix(doc, refactor, version(doc)) && doc.editor->undoJournal().undoLabel() == "refactor"); + { + INFO("a refactor"); + REQUIRE(checking.applyFix(doc, refactor, version(doc))); + CHECK(doc.editor->undoJournal().undoLabel() == "refactor"); + } doc.modifiable = false; - ensure("not to be changed: refused", !checking.applyFix(doc, fix("No", 0, 0, 1, "x"), version(doc))); + UNSCOPED_INFO("not to be changed: refused"); + CHECK_FALSE(checking.applyFix(doc, fix("No", 0, 0, 1, "x"), version(doc))); } - template<> template<> - void alscriptstudiochecking_object::test<9>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: Fix All waits for a check and asks before making many fixes in one step", "[alscriptstudiochecking]") { - set_test_name("Fix All: after the check where the text is not checked yet, one made at once, many asked first and made as one step"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); checking.askFixAll(doc, Doc::FixPick{}); - ensure("not checked: checked first", doc.check->fixAllAfterCheck.has_value() && services.statuses.back() == "FixChecking [NAME]=a"); + { + INFO("not checked: checked first"); + REQUIRE(doc.check->fixAllAfterCheck.has_value()); + CHECK(services.statuses.back() == "FixChecking [NAME]=a"); + } checking.pump(1.0); ALScriptProblem one = problem(0, "one"); one.fixes = { fix("First", 0, 0, 7, "float") }; studio.asks[0].answered(answer(doc, { one })); - ensure("then made", doc.editor->document().line(0) == "float count;" && !doc.check->fixAllAfterCheck); + { + INFO("then made"); + REQUIRE(doc.editor->document().line(0) == "float count;"); + REQUIRE_FALSE(doc.check->fixAllAfterCheck); + } checking.pump(1.0); ALScriptProblem two = problem(3, "two"); @@ -829,53 +997,79 @@ namespace tut one.fixes = { fix("First", 0, 0, 5, "integer") }; studio.asks.back().answered(answer(doc, { one, two, risky })); checking.askFixAll(doc, Doc::FixPick{}); - ensure("asked", (bool)studio.confirm && studio.confirmed["FIXES"].asString() == "Fixes [COUNT]=2"); - ensure("with what is left", studio.confirmed["LEFT"].asString() == " FixesLeft [COUNT]=1"); + { + INFO("asked"); + REQUIRE((bool)studio.confirm); + CHECK(studio.confirmed["FIXES"].asString() == "Fixes [COUNT]=2"); + } + UNSCOPED_INFO("with what is left"); + CHECK(studio.confirmed["LEFT"].asString() == " FixesLeft [COUNT]=1"); studio.confirm(); - ensure("made", doc.editor->document().line(0) == "integer count;" && - doc.editor->document().line(3) == " touch_start() { count = 1; }"); - ensure("as one step", doc.editor->undoJournal().undoLabel() == "fix" && services.statuses.back() == "FixesMade [COUNT]=2"); + { + INFO("made"); + REQUIRE(doc.editor->document().line(0) == "integer count;"); + CHECK(doc.editor->document().line(3) == " touch_start() { count = 1; }"); + } + { + INFO("as one step"); + CHECK(doc.editor->undoJournal().undoLabel() == "fix"); + CHECK(services.statuses.back() == "FixesMade [COUNT]=2"); + } checking.pump(1.0); studio.asks.back().answered(answer(doc)); checking.askFixAll(doc, Doc::FixPick{}); - ensure_equals("none", services.statuses.back(), std::string("FixNone")); + UNSCOPED_INFO("none"); + CHECK(services.statuses.back() == std::string("FixNone")); unit.reset(); studio.confirm(); - ensure("gone: nothing", doc.editor->document().line(0) == "integer count;"); + UNSCOPED_INFO("gone: nothing"); + CHECK(doc.editor->document().line(0) == "integer count;"); } - template<> template<> - void alscriptstudiochecking_object::test<10>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: fixesOn lists a line's fixes only for the text they were made in", "[alscriptstudiochecking]") { - set_test_name("a line's fixes as the editor lists them, of the text they were made in; and the problem a value is"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); ALScriptProblem one = problem(0, "one"); one.fixes = { fix("First", 0, 0, 7, "float") }; checking.ask(doc, Kind::Check, ALTextPos(), ALTextPos()); studio.asks[0].answered(answer(doc, { one, problem(2, "two") })); - ensure("asked for, made with the next frame", studio.waiting.count("a") == 1 && doc.shown().empty()); + { + INFO("asked for, made with the next frame"); + REQUIRE(studio.waiting.count("a") == 1); + REQUIRE(doc.shown().empty()); + } std::vector fixes; checking.fixesOn(doc, 0, fixes); - ensure("made first: one", studio.waiting.empty() && fixes.size() == 1 && fixes[0].title == "First" && - fixes[0].edits[0].second == "float"); + { + INFO("made first: one"); + REQUIRE(studio.waiting.empty()); + REQUIRE(fixes.size() == 1); + CHECK(fixes[0].title == "First"); + CHECK(fixes[0].edits[0].second == "float"); + } const Doc::Shown* shown = checking.shownOf(fixes[0].value); - ensure("its problem", shown && shown->message == "one"); + { + INFO("its problem"); + REQUIRE(shown); + CHECK(shown->message == "one"); + } fixes.clear(); checking.fixesOn(doc, 2, fixes); - ensure("none on another line", fixes.empty()); + UNSCOPED_INFO("none on another line"); + REQUIRE(fixes.empty()); doc.editor->insertText("x"); checking.fixesOn(doc, 0, fixes); - ensure("typed in since: none", fixes.empty()); + UNSCOPED_INFO("typed in since: none"); + REQUIRE(fixes.empty()); LLSD gone; gone["doc"] = "b"; - ensure("another tab's: none", !checking.shownOf(gone)); + UNSCOPED_INFO("another tab's: none"); + REQUIRE_FALSE(checking.shownOf(gone)); } - template<> template<> - void alscriptstudiochecking_object::test<11>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: changed preprocessor settings re-expand every tab a moment later", "[alscriptstudiochecking]") { - set_test_name("the preprocessor's settings changed: a moment on, every tab expanded afresh, run for a save, taught its words, checked"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); Doc& lua = tab("b"); @@ -886,25 +1080,39 @@ namespace tut checking.settingsChanged(false, 10.0); checking.settingsChanged(true, 10.1); checking.pump(10.2); - ensure("not yet", doc.expanded.valid); + UNSCOPED_INFO("not yet"); + CHECK(doc.expanded.valid); checking.pump(10.1 + 0.35); - ensure("afresh", !doc.expanded.valid && !doc.weighing->sent); - ensure_equals("run for a save", joined(studio.told), std::string("run a, run b")); - ensure("checked", doc.check->analysisDue == 0.0 && expansions.size() == 2); + { + INFO("afresh"); + REQUIRE_FALSE(doc.expanded.valid); + CHECK_FALSE(doc.weighing->sent); + } + UNSCOPED_INFO("run for a save"); + CHECK(joined(studio.told) == std::string("run a, run b")); + { + INFO("checked"); + CHECK(doc.check->analysisDue == 0.0); + REQUIRE(expansions.size() == 2); + } studio.told.clear(); checking.pump(20.0); - ensure("once", studio.told.empty()); + UNSCOPED_INFO("once"); + REQUIRE(studio.told.empty()); } - template<> template<> - void alscriptstudiochecking_object::test<12>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: refactors reaching past the text are dropped and other answers handed on", "[alscriptstudiochecking]") { - set_test_name("refactors offered at the caret, those reaching past the text dropped; other answers handed on or given the editor"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); checking.ask(doc, Kind::Actions, ALTextPos(0, 8), ALTextPos(0, 13)); - ensure("a stretch", studio.asks[0].request.endColumn == 13); - ensure("kept, to offer them over", doc.check->actionsAsked.begin == ALTextPos(0, 8) && doc.check->actionsAsked.end == ALTextPos(0, 13)); + UNSCOPED_INFO("a stretch"); + CHECK(studio.asks[0].request.endColumn == 13); + { + INFO("kept, to offer them over"); + REQUIRE(doc.check->actionsAsked.begin == ALTextPos(0, 8)); + CHECK(doc.check->actionsAsked.end == ALTextPos(0, 13)); + } ALScriptAnalysis::Result result; result.kind = Kind::Actions; result.id = "a"; @@ -916,12 +1124,17 @@ namespace tut straddle.edits[0].endLine = 9; result.actions = { inside, beyond, straddle }; studio.asks[0].answered(result); - ensure("kept", - doc.check->actions.size() == 1 && doc.check->actions[0].title == "Rename" && doc.check->actionsVersion == version(doc)); + { + INFO("kept"); + REQUIRE(doc.check->actions.size() == 1); + REQUIRE(doc.check->actions[0].title == "Rename"); + CHECK(doc.check->actionsVersion == version(doc)); + } result.version = version(doc) + 1; result.actions = { beyond }; studio.asks[0].answered(result); - ensure("of another text: dropped", doc.check->actions.size() == 1); + UNSCOPED_INFO("of another text: dropped"); + REQUIRE(doc.check->actions.size() == 1); checking.ask(doc, Kind::References, ALTextPos(0, 8), ALTextPos(0, 8)); ALScriptAnalysis::Result refs; refs.kind = Kind::References; @@ -930,20 +1143,24 @@ namespace tut refs.line = 0; refs.column = 8; studio.asks.back().answered(refs); - ensure_equals("handed on", studio.told.back(), std::string("references a 0:8")); + UNSCOPED_INFO("handed on"); + CHECK(studio.told.back() == std::string("references a 0:8")); doc.language.compileTarget = "none"; const size_t asks = studio.asks.size(); checking.ask(doc, Kind::Weigh, ALTextPos(), ALTextPos()); - ensure("nothing to weigh for: not asked", studio.asks.size() == asks); + UNSCOPED_INFO("nothing to weigh for: not asked"); + REQUIRE(studio.asks.size() == asks); doc.language.compileTarget = "mono"; checking.ask(doc, Kind::Weigh, ALTextPos(), ALTextPos()); - ensure("weighed for its targets", studio.asks.size() == asks + 1 && studio.asks.back().request.targets.size() == 1); + { + INFO("weighed for its targets"); + REQUIRE(studio.asks.size() == asks + 1); + REQUIRE(studio.asks.back().request.targets.size() == 1); + } } - template<> template<> - void alscriptstudiochecking_object::test<13>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: one expansion at a time while typing and then one for the latest text", "[alscriptstudiochecking]") { - set_test_name("preprocessed, typed in while an expansion is out: one at a time, then one for the latest text, not one a key"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); preprocessing = true; @@ -952,85 +1169,117 @@ namespace tut checking.ask(doc, Kind::Signature, ALTextPos(0, 2), ALTextPos(0, 2)); doc.editor->insertText(" "); checking.ask(doc, Kind::Signature, ALTextPos(0, 3), ALTextPos(0, 3)); - ensure_equals("one on its way, not one a key", expansions.size(), size_t(1)); + UNSCOPED_INFO("one on its way, not one a key"); + REQUIRE(expansions.size() == size_t(1)); expansions[0].second(expansion(doc.editor->text())); - ensure_equals("the next, for the text as it is now", expansions.size(), size_t(2)); - ensure("the latest question still waiting", doc.check->waiting.size() == 1 && doc.check->waiting[0].at == ALTextPos(0, 3) && studio.asks.empty()); + UNSCOPED_INFO("the next, for the text as it is now"); + REQUIRE(expansions.size() == size_t(2)); + { + INFO("the latest question still waiting"); + REQUIRE(doc.check->waiting.size() == 1); + CHECK(doc.check->waiting[0].at == ALTextPos(0, 3)); + REQUIRE(studio.asks.empty()); + } expansions[1].second(expansion(doc.editor->text())); - ensure_equals("then asked, once", studio.asks.size(), size_t(1)); - ensure("of the latest", studio.asks[0].request.version == version(doc)); + UNSCOPED_INFO("then asked, once"); + REQUIRE(studio.asks.size() == size_t(1)); + UNSCOPED_INFO("of the latest"); + CHECK(studio.asks[0].request.version == version(doc)); } - template<> template<> - void alscriptstudiochecking_object::test<14>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: the front tab is weighed with its check and a tab behind only checked", "[alscriptstudiochecking]") { - set_test_name("the tab in front weighed with its check, in the one job, and its weights handed on; a tab behind checked alone"); ALScriptStudioChecking& checking = make(); Doc& a = tab("a"); Doc& b = tab("b"); studio.front = "a"; checking.ask(a, Kind::Check, ALTextPos(), ALTextPos()); checking.ask(b, Kind::Check, ALTextPos(), ALTextPos()); - ensure_equals("both asked", studio.asks.size(), size_t(2)); - ensure("the front one with its targets", studio.asks[0].request.front && studio.asks[0].request.targets.size() == 1); - ensure("and noted as asked for", a.weighing->askedFor == version(a)); - ensure("the other without", !studio.asks[1].request.front && studio.asks[1].request.targets.empty() && b.weighing->askedFor != version(b)); + UNSCOPED_INFO("both asked"); + REQUIRE(studio.asks.size() == size_t(2)); + { + INFO("the front one with its targets"); + CHECK(studio.asks[0].request.front); + REQUIRE(studio.asks[0].request.targets.size() == 1); + } + UNSCOPED_INFO("and noted as asked for"); + CHECK(a.weighing->askedFor == version(a)); + { + INFO("the other without"); + CHECK_FALSE(studio.asks[1].request.front); + REQUIRE(studio.asks[1].request.targets.empty()); + CHECK(b.weighing->askedFor != version(b)); + } ALScriptAnalysis::Result weighed = answer(a, {}); ALScriptWeight weight; weight.target = ALScriptWeight::Target::Mono; weight.total = 100; weighed.weights = { weight }; studio.asks[0].answered(weighed); - ensure_equals("its problems shown", joined(studio.told), std::string("problems a, outline a")); - ensure("its weights handed on with the check", a.weighing->weight && a.weighing->weight->total == 100); + UNSCOPED_INFO("its problems shown"); + CHECK(joined(studio.told) == std::string("problems a, outline a")); + { + INFO("its weights handed on with the check"); + REQUIRE(a.weighing->weight); + CHECK(a.weighing->weight->total == 100); + } studio.told.clear(); studio.asks[1].answered(answer(b, {})); - ensure_equals("none for the other", joined(studio.told), std::string("problems b, outline b")); + UNSCOPED_INFO("none for the other"); + CHECK(joined(studio.told) == std::string("problems b, outline b")); } - template<> template<> - void alscriptstudiochecking_object::test<15>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: relint refilters LSL's last check and rechecks SLua or edited tabs", "[alscriptstudiochecking]") { - set_test_name("the lints chosen again: an LSL tab's last check filtered afresh, nothing asked; an SLua tab, or a text since typed in, checked again"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); checking.schedule(doc, true); checking.pump(1.0); studio.asks[0].answered(answer(doc, { problem(0, "wrong"), problem(1, "unused", ALScriptProblem::Severity::Warning) })); - ensure_equals("both taken", doc.check->analysis.size(), size_t(2)); + UNSCOPED_INFO("both taken"); + REQUIRE(doc.check->analysis.size() == size_t(2)); studio.told.clear(); gWarningsOff = true; checking.relint(doc); - ensure_equals("nothing asked", studio.asks.size(), size_t(1)); - ensure("the warning filtered out", doc.check->analysis.size() == 1 && doc.check->analysis[0].message == "wrong"); - ensure_equals("and shown", joined(studio.told), std::string("problems a")); + UNSCOPED_INFO("nothing asked"); + REQUIRE(studio.asks.size() == size_t(1)); + { + INFO("the warning filtered out"); + REQUIRE(doc.check->analysis.size() == 1); + CHECK(doc.check->analysis[0].message == "wrong"); + } + UNSCOPED_INFO("and shown"); + CHECK(joined(studio.told) == std::string("problems a")); gWarningsOff = false; checking.relint(doc); - ensure_equals("back again, from what the check said", doc.check->analysis.size(), size_t(2)); + UNSCOPED_INFO("back again, from what the check said"); + REQUIRE(doc.check->analysis.size() == size_t(2)); doc.editor->insertText("x"); checking.relint(doc); checking.pump(2.0); - ensure_equals("typed in since: checked again", studio.asks.size(), size_t(2)); + UNSCOPED_INFO("typed in since: checked again"); + REQUIRE(studio.asks.size() == size_t(2)); Doc& lua = tab("b"); lua.language.lua = true; const size_t asks = studio.asks.size(); checking.relint(lua); checking.pump(3.0); - ensure_equals("SLua: checked again", studio.asks.size(), asks + 1); + UNSCOPED_INFO("SLua: checked again"); + REQUIRE(studio.asks.size() == asks + 1); } - template<> template<> - void alscriptstudiochecking_object::test<16>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: SLua with requires is checked apart with its modules and its bundle", "[alscriptstudiochecking]") { - set_test_name("SLua with requires: the analyzers asked of the script apart, its modules and which require reaches which, the bundle to weigh; a module's problem in its file"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); doc.language.lua = true; doc.editor->setText("local util = require(\"util\")\nprint(util.x)\n"); preprocessing = true; checking.ask(doc, Kind::Check, ALTextPos(), ALTextPos()); - ensure_equals("expanded", expansions.size(), size_t(1)); - ensure("apart asked for", expansions[0].first.apart); + UNSCOPED_INFO("expanded"); + REQUIRE(expansions.size() == size_t(1)); + UNSCOPED_INFO("apart asked for"); + CHECK(expansions[0].first.apart); ALPreprocessor::Result result; result.map.addFile("a", "object:a"); result.map.addFile("util", "object:util"); @@ -1067,13 +1316,28 @@ namespace tut result.apart.modules.push_back(util); result.resolved.push_back({ "", "util", true, "object:util" }); expansions[0].second(result); - ensure_equals("asked", studio.asks.size(), size_t(1)); + UNSCOPED_INFO("asked"); + REQUIRE(studio.asks.size() == size_t(1)); const ALScriptAnalysis::Request& asked = studio.asks[0].request; - ensure("of the script apart", *asked.text == doc.editor->text()); - ensure("with its module", asked.modules && asked.modules->modules.size() == 1 && asked.modules->modules[0].key == "object:util"); - ensure("and which require reaches it", - asked.modules->reaches.size() == 1 && asked.modules->reaches[0].name == "util" && asked.modules->reaches[0].key == "object:util"); - ensure("the bundle to weigh", asked.bundle && *asked.bundle == result.text); + UNSCOPED_INFO("of the script apart"); + CHECK(*asked.text == doc.editor->text()); + { + INFO("with its module"); + REQUIRE(asked.modules); + REQUIRE(asked.modules->modules.size() == 1); + CHECK(asked.modules->modules[0].key == "object:util"); + } + { + INFO("and which require reaches it"); + REQUIRE(asked.modules->reaches.size() == 1); + REQUIRE(asked.modules->reaches[0].name == "util"); + CHECK(asked.modules->reaches[0].key == "object:util"); + } + { + INFO("the bundle to weigh"); + REQUIRE(asked.bundle); + CHECK(*asked.bundle == result.text); + } // What the checker said of the module, in the module's lines: in // its file, where its map puts it. ALScriptProblem in_module = problem(1, "wrong in util"); @@ -1085,14 +1349,14 @@ namespace tut mapped |= p.message == "wrong in util" && p.file == "object:util" && p.line == 11 && p.fixes.empty(); own |= p.message == "wrong here" && p.file.empty() && p.line == 1; } - ensure("the module's, in its file's lines", mapped); - ensure("the script's own, in its", own); + UNSCOPED_INFO("the module's, in its file's lines"); + CHECK(mapped); + UNSCOPED_INFO("the script's own, in its"); + CHECK(own); } - template<> template<> - void alscriptstudiochecking_object::test<17>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: a name declared const is said to be const where it is inspected", "[alscriptstudiochecking]") { - set_test_name("a name declared const, which the analyzers read with the word taken off, is said to be const where it is inspected"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); preprocessing = true; @@ -1115,14 +1379,14 @@ namespace tut studio.asks.back().answered(result); return studio.labels.empty() ? std::string() : studio.labels.back(); }; - ensure_equals("said const", inspect(1, 8, "integer count"), std::string("const integer count")); - ensure_equals("another name is not", inspect(0, 8, "integer helper"), std::string("integer helper")); + UNSCOPED_INFO("said const"); + CHECK(inspect(1, 8, "integer count") == std::string("const integer count")); + UNSCOPED_INFO("another name is not"); + CHECK(inspect(0, 8, "integer helper") == std::string("integer helper")); } - template<> template<> - void alscriptstudiochecking_object::test<18>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: the front tab is checked when due and others one a frame oldest first", "[alscriptstudiochecking]") { - set_test_name("the tab in front checked as soon as it is due; the others one a frame, the one due longest first"); ALScriptStudioChecking& checking = make(); Doc& a = tab("a"); Doc& b = tab("b"); @@ -1138,21 +1402,26 @@ namespace tut { asked += one.request.id; } - ensure_equals("in front, and the one due longest", asked, std::string("ca")); + UNSCOPED_INFO("in front, and the one due longest"); + CHECK(asked == std::string("ca")); checking.pump(1.0); - ensure("then the next", studio.asks.size() == 3 && studio.asks[2].request.id == "b"); + { + INFO("then the next"); + REQUIRE(studio.asks.size() == 3); + CHECK(studio.asks[2].request.id == "b"); + } checking.pump(1.0); - ensure_equals("and none again", studio.asks.size(), size_t(3)); + UNSCOPED_INFO("and none again"); + REQUIRE(studio.asks.size() == size_t(3)); } - template<> template<> - void alscriptstudiochecking_object::test<19>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: the inspector reuses the tip's answer for the same word and text", "[alscriptstudiochecking]") { - set_test_name("the tip and the inspector ask the same question: the second of a word, as the text stands, told what the first was"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); checking.ask(doc, Kind::Hover, ALTextPos(0, 8), ALTextPos(0, 8)); - ensure_equals("the tip asks", studio.asks.size(), size_t(1)); + UNSCOPED_INFO("the tip asks"); + REQUIRE(studio.asks.size() == size_t(1)); ALScriptAnalysis::Result said; said.kind = Kind::Hover; said.id = "a"; @@ -1163,21 +1432,24 @@ namespace tut said.hover.label = "integer count"; studio.asks[0].answered(said); checking.ask(doc, Kind::Inspect, ALTextPos(0, 10), ALTextPos(0, 10)); - ensure_equals("the inspector, of the same word: not asked", studio.asks.size(), size_t(1)); - ensure_equals("but told", studio.told.back(), std::string("inspect a 0:10")); - ensure_equals("what the tip was", studio.labels.back(), std::string("integer count")); + UNSCOPED_INFO("the inspector, of the same word: not asked"); + REQUIRE(studio.asks.size() == size_t(1)); + UNSCOPED_INFO("but told"); + CHECK(studio.told.back() == std::string("inspect a 0:10")); + UNSCOPED_INFO("what the tip was"); + CHECK(studio.labels.back() == std::string("integer count")); checking.ask(doc, Kind::Inspect, ALTextPos(1, 0), ALTextPos(1, 0)); - ensure_equals("another word: asked", studio.asks.size(), size_t(2)); + UNSCOPED_INFO("another word: asked"); + REQUIRE(studio.asks.size() == size_t(2)); doc.editor->setCaret(ALTextPos(0, 0)); doc.editor->insertText(" "); checking.ask(doc, Kind::Inspect, ALTextPos(0, 10), ALTextPos(0, 10)); - ensure_equals("typed in since: asked", studio.asks.size(), size_t(3)); + UNSCOPED_INFO("typed in since: asked"); + REQUIRE(studio.asks.size() == size_t(3)); } - template<> template<> - void alscriptstudiochecking_object::test<20>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: a notecard is checked as scripts read it and outlined only as JSON", "[alscriptstudiochecking]") { - set_test_name("a notecard checked as scripts read it, with no analyzer asked: its items making every line EOF, a line past 1024 bytes; outlined as JSON only"); ALScriptStudioChecking& checking = make(); const std::string long_line(1030, 'x'); Doc& card = tab("card", "one " + ALNotecardItems::charOf(0) + "\n" + long_line + "\n"); @@ -1189,33 +1461,49 @@ namespace tut card.items->loaded({ LLPointer(new LLInventoryItem()) }); checking.schedule(card, true); checking.pump(2.0); - ensure("no analyzer asked", studio.asks.empty()); - ensure_equals("two", card.check->analysis.size(), size_t(2)); - ensure("the items, at the first", card.check->analysis[0].line == 0 && card.check->analysis[0].column == 4 && - card.check->analysis[0].severity == ALScriptProblem::Severity::Warning); - ensure("the long line, from where it is cut", card.check->analysis[1].line == 1 && card.check->analysis[1].column == 1024 && - card.check->analysis[1].endColumn == 1030); - ensure("no outline as plain text", card.outline.empty()); + UNSCOPED_INFO("no analyzer asked"); + REQUIRE(studio.asks.empty()); + UNSCOPED_INFO("two"); + REQUIRE(card.check->analysis.size() == size_t(2)); + { + INFO("the items, at the first"); + REQUIRE(card.check->analysis[0].line == 0); + REQUIRE(card.check->analysis[0].column == 4); + CHECK(card.check->analysis[0].severity == ALScriptProblem::Severity::Warning); + } + { + INFO("the long line, from where it is cut"); + REQUIRE(card.check->analysis[1].line == 1); + REQUIRE(card.check->analysis[1].column == 1024); + CHECK(card.check->analysis[1].endColumn == 1030); + } + UNSCOPED_INFO("no outline as plain text"); + REQUIRE(card.outline.empty()); card.items.reset(); card.grammar = "json"; card.editor->setText("{ \"door\": { \"speed\": 2 } }\n"); checking.schedule(card, true); checking.pump(3.0); - ensure("nothing to say", card.check->analysis.empty()); - ensure("its keys outlined", card.outline.size() == 2 && card.outline[0].name == "door" && card.outline[1].name == "speed"); + UNSCOPED_INFO("nothing to say"); + REQUIRE(card.check->analysis.empty()); + { + INFO("its keys outlined"); + REQUIRE(card.outline.size() == 2); + CHECK(card.outline[0].name == "door"); + CHECK(card.outline[1].name == "speed"); + } Doc& file = tab("disk", "{ \"a\": 1 }\n"); file.file = "/tmp/a.json"; file.notecard = true; checking.schedule(file, true); - ensure("a text file on disk is not checked", file.check->analysisDue <= 0.0); + UNSCOPED_INFO("a text file on disk is not checked"); + CHECK(file.check->analysisDue <= 0.0); } - template<> template<> - void alscriptstudiochecking_object::test<21>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: Fix All previewed beside the text applies as one step unless it changed", "[alscriptstudiochecking]") { - set_test_name("Fix All previewed: the text after beside the text now, Apply offered, made as one step; not over a text changed since"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); // Asked before the check, asked again once it has answered. @@ -1227,17 +1515,31 @@ namespace tut two.fixes = { fix("Second", 3, 4, 15, "touch_start") }; const std::string before = doc.editor->wholeText(); studio.asks.back().answered(answer(doc, { one, two })); - ensure("asked, with a preview", (bool)studio.preview); + UNSCOPED_INFO("asked, with a preview"); + REQUIRE((bool)studio.preview); studio.preview(); - ensure("nothing made yet", doc.editor->wholeText() == before); + UNSCOPED_INFO("nothing made yet"); + CHECK(doc.editor->wholeText() == before); const std::string& compared = studio.told.back(); - ensure("the text now beside it after" + compared, - compared.rfind("compare a: " + before + " | float count;", 0) == 0 && compared.find(" touch_start() { count = 1; }") != std::string::npos && - compared.find("(CompareNow | FixAllAfter [FIXES]=Fixes [COUNT]=2") != std::string::npos); - ensure("Apply offered", services.reports.back().actions == Names{ "apply_fixes" } && services.reports.back().doc == "a"); - ensure("made", checking.applyPreviewed(doc) && doc.editor->document().line(0) == "float count;" && - doc.editor->undoJournal().undoLabel() == "fix"); - ensure("once", !checking.applyPreviewed(doc)); + { + INFO("the text now beside it after" + compared); + CHECK(compared.rfind("compare a: " + before + " | float count;", 0) == 0); + REQUIRE(compared.find(" touch_start() { count = 1; }") != std::string::npos); + REQUIRE(compared.find("(CompareNow | FixAllAfter [FIXES]=Fixes [COUNT]=2") != std::string::npos); + } + { + INFO("Apply offered"); + CHECK(services.reports.back().actions == Names{ "apply_fixes" }); + CHECK(services.reports.back().doc == "a"); + } + { + INFO("made"); + REQUIRE(checking.applyPreviewed(doc)); + REQUIRE(doc.editor->document().line(0) == "float count;"); + CHECK(doc.editor->undoJournal().undoLabel() == "fix"); + } + UNSCOPED_INFO("once"); + CHECK_FALSE(checking.applyPreviewed(doc)); checking.pump(1.0); ALScriptProblem three = problem(0, "three"); @@ -1247,18 +1549,24 @@ namespace tut studio.preview = nullptr; studio.asks.back().answered(answer(doc, { three, four })); checking.askFixAll(doc, Doc::FixPick{}); - ensure("asked again", (bool)studio.preview); + UNSCOPED_INFO("asked again"); + REQUIRE((bool)studio.preview); studio.preview(); doc.editor->setText("default {}\n"); - ensure("changed since: not made", !checking.applyPreviewed(doc) && doc.editor->wholeText() == "default {}\n"); - ensure("said", services.statuses.back() == "FixAllChangedSince" && services.statusFailures.back()); + { + INFO("changed since: not made"); + REQUIRE_FALSE(checking.applyPreviewed(doc)); + CHECK(doc.editor->wholeText() == "default {}\n"); + } + { + INFO("said"); + CHECK(services.statuses.back() == "FixAllChangedSince"); + REQUIRE(services.statusFailures.back()); + } } - template<> template<> - void alscriptstudiochecking_object::test<22>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: each LSL comment in an SLua script is a note to see to and none in LSL", "[alscriptstudiochecking]") { - set_test_name("each LSL comment in an SLua script a note to see to, before the check's own: Done, and the lint's fix of the line it " - "stands over with it; read again, not twice; none in LSL"); ALScriptStudioChecking& checking = make(); const std::string text = "local s = \"abc\"\n" "-- LSL: llcompat.GetSubString takes indexes from 0, as LSL did; ll.GetSubString takes them from 1.\n" @@ -1275,31 +1583,51 @@ namespace tut compat.fixes = { fix("Write it ll.GetSubString(s, 1, 3)", 2, 6, 36, "ll.GetSubString(s, 1, 3)") }; studio.asks.back().answered(answer(doc, { compat })); const ALScriptProblems& said = doc.check->analysis; - ensure_equals("two notes, then the lint", said.size(), size_t(3)); - ensure("the notes first", said[0].key == "SluaNote" && said[0].line == 1 && said[1].key == "SluaNote" && said[1].line == 3 && - said[2].code == "SlCompatCall"); - ensure("the lint's fix with the note's", said[0].fixes.size() == 2 && said[0].fixes[0].preferred && - said[0].fixes[0].title == "Write it ll.GetSubString(s, 1, 3), and take the note out"); - ensure("the other: Done alone", said[1].fixes.size() == 1 && !said[1].fixes[0].preferred); - ensure("made", checking.applyFix(doc, said[0].fixes[0], version(doc)) && - doc.editor->wholeText() == "local s = \"abc\"\nprint(ll.GetSubString(s, 1, 3))\n-- LSL: something else\nprint(s)\n"); + UNSCOPED_INFO("two notes, then the lint"); + REQUIRE(said.size() == size_t(3)); + { + INFO("the notes first"); + CHECK(said[0].key == "SluaNote"); + CHECK(said[0].line == 1); + CHECK(said[1].key == "SluaNote"); + CHECK(said[1].line == 3); + CHECK(said[2].code == "SlCompatCall"); + } + { + INFO("the lint's fix with the note's"); + REQUIRE(said[0].fixes.size() == 2); + CHECK(said[0].fixes[0].preferred); + CHECK(said[0].fixes[0].title == "Write it ll.GetSubString(s, 1, 3), and take the note out"); + } + { + INFO("the other: Done alone"); + REQUIRE(said[1].fixes.size() == 1); + CHECK_FALSE(said[1].fixes[0].preferred); + } + { + INFO("made"); + REQUIRE(checking.applyFix(doc, said[0].fixes[0], version(doc))); + CHECK(doc.editor->wholeText() == "local s = \"abc\"\nprint(ll.GetSubString(s, 1, 3))\n-- LSL: something else\nprint(s)\n"); + } checking.pump(2.0); studio.asks.back().answered(answer(doc)); - ensure("read again: the one left, once", doc.check->analysis.size() == 1 && doc.check->analysis[0].line == 2); + { + INFO("read again: the one left, once"); + REQUIRE(doc.check->analysis.size() == 1); + CHECK(doc.check->analysis[0].line == 2); + } Doc& lsl = tab("b", "// -- LSL: not SLua\ndefault { state_entry() {} }\n"); checking.schedule(lsl, true); checking.pump(3.0); studio.asks.back().answered(answer(lsl)); - ensure("none in LSL", lsl.check->analysis.empty()); + UNSCOPED_INFO("none in LSL"); + REQUIRE(lsl.check->analysis.empty()); } - template<> template<> - void alscriptstudiochecking_object::test<23>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: Fix All of what LSL left previews when unsafe and asks when all safe", "[alscriptstudiochecking]") { - set_test_name("what is left from LSL fixed: every preferred fix of it, not another problem's; seen first where any could change " - "what the script does, asked as Fix All asks where none could"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); doc.language.lua = true; @@ -1320,12 +1648,21 @@ namespace tut pick.migration = true; studio.preview = nullptr; checking.askFixAll(doc, pick); - ensure("not asked: seen", !studio.preview); + UNSCOPED_INFO("not asked: seen"); + REQUIRE_FALSE(studio.preview); const std::string& compared = studio.told.back(); - ensure("the two from LSL, not the other: " + compared, compared.find("FixAllAfter [FIXES]=Fixes [COUNT]=2") != std::string::npos && - compared.find("float count;") != std::string::npos); - ensure("Apply offered", services.reports.back().actions == Names{ "apply_fixes" }); - ensure("made", checking.applyPreviewed(doc) && doc.editor->document().line(0) == "float count;"); + { + INFO("the two from LSL, not the other: " + compared); + REQUIRE(compared.find("FixAllAfter [FIXES]=Fixes [COUNT]=2") != std::string::npos); + REQUIRE(compared.find("float count;") != std::string::npos); + } + UNSCOPED_INFO("Apply offered"); + CHECK(services.reports.back().actions == Names{ "apply_fixes" }); + { + INFO("made"); + REQUIRE(checking.applyPreviewed(doc)); + CHECK(doc.editor->document().line(0) == "float count;"); + } Doc& safe = tab("b"); safe.language.lua = true; @@ -1336,13 +1673,12 @@ namespace tut studio.asks.back().answered(answer(safe, { first, second })); studio.preview = nullptr; checking.askFixAll(safe, pick); - ensure("all safe: asked as Fix All asks", (bool)studio.preview); + UNSCOPED_INFO("all safe: asked as Fix All asks"); + REQUIRE((bool)studio.preview); } - template<> template<> - void alscriptstudiochecking_object::test<24>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: an unsafe fix of what LSL left is previewed and made by Apply", "[alscriptstudiochecking]") { - set_test_name("what is left from LSL put right where a fix could change the script: previewed beside the text, and made by Apply"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a", "local t = {}\nif #t then print(1) end\n"); doc.language.lua = true; @@ -1356,18 +1692,27 @@ namespace tut Doc::FixPick pick; pick.migration = true; checking.askFixAll(doc, pick); - ensure("previewed, not asked", !studio.preview && studio.told.back().rfind("compare a: ", 0) == 0); - ensure("Apply offered", services.reports.back().actions == Names{ "apply_fixes" }); - ensure("made by Apply", checking.applyPreviewed(doc)); - ensure_equals("put right", doc.editor->document().line(1), std::string("if #t ~= 0 then print(1) end")); - ensure("Apply again: nothing waiting, and said", !checking.applyPreviewed(doc) && services.statuses.back() == "FixAllNotPreviewed" && - services.statusFailures.back()); + { + INFO("previewed, not asked"); + REQUIRE_FALSE(studio.preview); + CHECK(studio.told.back().rfind("compare a: ", 0) == 0); + } + UNSCOPED_INFO("Apply offered"); + CHECK(services.reports.back().actions == Names{ "apply_fixes" }); + UNSCOPED_INFO("made by Apply"); + CHECK(checking.applyPreviewed(doc)); + UNSCOPED_INFO("put right"); + CHECK(doc.editor->document().line(1) == std::string("if #t ~= 0 then print(1) end")); + { + INFO("Apply again: nothing waiting, and said"); + CHECK_FALSE(checking.applyPreviewed(doc)); + CHECK(services.statuses.back() == "FixAllNotPreviewed"); + REQUIRE(services.statusFailures.back()); + } } - template<> template<> - void alscriptstudiochecking_object::test<25>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: a require alias fix names its folder only once its edit takes", "[alscriptstudiochecking]") { - set_test_name("a fix that moves a require onto a SLua alias of the studio's own names the folder once its edit is sure to take, and is refused with nothing changed where the name is another folder's"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); std::vector named; @@ -1379,9 +1724,12 @@ namespace tut ALScriptFix moved = fix("Name /inc as the SLua alias @inc, and require it as '@inc/util'", 0, 8, 13, "total", false); moved.key = "ScriptFixRequireAlias"; moved.args = { "@inc/util", "inc", "/inc" }; - ensure("made", checking.applyFix(doc, moved, version(doc))); - ensure("the folder named", named == std::vector{ "inc=/inc" }); - ensure_equals("and the text", doc.editor->document().line(0), std::string("integer total;")); + UNSCOPED_INFO("made"); + CHECK(checking.applyFix(doc, moved, version(doc))); + UNSCOPED_INFO("the folder named"); + CHECK(named == std::vector{ "inc=/inc" }); + UNSCOPED_INFO("and the text"); + CHECK(doc.editor->document().line(0) == std::string("integer total;")); ALScriptFix taken = fix("Name /lib as the SLua alias @inc, and require it as '@inc/util'", 0, 8, 13, "other", false); taken.key = "ScriptFixRequireAlias"; taken.args = { "@inc/util", "inc", "/lib" }; @@ -1389,34 +1737,50 @@ namespace tut // change, or that it would take past its limit. named.clear(); doc.editor->setReadOnly(true); - ensure("not made", !checking.applyFix(doc, taken, version(doc))); - ensure("and nothing named", named.empty()); + UNSCOPED_INFO("not made"); + CHECK_FALSE(checking.applyFix(doc, taken, version(doc))); + UNSCOPED_INFO("and nothing named"); + REQUIRE(named.empty()); doc.editor->setReadOnly(false); ALScriptFix longer = taken; longer.edits[0].text = "a_name_longer_than_the_text_has_room_for"; doc.editor->setMaxBytes(doc.editor->document().byteCount()); - ensure("past the limit: not made", !checking.applyFix(doc, longer, version(doc))); - ensure("nor named", named.empty()); + UNSCOPED_INFO("past the limit: not made"); + CHECK_FALSE(checking.applyFix(doc, longer, version(doc))); + UNSCOPED_INFO("nor named"); + REQUIRE(named.empty()); doc.editor->setMaxBytes(0); free = false; const U32 was_at = version(doc); - ensure("the name another folder's: refused", !checking.applyFix(doc, taken, version(doc))); - ensure("asked", named == std::vector{ "inc=/lib" }); - ensure("said", services.statuses.back().find("AliasTaken [NAME]=inc") == 0 && services.statusFailures.back()); - ensure("nothing changed", version(doc) == was_at && doc.editor->document().line(0) == "integer total;"); - ensure("nothing to redo", !doc.editor->undoJournal().canRedo()); + UNSCOPED_INFO("the name another folder's: refused"); + CHECK_FALSE(checking.applyFix(doc, taken, version(doc))); + UNSCOPED_INFO("asked"); + CHECK(named == std::vector{ "inc=/lib" }); + { + INFO("said"); + CHECK(services.statuses.back().find("AliasTaken [NAME]=inc") == 0); + REQUIRE(services.statusFailures.back()); + } + { + INFO("nothing changed"); + REQUIRE(version(doc) == was_at); + CHECK(doc.editor->document().line(0) == "integer total;"); + } + UNSCOPED_INFO("nothing to redo"); + CHECK_FALSE(doc.editor->undoJournal().canRedo()); ALScriptFix plain = fix("Require it as './util'", 0, 8, 13, "sum", false); plain.key = "ScriptFixRequireAs"; plain.args = { "./util" }; named.clear(); - ensure("a plain one names nothing", checking.applyFix(doc, plain, version(doc)) && named.empty()); + { + INFO("a plain one names nothing"); + CHECK(checking.applyFix(doc, plain, version(doc))); + REQUIRE(named.empty()); + } } - template<> template<> - void alscriptstudiochecking_object::test<26>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: an include's file keeps its old answer until relexed to its end", "[alscriptstudiochecking]") { - set_test_name("an include's file asked of again after an edit that changes how every line after it starts: what it was, while the text " - "is lexed to its end a slice at a time, then what it is; a check sent of the text as it stands"); ALScriptStudioChecking& checking = make(); std::string text; for (S32 i = 0; i < 3000; ++i) @@ -1426,34 +1790,42 @@ namespace tut Doc& doc = tab("disk:/lib.lsl", text); doc.file = "/lib.lsl"; doc.editor->setSyntax("lsl"); - ensure("a fragment", checking.lslFragment(doc)); + UNSCOPED_INFO("a fragment"); + CHECK(checking.lslFragment(doc)); ALSyntaxHighlighter& highlighter = doc.editor->highlighter(); const S32 last = doc.editor->document().lineCount() - 1; // A string opened at the top runs on to the end: every line after // it starts in it. doc.editor->document().insert(ALTextPos(0, 0), "\""); - ensure("asked again at once: a fragment", checking.lslFragment(doc)); + UNSCOPED_INFO("asked again at once: a fragment"); + CHECK(checking.lslFragment(doc)); highlighter.tokens(last); - ensure("the text not lexed to its end for it: " + std::to_string(highlighter.lastLexed()) + " of " + std::to_string(last + 1) + " left", - highlighter.lastLexed() > last / 2); - ensure("nor kept for the text as it stands", doc.check->fragment->first != version(doc)); - ensure("lexed to its end: what it is, kept", checking.lslFragment(doc) && doc.check->fragment->first == version(doc)); + UNSCOPED_INFO("the text not lexed to its end for it: " + std::to_string(highlighter.lastLexed()) + " of " + std::to_string(last + 1) + " left"); + CHECK(highlighter.lastLexed() > last / 2); + UNSCOPED_INFO("nor kept for the text as it stands"); + CHECK(doc.check->fragment->first != version(doc)); + { + INFO("lexed to its end: what it is, kept"); + REQUIRE(checking.lslFragment(doc)); + CHECK(doc.check->fragment->first == version(doc)); + } // A state at the end of a text set whole: still lexed when the check // is asked, which sends it as it stands, with no state put after it. doc.editor->setText(text + "default\n{\n state_entry() { }\n}\n"); checking.lslFragment(doc); checking.ask(doc, Kind::Check, ALTextPos(), ALTextPos()); - ensure_equals("asked once", studio.asks.size(), size_t(1)); - ensure("of the script as it stands", *studio.asks[0].request.text == doc.editor->text()); - ensure("and a script now", !checking.lslFragment(doc)); + UNSCOPED_INFO("asked once"); + REQUIRE(studio.asks.size() == size_t(1)); + UNSCOPED_INFO("of the script as it stands"); + CHECK(*studio.asks[0].request.text == doc.editor->text()); + UNSCOPED_INFO("and a script now"); + CHECK_FALSE(checking.lslFragment(doc)); } - template<> template<> - void alscriptstudiochecking_object::test<27>() + TEST_CASE_METHOD(alscriptstudiochecking_data, "alscriptstudiochecking: a require alias fix is held to the byte limit leaving out a composition", "[alscriptstudiochecking]") { - set_test_name("a fix that moves a require onto a SLua alias of the studio's own is held to the text's limit as its edit is, without a composition standing in the text"); ALScriptStudioChecking& checking = make(); Doc& doc = tab("a"); std::vector named; @@ -1466,19 +1838,25 @@ namespace tut ALCodeEditor& editor = *doc.editor; editor.setCaret(editor.document().end()); editor.preeditor().updatePreedit("xyz", LLPreeditor::segment_lengths_t{ 3 }, LLPreeditor::standouts_t{ false }, 3); - ensure("composing", editor.hasPreedit()); + UNSCOPED_INFO("composing"); + CHECK(editor.hasPreedit()); editor.setMaxBytes(SCRIPT.size() + 2); ALScriptFix longer = fix("Name /inc as the SLua alias @inc, and require it as '@inc/util'", 0, 8, 13, "counter_", false); longer.key = "ScriptFixRequireAlias"; longer.args = { "@inc/util", "inc", "/inc" }; - ensure("three more: past the limit, not made", !checking.applyFix(doc, longer, version(doc))); - ensure("nor named", named.empty()); + UNSCOPED_INFO("three more: past the limit, not made"); + CHECK_FALSE(checking.applyFix(doc, longer, version(doc))); + UNSCOPED_INFO("nor named"); + REQUIRE(named.empty()); ALScriptFix moved = longer; moved.edits[0].text = "counter"; - ensure("two more: made", checking.applyFix(doc, moved, version(doc))); - ensure("the folder named", named == std::vector{ "inc=/inc" }); - ensure_equals("and the text, the composition gone", editor.text(), "integer counter" + SCRIPT.substr(13)); + UNSCOPED_INFO("two more: made"); + CHECK(checking.applyFix(doc, moved, version(doc))); + UNSCOPED_INFO("the folder named"); + CHECK(named == std::vector{ "inc=/inc" }); + UNSCOPED_INFO("and the text, the composition gone"); + CHECK(editor.text() == "integer counter" + SCRIPT.substr(13)); editor.setMaxBytes(0); } } diff --git a/indra/newview/tests/alscriptstudiocommands_test.cpp b/indra/newview/tests/alscriptstudiocommands_test.cpp index c154a1e877..d53a8756c7 100644 --- a/indra/newview/tests/alscriptstudiocommands_test.cpp +++ b/indra/newview/tests/alscriptstudiocommands_test.cpp @@ -26,11 +26,11 @@ #include "../alscriptstudiocommands.h" -#include "../test/lltut.h" +#include #include -namespace tut +namespace { struct alscriptstudiocommands_data { @@ -39,82 +39,108 @@ namespace tut std::vector done; }; - typedef test_group alscriptstudiocommands_group; - typedef alscriptstudiocommands_group::object alscriptstudiocommands_object; - alscriptstudiocommands_group alscriptstudiocommands_instance("alscriptstudiocommands"); - - template<> template<> - void alscriptstudiocommands_object::test<1>() + TEST_CASE_METHOD(alscriptstudiocommands_data, "alscriptstudiocommands: a command runs by name and reports enabled and checked state", "[alscriptstudiocommands]") { - set_test_name("a command run by name, enabled where it says so or says nothing, and on where it is a toggle that is"); bool can = false; bool wrap = true; - ensure("registered", commands.add("save", [this]() { done.push_back("save"); }, [&can]() { return can; })); - ensure("and a toggle", commands.add("word_wrap", [&wrap]() { wrap = !wrap; }, nullptr, [&wrap]() { return wrap; })); - ensure("and one saying nothing of either", commands.add("close", [this]() { done.push_back("close"); })); + UNSCOPED_INFO("registered"); + CHECK(commands.add("save", [this]() { done.push_back("save"); }, [&can]() { return can; })); + UNSCOPED_INFO("and a toggle"); + CHECK(commands.add("word_wrap", [&wrap]() { wrap = !wrap; }, nullptr, [&wrap]() { return wrap; })); + UNSCOPED_INFO("and one saying nothing of either"); + CHECK(commands.add("close", [this]() { done.push_back("close"); })); - ensure("known", commands.has("save") && commands.has("word_wrap") && commands.has("close")); - ensure("not enabled while it says it cannot", !commands.enabled("save")); + { + INFO("known"); + REQUIRE(commands.has("save")); + REQUIRE(commands.has("word_wrap")); + REQUIRE(commands.has("close")); + } + UNSCOPED_INFO("not enabled while it says it cannot"); + CHECK_FALSE(commands.enabled("save")); can = true; - ensure("enabled once it can", commands.enabled("save")); - ensure("one saying nothing, always", commands.enabled("close")); + UNSCOPED_INFO("enabled once it can"); + CHECK(commands.enabled("save")); + UNSCOPED_INFO("one saying nothing, always"); + CHECK(commands.enabled("close")); commands.run("save"); commands.run("close"); - ensure("each run", done == std::vector{ "save", "close" }); + UNSCOPED_INFO("each run"); + CHECK(done == std::vector{ "save", "close" }); - ensure("the toggle on", commands.checked("word_wrap")); + UNSCOPED_INFO("the toggle on"); + CHECK(commands.checked("word_wrap")); commands.run("word_wrap"); - ensure("and off", !commands.checked("word_wrap") && !wrap); - ensure("no toggle is off", !commands.checked("save")); - ensure("nothing unknown asked", commands.unknownAsked().empty()); + { + INFO("and off"); + CHECK_FALSE(commands.checked("word_wrap")); + CHECK_FALSE(wrap); + } + UNSCOPED_INFO("no toggle is off"); + CHECK_FALSE(commands.checked("save")); + UNSCOPED_INFO("nothing unknown asked"); + REQUIRE(commands.unknownAsked().empty()); } - template<> template<> - void alscriptstudiocommands_object::test<2>() + TEST_CASE_METHOD(alscriptstudiocommands_data, "alscriptstudiocommands: a name registers once and keeps its first command", "[alscriptstudiocommands]") { - set_test_name("a name is registered once, and keeps what it was registered with first"); - ensure("the first", commands.add("save", [this]() { done.push_back("first"); })); - ensure("the second refused", !commands.add("save", [this]() { done.push_back("second"); })); - ensure("unlisted the same", !commands.addUnlisted("save", [this]() { done.push_back("third"); })); + UNSCOPED_INFO("the first"); + CHECK(commands.add("save", [this]() { done.push_back("first"); })); + UNSCOPED_INFO("the second refused"); + CHECK_FALSE(commands.add("save", [this]() { done.push_back("second"); })); + UNSCOPED_INFO("unlisted the same"); + CHECK_FALSE(commands.addUnlisted("save", [this]() { done.push_back("third"); })); commands.run("save"); - ensure("the first's", done == std::vector{ "first" }); - ensure("an unlisted one is a command like any", commands.addUnlisted("reveal", [this]() { done.push_back("reveal"); })); + UNSCOPED_INFO("the first's"); + CHECK(done == std::vector{ "first" }); + UNSCOPED_INFO("an unlisted one is a command like any"); + CHECK(commands.addUnlisted("reveal", [this]() { done.push_back("reveal"); })); commands.run("reveal"); - ensure_equals("run", done.back(), std::string("reveal")); + UNSCOPED_INFO("run"); + CHECK(done.back() == std::string("reveal")); std::vector names = commands.names(); std::sort(names.begin(), names.end()); - ensure("every name, once", names == std::vector{ "reveal", "save" }); + UNSCOPED_INFO("every name, once"); + CHECK(names == std::vector{ "reveal", "save" }); } - template<> template<> - void alscriptstudiocommands_object::test<3>() + TEST_CASE_METHOD(alscriptstudiocommands_data, "alscriptstudiocommands: an unknown name does nothing and is reported once", "[alscriptstudiocommands]") { - set_test_name("a name nothing registered does nothing, cannot be done, is off, and is said once"); commands.run("no_such"); - ensure("not enabled", !commands.enabled("no_such")); - ensure("off", !commands.checked("no_such")); - ensure("not done by a key", !commands.runIfEnabled("no_such")); - ensure("nor known", !commands.has("no_such")); - ensure("said once however often asked", commands.unknownAsked() == std::vector{ "no_such" }); + UNSCOPED_INFO("not enabled"); + CHECK_FALSE(commands.enabled("no_such")); + UNSCOPED_INFO("off"); + CHECK_FALSE(commands.checked("no_such")); + UNSCOPED_INFO("not done by a key"); + CHECK_FALSE(commands.runIfEnabled("no_such")); + UNSCOPED_INFO("nor known"); + REQUIRE_FALSE(commands.has("no_such")); + UNSCOPED_INFO("said once however often asked"); + CHECK(commands.unknownAsked() == std::vector{ "no_such" }); commands.enabled("another"); - ensure("and another once more", commands.unknownAsked() == std::vector{ "no_such", "another" }); + UNSCOPED_INFO("and another once more"); + CHECK(commands.unknownAsked() == std::vector{ "no_such", "another" }); } - template<> template<> - void alscriptstudiocommands_object::test<4>() + TEST_CASE_METHOD(alscriptstudiocommands_data, "alscriptstudiocommands: a key or an ex command does a command only where it can be done now", "[alscriptstudiocommands]") { - set_test_name("a key or an ex command does a command only where it can be done now"); bool can = false; commands.add("format", [this]() { done.push_back("format"); }, [&can]() { return can; }); - ensure("not while it cannot", !commands.runIfEnabled("format") && done.empty()); + { + INFO("not while it cannot"); + CHECK_FALSE(commands.runIfEnabled("format")); + REQUIRE(done.empty()); + } can = true; - ensure("once it can", commands.runIfEnabled("format") && done == std::vector{ "format" }); + { + INFO("once it can"); + CHECK(commands.runIfEnabled("format")); + CHECK(done == std::vector{ "format" }); + } } - template<> template<> - void alscriptstudiocommands_object::test<5>() + TEST_CASE_METHOD(alscriptstudiocommands_data, "alscriptstudiocommands: a command may register others as it runs", "[alscriptstudiocommands]") { - set_test_name("a command may register others as it runs"); commands.add("first", [this]() { // Enough to move the table's own storage about. for (int i = 0; i < 64; ++i) @@ -124,8 +150,10 @@ namespace tut done.push_back("first"); }); commands.run("first"); - ensure("ran to its end", done == std::vector{ "first" }); + UNSCOPED_INFO("ran to its end"); + CHECK(done == std::vector{ "first" }); commands.run("made_63"); - ensure_equals("and what it made runs", done.back(), std::string("made")); + UNSCOPED_INFO("and what it made runs"); + CHECK(done.back() == std::string("made")); } } diff --git a/indra/newview/tests/alscriptstudiocomparepairs_test.cpp b/indra/newview/tests/alscriptstudiocomparepairs_test.cpp index 07a9aeda66..81721692fc 100644 --- a/indra/newview/tests/alscriptstudiocomparepairs_test.cpp +++ b/indra/newview/tests/alscriptstudiocomparepairs_test.cpp @@ -31,7 +31,7 @@ #include "alluauservice.h" #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include namespace { @@ -77,7 +77,7 @@ namespace const std::string RIGHT = "function c()\n x = 1\n y = 2\n z = 3\nend\nfunction a()\n q = 9\n r = 8\nend\nfunction b()\n p = 1\nend"; } -namespace tut +namespace { struct alscriptstudiocomparepairs_data { @@ -91,7 +91,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = window.services().addDoc(id, ALScriptRef(LLUUID::generateNewID(), LLUUID::generateNewID()), id); doc.loaded = true; @@ -122,64 +122,96 @@ namespace tut } }; - typedef test_group alscriptstudiocomparepairs_group; - typedef alscriptstudiocomparepairs_group::object alscriptstudiocomparepairs_object; - tut::alscriptstudiocomparepairs_group alscriptstudiocomparepairs_test("alscriptstudiocomparepairs"); - - template<> template<> - void alscriptstudiocomparepairs_object::test<1>() + TEST_CASE_METHOD(alscriptstudiocomparepairs_data, "alscriptstudiocomparepairs: each text's outline is asked for and functions pair once both answer", "[alscriptstudiocomparepairs]") { - set_test_name("each text's outline asked for as the two are set, from its parse; the functions paired once both are answered"); Doc& doc = tab("tab"); doc.compareView->setTexts(LEFT, RIGHT); - ensure_equals("both asked", studio.asked.size(), size_t(2)); + UNSCOPED_INFO("both asked"); + REQUIRE(studio.asked.size() == size_t(2)); const ALScriptAnalysis::Request& left = studio.asked[0].request; - ensure("the left's shape, as SLua, in front", left.kind == ALScriptAnalysis::Kind::Shape && left.lua && left.front && *left.text == LEFT && - left.id != studio.asked[1].request.id); + { + INFO("the left's shape, as SLua, in front"); + REQUIRE(left.kind == ALScriptAnalysis::Kind::Shape); + REQUIRE(left.lua); + REQUIRE(left.front); + CHECK(*left.text == LEFT); + CHECK(left.id != studio.asked[1].request.id); + } studio.answer(0); - ensure("one answered: nothing yet", doc.compareView->model().pairs().empty() && beside(doc, 0, 0)); + { + INFO("one answered: nothing yet"); + REQUIRE(doc.compareView->model().pairs().empty()); + CHECK(beside(doc, 0, 0)); + } studio.answerAll(); - ensure_equals("a with a, b with b", said(doc.compareView->model().pairs()), std::string("[0-4 5-8][5-7 9-11]")); - ensure("lined up", beside(doc, 0, 5) && beside(doc, 4, 8)); + UNSCOPED_INFO("a with a, b with b"); + CHECK(said(doc.compareView->model().pairs()) == std::string("[0-4 5-8][5-7 9-11]")); + { + INFO("lined up"); + CHECK(beside(doc, 0, 5)); + CHECK(beside(doc, 4, 8)); + } } - template<> template<> - void alscriptstudiocomparepairs_object::test<2>() + TEST_CASE_METHOD(alscriptstudiocomparepairs_data, "alscriptstudiocomparepairs: a side typed in is asked again alone and a stale answer dropped", "[alscriptstudiocomparepairs]") { - set_test_name("typed in: the right's asked again alone, an answer for a text gone dropped, the pairs carried meanwhile; the left stepped: its own"); Doc& doc = tab("tab"); doc.compareView->setTexts(LEFT, RIGHT); studio.answerAll(); doc.compareView->setRightText("-- a note\n" + RIGHT); - ensure("the right alone asked", studio.asked.size() == 1 && studio.asked[0].request.id.find("right") != std::string::npos); - ensure("carried meanwhile", said(doc.compareView->model().pairs()) == "[0-4 6-9][5-7 10-12]" && beside(doc, 0, 6)); + { + INFO("the right alone asked"); + REQUIRE(studio.asked.size() == 1); + REQUIRE(studio.asked[0].request.id.find("right") != std::string::npos); + } + { + INFO("carried meanwhile"); + CHECK(said(doc.compareView->model().pairs()) == "[0-4 6-9][5-7 10-12]"); + CHECK(beside(doc, 0, 6)); + } const std::string again = "-- a note\n-- and another\nfunction b()\n p = 1\nend\n" + RIGHT; doc.compareView->setRightText(again); - ensure_equals("asked again", studio.asked.size(), size_t(2)); - ensure("numbered on", studio.asked[1].request.version > studio.asked[0].request.version); + UNSCOPED_INFO("asked again"); + REQUIRE(studio.asked.size() == size_t(2)); + UNSCOPED_INFO("numbered on"); + CHECK(studio.asked[1].request.version > studio.asked[0].request.version); studio.answer(0); - ensure_equals("the answer for the text gone dropped", said(doc.compareView->model().pairs()), std::string("[0-4 10-13][5-7 14-16]")); + UNSCOPED_INFO("the answer for the text gone dropped"); + CHECK(said(doc.compareView->model().pairs()) == std::string("[0-4 10-13][5-7 14-16]")); studio.answer(0); - ensure_equals("the answer now: the first b with the first", said(doc.compareView->model().pairs()), std::string("[0-4 10-13][5-7 2-4]")); + UNSCOPED_INFO("the answer now: the first b with the first"); + CHECK(said(doc.compareView->model().pairs()) == std::string("[0-4 10-13][5-7 2-4]")); doc.compareView->setLeftText("-- left\n" + LEFT); - ensure("the left alone asked", studio.asked.size() == 1 && studio.asked[0].request.id.find("left") != std::string::npos); + { + INFO("the left alone asked"); + REQUIRE(studio.asked.size() == 1); + REQUIRE(studio.asked[0].request.id.find("left") != std::string::npos); + } studio.answerAll(); - ensure_equals("paired again", said(doc.compareView->model().pairs()), std::string("[1-5 10-13][6-8 2-4]")); + UNSCOPED_INFO("paired again"); + CHECK(said(doc.compareView->model().pairs()) == std::string("[1-5 10-13][6-8 2-4]")); } - template<> template<> - void alscriptstudiocomparepairs_object::test<3>() + TEST_CASE_METHOD(alscriptstudiocomparepairs_data, "alscriptstudiocomparepairs: texts known already pair at once and ranges or a notecard ask nothing", "[alscriptstudiocomparepairs]") { - set_test_name("texts known already paired at once; none asked where there are ranges, nor for a notecard"); Doc& doc = tab("tab"); doc.compareView->setTexts(LEFT, RIGHT); studio.answerAll(); doc.compareView->setTexts(LEFT, RIGHT); - ensure("none asked, paired at once", studio.asked.empty() && !doc.compareView->model().pairs().empty()); + { + INFO("none asked, paired at once"); + REQUIRE(studio.asked.empty()); + REQUIRE_FALSE(doc.compareView->model().pairs().empty()); + } doc.compareView->setTexts(LEFT + "\n", RIGHT, { { 0, 0, 0, 0 } }); - ensure("ranges: none asked", studio.asked.empty() && doc.compareView->model().pairs().empty()); + { + INFO("ranges: none asked"); + REQUIRE(studio.asked.empty()); + REQUIRE(doc.compareView->model().pairs().empty()); + } Doc& card = tab("card", true); card.compareView->setTexts(LEFT, RIGHT); - ensure("a notecard: none asked", studio.asked.empty()); + UNSCOPED_INFO("a notecard: none asked"); + REQUIRE(studio.asked.empty()); } } diff --git a/indra/newview/tests/alscriptstudiocomparewith_test.cpp b/indra/newview/tests/alscriptstudiocomparewith_test.cpp index 93bb65a496..0e736096a9 100644 --- a/indra/newview/tests/alscriptstudiocomparewith_test.cpp +++ b/indra/newview/tests/alscriptstudiocomparewith_test.cpp @@ -32,7 +32,7 @@ #include "alscriptstudio_fixture.h" #include "fsyspath.h" -#include "../test/lltut.h" +#include #include #include @@ -127,7 +127,7 @@ namespace }; } -namespace tut +namespace { struct alscriptstudiocomparewith_data { @@ -179,7 +179,8 @@ namespace tut { doc.editor->selectAll(); doc.editor->insertText(text); - ensure("changed since saved", doc.editor->isDirty()); + UNSCOPED_INFO("changed since saved"); + REQUIRE(doc.editor->isDirty()); } // A file in the test's folder, written as it is given. std::string file(const std::string& name, const std::string& bytes) @@ -191,91 +192,99 @@ namespace tut } }; - typedef test_group alscriptstudiocomparewith_group; - typedef alscriptstudiocomparewith_group::object alscriptstudiocomparewith_object; - tut::alscriptstudiocomparewith_group alscriptstudiocomparewith_test("alscriptstudiocomparewith"); - - template<> template<> - void alscriptstudiocomparewith_object::test<1>() + TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: a saved tab alone is offered a file and an unloaded one nothing", "[alscriptstudiocomparewith]") { - set_test_name("a tab alone, as saved, is offered a file; one not loaded is offered nothing"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "default {}\n"); - ensure("it may be compared", ALScriptStudioCompareWith::canCompare(doc)); + UNSCOPED_INFO("it may be compared"); + CHECK(ALScriptStudioCompareWith::canCompare(doc)); unit->show(doc); - ensure_equals("asked once", studio.picks, 1); - ensure_equals("a file, and nothing else", listed(studio.values()), listed(Names{ "file" })); - ensure_equals("labelled", studio.candidates[0].label, said("CompareWithFile")); + UNSCOPED_INFO("asked once"); + CHECK(studio.picks == 1); + UNSCOPED_INFO("a file, and nothing else"); + CHECK(listed(studio.values()) == listed(Names{ "file" })); + UNSCOPED_INFO("labelled"); + CHECK(studio.candidates[0].label == said("CompareWithFile")); LLStringUtil::format_map_t args; args["[NAME]"] = "door"; - ensure_equals("titled by the tab", studio.picked, said("CompareWithTitle", args)); - ensure_equals("and its hint", studio.hint, said("CompareWithPlaceholder")); + UNSCOPED_INFO("titled by the tab"); + CHECK(studio.picked == said("CompareWithTitle", args)); + UNSCOPED_INFO("and its hint"); + CHECK(studio.hint == said("CompareWithPlaceholder")); Doc& loading = tab("lamp", "", false); - ensure("not before it has loaded", !ALScriptStudioCompareWith::canCompare(loading)); + UNSCOPED_INFO("not before it has loaded"); + CHECK_FALSE(ALScriptStudioCompareWith::canCompare(loading)); unit->show(loading); - ensure_equals("not asked", studio.picks, 1); + UNSCOPED_INFO("not asked"); + CHECK(studio.picks == 1); } - template<> template<> - void alscriptstudiocomparewith_object::test<2>() + TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: a changed tab is offered its saved text unless no step reaches it", "[alscriptstudiocomparewith]") { - set_test_name("its text as last saved offered once it has changed, and chosen beside it; said where no step reaches it"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "as saved\n"); change(doc, "as changed\n"); unit->show(doc); - ensure_equals("first", studio.values().front(), std::string("saved")); - ensure_equals("labelled", studio.candidates[0].label, said("CompareSaved")); + UNSCOPED_INFO("first"); + CHECK(studio.values().front() == std::string("saved")); + UNSCOPED_INFO("labelled"); + CHECK(studio.candidates[0].label == said("CompareSaved")); studio.choose("saved"); - ensure_equals("set beside", listed(studio.did), listed(Names{ "compare door: as saved\n | as changed\n (" + said("CompareSaved") + " | )" })); + UNSCOPED_INFO("set beside"); + CHECK(listed(studio.did) == listed(Names{ "compare door: as saved\n | as changed\n (" + said("CompareSaved") + " | )" })); // A change after an undo past the save: nothing reaches it. doc.editor->undoJournal().markNeverSaved(); studio.choose("saved"); - ensure_equals("not compared", studio.did.size(), 1U); - ensure_equals("said", services().statuses.back(), said("CompareNothingSaved")); - ensure("as a failure", services().statusFailures.back()); + UNSCOPED_INFO("not compared"); + REQUIRE(studio.did.size() == 1U); + UNSCOPED_INFO("said"); + CHECK(services().statuses.back() == said("CompareNothingSaved")); + UNSCOPED_INFO("as a failure"); + REQUIRE(services().statusFailures.back()); } - template<> template<> - void alscriptstudiocomparewith_object::test<3>() + TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: what was saved over it elsewhere is offered until it is settled", "[alscriptstudiocomparewith]") { - set_test_name("what was saved over it elsewhere offered where a save came up against it"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "mine\n"); unit->show(doc); - ensure("not where none did", studio.row("saved_there").value.empty()); + UNSCOPED_INFO("not where none did"); + REQUIRE(studio.row("saved_there").value.empty()); doc.savedThere = "theirs\n"; unit->show(doc); - ensure_equals("offered", studio.row("saved_there").label, said("CompareSavedThere")); + UNSCOPED_INFO("offered"); + CHECK(studio.row("saved_there").label == said("CompareSavedThere")); studio.choose("saved_there"); - ensure_equals("set beside", listed(studio.did), listed(Names{ "compare door: theirs\n | mine\n (" + said("CompareSavedThere") + " | )" })); + UNSCOPED_INFO("set beside"); + CHECK(listed(studio.did) == listed(Names{ "compare door: theirs\n | mine\n (" + said("CompareSavedThere") + " | )" })); // Settled since the list was made: nothing, and said. doc.savedThere.reset(); studio.choose("saved_there"); - ensure_equals("nothing more", studio.did.size(), 1U); - ensure_equals("said", services().statuses.back(), said("CompareSavedThereGone")); - ensure("as a failure", services().statusFailures.back()); + UNSCOPED_INFO("nothing more"); + REQUIRE(studio.did.size() == 1U); + UNSCOPED_INFO("said"); + CHECK(services().statuses.back() == said("CompareSavedThereGone")); + UNSCOPED_INFO("as a failure"); + REQUIRE(services().statusFailures.back()); } - template<> template<> - void alscriptstudiocomparewith_object::test<4>() + TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: other loaded tabs are offered in order and compared as they are now", "[alscriptstudiocomparewith]") { - set_test_name("every other tab loaded offered in the strip's order, said unsaved where it is; chosen as it is now"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& door = tab("door", "door\n"); Doc& lamp = tab("lamp", "lamp as saved\n"); @@ -283,10 +292,14 @@ namespace tut tab("gate", "", false); Doc& sign = tab("sign", "sign\n"); unit->show(door); - ensure_equals("the others loaded, in order", listed(studio.values()), listed(Names{ "tab:lamp", "tab:sign", "file" })); - ensure_equals("by name", studio.row("tab:lamp").label, std::string("lamp")); - ensure_equals("unsaved", studio.row("tab:lamp").detail, said("CompareWithTabUnsaved")); - ensure_equals("saved", studio.row("tab:sign").detail, said("CompareWithTab")); + UNSCOPED_INFO("the others loaded, in order"); + CHECK(listed(studio.values()) == listed(Names{ "tab:lamp", "tab:sign", "file" })); + UNSCOPED_INFO("by name"); + CHECK(studio.row("tab:lamp").label == std::string("lamp")); + UNSCOPED_INFO("unsaved"); + CHECK(studio.row("tab:lamp").detail == said("CompareWithTabUnsaved")); + UNSCOPED_INFO("saved"); + CHECK(studio.row("tab:sign").detail == said("CompareWithTab")); // Typed since the list was made: what is set beside is the tab now. change(lamp, "lamp later\n"); @@ -295,98 +308,113 @@ namespace tut unsaved["[TITLE]"] = "lamp"; // Titled as a copy of it as it was, which stays as it is. const auto snapshot = [this](const std::string& name) { return this->said("CompareTabSnapshot", { { "[NAME]", name } }); }; - ensure_equals("unsaved, as it is now", studio.did.back(), + UNSCOPED_INFO("unsaved, as it is now"); + CHECK(studio.did.back() == "compare door: lamp later\n | door\n (" + snapshot(said("CompareUnsaved", unsaved)) + " | )"); studio.choose("tab:sign"); - ensure_equals("saved, by its name", studio.did.back(), "compare door: sign\n | door\n (" + snapshot("sign") + " | )"); + UNSCOPED_INFO("saved, by its name"); + CHECK(studio.did.back() == "compare door: sign\n | door\n (" + snapshot("sign") + " | )"); // Closed while the list was up: nothing, and said, by the name it // had in the list. sign.loaded = false; services().docs.erase(services().docs.begin() + 3); studio.choose("tab:sign"); - ensure_equals("nothing more", studio.did.size(), 2U); - ensure_equals("said", services().statuses.back(), said("CompareTabClosed", { { "[NAME]", "sign" } })); - ensure("as a failure", services().statusFailures.back()); + UNSCOPED_INFO("nothing more"); + REQUIRE(studio.did.size() == 2U); + UNSCOPED_INFO("said"); + CHECK(services().statuses.back() == said("CompareTabClosed", { { "[NAME]", "sign" } })); + UNSCOPED_INFO("as a failure"); + REQUIRE(services().statusFailures.back()); } - template<> template<> - void alscriptstudiocomparewith_object::test<5>() + TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: the clipboard is offered with its line count when it holds text", "[alscriptstudiocomparewith]") { - set_test_name("the clipboard offered with how many lines it holds, where it holds text; chosen as it holds now"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "door\n"); unit->show(doc); - ensure("not without text", studio.row("clipboard").value.empty()); + UNSCOPED_INFO("not without text"); + REQUIRE(studio.row("clipboard").value.empty()); studio.clipboard = std::string(); unit->show(doc); - ensure("not with none", studio.row("clipboard").value.empty()); + UNSCOPED_INFO("not with none"); + REQUIRE(studio.row("clipboard").value.empty()); studio.clipboard = "one\ntwo\n"; unit->show(doc); - ensure_equals("labelled", studio.row("clipboard").label, said("CompareClipboard")); - ensure_equals("two lines", studio.row("clipboard").detail, services().counted("CompareWithLines", 2)); + UNSCOPED_INFO("labelled"); + CHECK(studio.row("clipboard").label == said("CompareClipboard")); + UNSCOPED_INFO("two lines"); + CHECK(studio.row("clipboard").detail == services().counted("CompareWithLines", 2)); studio.clipboard = "one\ntwo\nthree"; unit->show(doc); - ensure_equals("a last line without a break counted", studio.row("clipboard").detail, services().counted("CompareWithLines", 3)); + UNSCOPED_INFO("a last line without a break counted"); + CHECK(studio.row("clipboard").detail == services().counted("CompareWithLines", 3)); studio.clipboard = "copied since\n"; studio.choose("clipboard"); - ensure_equals("as it holds now", listed(studio.did), listed(Names{ "compare door: copied since\n | door\n (" + said("CompareClipboard") + " | )" })); + UNSCOPED_INFO("as it holds now"); + CHECK(listed(studio.did) == listed(Names{ "compare door: copied since\n | door\n (" + said("CompareClipboard") + " | )" })); studio.clipboard.reset(); studio.choose("clipboard"); - ensure_equals("not once emptied", studio.did.size(), 1U); - ensure_equals("said", services().statuses.back(), said("CompareWithClipboardEmpty")); + UNSCOPED_INFO("not once emptied"); + REQUIRE(studio.did.size() == 1U); + UNSCOPED_INFO("said"); + CHECK(services().statuses.back() == said("CompareWithClipboardEmpty")); } - template<> template<> - void alscriptstudiocomparewith_object::test<6>() + TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: a picked file is compared with LF line breaks or said unreadable", "[alscriptstudiocomparewith]") { - set_test_name("a file picked is read with its line breaks as an editor keeps them and set beside under its name; said where unreadable"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "door\n"); unit->show(doc); studio.choose("file"); - ensure_equals("one file asked for", studio.filesAsked, 1); - ensure("only one", !studio.manyAsked); + UNSCOPED_INFO("one file asked for"); + CHECK(studio.filesAsked == 1); + UNSCOPED_INFO("only one"); + CHECK_FALSE(studio.manyAsked); studio.files({}); - ensure("none picked, nothing", studio.did.empty()); + UNSCOPED_INFO("none picked, nothing"); + REQUIRE(studio.did.empty()); const std::string path = file("other.lsl", "one\r\ntwo\r\n"); studio.files({ path }); - ensure_equals("set beside", listed(studio.did), listed(Names{ "compare door: one\ntwo\n | door\n (other.lsl | )" })); + UNSCOPED_INFO("set beside"); + CHECK(listed(studio.did) == listed(Names{ "compare door: one\ntwo\n | door\n (other.lsl | )" })); unit->show(doc); studio.choose("file"); const std::string missing = folder + "/missing.lsl"; studio.files({ missing }); - ensure_equals("not compared", studio.did.size(), 1U); + UNSCOPED_INFO("not compared"); + REQUIRE(studio.did.size() == 1U); LLStringUtil::format_map_t args; args["[FILE]"] = missing; - ensure_equals("said", services().statuses.back(), said("LoadFromFileFailed", args)); - ensure("as a failure", services().statusFailures.back()); + UNSCOPED_INFO("said"); + CHECK(services().statuses.back() == said("LoadFromFileFailed", args)); + UNSCOPED_INFO("as a failure"); + REQUIRE(services().statusFailures.back()); // The tab closed while the files were picked: nothing. unit->show(doc); studio.choose("file"); services().docs.clear(); studio.files({ path }); - ensure_equals("nothing more", studio.did.size(), 1U); + UNSCOPED_INFO("nothing more"); + REQUIRE(studio.did.size() == 1U); } - template<> template<> - void alscriptstudiocomparewith_object::test<7>() + TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: recent files but the tab's own are offered by name and folder", "[alscriptstudiocomparewith]") { - set_test_name("the files opened lately offered by name and folder, but the tab's own; one chosen set beside"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "door\n"); const std::string own = file("door.lsl", "door\n"); @@ -394,46 +422,51 @@ namespace tut doc.file = own; studio.recent = { own, other }; unit->show(doc); - ensure_equals("the other alone", listed(studio.values()), listed(Names{ "file", "recent:0" })); - ensure_equals("by name", studio.row("recent:0").label, std::string("lamp.lsl")); - ensure_equals("and folder", studio.row("recent:0").detail, gDirUtilp->getDirName(other)); + UNSCOPED_INFO("the other alone"); + CHECK(listed(studio.values()) == listed(Names{ "file", "recent:0" })); + UNSCOPED_INFO("by name"); + CHECK(studio.row("recent:0").label == std::string("lamp.lsl")); + UNSCOPED_INFO("and folder"); + CHECK(studio.row("recent:0").detail == gDirUtilp->getDirName(other)); studio.choose("recent:0"); - ensure_equals("set beside", listed(studio.did), listed(Names{ "compare door: lamp\n | door\n (lamp.lsl | )" })); + UNSCOPED_INFO("set beside"); + CHECK(listed(studio.did) == listed(Names{ "compare door: lamp\n | door\n (lamp.lsl | )" })); } - template<> template<> - void alscriptstudiocomparewith_object::test<8>() + TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: local history is offered with its save count when it has any", "[alscriptstudiocomparewith]") { - set_test_name("its local history offered with how many saves are kept, where any are; chosen, its saves listed"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "door\n"); unit->show(doc); - ensure("not with none kept", studio.row("history").value.empty()); + UNSCOPED_INFO("not with none kept"); + REQUIRE(studio.row("history").value.empty()); for (const char* text : { "first", "second" }) { ALSavedText one; one.key = ALScriptStudioHistory::keyOf(doc); one.text = text; one.when = LLDate::now(); - ensure("kept", history->keep(one)); + UNSCOPED_INFO("kept"); + REQUIRE(history->keep(one)); } unit->show(doc); - ensure_equals("labelled", studio.row("history").label, said("CompareWithHistory")); - ensure_equals("two kept", studio.row("history").detail, services().counted("CompareWithSaves", 2)); + UNSCOPED_INFO("labelled"); + CHECK(studio.row("history").label == said("CompareWithHistory")); + UNSCOPED_INFO("two kept"); + CHECK(studio.row("history").detail == services().counted("CompareWithSaves", 2)); studio.choose("history"); - ensure_equals("listed", listed(studio.did), listed(Names{ "history door" })); + UNSCOPED_INFO("listed"); + CHECK(listed(studio.did) == listed(Names{ "history door" })); } - template<> template<> - void alscriptstudiocomparewith_object::test<9>() + TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: items like it are offered last by name and place and found by place", "[alscriptstudiocomparewith]") { - set_test_name("the items like it in objects in hand offered by name and place, last; one chosen loaded under both"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } const std::string sep = ALScriptExplorerModel::PLACE_SEPARATOR; Doc& doc = tab("door", "door\n"); @@ -441,32 +474,39 @@ namespace tut Item{ ALScriptRef(LLUUID::generateNewID(), LLUUID::generateNewID()), "door", "" } }; studio.clipboard = "x"; unit->show(doc); - ensure_equals("after the rest", listed(studio.values()), listed(Names{ "clipboard", "file", "item:0", "item:1" })); - ensure_equals("by name", studio.row("item:0").label, std::string("door")); - ensure_equals("and place", studio.row("item:0").detail, "House" + sep + "Front"); + UNSCOPED_INFO("after the rest"); + CHECK(listed(studio.values()) == listed(Names{ "clipboard", "file", "item:0", "item:1" })); + UNSCOPED_INFO("by name"); + CHECK(studio.row("item:0").label == std::string("door")); + UNSCOPED_INFO("and place"); + CHECK(studio.row("item:0").detail == "House" + sep + "Front"); studio.choose("item:0"); studio.choose("item:1"); - ensure_equals("each under its place and name", listed(studio.did), + UNSCOPED_INFO("each under its place and name"); + CHECK(listed(studio.did) == listed(Names{ "item door: door (House" + sep + "Front" + sep + "door)", "item door: door (door)" })); // Its place is what is typed to find it. const std::vector ranked = ALQuickOpen::rank(studio.candidates, "front"); - ensure("found by its place", !ranked.empty() && studio.candidates[ranked.front()].value == "item:0"); + { + INFO("found by its place"); + REQUIRE_FALSE(ranked.empty()); + CHECK(studio.candidates[ranked.front()].value == "item:0"); + } } - template<> template<> - void alscriptstudiocomparewith_object::test<10>() + TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: a choice made after the window has gone does nothing", "[alscriptstudiocomparewith]") { - set_test_name("a choice made after the window has gone does nothing"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "door\n"); studio.clipboard = "copied\n"; unit->show(doc); unit.reset(); studio.choose("clipboard"); - ensure("nothing", studio.did.empty()); + UNSCOPED_INFO("nothing"); + REQUIRE(studio.did.empty()); } } diff --git a/indra/newview/tests/alscriptstudiodoc_test.cpp b/indra/newview/tests/alscriptstudiodoc_test.cpp index a906e5f2e9..099828b5bb 100644 --- a/indra/newview/tests/alscriptstudiodoc_test.cpp +++ b/indra/newview/tests/alscriptstudiodoc_test.cpp @@ -32,7 +32,7 @@ #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include #include #include @@ -58,7 +58,7 @@ namespace }; } -namespace tut +namespace { struct alscriptstudiodoc_data { @@ -71,55 +71,64 @@ namespace tut return one; } }; - typedef test_group alscriptstudiodoc_group; - typedef alscriptstudiodoc_group::object alscriptstudiodoc_object; - alscriptstudiodoc_group alscriptstudiodoc_instance("ALScriptStudioDoc"); - template<> template<> - void alscriptstudiodoc_object::test<1>() + TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: what counts as unsaved and when a save is under way", "[ALScriptStudioDoc]") { - set_test_name("unsaved is the text, or a compile target or an experience picked; a save is under way at any stage of it, or while the preprocessor runs"); Doc doc; - ensure("nothing changed", !doc.unsaved()); + UNSCOPED_INFO("nothing changed"); + CHECK_FALSE(doc.unsaved()); doc.targetChosen = true; - ensure("a compile target picked", doc.unsaved()); + UNSCOPED_INFO("a compile target picked"); + CHECK(doc.unsaved()); doc.targetChosen = false; doc.experienceChosen = true; - ensure("an experience picked", doc.unsaved()); + UNSCOPED_INFO("an experience picked"); + CHECK(doc.unsaved()); - ensure("no save", !doc.saveUnderway()); + UNSCOPED_INFO("no save"); + CHECK_FALSE(doc.saveUnderway()); doc.preprocessing = true; - ensure("the preprocessor running, which a save may wait on", doc.saveUnderway()); + UNSCOPED_INFO("the preprocessor running, which a save may wait on"); + CHECK(doc.saveUnderway()); doc.preprocessing = false; ALScriptSaveFlow::Tab tab; tab.holdOnErrors = true; doc.save.route(tab); - ensure("waiting on a check", doc.saveUnderway()); + UNSCOPED_INFO("waiting on a check"); + CHECK(doc.saveUnderway()); doc.save.checked(); - ensure("and not once it has come", !doc.saveUnderway()); + UNSCOPED_INFO("and not once it has come"); + CHECK_FALSE(doc.saveUnderway()); doc.save.sent(ALTextUndo::SavePoint(), std::nullopt, {}); - ensure("sent", doc.saveUnderway()); + UNSCOPED_INFO("sent"); + CHECK(doc.saveUnderway()); } - template<> template<> - void alscriptstudiodoc_object::test<2>() + TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: the expansion is in front only where there is one", "[ALScriptStudioDoc]") { - set_test_name("the expansion is in front only where there is one"); Doc doc; doc.view = Doc::View::Expanded; - ensure("nothing expanded yet: the source", doc.shownView() == Doc::View::Source); - ensure("and its text", doc.shownText() == doc.editor); + UNSCOPED_INFO("nothing expanded yet: the source"); + CHECK(doc.shownView() == Doc::View::Source); + UNSCOPED_INFO("and its text"); + CHECK(doc.shownText() == doc.editor); } - template<> template<> - void alscriptstudiodoc_object::test<3>() + TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: levelOf reads compiler words and severities and ProblemTraits a row", "[ALScriptStudioDoc]") { - set_test_name("levels: the compiler's words, the checkers' severities, the marks, and how the findings store reads a problem"); - ensure("WARNING", Doc::levelOf("WARNING") == Doc::Level::Warning); - ensure("WARN", Doc::levelOf("WARN") == Doc::Level::Warning); - ensure("anything else is an error, as the server has two", Doc::levelOf("ERROR") == Doc::Level::Error && Doc::levelOf("oops") == Doc::Level::Error); - ensure("a note", Doc::levelOf(ALScriptProblem::Severity::Note) == Doc::Level::Note); - ensure("named", std::string(Doc::levelName(Doc::Level::Warning)) == "WARNING"); + UNSCOPED_INFO("WARNING"); + CHECK(Doc::levelOf("WARNING") == Doc::Level::Warning); + UNSCOPED_INFO("WARN"); + CHECK(Doc::levelOf("WARN") == Doc::Level::Warning); + { + INFO("anything else is an error, as the server has two"); + CHECK(Doc::levelOf("ERROR") == Doc::Level::Error); + CHECK(Doc::levelOf("oops") == Doc::Level::Error); + } + UNSCOPED_INFO("a note"); + CHECK(Doc::levelOf(ALScriptProblem::Severity::Note) == Doc::Level::Note); + UNSCOPED_INFO("named"); + CHECK(std::string(Doc::levelName(Doc::Level::Warning)) == "WARNING"); Doc::Shown shown; shown.level = Doc::Level::Warning; @@ -127,29 +136,37 @@ namespace tut shown.message = "unused local"; shown.fileName = "util.luau"; shown.fixes = { fix(ALScriptFix::Kind::Suppress) }; - ensure("a suppression is no fix", !Doc::ProblemTraits::fixable(shown)); + UNSCOPED_INFO("a suppression is no fix"); + CHECK_FALSE(Doc::ProblemTraits::fixable(shown)); shown.fixes.push_back(fix(ALScriptFix::Kind::Fix)); - ensure("a change is", Doc::ProblemTraits::fixable(shown)); - ensure("found by its level's name", Doc::ProblemTraits::mentions(shown, "warn")); - ensure("by its include", Doc::ProblemTraits::mentions(shown, "util")); - ensure("not by what it does not say", !Doc::ProblemTraits::mentions(shown, "state")); - ensure("its rule is where it came from", Doc::ProblemTraits::rule(shown) == "Luau"); - ensure("its level", Doc::ProblemTraits::level(shown) == ALFindingLevel::Warning); + UNSCOPED_INFO("a change is"); + CHECK(Doc::ProblemTraits::fixable(shown)); + UNSCOPED_INFO("found by its level's name"); + CHECK(Doc::ProblemTraits::mentions(shown, "warn")); + UNSCOPED_INFO("by its include"); + CHECK(Doc::ProblemTraits::mentions(shown, "util")); + UNSCOPED_INFO("not by what it does not say"); + CHECK_FALSE(Doc::ProblemTraits::mentions(shown, "state")); + UNSCOPED_INFO("its rule is where it came from"); + CHECK(Doc::ProblemTraits::rule(shown) == "Luau"); + UNSCOPED_INFO("its level"); + CHECK(Doc::ProblemTraits::level(shown) == ALFindingLevel::Warning); } - template<> template<> - void alscriptstudiodoc_object::test<4>() + TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: the fake services say skin words and counts and find tabs", "[ALScriptStudioDoc]") { - set_test_name("the fake of the window's services: the studio's own words, counted, and its tabs found"); al_studio_test::StudioWindow window; if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } al_studio_test::FakeServices services(window.floater); - ensure_equals("a word of the skin's", services.words("ObjectNameComing"), std::string("\xE2\x80\xA6")); - ensure_equals("one", services.counted("Fixes", 1), std::string("1 fix")); - ensure_equals("many", services.counted("Fixes", 3), std::string("3 fixes")); + UNSCOPED_INFO("a word of the skin's"); + CHECK(services.words("ObjectNameComing") == std::string("\xE2\x80\xA6")); + UNSCOPED_INFO("one"); + CHECK(services.counted("Fixes", 1) == std::string("1 fix")); + UNSCOPED_INFO("many"); + CHECK(services.counted("Fixes", 3) == std::string("3 fixes")); LLUUID object, item; object.generate(); @@ -158,58 +175,93 @@ namespace tut Doc& script = services.addDoc("script", ref, "Door"); Doc& file = services.addDoc("disk:/lib.lsl"); file.file = "/lib.lsl"; - ensure("the first in front", services.frontDoc() == &script); - ensure("by id", services.findDoc("disk:/lib.lsl") == &file); - ensure("by what it holds", services.findDoc(ref) == &script); - ensure("none", services.findDoc("nothing") == nullptr); + UNSCOPED_INFO("the first in front"); + CHECK(services.frontDoc() == &script); + UNSCOPED_INFO("by id"); + CHECK(services.findDoc("disk:/lib.lsl") == &file); + UNSCOPED_INFO("by what it holds"); + CHECK(services.findDoc(ref) == &script); + UNSCOPED_INFO("none"); + REQUIRE(services.findDoc("nothing") == nullptr); services.report("Saved", false, &script, { "retry" }); - ensure("said of the tab", services.reports.size() == 1 && services.reports.front().doc == "script" && services.reports.front().actions.size() == 1); + { + INFO("said of the tab"); + REQUIRE(services.reports.size() == 1); + CHECK(services.reports.front().doc == "script"); + REQUIRE(services.reports.front().actions.size() == 1); + } services.openScript(ref, "Door", std::nullopt, 12); - ensure("asked to open at a line", services.opened.size() == 1 && services.opened.front().line == 12); + { + INFO("asked to open at a line"); + REQUIRE(services.opened.size() == 1); + CHECK(services.opened.front().line == 12); + } } - template<> template<> - void alscriptstudiodoc_object::test<5>() + TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: namedIn finds an include line or a require call and foundAs a run's find", "[ALScriptStudioDoc]") { - set_test_name("an include or a module a place names: anywhere on an #include line, or in a require call; and what a run found it as"); const ALTextDocument lsl("default {}\n # include \"lib/util.lsl\" // the helpers\n#include \n#define X \"y.lsl\"\n"); const std::vector none; const std::optional util = Doc::namedIn(lsl, ALTextPos(1, 0), false, none); - ensure("on its line, before the #", util.has_value() && util->name == "lib/util.lsl" && !util->require); - ensure("the whole line", util->range == ALTextRange(ALTextPos(1, 0), ALTextPos(1, lsl.lineLength(1)))); - ensure("angled", Doc::namedIn(lsl, ALTextPos(2, 12), false, none)->name == "sys.lsl"); - ensure("not a string elsewhere", - !Doc::namedIn(lsl, ALTextPos(3, 12), false, none) && !Doc::namedIn(lsl, ALTextPos(0, 3), false, none)); + { + INFO("on its line, before the #"); + REQUIRE(util.has_value()); + REQUIRE(util->name == "lib/util.lsl"); + CHECK_FALSE(util->require); + } + UNSCOPED_INFO("the whole line"); + CHECK(util->range == ALTextRange(ALTextPos(1, 0), ALTextPos(1, lsl.lineLength(1)))); + UNSCOPED_INFO("angled"); + CHECK(Doc::namedIn(lsl, ALTextPos(2, 12), false, none)->name == "sys.lsl"); + { + INFO("not a string elsewhere"); + REQUIRE_FALSE(Doc::namedIn(lsl, ALTextPos(3, 12), false, none)); + REQUIRE_FALSE(Doc::namedIn(lsl, ALTextPos(0, 3), false, none)); + } const std::string source = "local m = require(\"mod\")\nlocal n = 1\n"; const ALTextDocument lua(source); const std::vector calls = ALPreprocessor::requiresIn(source); const std::optional mod = Doc::namedIn(lua, ALTextPos(0, 12), true, calls); - ensure("in a require call", mod.has_value() && mod->name == "mod" && mod->require); - ensure("over the call", mod->range == ALTextRange(ALTextPos(0, 10), ALTextPos(0, 24))); - ensure("not before it", !Doc::namedIn(lua, ALTextPos(0, 3), true, calls)); - ensure("not in LSL", !Doc::namedIn(lua, ALTextPos(0, 12), false, calls)); + { + INFO("in a require call"); + REQUIRE(mod.has_value()); + REQUIRE(mod->name == "mod"); + CHECK(mod->require); + } + UNSCOPED_INFO("over the call"); + CHECK(mod->range == ALTextRange(ALTextPos(0, 10), ALTextPos(0, 24))); + UNSCOPED_INFO("not before it"); + REQUIRE_FALSE(Doc::namedIn(lua, ALTextPos(0, 3), true, calls)); + UNSCOPED_INFO("not in LSL"); + REQUIRE_FALSE(Doc::namedIn(lua, ALTextPos(0, 12), false, calls)); Doc doc; - ensure("no run, nothing found", doc.foundAs("lib/util.lsl").empty()); + UNSCOPED_INFO("no run, nothing found"); + REQUIRE(doc.foundAs("lib/util.lsl").empty()); doc.expanded.valid = true; doc.expanded.resolved = { { "", "lib/util.lsl", false, "disk:/s/lib/util.lsl" }, { "disk:/s/lib/util.lsl", "inner.lsl", false, "disk:/s/inner.lsl" }, { "", "mod", true, "inv:mod" } }; - ensure_equals("the script's own", doc.foundAs("lib/util.lsl"), std::string("disk:/s/lib/util.lsl")); - ensure("not an include's own", doc.foundAs("inner.lsl").empty()); - ensure("a module as a module", doc.foundAs("mod", true) == "inv:mod" && doc.foundAs("mod", false).empty()); + UNSCOPED_INFO("the script's own"); + CHECK(doc.foundAs("lib/util.lsl") == std::string("disk:/s/lib/util.lsl")); + UNSCOPED_INFO("not an include's own"); + REQUIRE(doc.foundAs("inner.lsl").empty()); + { + INFO("a module as a module"); + CHECK(doc.foundAs("mod", true) == "inv:mod"); + REQUIRE(doc.foundAs("mod", false).empty()); + } doc.expanded.valid = false; doc.uploaded.valid = true; doc.uploaded.resolved = { { "", "lib/util.lsl", false, "disk:/s/other.lsl" } }; - ensure_equals("or the last save's run", doc.foundAs("lib/util.lsl"), std::string("disk:/s/other.lsl")); + UNSCOPED_INFO("or the last save's run"); + CHECK(doc.foundAs("lib/util.lsl") == std::string("disk:/s/other.lsl")); } - template<> template<> - void alscriptstudiodoc_object::test<6>() + TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: run-time errors are held until the map is known then placed and counted", "[ALScriptStudioDoc]") { - set_test_name("a run-time error read back to the source, counted where said again; held until the map is known, then placed"); Doc doc; // Six lines run: the first two the include's, the rest the // script's from its first line on. @@ -230,34 +282,68 @@ namespace tut Doc::RuntimeProblem said; said.line = 4; said.message = "Math Error"; - ensure_equals("no map: as the region counts it", doc.placeOfRunning(4, -1).line, 4); + UNSCOPED_INFO("no map: as the region counts it"); + CHECK(doc.placeOfRunning(4, -1).line == 4); doc.heardRuntime(said, true); - ensure("held", doc.runtime.empty() && doc.runtimeHeld.size() == 1); + { + INFO("held"); + REQUIRE(doc.runtime.empty()); + REQUIRE(doc.runtimeHeld.size() == 1); + } doc.heardRuntime(said, true); doc.uploaded.valid = true; doc.uploaded.map = map; const Doc::RunningPlace place = doc.placeOfRunning(1, 3); - ensure("an include's line, by its path and name", place.line == 1 && place.column == 3 && place.file == "disk:/s/lib.lsl" && place.fileName == "lib.lsl"); + { + INFO("an include's line, by its path and name"); + CHECK(place.line == 1); + CHECK(place.column == 3); + CHECK(place.file == "disk:/s/lib.lsl"); + CHECK(place.fileName == "lib.lsl"); + } doc.placeHeldRuntime(); - ensure("placed, and let go of", doc.runtimeHeld.empty() && doc.runtime.size() == 1); - ensure("at the source's line, said twice", doc.runtime[0].line == 2 && doc.runtime[0].file.empty() && doc.runtime[0].count == 2); + { + INFO("placed, and let go of"); + REQUIRE(doc.runtimeHeld.empty()); + REQUIRE(doc.runtime.size() == 1); + } + { + INFO("at the source's line, said twice"); + CHECK(doc.runtime[0].line == 2); + REQUIRE(doc.runtime[0].file.empty()); + REQUIRE(doc.runtime[0].count == 2); + } doc.heardRuntime(said, false); - ensure_equals("said again: counted", doc.runtime[0].count, 3); + UNSCOPED_INFO("said again: counted"); + REQUIRE(doc.runtime[0].count == 3); said.line = 0; doc.heardRuntime(said, false); - ensure("in the include", doc.runtime.size() == 2 && doc.runtime[1].file == "disk:/s/lib.lsl" && doc.runtime[1].line == 0); + { + INFO("in the include"); + REQUIRE(doc.runtime.size() == 2); + CHECK(doc.runtime[1].file == "disk:/s/lib.lsl"); + CHECK(doc.runtime[1].line == 0); + } const Doc::RunningPlace made = doc.placeOfRunning(9, -1); - ensure("past the map: code the preprocessor made, at its own line", made.generated && made.line == 9 && made.file.empty()); + { + INFO("past the map: code the preprocessor made, at its own line"); + CHECK(made.generated); + CHECK(made.line == 9); + REQUIRE(made.file.empty()); + } said.line = 9; doc.heardRuntime(said, false); - ensure("said to be there", doc.runtime.size() == 3 && doc.runtime[2].file == Doc::GENERATED && doc.runtime[2].line == 9); + { + INFO("said to be there"); + REQUIRE(doc.runtime.size() == 3); + CHECK(doc.runtime[2].file == Doc::GENERATED); + CHECK(doc.runtime[2].line == 9); + } } - template<> template<> - void alscriptstudiodoc_object::test<7>() + TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: setShown counts errors and warnings but not notes", "[ALScriptStudioDoc]") { - set_test_name("the rows put in counted: errors and warnings, notes not; counted again when others are put in"); Doc doc; std::vector rows(4); rows[0].level = Doc::Level::Error; @@ -265,21 +351,27 @@ namespace tut rows[2].level = Doc::Level::Warning; rows[3].level = Doc::Level::Note; doc.setShown(rows); - ensure("four rows", doc.shown().size() == 4); - ensure_equals("one error", doc.shownErrors, 1); - ensure_equals("two warnings", doc.shownWarnings, 2); + UNSCOPED_INFO("four rows"); + REQUIRE(doc.shown().size() == 4); + UNSCOPED_INFO("one error"); + CHECK(doc.shownErrors == 1); + UNSCOPED_INFO("two warnings"); + CHECK(doc.shownWarnings == 2); doc.setShown({}); - ensure("none", doc.shown().empty() && doc.shownErrors == 0 && doc.shownWarnings == 0); + { + INFO("none"); + REQUIRE(doc.shown().empty()); + CHECK(doc.shownErrors == 0); + CHECK(doc.shownWarnings == 0); + } } - template<> template<> - void alscriptstudiodoc_object::test<8>() + TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: a notecard's items carry into another tab but a script tab has none", "[ALScriptStudioDoc]") { - set_test_name("a notecard's items carried into another tab; a script's tab carries none"); al_studio_test::StudioWindow window; if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } ALCodeEditor::Params p(LLUICtrlFactory::getDefaultParams()); p.name = "editor"; @@ -293,20 +385,24 @@ namespace tut card.items->loaded({ a, b }); Doc there; card.carryItemsTo(there); - ensure("carried", there.carriedEmbedded && there.carriedEmbedded->size() == 2 && (*there.carriedEmbedded)[1] == b); + { + INFO("carried"); + REQUIRE(there.carriedEmbedded); + REQUIRE(there.carriedEmbedded->size() == 2); + CHECK((*there.carriedEmbedded)[1] == b); + } Doc script, after; script.carryItemsTo(after); - ensure("a script's tab carries nothing", !after.carriedEmbedded); + UNSCOPED_INFO("a script's tab carries nothing"); + REQUIRE_FALSE(after.carriedEmbedded); } - template<> template<> - void alscriptstudiodoc_object::test<9>() + TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: undo follows the view in front but the tab's own for a comparison of it", "[ALScriptStudioDoc]") { - set_test_name("undo takes back the view in front's steps, but the tab's own while a comparison that follows the tab is in front"); al_studio_test::StudioWindow window; if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } ALCodeEditor::Params p(LLUICtrlFactory::getDefaultParams()); p.name = "editor"; @@ -319,22 +415,22 @@ namespace tut dp.rect = LLRect(0, 200, 400, 0); doc.compareView = LLUICtrlFactory::create(dp); window.floater->addChild(doc.compareView); - ensure("the source's", doc.undoText() == doc.editor); + UNSCOPED_INFO("the source's"); + CHECK(doc.undoText() == doc.editor); doc.view = Doc::View::Compare; - ensure("a comparison of texts of no tab's: its side's, which has none", doc.undoText() == doc.compareView->shown()); + UNSCOPED_INFO("a comparison of texts of no tab's: its side's, which has none"); + CHECK(doc.undoText() == doc.compareView->shown()); doc.compareTitles = Doc::CompareTitles{ "Saved", "Now" }; - ensure("one that follows the tab: the tab's", doc.undoText() == doc.editor); + UNSCOPED_INFO("one that follows the tab: the tab's"); + CHECK(doc.undoText() == doc.editor); } - template<> template<> - void alscriptstudiodoc_object::test<10>() + TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: a save's envelope carries an upload header only where one is asked for", "[ALScriptStudioDoc]") { - set_test_name("a save's envelope carries an upload header where one is asked for -- what the save hashes to, when and who, " - "between the target line and the code, which it moves down by its lines -- and none where not"); al_studio_test::StudioWindow window; if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } ALCodeEditor::Params p(LLUICtrlFactory::getDefaultParams()); p.name = "editor"; @@ -347,20 +443,34 @@ namespace tut const std::string expanded = "default { state_entry() { llOwnerSay((string)1); } }\n"; const ALScriptEnvelope plain = doc.envelopeFor(expanded, "Test 1.0"); - ensure("none unasked", plain.header.empty()); + UNSCOPED_INFO("none unasked"); + REQUIRE(plain.header.empty()); ALScriptHeaderOptions asked; asked.on = true; asked.creator = "Some One"; const ALScriptEnvelope with = doc.envelopeFor(expanded, "Test 1.0", asked); const std::optional said = ALUploadHeader::parse(with.header, false); - ensure("ours, read back: " + with.header, said.has_value() && said->ours); - ensure_equals("its hash", said->hash, ALUploadHeader::hashOf("mono", doc.editor->text(), expanded)); - ensure_equals("who", said->creator, std::string("Some One")); - ensure("no file: a tab has no link", said->file.empty()); + { + INFO("ours, read back: " + with.header); + REQUIRE(said.has_value()); + CHECK(said->ours); + } + UNSCOPED_INFO("its hash"); + CHECK(said->hash == ALUploadHeader::hashOf("mono", doc.editor->text(), expanded)); + UNSCOPED_INFO("who"); + CHECK(said->creator == std::string("Some One")); + UNSCOPED_INFO("no file: a tab has no link"); + REQUIRE(said->file.empty()); const int lines = static_cast(std::count(with.header.begin(), with.header.end(), '\n')); - ensure_equals("the code its lines down", with.codeLine(), plain.codeLine() + lines); + UNSCOPED_INFO("the code its lines down"); + CHECK(with.codeLine() == plain.codeLine() + lines); const std::optional back = ALScriptEnvelope::parse(with.wrap()); - ensure("parsed back with it", back.has_value() && back->header == with.header && back->expanded == expanded); + { + INFO("parsed back with it"); + REQUIRE(back.has_value()); + REQUIRE(back->header == with.header); + CHECK(back->expanded == expanded); + } } } diff --git a/indra/newview/tests/alscriptstudioexpandedcompare_test.cpp b/indra/newview/tests/alscriptstudioexpandedcompare_test.cpp index a59469f858..2e87aa38d6 100644 --- a/indra/newview/tests/alscriptstudioexpandedcompare_test.cpp +++ b/indra/newview/tests/alscriptstudioexpandedcompare_test.cpp @@ -31,7 +31,7 @@ #include "alscriptstudio_fixture.h" #include "alsourcemap.h" -#include "../test/lltut.h" +#include #include @@ -93,7 +93,7 @@ namespace } } -namespace tut +namespace { struct alscriptstudioexpandedcompare_data { @@ -148,14 +148,8 @@ namespace tut } }; - typedef test_group alscriptstudioexpandedcompare_group; - typedef alscriptstudioexpandedcompare_group::object alscriptstudioexpandedcompare_object; - tut::alscriptstudioexpandedcompare_group alscriptstudioexpandedcompare_test("alscriptstudioexpandedcompare"); - - template<> template<> - void alscriptstudioexpandedcompare_object::test<1>() + TEST_CASE_METHOD(alscriptstudioexpandedcompare_data, "alscriptstudioexpandedcompare: rangesOf pairs each output line with the source lines it came from", "[alscriptstudioexpandedcompare]") { - set_test_name("each output line beside the script's own lines it came from; lines standing for the same joined; an include's and nothing's in none"); ALSourceMap map; map.addFile("script", std::string()); map.addFile("include", "include.lsl"); @@ -169,89 +163,110 @@ namespace tut map.add(segment(4, 0, 8, 0, 3, 2, false)); map.add(segment(6, 0, 4, 0, 5, 0)); map.finish(); - ensure_equals("the ranges", said(ALScriptStudioExpandedCompare::rangesOf(map)), std::string("[0-0 1-1][1-2 2-2][3-3 3-4][5-5 6-6]")); - ensure("none for nothing", ALScriptStudioExpandedCompare::rangesOf(ALSourceMap()).empty()); + UNSCOPED_INFO("the ranges"); + CHECK(said(ALScriptStudioExpandedCompare::rangesOf(map)) == std::string("[0-0 1-1][1-2 2-2][3-3 3-4][5-5 6-6]")); + UNSCOPED_INFO("none for nothing"); + REQUIRE(ALScriptStudioExpandedCompare::rangesOf(ALSourceMap()).empty()); } - template<> template<> - void alscriptstudioexpandedcompare_object::test<2>() + TEST_CASE_METHOD(alscriptstudioexpandedcompare_data, "alscriptstudioexpandedcompare: the source is lined up beside what a save sends and typing maps back", "[alscriptstudioexpandedcompare]") { - set_test_name("the source beside what a save sends, lined up by the map, the include's line alone; typing goes on in the source where the map says"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& door = tab("door"); - ensure("it can be compared", ALScriptStudioExpandedCompare::canCompare(door)); + UNSCOPED_INFO("it can be compared"); + CHECK(ALScriptStudioExpandedCompare::canCompare(door)); unit->compare(door); - ensure("shown at once, no run asked", studio.compares == 1 && studio.runs == 0); - ensure_equals("under the tab's name and the expansion's", studio.titles, "door | " + services().words("ComparePreprocessed")); - ensure_equals("lined up by line", said(studio.given), std::string("[0-0 1-1][1-1 2-2]")); + { + INFO("shown at once, no run asked"); + CHECK(studio.compares == 1); + CHECK(studio.runs == 0); + } + UNSCOPED_INFO("under the tab's name and the expansion's"); + CHECK(studio.titles == "door | " + services().words("ComparePreprocessed")); + UNSCOPED_INFO("lined up by line"); + CHECK(said(studio.given) == std::string("[0-0 1-1][1-1 2-2]")); ALDiffView& view = *door.compareView; - ensure("the source's first line beside the expansion's second", - view.left()->layout().lineTop(0) == view.right()->layout().lineTop(1)); - ensure_equals("the include's line put in, nothing else changed", view.changeCount(), 1); + UNSCOPED_INFO("the source's first line beside the expansion's second"); + CHECK(view.left()->layout().lineTop(0) == view.right()->layout().lineTop(1)); + UNSCOPED_INFO("the include's line put in, nothing else changed"); + CHECK(view.changeCount() == 1); view.right()->setFocus(true); view.right()->goTo(ALTextPos(2, 8)); view.right()->handleUnicodeChar('x', false); - ensure("typed where the line came from", studio.typedAt.size() == 1 && studio.typedAt[0] == ALTextPos(1, 8)); - ensure_equals("in the source", door.editor->wholeText(), std::string("integer a;\ninteger xb;")); + { + INFO("typed where the line came from"); + REQUIRE(studio.typedAt.size() == 1); + CHECK(studio.typedAt[0] == ALTextPos(1, 8)); + } + UNSCOPED_INFO("in the source"); + CHECK(door.editor->wholeText() == std::string("integer a;\ninteger xb;")); unit->compare(door); view.right()->setFocus(true); view.right()->goTo(ALTextPos(0, 3)); view.right()->handleUnicodeChar('y', false); - ensure("an include's line: nowhere", studio.typedAt.size() == 1); + UNSCOPED_INFO("an include's line: nowhere"); + REQUIRE(studio.typedAt.size() == 1); } - template<> template<> - void alscriptstudioexpandedcompare_object::test<3>() + TEST_CASE_METHOD(alscriptstudioexpandedcompare_data, "alscriptstudioexpandedcompare: a stale expansion is run again first and shown once current", "[alscriptstudioexpandedcompare]") { - set_test_name("an expansion older than the text made again first, and the comparison shown once one of the text as it is comes; a tab closed while it waits let go of"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& door = tab("door"); door.editor->goTo(ALTextPos(0, 0)); door.editor->insertText("// "); unit->compare(door); - ensure("a run asked, nothing shown", studio.runs == 1 && studio.compares == 0); + { + INFO("a run asked, nothing shown"); + CHECK(studio.runs == 1); + CHECK(studio.compares == 0); + } unit->expanded(door); - ensure("a run of the older text: still waiting", studio.compares == 0); + UNSCOPED_INFO("a run of the older text: still waiting"); + CHECK(studio.compares == 0); door.uploaded.version = door.editor->document().version(); unit->expanded(door); - ensure("shown", studio.compares == 1); + UNSCOPED_INFO("shown"); + CHECK(studio.compares == 1); unit->expanded(door); - ensure("once", studio.compares == 1); + UNSCOPED_INFO("once"); + CHECK(studio.compares == 1); // A tab closed while it waited is let go of as the next is asked. Doc& gate = tab("gate"); gate.editor->insertText("// "); unit->compare(gate); - ensure("waiting", unit->waiting("gate")); + UNSCOPED_INFO("waiting"); + CHECK(unit->waiting("gate")); services().docs.erase(std::remove_if(services().docs.begin(), services().docs.end(), [](const std::unique_ptr& doc) { return doc->id == "gate"; }), services().docs.end()); unit->expanded(door); - ensure("closed: let go of", !unit->waiting("gate")); + UNSCOPED_INFO("closed: let go of"); + CHECK_FALSE(unit->waiting("gate")); Doc& lamp = tab("lamp"); lamp.expandedEditor = nullptr; - ensure("not one a save preprocesses", !ALScriptStudioExpandedCompare::canCompare(lamp)); + UNSCOPED_INFO("not one a save preprocesses"); + CHECK_FALSE(ALScriptStudioExpandedCompare::canCompare(lamp)); lamp.expandedEditor = editor("expanded_again", ""); lamp.loaded = false; - ensure("nor before it has loaded", !ALScriptStudioExpandedCompare::canCompare(lamp)); + UNSCOPED_INFO("nor before it has loaded"); + CHECK_FALSE(ALScriptStudioExpandedCompare::canCompare(lamp)); } - template<> template<> - void alscriptstudioexpandedcompare_object::test<4>() + TEST_CASE_METHOD(alscriptstudioexpandedcompare_data, "alscriptstudioexpandedcompare: a real preprocessor run lines each source line up with its output", "[alscriptstudioexpandedcompare]") { - set_test_name("over a real run: an include's lines alone on the right, every line of the script's own beside what it became, a macro's call beside what it made"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } const std::string source = "#include \"lib.lsl\"\n" "#define GREET(x) llOwnerSay(x)\n" @@ -274,7 +289,8 @@ namespace tut return ALPreprocessor::Found::Yes; }; const ALPreprocessor::Result result = ALPreprocessor::run(source, options); - ensure("expanded", result.text.find("llOwnerSay(\"hi\")") != std::string::npos); + UNSCOPED_INFO("expanded"); + REQUIRE(result.text.find("llOwnerSay(\"hi\")") != std::string::npos); Doc& door = tab("door"); door.editor->setText(source); @@ -295,61 +311,93 @@ namespace tut return -1; }; const auto beside = [&view](S32 left, S32 right) { return right >= 0 && view.left()->layout().lineTop(left) == view.right()->layout().lineTop(right); }; - ensure("the include's lines in the output", where("gLib") >= 0); - ensure("default beside default", beside(2, where("default"))); - ensure("state_entry beside state_entry", beside(4, where("state_entry"))); - ensure("the macro's call beside what it made", beside(6, where("llOwnerSay"))); - ensure("the last brace beside the last brace", beside(8, static_cast(out.size()) - (out.back().empty() ? 2 : 1))); + UNSCOPED_INFO("the include's lines in the output"); + CHECK(where("gLib") >= 0); + UNSCOPED_INFO("default beside default"); + CHECK(beside(2, where("default"))); + UNSCOPED_INFO("state_entry beside state_entry"); + CHECK(beside(4, where("state_entry"))); + UNSCOPED_INFO("the macro's call beside what it made"); + CHECK(beside(6, where("llOwnerSay"))); + UNSCOPED_INFO("the last brace beside the last brace"); + REQUIRE(beside(8, static_cast(out.size()) - (out.back().empty() ? 2 : 1))); // What the map alone says: the call's line stands for what it made. const S32 call = view.model().rangeAt(ALDiffModel::Column::Left, 6); - ensure("the call's line in a range", call >= 0); - ensure_equals("whose output is what it made", view.model().ranges()[static_cast(call)].rightFirst, where("llOwnerSay")); - ensure("the directives in none", view.model().rangeAt(ALDiffModel::Column::Left, 0) < 0 && view.model().rangeAt(ALDiffModel::Column::Left, 1) < 0); + UNSCOPED_INFO("the call's line in a range"); + CHECK(call >= 0); + UNSCOPED_INFO("whose output is what it made"); + CHECK(view.model().ranges()[static_cast(call)].rightFirst == where("llOwnerSay")); + { + INFO("the directives in none"); + CHECK(view.model().rangeAt(ALDiffModel::Column::Left, 0) < 0); + CHECK(view.model().rangeAt(ALDiffModel::Column::Left, 1) < 0); + } } - template<> template<> - void alscriptstudioexpandedcompare_object::test<5>() + TEST_CASE_METHOD(alscriptstudioexpandedcompare_data, "alscriptstudioexpandedcompare: a stale run's answer asks again and a wait is dropped when the tab moves on", "[alscriptstudioexpandedcompare]") { - set_test_name("a run of an older text answering, its own dropped while that one was on its way, asks again; said while it waits; let go of once the tab shows something else"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& door = tab("door"); door.editor->goTo(ALTextPos(0, 0)); door.editor->insertText("// "); unit->compare(door); - ensure("a run asked", studio.runs == 1); - ensure_equals("said while it waits", services().statuses.back(), services().words("Preprocessing", { { "[NAME]", "door" } })); + UNSCOPED_INFO("a run asked"); + CHECK(studio.runs == 1); + UNSCOPED_INFO("said while it waits"); + CHECK(services().statuses.back() == services().words("Preprocessing", { { "[NAME]", "door" } })); // The window was busy: the run that answers is the one before. unit->expanded(door); - ensure("asked again rather than left waiting", studio.runs == 2 && studio.compares == 0 && unit->waiting("door")); + { + INFO("asked again rather than left waiting"); + CHECK(studio.runs == 2); + CHECK(studio.compares == 0); + CHECK(unit->waiting("door")); + } door.uploaded.version = door.editor->document().version(); unit->expanded(door); - ensure("shown once the run of the text now answers", studio.compares == 1 && !unit->waiting("door")); + { + INFO("shown once the run of the text now answers"); + CHECK(studio.compares == 1); + CHECK_FALSE(unit->waiting("door")); + } // Another comparison started while it waits: let go of, not put // over it. door.view = Doc::View::Source; door.editor->insertText("// "); unit->compare(door); - ensure("waiting", unit->waiting("door")); + UNSCOPED_INFO("waiting"); + CHECK(unit->waiting("door")); studio.compareRanged(door, "other", door.editor->wholeText(), "other", "door", {}); door.view = Doc::View::Compare; door.uploaded.version = door.editor->document().version(); const S32 runs = studio.runs; unit->expanded(door); - ensure("let go of", !unit->waiting("door")); - ensure("the other comparison left as it is", studio.compares == 2 && studio.runs == runs && studio.titles == "other | door"); + UNSCOPED_INFO("let go of"); + CHECK_FALSE(unit->waiting("door")); + { + INFO("the other comparison left as it is"); + CHECK(studio.compares == 2); + CHECK(studio.runs == runs); + CHECK(studio.titles == "other | door"); + } // Asked from a comparison, which is then closed: let go of. door.editor->insertText("// "); unit->compare(door); - ensure("waiting again", unit->waiting("door")); + UNSCOPED_INFO("waiting again"); + CHECK(unit->waiting("door")); door.view = Doc::View::Source; door.uploaded.version = door.editor->document().version(); unit->expanded(door); - ensure("closed: let go of", !unit->waiting("door") && studio.compares == 2); + { + INFO("closed: let go of"); + CHECK_FALSE(unit->waiting("door")); + CHECK(studio.compares == 2); + } // Still in the comparison it was asked from, which follows the // tab: shown over it. @@ -359,6 +407,10 @@ namespace tut door.compareView->setRightText(door.editor->wholeText()); door.uploaded.version = door.editor->document().version(); unit->expanded(door); - ensure("shown", studio.compares == 3 && !unit->waiting("door")); + { + INFO("shown"); + CHECK(studio.compares == 3); + CHECK_FALSE(unit->waiting("door")); + } } } diff --git a/indra/newview/tests/alscriptstudiofiles_test.cpp b/indra/newview/tests/alscriptstudiofiles_test.cpp index 4d27ef2112..5aaeaa77e3 100644 --- a/indra/newview/tests/alscriptstudiofiles_test.cpp +++ b/indra/newview/tests/alscriptstudiofiles_test.cpp @@ -33,7 +33,7 @@ #include "fsyspath.h" -#include "../test/lltut.h" +#include #include #include @@ -111,7 +111,7 @@ namespace }; } -namespace tut +namespace { struct alscriptstudiofiles_data { @@ -136,7 +136,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } const std::string name = "alscriptstudiofiles_" + LLUUID::generateNewID().asString(); const fsyspath made = std::filesystem::temp_directory_path() / fsyspath(name); @@ -189,67 +189,97 @@ namespace tut const al_studio_test::FakeServices::Said& said() const { return services.reports.back(); } }; - typedef test_group alscriptstudiofiles_group; - typedef alscriptstudiofiles_group::object alscriptstudiofiles_object; - alscriptstudiofiles_group alscriptstudiofiles_instance("alscriptstudiofiles"); - - template<> template<> - void alscriptstudiofiles_object::test<1>() + TEST_CASE_METHOD(alscriptstudiofiles_data, "alscriptstudiofiles: what a file's name says it holds", "[alscriptstudiofiles]") { - set_test_name("what a file's name says it holds"); typedef ALScriptStudioFiles F; - ensure("LSL", F::languageOf("/a/b.lsl", false).script && !F::languageOf("/a/b.lsl", true).lua); - ensure("SLua by .luau and .lua, whatever the case", F::languageOf("/a/b.LUAU", false).lua && F::languageOf("/a/b.lua", false).lua); - ensure("text", !F::languageOf("/a/b.txt", false).script && F::languageOf("/a/b.txt", false).said); - ensure("no extension: what it was asked for as", F::languageOf("/a/b", true).script && F::languageOf("/a/b", true).lua && - !F::languageOf("/a/b", true).said); + { + INFO("LSL"); + CHECK(F::languageOf("/a/b.lsl", false).script); + CHECK_FALSE(F::languageOf("/a/b.lsl", true).lua); + } + { + INFO("SLua by .luau and .lua, whatever the case"); + CHECK(F::languageOf("/a/b.LUAU", false).lua); + CHECK(F::languageOf("/a/b.lua", false).lua); + } + { + INFO("text"); + CHECK_FALSE(F::languageOf("/a/b.txt", false).script); + CHECK(F::languageOf("/a/b.txt", false).said); + } + { + INFO("no extension: what it was asked for as"); + CHECK(F::languageOf("/a/b", true).script); + CHECK(F::languageOf("/a/b", true).lua); + CHECK_FALSE(F::languageOf("/a/b", true).said); + } } - template<> template<> - void alscriptstudiofiles_object::test<2>() + TEST_CASE_METHOD(alscriptstudiofiles_data, "alscriptstudiofiles: the recent lists keep ten newest first each once and survive the state", "[alscriptstudiofiles]") { - set_test_name("the recent lists: newest first, each once, ten at most; a file tab not a script; cleared; kept with the state"); ALScriptStudioFiles& unit = make(); for (int i = 0; i < 12; ++i) { unit.noteFile("/f" + std::to_string(i)); } unit.noteFile("/f5"); - ensure_equals("ten", unit.recentFiles().size(), size_t(10)); + UNSCOPED_INFO("ten"); + REQUIRE(unit.recentFiles().size() == size_t(10)); const Names& files = unit.recentFiles(); - ensure("newest first, the one noted again moved up", - files[0] == "/f5" && files[1] == "/f11" && std::count(files.begin(), files.end(), "/f5") == 1); + { + INFO("newest first, the one noted again moved up"); + CHECK(files[0] == "/f5"); + CHECK(files[1] == "/f11"); + CHECK(std::count(files.begin(), files.end(), "/f5") == 1); + } Doc& a = scriptTab("a", "x"); Doc& b = scriptTab("b", "y"); unit.noteScript(a); unit.noteScript(b); unit.noteScript(a); - ensure("scripts each once, newest first", unit.recentScripts().size() == 2 && unit.recentScripts()[0].ref == a.ref); + { + INFO("scripts each once, newest first"); + REQUIRE(unit.recentScripts().size() == 2); + CHECK(unit.recentScripts()[0].ref == a.ref); + } Doc& f = fileTab("f.lsl", "z"); unit.noteScript(f); - ensure("a file's tab is no script", unit.recentScripts().size() == 2); - ensure_equals("the window told each time", studio.recentTold, 16); + UNSCOPED_INFO("a file's tab is no script"); + REQUIRE(unit.recentScripts().size() == 2); + UNSCOPED_INFO("the window told each time"); + CHECK(studio.recentTold == 16); LLSD state; unit.writeState(state); ALScriptStudioFiles again(services, studio, studio, studio, studio); again.readState(state); - ensure("read back as written", again.recentFiles() == unit.recentFiles() && again.recentScripts().size() == 2 && - again.recentScripts()[1].ref == b.ref && again.recentScripts()[1].name == "b"); + { + INFO("read back as written"); + CHECK(again.recentFiles() == unit.recentFiles()); + REQUIRE(again.recentScripts().size() == 2); + CHECK(again.recentScripts()[1].ref == b.ref); + CHECK(again.recentScripts()[1].name == "b"); + } unit.clearRecent(); - ensure("cleared", unit.recentFiles().empty() && unit.recentScripts().empty() && studio.recentTold == 17); + { + INFO("cleared"); + REQUIRE(unit.recentFiles().empty()); + REQUIRE(unit.recentScripts().empty()); + CHECK(studio.recentTold == 17); + } LLSD odd; odd["recent_files"] = LLSD().with(0, "/x").with(1, "").with(2, "/x").with(3, "/y"); odd["recent_scripts"] = LLSD().with(0, LLSD().with("object", LLUUID::null).with("item", LLUUID::null).with("name", "none")); again.readState(odd); - ensure("read back: each once, none empty, no script without what holds it", - again.recentFiles() == Names{ "/x", "/y" } && again.recentScripts().empty()); + { + INFO("read back: each once, none empty, no script without what holds it"); + CHECK(again.recentFiles() == Names{ "/x", "/y" }); + REQUIRE(again.recentScripts().empty()); + } } - template<> template<> - void alscriptstudiofiles_object::test<3>() + TEST_CASE_METHOD(alscriptstudiofiles_data, "alscriptstudiofiles: Open Recent lists scripts then files and a folder where names clash", "[alscriptstudiofiles]") { - set_test_name("Open Recent filled: scripts then files under their headings, a folder where two share a name; nothing to say so"); ALScriptStudioFiles& unit = make(); LLMenuGL::Params p; p.name = "open_recent"; @@ -258,175 +288,274 @@ namespace tut // menus, which there are none of here. studio.menu->setVisible(false); unit.fillMenu(); - ensure("nothing", studio.menu->findChild("no_recent") != nullptr); + UNSCOPED_INFO("nothing"); + REQUIRE(studio.menu->findChild("no_recent") != nullptr); unit.noteFile("/one/same.lsl"); unit.noteFile("/two/same.lsl"); unit.noteFile("/two/other.lsl"); - ensure("files alone: no heading", studio.menu->findChild("recent_heading_RecentFiles") == nullptr && - studio.menu->findChild("recent_/two/other.lsl") != nullptr); + { + INFO("files alone: no heading"); + REQUIRE(studio.menu->findChild("recent_heading_RecentFiles") == nullptr); + REQUIRE(studio.menu->findChild("recent_/two/other.lsl") != nullptr); + } Doc& a = scriptTab("a", "x"); unit.noteScript(a); - ensure("both: headings", studio.menu->findChild("recent_heading_RecentScripts") != nullptr && - studio.menu->findChild("recent_heading_RecentFiles") != nullptr); + { + INFO("both: headings"); + REQUIRE(studio.menu->findChild("recent_heading_RecentScripts") != nullptr); + REQUIRE(studio.menu->findChild("recent_heading_RecentFiles") != nullptr); + } LLMenuItemCallGL* same = studio.menu->findChild("recent_/one/same.lsl"); - ensure("a folder after a name two share", same && same->getLabel().find("(/one)") != std::string::npos); + { + INFO("a folder after a name two share"); + REQUIRE(same); + REQUIRE(same->getLabel().find("(/one)") != std::string::npos); + } LLMenuItemCallGL* other = studio.menu->findChild("recent_/two/other.lsl"); - ensure("one alone, by its name", other && other->getLabel() == "other.lsl"); + { + INFO("one alone, by its name"); + REQUIRE(other); + CHECK(other->getLabel() == "other.lsl"); + } other->onCommit(); - ensure("picked: opened", studio.opened == Names{ "/two/other.lsl" }); + UNSCOPED_INFO("picked: opened"); + CHECK(studio.opened == Names{ "/two/other.lsl" }); LLMenuItemCallGL* script = studio.menu->findChild("recent_" + a.ref.id()); - ensure("a script by its name", script && script->getLabel() == "a"); + { + INFO("a script by its name"); + REQUIRE(script); + CHECK(script->getLabel() == "a"); + } script->onCommit(); - ensure("picked: opened as a script", !services.opened.empty() && services.opened.back().ref == a.ref); + { + INFO("picked: opened as a script"); + REQUIRE_FALSE(services.opened.empty()); + CHECK(services.opened.back().ref == a.ref); + } studio.menu->findChild("clear_recent")->onCommit(); - ensure("the clear item clears", unit.recentFiles().empty() && studio.menu->findChild("no_recent") != nullptr); + { + INFO("the clear item clears"); + REQUIRE(unit.recentFiles().empty()); + REQUIRE(studio.menu->findChild("no_recent") != nullptr); + } studio.menu->die(); studio.menu = nullptr; } - template<> template<> - void alscriptstudiofiles_object::test<4>() + TEST_CASE_METHOD(alscriptstudiofiles_data, "alscriptstudiofiles: writing a tab's file settles it and a failed write stops the save", "[alscriptstudiofiles]") { - set_test_name("a tab's file written: said, settled and told of; one that will not go said, and the save stopped"); ALScriptStudioFiles& unit = make(); Doc& f = fileTab("f.lsl", "old"); unit.watch(f); f.editor->setText("new"); unit.write(f); - ensure_equals("written", contents(f.file), std::string("new")); - ensure("its own write is no change to the watch", !f.watch->check() && !f.watch->check()); - ensure("said, settled, told of", !said().failure && studio.settled == Names{ f.id } && studio.written == Names{ f.file }); + UNSCOPED_INFO("written"); + CHECK(contents(f.file) == std::string("new")); + { + INFO("its own write is no change to the watch"); + REQUIRE_FALSE(f.watch->check()); + CHECK_FALSE(f.watch->check()); + } + { + INFO("said, settled, told of"); + CHECK_FALSE(said().failure); + CHECK(studio.settled == Names{ f.id }); + CHECK(studio.written == Names{ f.file }); + } Doc& g = fileTab("g.lsl", "x"); g.file = in("no/such/folder/g.lsl"); unit.write(g); - ensure("will not go: said and stopped, not settled", - said().failure && studio.stops == Names{ g.id } && studio.settled.size() == 1); + { + INFO("will not go: said and stopped, not settled"); + CHECK(said().failure); + CHECK(studio.stops == Names{ g.id }); + REQUIRE(studio.settled.size() == 1); + } } - template<> template<> - void alscriptstudiofiles_object::test<5>() + TEST_CASE_METHOD(alscriptstudiofiles_data, "alscriptstudiofiles: an outside change is taken into a clean tab and asked about otherwise", "[alscriptstudiofiles]") { - set_test_name("a file changed outside is taken where the tab is clean; asked about once where it is not, and read again if so answered"); ALScriptStudioFiles& unit = make(); Doc& f = fileTab("f.lsl", "one"); unit.watch(f); - ensure("watched", f.watch && f.watch->path() == f.file); + { + INFO("watched"); + REQUIRE(f.watch); + CHECK(f.watch->path() == f.file); + } write(f.file, "two"); unit.changedOutside(f.id, f.file); - ensure("clean: taken, settled, said", studio.taken == Names{ "two" } && studio.settled == Names{ f.id } && !said().failure); + { + INFO("clean: taken, settled, said"); + CHECK(studio.taken == Names{ "two" }); + CHECK(studio.settled == Names{ f.id }); + CHECK_FALSE(said().failure); + } // Read in, not written: what it masters is the masters' watch's to // send, not the tab's. - ensure("not taken for a write of the studio's", studio.written.empty()); + UNSCOPED_INFO("not taken for a write of the studio's"); + REQUIRE(studio.written.empty()); unit.changedOutside(f.id, f.file); - ensure("the same again: nothing", studio.taken.size() == 1); + UNSCOPED_INFO("the same again: nothing"); + REQUIRE(studio.taken.size() == 1); f.editor->setCaret(f.editor->document().end()); f.editor->insertText(" typed"); write(f.file, "three"); unit.changedOutside(f.id, f.file); - ensure("not clean: said and asked, not taken", said().failure && studio.asked == Names{ f.id } && studio.taken.size() == 1); + { + INFO("not clean: said and asked, not taken"); + CHECK(said().failure); + CHECK(studio.asked == Names{ f.id }); + REQUIRE(studio.taken.size() == 1); + } unit.changedOutside(f.id, f.file); - ensure("asked once while the question is up", studio.asked.size() == 1); + UNSCOPED_INFO("asked once while the question is up"); + REQUIRE(studio.asked.size() == 1); studio.answer(false); - ensure("kept: nothing read", studio.reverted.empty() && !f.askingReload); + { + INFO("kept: nothing read"); + REQUIRE(studio.reverted.empty()); + CHECK_FALSE(f.askingReload); + } unit.changedOutside(f.id, f.file); studio.answer(true); - ensure("read again", studio.reverted == Names{ f.id }); + UNSCOPED_INFO("read again"); + CHECK(studio.reverted == Names{ f.id }); unit.changedOutside("nobody", f.file); const S32 before = studio.reachChanges; std::filesystem::remove(fsyspath(f.file)); unit.changedOutside(f.id, f.file); - ensure("gone or unknown: nothing", studio.asked.size() == 2); - ensure("but what is in reach looked at again", studio.reachChanges == before + 1); + UNSCOPED_INFO("gone or unknown: nothing"); + REQUIRE(studio.asked.size() == 2); + UNSCOPED_INFO("but what is in reach looked at again"); + CHECK(studio.reachChanges == before + 1); } - template<> template<> - void alscriptstudiofiles_object::test<6>() + TEST_CASE_METHOD(alscriptstudiofiles_data, "alscriptstudiofiles: Open picks several and Load and Insert one for the tab asked from", "[alscriptstudiofiles]") { - set_test_name("the pickers: Open several, Load and Insert one for the tab asked from, whatever is in front when the answer comes"); ALScriptStudioFiles& unit = make(); unit.openFromDisk(); - ensure("several", studio.pickedSeveral); + UNSCOPED_INFO("several"); + CHECK(studio.pickedSeveral); studio.toOpen({ "/a.lsl", "/b.luau" }); - ensure("each opened", studio.opened == Names{ "/a.lsl", "/b.luau" }); + UNSCOPED_INFO("each opened"); + CHECK(studio.opened == Names{ "/a.lsl", "/b.luau" }); Doc& a = scriptTab("a", "first"); write(in("load.txt"), "loaded"); unit.load(false); - ensure("one", !studio.pickedSeveral); + UNSCOPED_INFO("one"); + CHECK_FALSE(studio.pickedSeveral); Doc& b = scriptTab("b", "other"); services.front = 1; studio.toOpen({ in("load.txt") }); - ensure("the tab asked from, brought forward, its text replaced", a.editor->text() == "loaded" && b.editor->text() == "other" && - studio.activated == Names{ "a" }); + { + INFO("the tab asked from, brought forward, its text replaced"); + REQUIRE(a.editor->text() == "loaded"); + CHECK(b.editor->text() == "other"); + CHECK(studio.activated == Names{ "a" }); + } services.front = 1; b.editor->setCaret(ALTextPos(0, 2)); unit.load(true); studio.toOpen({ in("load.txt") }); - ensure_equals("inserted at the caret", b.editor->text(), std::string("otloadedher")); + UNSCOPED_INFO("inserted at the caret"); + CHECK(b.editor->text() == std::string("otloadedher")); unit.chosenToLoad("b", { in("nothing.txt") }, false); - ensure("unreadable: said", !services.statuses.empty() && b.editor->text() == "otloadedher"); + { + INFO("unreadable: said"); + REQUIRE_FALSE(services.statuses.empty()); + CHECK(b.editor->text() == "otloadedher"); + } b.modifiable = false; unit.chosenToLoad("b", { in("load.txt") }, false); - ensure("unchangeable: left", b.editor->text() == "otloadedher"); + UNSCOPED_INFO("unchangeable: left"); + CHECK(b.editor->text() == "otloadedher"); } - template<> template<> - void alscriptstudiofiles_object::test<7>() + TEST_CASE_METHOD(alscriptstudiofiles_data, "alscriptstudiofiles: Save to File writes a copy and Save As makes the tab the new file", "[alscriptstudiofiles]") { - set_test_name("Save to File writes a copy; Save As makes the tab the new file, watched there and noted; the same file is a save"); ALScriptStudioFiles& unit = make(); Doc& s = scriptTab("s", "script text"); services.front = 0; unit.saveCopy(); - ensure_equals("named after the tab", studio.savedAs, std::string("s")); + UNSCOPED_INFO("named after the tab"); + CHECK(studio.savedAs == std::string("s")); studio.toSave({ in("copy.lsl") }); - ensure("a copy written, said", contents(in("copy.lsl")) == "script text" && !said().failure); + { + INFO("a copy written, said"); + CHECK(contents(in("copy.lsl")) == "script text"); + CHECK_FALSE(said().failure); + } Doc& f = fileTab("f.lsl", "file text"); services.front = 1; unit.watch(f); unit.saveAs(); studio.toSave({ in("g.luau") }); - ensure_equals("written there", contents(in("g.luau")), std::string("file text")); - ensure("the tab that file now", studio.became == Names{ in("g.luau") } && f.file == in("g.luau")); - ensure("watched there", f.watch && f.watch->path() == in("g.luau")); - ensure("noted, settled, checked", unit.recentFiles().front() == in("g.luau") && studio.settled.back() == f.id && - studio.checked.back() == f.id + " now"); - ensure("told of as written", studio.written == Names{ in("g.luau") }); + UNSCOPED_INFO("written there"); + CHECK(contents(in("g.luau")) == std::string("file text")); + { + INFO("the tab that file now"); + CHECK(studio.became == Names{ in("g.luau") }); + CHECK(f.file == in("g.luau")); + } + { + INFO("watched there"); + REQUIRE(f.watch); + CHECK(f.watch->path() == in("g.luau")); + } + { + INFO("noted, settled, checked"); + CHECK(unit.recentFiles().front() == in("g.luau")); + CHECK(studio.settled.back() == f.id); + CHECK(studio.checked.back() == f.id + " now"); + } + UNSCOPED_INFO("told of as written"); + CHECK(studio.written == Names{ in("g.luau") }); f.editor->setText("changed"); unit.chosenToSaveAs(f.id, { f.file }); - ensure("its own file again: a save", contents(f.file) == "changed" && studio.became.size() == 1); + { + INFO("its own file again: a save"); + CHECK(contents(f.file) == "changed"); + REQUIRE(studio.became.size() == 1); + } Doc& other = fileTab("other.lsl", "o"); unit.chosenToSaveAs(f.id, { other.file }); - ensure("a file another tab has: said, and nothing written", !services.statuses.empty() && - services.statuses.back().find("FileOpenElsewhere") == 0 && - contents(other.file) == "o" && studio.became.size() == 1); + { + INFO("a file another tab has: said, and nothing written"); + REQUIRE_FALSE(services.statuses.empty()); + CHECK(services.statuses.back().find("FileOpenElsewhere") == 0); + CHECK(contents(other.file) == "o"); + REQUIRE(studio.became.size() == 1); + } } - template<> template<> - void alscriptstudiofiles_object::test<8>() + TEST_CASE_METHOD(alscriptstudiofiles_data, "alscriptstudiofiles: a file with a non-ASCII path is written and read back with LF endings", "[alscriptstudiofiles]") { - set_test_name("a file whose name and folder go past ASCII is written and read back, its line endings as an editor keeps them"); make(); // A user's folder and a script's name as a German speaker might // have them: on Windows, read in the ANSI code page, no such file. const fsyspath folder_path = fsyspath(in("J\xC3\xBCrgen")); std::filesystem::create_directories(folder_path); const std::string path = fsyspath(folder_path / fsyspath("\xC3\x9C" "berpr\xC3\xBC" "fung.lsl")).string(); - ensure("written", ALFileWrite::temp(path, "default\r\n{\r\n}\r\n")); + UNSCOPED_INFO("written"); + CHECK(ALFileWrite::temp(path, "default\r\n{\r\n}\r\n")); std::string text; - ensure("read back", ALScriptFileIO::readWholeFile(path, text)); - ensure_equals("as an editor keeps it", text, std::string("default\n{\n}\n")); - ensure("and where it was asked to be", std::filesystem::exists(fsyspath(path))); + UNSCOPED_INFO("read back"); + REQUIRE(ALScriptFileIO::readWholeFile(path, text)); + UNSCOPED_INFO("as an editor keeps it"); + CHECK(text == std::string("default\n{\n}\n")); + UNSCOPED_INFO("and where it was asked to be"); + CHECK(std::filesystem::exists(fsyspath(path))); } - template<> template<> - void alscriptstudiofiles_object::test<9>() + TEST_CASE_METHOD(alscriptstudiofiles_data, "alscriptstudiofiles: pruneRecent drops scripts said gone and files no longer on disk", "[alscriptstudiofiles]") { - set_test_name("what was opened lately and cannot be had any more is let go of: a script said gone, a file no longer on disk"); ALScriptStudioFiles& unit = make(); - ensure("written", ALFileWrite::temp(in("here.lsl"), "x")); + UNSCOPED_INFO("written"); + CHECK(ALFileWrite::temp(in("here.lsl"), "x")); unit.noteFile(in("here.lsl")); unit.noteFile(in("gone.lsl")); Doc& a = scriptTab("a", "x"); @@ -434,33 +563,53 @@ namespace tut unit.noteScript(a); unit.noteScript(b); const S32 told = studio.recentTold; - ensure("the file no longer there let go of", unit.pruneRecent([](const ALScriptRef&) { return false; }) && - unit.recentFiles() == Names{ in("here.lsl") } && unit.recentScripts().size() == 2 && - studio.recentTold == told + 1); - ensure("nothing more gone, nothing done", !unit.pruneRecent([](const ALScriptRef&) { return false; }) && studio.recentTold == told + 1); + { + INFO("the file no longer there let go of"); + CHECK(unit.pruneRecent([](const ALScriptRef&) { return false; })); + CHECK(unit.recentFiles() == Names{ in("here.lsl") }); + REQUIRE(unit.recentScripts().size() == 2); + CHECK(studio.recentTold == told + 1); + } + { + INFO("nothing more gone, nothing done"); + CHECK_FALSE(unit.pruneRecent([](const ALScriptRef&) { return false; })); + CHECK(studio.recentTold == told + 1); + } const ALScriptRef lost = b.ref; - ensure("pruned", unit.pruneRecent([lost](const ALScriptRef& ref) { return ref == lost; })); - ensure("the gone script let go of", unit.recentScripts().size() == 1 && unit.recentScripts()[0].ref == a.ref); - ensure("the file still there kept", unit.recentFiles() == Names{ in("here.lsl") }); + UNSCOPED_INFO("pruned"); + CHECK(unit.pruneRecent([lost](const ALScriptRef& ref) { return ref == lost; })); + { + INFO("the gone script let go of"); + REQUIRE(unit.recentScripts().size() == 1); + CHECK(unit.recentScripts()[0].ref == a.ref); + } + UNSCOPED_INFO("the file still there kept"); + CHECK(unit.recentFiles() == Names{ in("here.lsl") }); } - template<> template<> - void alscriptstudiofiles_object::test<10>() + TEST_CASE_METHOD(alscriptstudiofiles_data, "alscriptstudiofiles: textSyntaxOf picks a grammar by extension in any case or else text", "[alscriptstudiofiles]") { - set_test_name("a file that is no script is coloured by the grammar whose file names its extension, whatever its case, and as text where none does"); // The grammars are the source tree's, which the UI is pointed at. if (!ll_test::HeadlessUI::get().ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } typedef ALScriptStudioFiles F; - ensure_equals("XML", F::textSyntaxOf("/a/s.XML"), std::string("xml")); - ensure_equals("a skin's file", F::textSyntaxOf("/a/s.xui"), std::string("xml")); - ensure_equals("JSON", F::textSyntaxOf("/a/s.json"), std::string("json")); - ensure_equals("a notecard of settings", F::textSyntaxOf("/a/door.ini"), std::string("config")); - ensure_equals("and another way of naming one", F::textSyntaxOf("/a/door.CFG"), std::string("config")); - ensure_equals("text", F::textSyntaxOf("/a/s.txt"), std::string("text")); - ensure_equals("a name no grammar knows", F::textSyntaxOf("/a/s.dat"), std::string("text")); - ensure_equals("and none", F::textSyntaxOf("/a/s"), std::string("text")); + UNSCOPED_INFO("XML"); + CHECK(F::textSyntaxOf("/a/s.XML") == std::string("xml")); + UNSCOPED_INFO("a skin's file"); + CHECK(F::textSyntaxOf("/a/s.xui") == std::string("xml")); + UNSCOPED_INFO("JSON"); + CHECK(F::textSyntaxOf("/a/s.json") == std::string("json")); + UNSCOPED_INFO("a notecard of settings"); + CHECK(F::textSyntaxOf("/a/door.ini") == std::string("config")); + UNSCOPED_INFO("and another way of naming one"); + CHECK(F::textSyntaxOf("/a/door.CFG") == std::string("config")); + UNSCOPED_INFO("text"); + CHECK(F::textSyntaxOf("/a/s.txt") == std::string("text")); + UNSCOPED_INFO("a name no grammar knows"); + CHECK(F::textSyntaxOf("/a/s.dat") == std::string("text")); + UNSCOPED_INFO("and none"); + CHECK(F::textSyntaxOf("/a/s") == std::string("text")); } } diff --git a/indra/newview/tests/alscriptstudiohistory_test.cpp b/indra/newview/tests/alscriptstudiohistory_test.cpp index 49578d2de0..e279ac1a08 100644 --- a/indra/newview/tests/alscriptstudiohistory_test.cpp +++ b/indra/newview/tests/alscriptstudiohistory_test.cpp @@ -34,7 +34,7 @@ #include "alscriptstudio_fixture.h" #include "fsyspath.h" -#include "../test/lltut.h" +#include #include @@ -93,7 +93,7 @@ namespace }; } -namespace tut +namespace { struct alscriptstudiohistory_data { @@ -147,41 +147,42 @@ namespace tut one.text = text; one.when = LLDate(LLDate::now().secondsSinceEpoch() - ago); one.asset = asset; - ensure("kept", history->keep(one)); + UNSCOPED_INFO("kept"); + REQUIRE(history->keep(one)); } }; - typedef test_group alscriptstudiohistory_group; - typedef alscriptstudiohistory_group::object alscriptstudiohistory_object; - tut::alscriptstudiohistory_group alscriptstudiohistory_test("alscriptstudiohistory"); - - template<> template<> - void alscriptstudiohistory_object::test<1>() + TEST_CASE_METHOD(alscriptstudiohistory_data, "alscriptstudiohistory: keyOf keys saves by item and object and gives a file no key", "[alscriptstudiohistory]") { - set_test_name("an item's saves are kept by the item, in its object or not; a file's are not kept here"); Doc doc; doc.ref = ALScriptRef(LLUUID::null, LLUUID::generateNewID()); - ensure_equals("an inventory item's", ALScriptStudioHistory::keyOf(doc), ALRecoveryStore::keyOf(LLUUID::null, doc.ref.item, std::string())); + UNSCOPED_INFO("an inventory item's"); + CHECK(ALScriptStudioHistory::keyOf(doc) == ALRecoveryStore::keyOf(LLUUID::null, doc.ref.item, std::string())); doc.ref = ALScriptRef(LLUUID::generateNewID(), LLUUID::generateNewID()); - ensure_equals("an object's", ALScriptStudioHistory::keyOf(doc), ALRecoveryStore::keyOf(doc.ref.object, doc.ref.item, std::string())); + UNSCOPED_INFO("an object's"); + CHECK(ALScriptStudioHistory::keyOf(doc) == ALRecoveryStore::keyOf(doc.ref.object, doc.ref.item, std::string())); doc.file = "/somewhere/door.lsl"; - ensure("none for a file", ALScriptStudioHistory::keyOf(doc).empty()); + UNSCOPED_INFO("none for a file"); + REQUIRE(ALScriptStudioHistory::keyOf(doc).empty()); } - template<> template<> - void alscriptstudiohistory_object::test<2>() + TEST_CASE_METHOD(alscriptstudiohistory_data, "alscriptstudiohistory: a tab's saves list newest first with their sizes or say there are none", "[alscriptstudiohistory]") { - set_test_name("a tab's saves listed newest first: when, how long, against the one before, and which is saved now; none said so"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "now"); unit.show(doc); - ensure("nothing to list", studio.candidates.empty() && !services().statuses.empty()); + { + INFO("nothing to list"); + REQUIRE(studio.candidates.empty()); + REQUIRE_FALSE(services().statuses.empty()); + } LLStringUtil::format_map_t args; args["[NAME]"] = "door"; - ensure_equals("said so", services().statuses.back(), said("HistoryNone", args)); + UNSCOPED_INFO("said so"); + CHECK(services().statuses.back() == said("HistoryNone", args)); const LLUUID current = LLUUID::generateNewID(); saved(doc, "12345", 300.0); @@ -189,57 +190,76 @@ namespace tut saved(doc, "123", 100.0, current); doc.assetId = current; unit.show(doc); - ensure_equals("three", studio.candidates.size(), 3U); - ensure_equals("titled", studio.picked, said("HistoryTitle", args)); + UNSCOPED_INFO("three"); + REQUIRE(studio.candidates.size() == 3U); + UNSCOPED_INFO("titled"); + CHECK(studio.picked == said("HistoryTitle", args)); const std::vector listed = history->list(ALScriptStudioHistory::keyOf(doc)); - ensure_equals("labelled by when", studio.candidates[0].label, ALRecoveryEntry::sayWhen(listed[0].when)); + UNSCOPED_INFO("labelled by when"); + CHECK(studio.candidates[0].label == ALRecoveryEntry::sayWhen(listed[0].when)); const std::string& newest = studio.candidates[0].detail; - ensure("its length" + newest, newest.find(services().counted("HistoryBytes", 3)) != std::string::npos); - ensure("shorter than the one before" + newest, newest.find(services().counted("HistoryShorter", 4)) != std::string::npos); - ensure("saved now" + newest, newest.find(said("HistoryCurrent")) != std::string::npos); + UNSCOPED_INFO("its length" + newest); + REQUIRE(newest.find(services().counted("HistoryBytes", 3)) != std::string::npos); + UNSCOPED_INFO("shorter than the one before" + newest); + REQUIRE(newest.find(services().counted("HistoryShorter", 4)) != std::string::npos); + UNSCOPED_INFO("saved now" + newest); + REQUIRE(newest.find(said("HistoryCurrent")) != std::string::npos); const std::string& middle = studio.candidates[1].detail; - ensure("longer" + middle, middle.find(services().counted("HistoryLonger", 2)) != std::string::npos); - ensure("not saved now" + middle, middle.find(said("HistoryCurrent")) == std::string::npos); - ensure("the first kept says nothing of one before", studio.candidates[2].detail.find(said("HistorySameLength")) == std::string::npos && - studio.candidates[2].detail.find("longer") == std::string::npos); + UNSCOPED_INFO("longer" + middle); + REQUIRE(middle.find(services().counted("HistoryLonger", 2)) != std::string::npos); + UNSCOPED_INFO("not saved now" + middle); + REQUIRE(middle.find(said("HistoryCurrent")) == std::string::npos); + { + INFO("the first kept says nothing of one before"); + REQUIRE(studio.candidates[2].detail.find(said("HistorySameLength")) == std::string::npos); + REQUIRE(studio.candidates[2].detail.find("longer") == std::string::npos); + } } - template<> template<> - void alscriptstudiohistory_object::test<3>() + TEST_CASE_METHOD(alscriptstudiohistory_data, "alscriptstudiohistory: a chosen save is compared with the tab now or once the tab has loaded", "[alscriptstudiohistory]") { - set_test_name("a save chosen is compared with the tab now, and offered back; before the tab has loaded, once it has"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "the text now"); saved(doc, "the text then", 100.0); unit.show(doc); studio.choose(studio.candidates[0].value); - ensure_equals("compared", studio.did.size(), 1U); + UNSCOPED_INFO("compared"); + REQUIRE(studio.did.size() == 1U); LLStringUtil::format_map_t when; when["[WHEN]"] = studio.candidates[0].label; when["[NAME]"] = "door"; - ensure_equals("then beside now", studio.did[0], + UNSCOPED_INFO("then beside now"); + CHECK(studio.did[0] == "compare door: the text then | the text now (" + said("HistorySavedAt", when) + " | " + said("CompareNow") + ")"); - ensure("held to offer back", doc.historyShown && doc.historyShown->text == "the text then"); - ensure("the notice said again", studio.notices == 1); + { + INFO("held to offer back"); + REQUIRE(doc.historyShown); + CHECK(doc.historyShown->text == "the text then"); + } + UNSCOPED_INFO("the notice said again"); + CHECK(studio.notices == 1); Doc& loading = tab("lamp", "", false); saved(loading, "a lamp's text", 50.0); unit.show(loading); studio.choose(studio.candidates[0].value); - ensure_equals("not compared yet", studio.did.size(), 1U); - ensure("once it has loaded", loading.pendingCompare && loading.pendingCompare->text == "a lamp's text"); + UNSCOPED_INFO("not compared yet"); + REQUIRE(studio.did.size() == 1U); + { + INFO("once it has loaded"); + REQUIRE(loading.pendingCompare); + CHECK(loading.pendingCompare->text == "a lamp's text"); + } } - template<> template<> - void alscriptstudiohistory_object::test<4>() + TEST_CASE_METHOD(alscriptstudiohistory_data, "alscriptstudiohistory: the notice offers a save back only where the tab may be changed", "[alscriptstudiohistory]") { - set_test_name("the notice offers a save back where the tab may be changed; restored as carried text, the comparison ended"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "now"); ALSavedText shown; @@ -249,16 +269,17 @@ namespace tut LLStringUtil::format_map_t args; args["[WHEN]"] = ALRecoveryEntry::sayWhen(shown.when); const ALScriptNoticeBar::Notice notice = ALScriptStudioOrphans::noticeFor(&doc, services()); - ensure_equals("said", notice.text, said("NoticeHistory", args)); - ensure_equals("offered back", notice.buttons[0].first, std::string("restore_saved")); + UNSCOPED_INFO("said"); + CHECK(notice.text == said("NoticeHistory", args)); + UNSCOPED_INFO("offered back"); + CHECK(notice.buttons[0].first == std::string("restore_saved")); doc.modifiable = false; - ensure("not where it may not be changed", ALScriptStudioOrphans::noticeFor(&doc, services()).buttons[0].first.empty()); + UNSCOPED_INFO("not where it may not be changed"); + REQUIRE(ALScriptStudioOrphans::noticeFor(&doc, services()).buttons[0].first.empty()); } - template<> template<> - void alscriptstudiohistory_object::test<5>() + TEST_CASE_METHOD(alscriptstudiohistory_data, "alscriptstudiohistory: candidatesOf describes saves with the words and joiner it is given", "[alscriptstudiohistory]") { - set_test_name("a list of saves in a window's own words: each asked by name, with a count where it has one, and joined as it joins"); std::vector saves(3); saves[0].bytes = 10; saves[0].asset = LLUUID::generateNewID(); @@ -279,21 +300,25 @@ namespace tut return out; }; const std::vector listed = ALScriptStudioHistory::candidatesOf(saves, saves[0].asset, words, joined); - ensure_equals("each", listed.size(), 3U); - ensure_equals("the newest", listed[0].detail, std::string("HistoryBytes(10) + HistorySameLength + HistoryCurrent")); - ensure_equals("shorter than the first", listed[1].detail, std::string("HistoryBytes(10) + HistoryShorter(2)")); - ensure_equals("the first says only its length", listed[2].detail, std::string("HistoryBytes(12)")); - ensure_equals("by when", listed[2].label, ALRecoveryEntry::sayWhen(saves[2].when)); - ensure_equals("valued by place", listed[1].value, std::string("1")); + UNSCOPED_INFO("each"); + REQUIRE(listed.size() == 3U); + UNSCOPED_INFO("the newest"); + CHECK(listed[0].detail == std::string("HistoryBytes(10) + HistorySameLength + HistoryCurrent")); + UNSCOPED_INFO("shorter than the first"); + CHECK(listed[1].detail == std::string("HistoryBytes(10) + HistoryShorter(2)")); + UNSCOPED_INFO("the first says only its length"); + CHECK(listed[2].detail == std::string("HistoryBytes(12)")); + UNSCOPED_INFO("by when"); + CHECK(listed[2].label == ALRecoveryEntry::sayWhen(saves[2].when)); + UNSCOPED_INFO("valued by place"); + CHECK(listed[1].value == std::string("1")); } - template<> template<> - void alscriptstudiohistory_object::test<6>() + TEST_CASE_METHOD(alscriptstudiohistory_data, "alscriptstudiohistory: a compared save gets a slider that steps the left through the saves", "[alscriptstudiohistory]") { - set_test_name("a save compared has a slider over the item's saves, oldest first; stepped, the left is that save, its title and the offer back with it"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } studio.host = window.floater; Doc& doc = tab("door", "now\nsame"); @@ -304,34 +329,52 @@ namespace tut // Listed newest first: the middle one. studio.choose(studio.candidates[1].value); ALDiffView& view = *doc.compareView; - ensure("the slider", view.bar()->getChild("versions")->getVisible()); - ensure_equals("at the middle of three, oldest first", view.bar()->versionShown(), 1); - ensure_equals("the second", view.leftText(), std::string("second\nsame")); + UNSCOPED_INFO("the slider"); + CHECK(view.bar()->getChild("versions")->getVisible()); + UNSCOPED_INFO("at the middle of three, oldest first"); + CHECK(view.bar()->versionShown() == 1); + UNSCOPED_INFO("the second"); + CHECK(view.leftText() == std::string("second\nsame")); const S32 notices = studio.notices; ALViewType::as(view.bar()->getChild("newer"))->press(); - ensure_equals("the newest on the left", view.leftText(), std::string("third\nsame")); - ensure("held to offer back", doc.historyShown && doc.historyShown->text == "third\nsame"); + UNSCOPED_INFO("the newest on the left"); + CHECK(view.leftText() == std::string("third\nsame")); + { + INFO("held to offer back"); + REQUIRE(doc.historyShown); + CHECK(doc.historyShown->text == "third\nsame"); + } const std::vector listed = history->list(ALScriptStudioHistory::keyOf(doc)); LLStringUtil::format_map_t when; when["[NAME]"] = "door"; when["[WHEN]"] = ALRecoveryEntry::sayWhen(listed[0].when); - ensure_equals("titled by it", doc.compareTitles->theirs, said("HistorySavedAt", when)); - ensure("said again", !studio.retitled.empty() && studio.retitled.back() == said("HistorySavedAt", when) && studio.notices == notices + 1); - ensure_equals("the right still the tab", view.rightText(), std::string("now\nsame")); + UNSCOPED_INFO("titled by it"); + CHECK(doc.compareTitles->theirs == said("HistorySavedAt", when)); + { + INFO("said again"); + REQUIRE_FALSE(studio.retitled.empty()); + CHECK(studio.retitled.back() == said("HistorySavedAt", when)); + CHECK(studio.notices == notices + 1); + } + UNSCOPED_INFO("the right still the tab"); + CHECK(view.rightText() == std::string("now\nsame")); ALViewType::as(view.bar()->getChild("older"))->press(); ALViewType::as(view.bar()->getChild("older"))->press(); - ensure("the oldest", view.leftText() == "first\nsame" && doc.historyShown->text == "first\nsame" && view.bar()->versionShown() == 0); + { + INFO("the oldest"); + REQUIRE(view.leftText() == "first\nsame"); + CHECK(doc.historyShown->text == "first\nsame"); + CHECK(view.bar()->versionShown() == 0); + } } - template<> template<> - void alscriptstudiohistory_object::test<7>() + TEST_CASE_METHOD(alscriptstudiohistory_data, "alscriptstudiohistory: a save chosen before load gets its slider when shown and a lone one none", "[alscriptstudiohistory]") { - set_test_name("a save chosen before its tab has loaded gets its slider once the comparison is shown; one save alone, none"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } studio.host = window.floater; Doc& loading = tab("lamp", "", false); @@ -339,7 +382,11 @@ namespace tut saved(loading, "two", 100.0); unit.show(loading); studio.choose(studio.candidates[0].value); - ensure("waiting, with something to do once shown", loading.pendingCompare && loading.pendingCompare->shown); + { + INFO("waiting, with something to do once shown"); + REQUIRE(loading.pendingCompare); + REQUIRE(loading.pendingCompare->shown); + } // As the window does once the tab has loaded. loading.loaded = true; loading.editor->setText("two"); @@ -347,23 +394,28 @@ namespace tut loading.pendingCompare.reset(); studio.compareWithTab(loading, pending.text, pending.theirTitle, pending.ownTitle, pending.ranges); pending.shown(loading); - ensure("the slider, at the newest", loading.compareView->bar()->getChild("versions")->getVisible() && - loading.compareView->bar()->versionShown() == 1); + { + INFO("the slider, at the newest"); + REQUIRE(loading.compareView->bar()->getChild("versions")->getVisible()); + CHECK(loading.compareView->bar()->versionShown() == 1); + } Doc& alone = tab("gate", "now"); saved(alone, "only", 100.0); unit.show(alone); studio.choose(studio.candidates[0].value); - ensure("one save: no slider", alone.compareView && !alone.compareView->bar()->getChild("versions")->getVisible()); + { + INFO("one save: no slider"); + REQUIRE(alone.compareView); + CHECK_FALSE(alone.compareView->bar()->getChild("versions")->getVisible()); + } } - template<> template<> - void alscriptstudiohistory_object::test<8>() + TEST_CASE_METHOD(alscriptstudiohistory_data, "alscriptstudiohistory: stepping to an unreadable save says so and puts the slider back", "[alscriptstudiohistory]") { - set_test_name("a save stepped to that can no longer be read: said, the slider put back, the left as it was"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } studio.host = window.floater; Doc& doc = tab("door", "now"); @@ -372,7 +424,8 @@ namespace tut unit.show(doc); studio.choose(studio.candidates[0].value); ALDiffView& view = *doc.compareView; - ensure_equals("at the newest", view.bar()->versionShown(), 1); + UNSCOPED_INFO("at the newest"); + CHECK(view.bar()->versionShown() == 1); // The older one gone from disk since it was listed. const std::vector listed = history->list(ALScriptStudioHistory::keyOf(doc)); std::error_code gone; @@ -381,18 +434,22 @@ namespace tut LLStringUtil::format_map_t args; args["[NAME]"] = "door"; args["[WHEN]"] = ALRecoveryEntry::sayWhen(listed[1].when); - ensure_equals("said", services().statuses.back(), said("HistoryUnreadable", args)); - ensure("the slider put back", view.bar()->versionShown() == 1); - ensure("the left as it was", view.leftText() == "newer" && doc.historyShown->text == "newer"); + UNSCOPED_INFO("said"); + CHECK(services().statuses.back() == said("HistoryUnreadable", args)); + UNSCOPED_INFO("the slider put back"); + CHECK(view.bar()->versionShown() == 1); + { + INFO("the left as it was"); + CHECK(view.leftText() == "newer"); + CHECK(doc.historyShown->text == "newer"); + } } - template<> template<> - void alscriptstudiohistory_object::test<9>() + TEST_CASE_METHOD(alscriptstudiohistory_data, "alscriptstudiohistory: a save stepped to is read once and kept after its file is gone", "[alscriptstudiohistory]") { - set_test_name("a save stepped to is read once and kept: stepped back to after its file is gone, still there"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } studio.host = window.floater; Doc& doc = tab("door", "now"); @@ -404,22 +461,26 @@ namespace tut ALDiffView& view = *doc.compareView; const auto press = [&view](const char* name) { ALViewType::as(view.bar()->getChild(name))->press(); }; press("older"); - ensure_equals("the oldest", view.leftText(), std::string("first")); + UNSCOPED_INFO("the oldest"); + CHECK(view.leftText() == std::string("first")); press("newer"); const std::vector listed = history->list(ALScriptStudioHistory::keyOf(doc)); std::error_code gone; std::filesystem::remove(fsyspath(listed[2].path), gone); press("older"); - ensure("the oldest again, as it was read", view.leftText() == "first" && view.bar()->versionShown() == 0 && doc.historyShown->text == "first"); + { + INFO("the oldest again, as it was read"); + REQUIRE(view.leftText() == "first"); + CHECK(view.bar()->versionShown() == 0); + CHECK(doc.historyShown->text == "first"); + } } - template<> template<> - void alscriptstudiohistory_object::test<10>() + TEST_CASE_METHOD(alscriptstudiohistory_data, "alscriptstudiohistory: letting go of a save as its comparison is left removes its slider", "[alscriptstudiohistory]") { - set_test_name("a save let go of as its comparison is left takes its slider with it: shown again, nothing steps a left that is no longer the save's"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } studio.host = window.floater; Doc& doc = tab("door", "now"); @@ -428,13 +489,23 @@ namespace tut unit.show(doc); studio.choose(studio.candidates[0].value); ALDiffView& view = *doc.compareView; - ensure("the slider", view.bar()->getChild("versions")->getVisible() && view.bar()->versionCount() == 2); + { + INFO("the slider"); + REQUIRE(view.bar()->getChild("versions")->getVisible()); + CHECK(view.bar()->versionCount() == 2); + } // As leaving the comparison does: Escape, or a keystroke typed into // the source. ALScriptStudioHistory::letGo(doc); - ensure("let go of", !doc.historyShown); - ensure("and its slider", view.bar()->versionCount() == 0 && !view.bar()->getChild("versions")->getVisible()); + UNSCOPED_INFO("let go of"); + REQUIRE_FALSE(doc.historyShown); + { + INFO("and its slider"); + REQUIRE(view.bar()->versionCount() == 0); + CHECK_FALSE(view.bar()->getChild("versions")->getVisible()); + } ALViewType::as(view.bar()->getChild("older"))->press(); - ensure_equals("nothing stepped", view.leftText(), std::string("second")); + UNSCOPED_INFO("nothing stepped"); + CHECK(view.leftText() == std::string("second")); } } diff --git a/indra/newview/tests/alscriptstudiomasters_test.cpp b/indra/newview/tests/alscriptstudiomasters_test.cpp index 6422a36d2b..e924cb4b27 100644 --- a/indra/newview/tests/alscriptstudiomasters_test.cpp +++ b/indra/newview/tests/alscriptstudiomasters_test.cpp @@ -36,7 +36,7 @@ #include "newview_test_fakes.h" #include "workqueue.h" -#include "../test/lltut.h" +#include #include @@ -214,7 +214,7 @@ namespace }; } -namespace tut +namespace { struct alscriptstudiomasters_data { @@ -256,7 +256,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } const fsyspath made = std::filesystem::temp_directory_path() / fsyspath("alscriptstudiomasters_" + LLUUID::generateNewID().asString()); std::filesystem::create_directories(made); @@ -327,73 +327,84 @@ namespace tut typedef std::vector Names; }; - typedef test_group alscriptstudiomasters_group; - typedef alscriptstudiomasters_group::object alscriptstudiomasters_object; - alscriptstudiomasters_group alscriptstudiomasters_instance("alscriptstudiomasters"); - - template<> template<> - void alscriptstudiomasters_object::test<1>() + TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: only a loaded changeable item's unlinked tab may be linked", "[alscriptstudiomasters]") { - set_test_name("a tab may be linked where it is an item's, loaded, may be changed and is linked to nothing yet"); make(); Doc& script = itemTab("door", "default {}\n"); Doc& card = itemTab("card", "notes\n", false, true); - ensure("no tab", !unit->canLink(nullptr)); - ensure("an item's script", unit->canLink(&script)); - ensure("an item's notecard", unit->canLink(&card)); + UNSCOPED_INFO("no tab"); + CHECK_FALSE(unit->canLink(nullptr)); + UNSCOPED_INFO("an item's script"); + CHECK(unit->canLink(&script)); + UNSCOPED_INFO("an item's notecard"); + CHECK(unit->canLink(&card)); script.loaded = false; - ensure("not while it loads", !unit->canLink(&script)); + UNSCOPED_INFO("not while it loads"); + CHECK_FALSE(unit->canLink(&script)); script.loaded = true; script.modifiable = false; - ensure("not where it may not be changed", !unit->canLink(&script)); + UNSCOPED_INFO("not where it may not be changed"); + CHECK_FALSE(unit->canLink(&script)); script.modifiable = true; const ALScriptRef ref = script.ref; script.ref = ALScriptRef(); - ensure("not with no item", !unit->canLink(&script)); + UNSCOPED_INFO("not with no item"); + CHECK_FALSE(unit->canLink(&script)); script.ref = ref; studio->openMasterFile(in("a.lsl"), false); - ensure("not a file's tab", !unit->canLink(services.findDoc("disk:" + in("a.lsl")))); + UNSCOPED_INFO("not a file's tab"); + CHECK_FALSE(unit->canLink(services.findDoc("disk:" + in("a.lsl")))); write(in("door.lsl"), "default {}\n"); linkFromElsewhere(script, in("door.lsl")); - ensure("not once it is linked", !unit->canLink(&script)); - ensure("another file's tab masters nothing", !unit->mastersAny(services.findDoc("disk:" + in("a.lsl")))); + UNSCOPED_INFO("not once it is linked"); + CHECK_FALSE(unit->canLink(&script)); + UNSCOPED_INFO("another file's tab masters nothing"); + CHECK_FALSE(unit->mastersAny(services.findDoc("disk:" + in("a.lsl")))); studio->openMasterFile(in("door.lsl"), false); - ensure("the master's tab masters it", unit->mastersAny(services.findDoc("disk:" + in("door.lsl")))); + UNSCOPED_INFO("the master's tab masters it"); + CHECK(unit->mastersAny(services.findDoc("disk:" + in("door.lsl")))); } - template<> template<> - void alscriptstudiomasters_object::test<2>() + TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a notecard carrying items is refused with a reason before any pick", "[alscriptstudiomasters]") { - set_test_name("a notecard carrying items is not linked, and says why, before any file is picked; a script, or a notecard carrying none, carries nothing"); make(); Doc& script = itemTab("door", "default {}\n"); Doc& empty = itemTab("empty", "notes\n", false, true); - ensure("a script carries nothing", !unit->carriesItems(script)); + UNSCOPED_INFO("a script carries nothing"); + CHECK_FALSE(unit->carriesItems(script)); empty.items = std::make_shared(*empty.editor, ALNotecardEmbedded::Holder(), world); - ensure("a notecard with none carries nothing", !unit->carriesItems(empty)); - ensure("and says nothing", services.reports.empty()); + UNSCOPED_INFO("a notecard with none carries nothing"); + CHECK_FALSE(unit->carriesItems(empty)); + UNSCOPED_INFO("and says nothing"); + REQUIRE(services.reports.empty()); Doc& card = itemTab("card", "a b\n", false, true); card.items = std::make_shared(*card.editor, ALNotecardEmbedded::Holder(), world); LLPointer landmark = new LLInventoryItem(); card.items->loaded({ landmark }); - ensure("one with an item carries it", unit->carriesItems(card)); - ensure("said, on its tab, as a failure", says(said().text, "MasterNotecardCarries") && said().failure && said().doc == "card"); + UNSCOPED_INFO("one with an item carries it"); + CHECK(unit->carriesItems(card)); + { + INFO("said, on its tab, as a failure"); + CHECK(says(said().text, "MasterNotecardCarries")); + CHECK(said().failure); + CHECK(said().doc == "card"); + } studio->picked = in("card.txt"); write(in("card.txt"), "a b\n"); unit->linkToFile(card); - ensure_equals("no file asked for", studio->picks, 0); - ensure("nothing linked", !disk.linkOf(card.ref)); + UNSCOPED_INFO("no file asked for"); + CHECK(studio->picks == 0); + UNSCOPED_INFO("nothing linked"); + REQUIRE_FALSE(disk.linkOf(card.ref)); } - template<> template<> - void alscriptstudiomasters_object::test<3>() + TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a file picked of another language is refused and its own is linked", "[alscriptstudiomasters]") { - set_test_name("a file picked of another language is refused, and said, before anything is linked: LSL, SLua, a notecard's, and a name with no extension"); make(); Doc& lsl = itemTab("door", "default {}\n"); Doc& slua = itemTab("lamp", "print(1)\n", true); @@ -407,12 +418,18 @@ namespace tut return !disk.linkOf(doc.ref) && services.reports.size() == before + 1 && alscriptstudiomasters_data::says(said().text, word) && said().failure && said().doc == doc.id && services.findDoc(doc.id) == &doc; }; - ensure("SLua for an LSL script", refused(lsl, "door.luau", "MasterNotLSLFile")); - ensure("a notecard's file for an LSL script", refused(lsl, "door.txt", "MasterNotLSLFile")); - ensure("no extension at all", refused(lsl, "door", "MasterNotLSLFile")); - ensure("LSL for an SLua script", refused(slua, "lamp.lsl", "MasterNotSLuaFile")); - ensure("a script's file for a notecard", refused(card, "card.lsl", "MasterNotNotecardFile")); - ensure("nothing closed", studio->closed.empty()); + UNSCOPED_INFO("SLua for an LSL script"); + CHECK(refused(lsl, "door.luau", "MasterNotLSLFile")); + UNSCOPED_INFO("a notecard's file for an LSL script"); + CHECK(refused(lsl, "door.txt", "MasterNotLSLFile")); + UNSCOPED_INFO("no extension at all"); + CHECK(refused(lsl, "door", "MasterNotLSLFile")); + UNSCOPED_INFO("LSL for an SLua script"); + CHECK(refused(slua, "lamp.lsl", "MasterNotSLuaFile")); + UNSCOPED_INFO("a script's file for a notecard"); + CHECK(refused(card, "card.lsl", "MasterNotNotecardFile")); + UNSCOPED_INFO("nothing closed"); + REQUIRE(studio->closed.empty()); // Each of its own language: linked, its tab giving way. const ALScriptRef lsl_ref = lsl.ref, slua_ref = slua.ref, card_ref = card.ref; @@ -428,15 +445,31 @@ namespace tut const std::optional a = disk.linkOf(lsl_ref); const std::optional b = disk.linkOf(slua_ref); const std::optional c = disk.linkOf(card_ref); - ensure("LSL", a && a->master == in("door.lsl") && !a->lua && !a->notecard && a->target == "mono"); - ensure("SLua, by .lua too", b && b->lua && b->target == "luau"); - ensure("a notecard: no language, no target", c && c->notecard && !c->lua && c->target.empty()); + { + INFO("LSL"); + REQUIRE(a); + REQUIRE(a->master == in("door.lsl")); + REQUIRE_FALSE(a->lua); + REQUIRE_FALSE(a->notecard); + CHECK(a->target == "mono"); + } + { + INFO("SLua, by .lua too"); + REQUIRE(b); + REQUIRE(b->lua); + CHECK(b->target == "luau"); + } + { + INFO("a notecard: no language, no target"); + REQUIRE(c); + REQUIRE(c->notecard); + REQUIRE_FALSE(c->lua); + REQUIRE(c->target.empty()); + } } - template<> template<> - void alscriptstudiomasters_object::test<4>() + TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a linked clean tab gives way and takes the stamp of a matching file", "[alscriptstudiomasters]") { - set_test_name("a clean tab linked: it gives way to its file's tab; where the file is what it holds the file's stamp is taken, else Send File and Compare are offered there"); make(); Doc& same = itemTab("door", "default {}\n"); const LLUUID asset = same.assetId; @@ -444,18 +477,44 @@ namespace tut write(in("door.lsl"), "default {}\n"); studio->picked = in("door.lsl"); unit->linkToFile(same); - ensure("nothing asked", studio->asked.empty()); + UNSCOPED_INFO("nothing asked"); + REQUIRE(studio->asked.empty()); const std::optional link = disk.linkOf(ref); - ensure("linked as picked, from the world's asset", link && link->made == ALMasterLink::Made::Picked && link->base == asset && - link->itemName == "door" && link->objectName == "Door"); - ensure("the file's stamp taken, as from a send of it", link->stamp != 0 && link->stamp == ALFileStamp::of(in("door.lsl")).time); - ensure("its tab closed, the file's opened in its place", studio->closed == Names{ "door" } && studio->opened == Names{ in("door.lsl") } && - !services.findDoc(ref)); + { + INFO("linked as picked, from the world's asset"); + REQUIRE(link); + REQUIRE(link->made == ALMasterLink::Made::Picked); + REQUIRE(link->base == asset); + REQUIRE(link->itemName == "door"); + CHECK(link->objectName == "Door"); + } + { + INFO("the file's stamp taken, as from a send of it"); + REQUIRE(link->stamp != 0); + CHECK(link->stamp == ALFileStamp::of(in("door.lsl")).time); + } + { + INFO("its tab closed, the file's opened in its place"); + REQUIRE(studio->closed == Names{ "door" }); + CHECK(studio->opened == Names{ in("door.lsl") }); + REQUIRE_FALSE(services.findDoc(ref)); + } Doc* tab = services.findDoc("disk:" + in("door.lsl")); - ensure("said there, with nothing offered", tab && says(said().text, "MasterLinked") && !says(said().text, "MasterLinkDiffers") && - said().doc == tab->id && said().actions.empty()); - ensure("the file's tab acts on the script", tab->master->offerFor == ref); - ensure("nothing written or sent", disk.written.empty() && disk.sent.empty()); + { + INFO("said there, with nothing offered"); + REQUIRE(tab); + CHECK(says(said().text, "MasterLinked")); + CHECK_FALSE(says(said().text, "MasterLinkDiffers")); + CHECK(said().doc == tab->id); + REQUIRE(said().actions.empty()); + } + UNSCOPED_INFO("the file's tab acts on the script"); + CHECK(tab->master->offerFor == ref); + { + INFO("nothing written or sent"); + REQUIRE(disk.written.empty()); + REQUIRE(disk.sent.empty()); + } Doc& other = itemTab("lamp", "default { state_entry() {} }\n"); write(in("lamp.lsl"), "default {}\n"); @@ -463,17 +522,23 @@ namespace tut const ALScriptRef other_ref = other.ref; unit->linkToFile(other); const std::optional differing = disk.linkOf(other_ref); - ensure("a file it is not what the script holds: no stamp", differing && differing->stamp == 0); + { + INFO("a file it is not what the script holds: no stamp"); + REQUIRE(differing); + CHECK(differing->stamp == 0); + } Doc* lamp = services.findDoc("disk:" + in("lamp.lsl")); - ensure("a file it is not: said, Send File and Compare offered on the file's tab", - lamp && says(said().text, "MasterLinkDiffers") && said().doc == lamp->id && - said().actions == Names{ "master_send", "master_compare" }); + { + INFO("a file it is not: said, Send File and Compare offered on the file's tab"); + REQUIRE(lamp); + CHECK(says(said().text, "MasterLinkDiffers")); + CHECK(said().doc == lamp->id); + CHECK(said().actions == Names{ "master_send", "master_compare" }); + } } - template<> template<> - void alscriptstudiomasters_object::test<5>() + TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: linking a tab with unsaved changes asks to cancel or discard or write", "[alscriptstudiomasters]") { - set_test_name("a tab with unsaved changes linked: asked first; Cancel links nothing, Discard holds the file up to the text as last saved, Write puts what was typed in the file"); make(); // Cancel: nothing. Doc& door = itemTab("door", "default {}\n"); @@ -482,10 +547,16 @@ namespace tut studio->picked = in("door.lsl"); studio->answer = Unsaved::Cancel; unit->linkToFile(door); - ensure("asked, the file named", studio->asked == Names{ "door " + in("door.lsl") }); - ensure("Cancel: not linked, the tab kept with what was typed, the file as it was", - !disk.linkOf(door.ref) && services.findDoc("door") == &door && door.editor->isDirty() && - contents(in("door.lsl")) == "default {}\n" && studio->closed.empty()); + UNSCOPED_INFO("asked, the file named"); + CHECK(studio->asked == Names{ "door " + in("door.lsl") }); + { + INFO("Cancel: not linked, the tab kept with what was typed, the file as it was"); + REQUIRE_FALSE(disk.linkOf(door.ref)); + REQUIRE(services.findDoc("door") == &door); + CHECK(door.editor->isDirty()); + CHECK(contents(in("door.lsl")) == "default {}\n"); + REQUIRE(studio->closed.empty()); + } // Discard, the file what the world holds: as a clean tab is linked, // whatever was typed. @@ -493,10 +564,22 @@ namespace tut studio->answer = Unsaved::Discard; unit->linkToFile(door); std::optional link = disk.linkOf(door_ref); - ensure("Discard: linked, the tab gone", link && studio->closed == Names{ "door" }); - ensure("the file is what the tab last saved: its stamp taken, nothing offered", - link->stamp == ALFileStamp::of(in("door.lsl")).time && !says(said().text, "MasterLinkDiffers") && said().actions.empty()); - ensure("the file untouched", contents(in("door.lsl")) == "default {}\n" && disk.written.empty()); + { + INFO("Discard: linked, the tab gone"); + REQUIRE(link); + CHECK(studio->closed == Names{ "door" }); + } + { + INFO("the file is what the tab last saved: its stamp taken, nothing offered"); + CHECK(link->stamp == ALFileStamp::of(in("door.lsl")).time); + CHECK_FALSE(says(said().text, "MasterLinkDiffers")); + REQUIRE(said().actions.empty()); + } + { + INFO("the file untouched"); + CHECK(contents(in("door.lsl")) == "default {}\n"); + REQUIRE(disk.written.empty()); + } // Discard, the file what was typed and is let go of: not what the // world holds. @@ -507,8 +590,13 @@ namespace tut const ALScriptRef lamp_ref = lamp.ref; unit->linkToFile(lamp); link = disk.linkOf(lamp_ref); - ensure("the file held up to the saved text, not to what was dropped: it differs, no stamp, Send File and Compare offered", - link && link->stamp == 0 && says(said().text, "MasterLinkDiffers") && said().actions == Names{ "master_send", "master_compare" }); + { + INFO("the file held up to the saved text, not to what was dropped: it differs, no stamp, Send File and Compare offered"); + REQUIRE(link); + CHECK(link->stamp == 0); + CHECK(says(said().text, "MasterLinkDiffers")); + CHECK(said().actions == Names{ "master_send", "master_compare" }); + } // Write: what was typed in the file first, which the world does not // hold. @@ -520,19 +608,29 @@ namespace tut const ALScriptRef bell_ref = bell.ref; unit->linkToFile(bell); link = disk.linkOf(bell_ref); - ensure_equals("Write: the file holds what was typed", contents(in("bell.lsl")), std::string("default {}\n// mine\n")); - ensure("the write the studio's own", disk.written == Names{ in("bell.lsl") }); - ensure("linked, differing from the world: no stamp, Send File and Compare offered", - link && link->stamp == 0 && says(said().text, "MasterLinkDiffers") && said().actions == Names{ "master_send", "master_compare" }); - ensure("its tab gone", !services.findDoc(bell_ref)); + UNSCOPED_INFO("Write: the file holds what was typed"); + CHECK(contents(in("bell.lsl")) == std::string("default {}\n// mine\n")); + UNSCOPED_INFO("the write the studio's own"); + CHECK(disk.written == Names{ in("bell.lsl") }); + { + INFO("linked, differing from the world: no stamp, Send File and Compare offered"); + REQUIRE(link); + CHECK(link->stamp == 0); + CHECK(says(said().text, "MasterLinkDiffers")); + CHECK(said().actions == Names{ "master_send", "master_compare" }); + } + UNSCOPED_INFO("its tab gone"); + REQUIRE_FALSE(services.findDoc(bell_ref)); Doc* tab = services.findDoc("disk:" + in("bell.lsl")); - ensure("the file's tab holds what was typed", tab && tab->editor->wholeText() == "default {}\n// mine\n"); + { + INFO("the file's tab holds what was typed"); + REQUIRE(tab); + CHECK(tab->editor->wholeText() == "default {}\n// mine\n"); + } } - template<> template<> - void alscriptstudiomasters_object::test<6>() + TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a link from elsewhere closes a clean tab and tells a typed one once", "[alscriptstudiomasters]") { - set_test_name("linked from elsewhere: a clean tab gives way to its file's once the links have changed; one with something typed is kept and told once, with Compare with File, Open File and Unlink"); make(); Doc& clean = itemTab("door", "default {}\n"); Doc& dirty = itemTab("lamp", "default {}\n"); @@ -542,41 +640,58 @@ namespace tut write(in("lamp.lsl"), "default {}\n"); linkFromElsewhere(clean, in("door.lsl")); linkFromElsewhere(dirty, in("lamp.lsl")); - ensure("nothing done while whoever changed the links is", studio->closed.empty() && services.reports.empty()); + { + INFO("nothing done while whoever changed the links is"); + REQUIRE(studio->closed.empty()); + REQUIRE(services.reports.empty()); + } settle(); - ensure("the clean one gave way to its file's", studio->closed == Names{ "door" } && !services.findDoc(clean_ref) && - services.findDoc("disk:" + in("door.lsl"))); + { + INFO("the clean one gave way to its file's"); + CHECK(studio->closed == Names{ "door" }); + REQUIRE_FALSE(services.findDoc(clean_ref)); + REQUIRE(services.findDoc("disk:" + in("door.lsl"))); + } const auto told = [&](const std::string& id) { return std::count_if(services.reports.begin(), services.reports.end(), [&](const al_studio_test::FakeServices::Said& one) { return one.doc == id && alscriptstudiomasters_data::says(one.text, "MasterLinkedUnsaved"); }); }; - ensure_equals("the one with something typed told once", told("lamp"), 1); + UNSCOPED_INFO("the one with something typed told once"); + CHECK(told("lamp") == 1); const al_studio_test::FakeServices::Said& lamp = *std::find_if(services.reports.begin(), services.reports.end(), [](const al_studio_test::FakeServices::Said& one) { return one.doc == "lamp"; }); - ensure("as a failure, with its file to compare with and to open, and the link to let go of", - lamp.failure && lamp.actions == Names{ "master_compare_file", "master_open_file", "master_unlink" }); - ensure("and kept", services.findDoc("lamp") == &dirty && dirty.editor->isDirty()); + { + INFO("as a failure, with its file to compare with and to open, and the link to let go of"); + CHECK(lamp.failure); + CHECK(lamp.actions == Names{ "master_compare_file", "master_open_file", "master_unlink" }); + } + { + INFO("and kept"); + REQUIRE(services.findDoc("lamp") == &dirty); + CHECK(dirty.editor->isDirty()); + } // The links changing again: not told again. Doc& bell = itemTab("bell", "default {}\n"); write(in("bell.lsl"), "default {}\n"); linkFromElsewhere(bell, in("bell.lsl")); settle(); - ensure_equals("told once only", told("lamp"), 1); - ensure("the next clean one gave way", !services.findDoc("bell")); + UNSCOPED_INFO("told once only"); + CHECK(told("lamp") == 1); + UNSCOPED_INFO("the next clean one gave way"); + REQUIRE_FALSE(services.findDoc("bell")); // A tab of a file gone, or of a link held, is left as it is. Doc& gone = itemTab("gone", "default {}\n"); linkFromElsewhere(gone, in("nowhere.lsl")); settle(); - ensure("a file gone: left", services.findDoc("gone") == &gone); + UNSCOPED_INFO("a file gone: left"); + CHECK(services.findDoc("gone") == &gone); } - template<> template<> - void alscriptstudiomasters_object::test<7>() + TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a tab kept for what was typed gives way once saved or reverted", "[alscriptstudiomasters]") { - set_test_name("a tab kept for what was typed gives way once that is saved -- its file's tab offering Send File and Compare where the world now differs -- or reverted"); make(); Doc& door = itemTab("door", "default {}\n"); type(door, "// mine\n"); @@ -584,20 +699,32 @@ namespace tut const ALScriptRef door_ref = door.ref; ALMasterLink link = linkFromElsewhere(door, in("door.lsl")); settle(); - ensure("kept", services.findDoc("door") == &door); + UNSCOPED_INFO("kept"); + CHECK(services.findDoc("door") == &door); // Saved from here: the world holds what was typed, and the save // heard marks the link differing. door.editor->resetDirty(); link.state = ALMasterLink::State::Differing; disk.link(link); - ensure("not while the save is still being heard", services.findDoc("door") == &door); + UNSCOPED_INFO("not while the save is still being heard"); + CHECK(services.findDoc("door") == &door); settle(); - ensure("clean: it gave way, whatever it was told", !services.findDoc(door_ref) && studio->closed == Names{ "door" }); + { + INFO("clean: it gave way, whatever it was told"); + REQUIRE_FALSE(services.findDoc(door_ref)); + CHECK(studio->closed == Names{ "door" }); + } Doc* tab = services.findDoc("disk:" + in("door.lsl")); - ensure("its file's tab says so, offering to send the file over the world's or to compare them", - tab && said().doc == tab->id && says(said().text, "MasterGaveWay") && says(said().text, "MasterLinkDiffers") && - said().actions == Names{ "master_send", "master_compare" } && tab->master->offerFor == door_ref); + { + INFO("its file's tab says so, offering to send the file over the world's or to compare them"); + REQUIRE(tab); + REQUIRE(said().doc == tab->id); + CHECK(says(said().text, "MasterGaveWay")); + CHECK(says(said().text, "MasterLinkDiffers")); + CHECK(said().actions == Names{ "master_send", "master_compare" }); + CHECK(tab->master->offerFor == door_ref); + } // Saved with what the file last sent: the links do not change, and // the save heard looks again itself. @@ -611,15 +738,21 @@ namespace tut saved.ref = lamp.ref; unit->saved(saved); settle(); - ensure("gave way on the save alone", !services.findDoc(ALScriptRef(lamp_link.object, lamp_link.item))); - ensure("nothing offered: the world holds what the file does", says(said().text, "MasterGaveWay") && said().actions.empty()); + UNSCOPED_INFO("gave way on the save alone"); + REQUIRE_FALSE(services.findDoc(ALScriptRef(lamp_link.object, lamp_link.item))); + { + INFO("nothing offered: the world holds what the file does"); + CHECK(says(said().text, "MasterGaveWay")); + REQUIRE(said().actions.empty()); + } // A save of a script with no tab here, or not linked: nothing. saved.ref = ALScriptRef(LLUUID::generateNewID(), LLUUID::generateNewID()); const size_t before = services.reports.size(); unit->saved(saved); settle(); - ensure("nothing", services.reports.size() == before); + UNSCOPED_INFO("nothing"); + REQUIRE(services.reports.size() == before); // Reverted: loaded again, clean. Doc& bell = itemTab("bell", "default {}\n"); @@ -630,13 +763,15 @@ namespace tut bell.editor->setText("default {}\n"); unit->loaded(bell); settle(); - ensure("reverted: gave way", !services.findDoc(ALScriptRef(bell_link.object, bell_link.item)) && says(said().text, "MasterGaveWay")); + { + INFO("reverted: gave way"); + REQUIRE_FALSE(services.findDoc(ALScriptRef(bell_link.object, bell_link.item))); + CHECK(says(said().text, "MasterGaveWay")); + } } - template<> template<> - void alscriptstudiomasters_object::test<8>() + TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a kept tab's offers compare with its file or open it or unlink it", "[alscriptstudiomasters]") { - set_test_name("the offers on a tab kept for what was typed: its file on disk set beside it, its file's tab opened beside it, the link let go of"); make(); Doc& door = itemTab("door", "default {}\n"); type(door, "// mine\n"); @@ -645,38 +780,64 @@ namespace tut settle(); unit->offer(door, "master_compare_file"); - ensure_equals("compared once", studio->compared.size(), size_t(1)); + UNSCOPED_INFO("compared once"); + REQUIRE(studio->compared.size() == size_t(1)); const FakeMastersWindow::Compared& compared = studio->compared.back(); - ensure("in the tab's place: the file on disk, then what was typed", compared.doc == "door" && - compared.left == "default { touch_start(integer n) {} }\n" && - compared.right == "default {}\n// mine\n"); - ensure("each named", says(compared.leftTitle, "CompareMasterOnDisk") && says(compared.leftTitle, "door.lsl") && - says(compared.rightTitle, "CompareNow")); + { + INFO("in the tab's place: the file on disk, then what was typed"); + CHECK(compared.doc == "door"); + CHECK(compared.left == "default { touch_start(integer n) {} }\n"); + CHECK(compared.right == "default {}\n// mine\n"); + } + { + INFO("each named"); + CHECK(says(compared.leftTitle, "CompareMasterOnDisk")); + CHECK(says(compared.leftTitle, "door.lsl")); + CHECK(says(compared.rightTitle, "CompareNow")); + } unit->offer(door, "master_open_file"); Doc* tab = services.findDoc("disk:" + in("door.lsl")); - ensure("the file's tab opened, this one kept", tab && services.findDoc("door") == &door && studio->closed.empty()); - ensure("the file's tab acts on the script", tab->master->offerFor == door.ref); + { + INFO("the file's tab opened, this one kept"); + REQUIRE(tab); + CHECK(services.findDoc("door") == &door); + REQUIRE(studio->closed.empty()); + } + UNSCOPED_INFO("the file's tab acts on the script"); + CHECK(tab->master->offerFor == door.ref); std::filesystem::remove(fsyspath(in("door.lsl"))); unit->offer(door, "master_compare_file"); - ensure("a file that cannot be read: said, nothing compared", studio->compared.size() == 1 && says(said().text, "MasterNotRead") && said().failure); + { + INFO("a file that cannot be read: said, nothing compared"); + REQUIRE(studio->compared.size() == 1); + CHECK(says(said().text, "MasterNotRead")); + CHECK(said().failure); + } // Not offered on a file's own tab. unit->offer(*tab, "master_compare_file"); unit->offer(*tab, "master_open_file"); - ensure("nothing from a file's tab", studio->compared.size() == 1 && studio->opened.size() == 1); + { + INFO("nothing from a file's tab"); + REQUIRE(studio->compared.size() == 1); + REQUIRE(studio->opened.size() == 1); + } unit->offer(door, "master_unlink"); - ensure("let go of, and said", !disk.linkOf(door.ref) && says(said().text, "MasterUnlinked")); + { + INFO("let go of, and said"); + REQUIRE_FALSE(disk.linkOf(door.ref)); + CHECK(says(said().text, "MasterUnlinked")); + } unit->offer(door, "master_compare_file"); - ensure("nothing to compare once unlinked", studio->compared.size() == 1); + UNSCOPED_INFO("nothing to compare once unlinked"); + REQUIRE(studio->compared.size() == 1); } - template<> template<> - void alscriptstudiomasters_object::test<9>() + TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: the Link offer links a script's named file only while nothing is typed", "[alscriptstudiomasters]") { - set_test_name("the file a script names is linked by Link while nothing is typed in its tab; with something typed, it is to be saved or reverted first, and nothing is written"); make(); Doc& door = itemTab("door", "default {}\n"); write(in("door.lsl"), "default {}\n"); @@ -684,30 +845,50 @@ namespace tut const ALScriptRef door_ref = door.ref; unit->offer(door, "master_link_hint"); const std::optional link = disk.linkOf(door_ref); - ensure("clean: linked, as named", link && link->made == ALMasterLink::Made::Hint && link->master == in("door.lsl")); + { + INFO("clean: linked, as named"); + REQUIRE(link); + REQUIRE(link->made == ALMasterLink::Made::Hint); + CHECK(link->master == in("door.lsl")); + } Doc& lamp = itemTab("lamp", "default {}\n"); type(lamp, "// mine\n"); write(in("lamp.lsl"), "default {}\n"); lamp.master->hinted = in("lamp.lsl"); unit->offer(lamp, "master_link_hint"); - ensure("with something typed: not linked, nothing asked, the tab kept", - !disk.linkOf(lamp.ref) && studio->asked.empty() && services.findDoc("lamp") == &lamp && - lamp.editor->isDirty()); - ensure("said, Link offered again for after", says(said().text, "MasterHintUnsaved") && said().failure && said().doc == "lamp" && - said().actions == Names{ "master_link_hint" }); - ensure("nothing written", contents(in("lamp.lsl")) == "default {}\n" && disk.written.empty()); + { + INFO("with something typed: not linked, nothing asked, the tab kept"); + REQUIRE_FALSE(disk.linkOf(lamp.ref)); + REQUIRE(studio->asked.empty()); + REQUIRE(services.findDoc("lamp") == &lamp); + CHECK(lamp.editor->isDirty()); + } + { + INFO("said, Link offered again for after"); + CHECK(says(said().text, "MasterHintUnsaved")); + CHECK(said().failure); + CHECK(said().doc == "lamp"); + CHECK(said().actions == Names{ "master_link_hint" }); + } + { + INFO("nothing written"); + CHECK(contents(in("lamp.lsl")) == "default {}\n"); + REQUIRE(disk.written.empty()); + } const ALScriptRef lamp_ref = lamp.ref; lamp.editor->resetDirty(); unit->offer(lamp, "master_link_hint"); - ensure("saved: linked, its tab giving way", disk.linkOf(lamp_ref) && !services.findDoc(lamp_ref)); + { + INFO("saved: linked, its tab giving way"); + REQUIRE(disk.linkOf(lamp_ref)); + REQUIRE_FALSE(services.findDoc(lamp_ref)); + } } - template<> template<> - void alscriptstudiomasters_object::test<10>() + TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a kept tab made clean by an undo is offered Switch to File", "[alscriptstudiomasters]") { - set_test_name("a tab kept for what was typed, made clean by an undo, is kept and offered to switch to its file, and told again when typed in; Switch to File gives way, as a revert or a save of it does"); make(); Doc& door = itemTab("door", "default {}\n"); wire(door); @@ -716,45 +897,83 @@ namespace tut const ALScriptRef door_ref = door.ref; linkFromElsewhere(door, in("door.lsl")); settle(); - ensure("kept and told", services.findDoc(door_ref) == &door && says(said().text, "MasterLinkedUnsaved") && said().doc == "door"); + { + INFO("kept and told"); + CHECK(services.findDoc(door_ref) == &door); + CHECK(says(said().text, "MasterLinkedUnsaved")); + CHECK(said().doc == "door"); + } const size_t said_before = services.reports.size(); const S32 notices = studio->notices; door.editor->undo(); - ensure("clean again by the undo", !door.editor->isDirty()); - ensure("not closed under the author", services.findDoc(door_ref) == &door && studio->closed.empty()); - ensure("its notice: nothing unsaved left, Switch to File offered with the rest", - door.offer && says(door.offer->text, "MasterLinkedClean") && - door.offer->actions == Names{ "master_give_way", "master_compare_file", "master_open_file", "master_unlink" } && - studio->notices == notices + 1); - ensure("over the tab alone, not in Output", services.reports.size() == said_before); + UNSCOPED_INFO("clean again by the undo"); + CHECK_FALSE(door.editor->isDirty()); + { + INFO("not closed under the author"); + CHECK(services.findDoc(door_ref) == &door); + REQUIRE(studio->closed.empty()); + } + { + INFO("its notice: nothing unsaved left, Switch to File offered with the rest"); + REQUIRE(door.offer); + REQUIRE(says(door.offer->text, "MasterLinkedClean")); + CHECK(door.offer->actions == Names{ "master_give_way", "master_compare_file", "master_open_file", "master_unlink" }); + CHECK(studio->notices == notices + 1); + } + UNSCOPED_INFO("over the tab alone, not in Output"); + REQUIRE(services.reports.size() == said_before); // The links changing meanwhile: kept still. Doc& bell = itemTab("bell", "default {}\n"); write(in("bell.lsl"), "default {}\n"); linkFromElsewhere(bell, in("bell.lsl")); settle(); - ensure("kept as the links change", services.findDoc(door_ref) == &door && !services.findDoc("bell")); + { + INFO("kept as the links change"); + CHECK(services.findDoc(door_ref) == &door); + REQUIRE_FALSE(services.findDoc("bell")); + } door.editor->redo(); - ensure("typed in again by the redo: the notice back to what was typed", - door.editor->isDirty() && door.offer && says(door.offer->text, "MasterLinkedUnsaved") && - door.offer->actions == Names{ "master_compare_file", "master_open_file", "master_unlink" }); + { + INFO("typed in again by the redo: the notice back to what was typed"); + REQUIRE(door.editor->isDirty()); + REQUIRE(door.offer); + REQUIRE(says(door.offer->text, "MasterLinkedUnsaved")); + CHECK(door.offer->actions == Names{ "master_compare_file", "master_open_file", "master_unlink" }); + } door.editor->undo(); - ensure("and clean again", door.offer && says(door.offer->text, "MasterLinkedClean")); + { + INFO("and clean again"); + REQUIRE(door.offer); + CHECK(says(door.offer->text, "MasterLinkedClean")); + } // Switch to File taken once typed in again: kept, and told so. type(door, "x"); door.offer.reset(); unit->offer(door, "master_give_way"); - ensure("typed in since it was offered: kept, told so", services.findDoc(door_ref) == &door && door.offer && - says(door.offer->text, "MasterLinkedUnsaved")); + { + INFO("typed in since it was offered: kept, told so"); + REQUIRE(services.findDoc(door_ref) == &door); + REQUIRE(door.offer); + CHECK(says(door.offer->text, "MasterLinkedUnsaved")); + } door.editor->undo(); - ensure("clean again", door.offer && says(door.offer->text, "MasterLinkedClean")); + { + INFO("clean again"); + REQUIRE(door.offer); + CHECK(says(door.offer->text, "MasterLinkedClean")); + } unit->offer(door, "master_give_way"); - ensure("Switch to File: the file's tab in its place, said there", - !services.findDoc(door_ref) && studio->closed.back() == "door" && says(said().text, "MasterGaveWay") && - said().doc == "disk:" + in("door.lsl")); + { + INFO("Switch to File: the file's tab in its place, said there"); + REQUIRE_FALSE(services.findDoc(door_ref)); + CHECK(studio->closed.back() == "door"); + CHECK(says(said().text, "MasterGaveWay")); + CHECK(said().doc == "disk:" + in("door.lsl")); + } // Reverted once clean: gives way, as a revert does. Doc& lamp = itemTab("lamp", "default {}\n"); @@ -765,11 +984,19 @@ namespace tut linkFromElsewhere(lamp, in("lamp.lsl")); settle(); lamp.editor->undo(); - ensure("kept once clean", services.findDoc(lamp_ref) == &lamp && says(lamp.offer->text, "MasterLinkedClean")); + { + INFO("kept once clean"); + REQUIRE(services.findDoc(lamp_ref) == &lamp); + CHECK(says(lamp.offer->text, "MasterLinkedClean")); + } lamp.editor->setText("default {}\n"); unit->loaded(lamp); settle(); - ensure("reverted: gave way", !services.findDoc(lamp_ref) && says(said().text, "MasterGaveWay")); + { + INFO("reverted: gave way"); + REQUIRE_FALSE(services.findDoc(lamp_ref)); + CHECK(says(said().text, "MasterGaveWay")); + } // Saved once clean: gives way, as a save does. Doc& gate = itemTab("gate", "default {}\n"); @@ -780,11 +1007,16 @@ namespace tut linkFromElsewhere(gate, in("gate.lsl")); settle(); gate.editor->undo(); - ensure("kept once clean", services.findDoc(gate_ref) == &gate); + UNSCOPED_INFO("kept once clean"); + CHECK(services.findDoc(gate_ref) == &gate); ALScriptSaved saved; saved.ref = gate_ref; unit->saved(saved); settle(); - ensure("saved: gave way", !services.findDoc(gate_ref) && says(said().text, "MasterGaveWay")); + { + INFO("saved: gave way"); + REQUIRE_FALSE(services.findDoc(gate_ref)); + CHECK(says(said().text, "MasterGaveWay")); + } } } diff --git a/indra/newview/tests/alscriptstudiomerging_test.cpp b/indra/newview/tests/alscriptstudiomerging_test.cpp index a0445ec5f8..2624eb9d43 100644 --- a/indra/newview/tests/alscriptstudiomerging_test.cpp +++ b/indra/newview/tests/alscriptstudiomerging_test.cpp @@ -32,7 +32,7 @@ #include "alflatbutton.h" #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include #include @@ -83,7 +83,7 @@ namespace }; } -namespace tut +namespace { struct alscriptstudiomerging_data { @@ -143,156 +143,221 @@ namespace tut LLStringUtil::format_map_t named(const Doc& doc) { return { { "[NAME]", doc.name } }; } }; - typedef test_group alscriptstudiomerging_group; - typedef alscriptstudiomerging_group::object alscriptstudiomerging_object; - tut::alscriptstudiomerging_group alscriptstudiomerging_test("alscriptstudiomerging"); - - template<> template<> - void alscriptstudiomerging_object::test<1>() + TEST_CASE_METHOD(alscriptstudiomerging_data, "alscriptstudiomerging: mergeSaved puts in theirs as one undo step and leaves conflicts to settle", "[alscriptstudiomerging]") { - set_test_name("saved elsewhere, merged: what only theirs changed put in as one step to undo, the rest a merge to settle; take and keep done with"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door"); doc.savedThere = theirs; - ensure("it can be merged", ALScriptStudioMerging::canMerge(doc)); + UNSCOPED_INFO("it can be merged"); + CHECK(ALScriptStudioMerging::canMerge(doc)); unit->mergeSaved(doc); - ensure_equals("theirs's line put in, ours kept", doc.editor->wholeText(), lines(8, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "mine 6" } })); - ensure("compared under the saved elsewhere's title", studio.titles.size() == 1 && studio.titles[0] == said("CompareSavedThere")); - ensure("as a merge", doc.compareView && doc.compareView->merging()); - ensure_equals("one conflict", doc.compareView->conflictCount(), 1); - ensure("take and keep done with", !doc.savedThere && studio.notices == 1); - ensure_equals("said", services().reports.back().text, services().counted("MergeConflicts", 1, named(doc))); + UNSCOPED_INFO("theirs's line put in, ours kept"); + CHECK(doc.editor->wholeText() == lines(8, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "mine 6" } })); + { + INFO("compared under the saved elsewhere's title"); + REQUIRE(studio.titles.size() == 1); + CHECK(studio.titles[0] == said("CompareSavedThere")); + } + { + INFO("as a merge"); + REQUIRE(doc.compareView); + CHECK(doc.compareView->merging()); + } + UNSCOPED_INFO("one conflict"); + CHECK(doc.compareView->conflictCount() == 1); + { + INFO("take and keep done with"); + REQUIRE_FALSE(doc.savedThere); + CHECK(studio.notices == 1); + } + UNSCOPED_INFO("said"); + CHECK(services().reports.back().text == services().counted("MergeConflicts", 1, named(doc))); // Settled from the comparison's bar: an edit of the tab. doc.compareView->right()->setFocus(true); doc.compareView->right()->goTo(ALTextPos(6, 0)); ALViewType::as(doc.compareView->bar()->getChild("keep_both"))->press(); - ensure_equals("mine then theirs", doc.editor->wholeText(), + UNSCOPED_INFO("mine then theirs"); + CHECK(doc.editor->wholeText() == lines(9, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "mine 6" }, { 7, "theirs 6" }, { 8, "line 7" } })); - ensure_equals("none left", doc.compareView->conflictCount(), 0); + UNSCOPED_INFO("none left"); + CHECK(doc.compareView->conflictCount() == 0); // Each a step to undo: the settling, then the merge. doc.editor->undo(); doc.editor->undo(); - ensure_equals("back to ours", doc.editor->wholeText(), ours); + UNSCOPED_INFO("back to ours"); + CHECK(doc.editor->wholeText() == ours); } - template<> template<> - void alscriptstudiomerging_object::test<2>() + TEST_CASE_METHOD(alscriptstudiomerging_data, "alscriptstudiomerging: with nothing both changed a merge is clean and said so", "[alscriptstudiomerging]") { - set_test_name("nothing both changed: merged, and said so"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door"); doc.savedThere = lines(8, { { 0, "theirs 0" } }); unit->mergeSaved(doc); - ensure_equals("merged", doc.editor->wholeText(), lines(8, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "mine 6" } })); - ensure("no conflicts", doc.compareView->merging() && doc.compareView->conflictCount() == 0); - ensure_equals("said", services().reports.back().text, said("MergeClean", named(doc))); + UNSCOPED_INFO("merged"); + CHECK(doc.editor->wholeText() == lines(8, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "mine 6" } })); + { + INFO("no conflicts"); + REQUIRE(doc.compareView->merging()); + CHECK(doc.compareView->conflictCount() == 0); + } + UNSCOPED_INFO("said"); + CHECK(services().reports.back().text == said("MergeClean", named(doc))); } - template<> template<> - void alscriptstudiomerging_object::test<3>() + TEST_CASE_METHOD(alscriptstudiomerging_data, "alscriptstudiomerging: with no base or a read-only tab the texts are compared rather than merged", "[alscriptstudiomerging]") { - set_test_name("what both were no longer known, or the tab not to be changed: compared as they are, take and keep still offered, and said why"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door"); doc.savedThere = theirs; doc.editor->undoJournal().markNeverSaved(); unit->mergeSaved(doc); - ensure_equals("nothing put in", doc.editor->wholeText(), ours); - ensure("compared, not merged", doc.compareView && !doc.compareView->merging() && doc.compareView->changeCount() > 0); - ensure("take and keep still offered", doc.savedThere && studio.notices == 0); - ensure_equals("said", services().statuses.back(), said("MergeNoBase", named(doc))); + UNSCOPED_INFO("nothing put in"); + CHECK(doc.editor->wholeText() == ours); + { + INFO("compared, not merged"); + REQUIRE(doc.compareView); + REQUIRE_FALSE(doc.compareView->merging()); + CHECK(doc.compareView->changeCount() > 0); + } + { + INFO("take and keep still offered"); + REQUIRE(doc.savedThere); + CHECK(studio.notices == 0); + } + UNSCOPED_INFO("said"); + CHECK(services().statuses.back() == said("MergeNoBase", named(doc))); Doc& locked = tab("lamp"); locked.modifiable = false; locked.savedThere = theirs; - ensure("cannot be merged", !ALScriptStudioMerging::canMerge(locked)); + UNSCOPED_INFO("cannot be merged"); + CHECK_FALSE(ALScriptStudioMerging::canMerge(locked)); unit->mergeSaved(locked); - ensure("compared as they are", locked.editor->wholeText() == ours && locked.compareView && !locked.compareView->merging()); - ensure_equals("said", services().statuses.back(), said("MergeReadOnly", named(locked))); + { + INFO("compared as they are"); + REQUIRE(locked.editor->wholeText() == ours); + REQUIRE(locked.compareView); + CHECK_FALSE(locked.compareView->merging()); + } + UNSCOPED_INFO("said"); + CHECK(services().statuses.back() == said("MergeReadOnly", named(locked))); } - template<> template<> - void alscriptstudiomerging_object::test<4>() + TEST_CASE_METHOD(alscriptstudiomerging_data, "alscriptstudiomerging: mergeWorld merges the world's text once loaded unless the unit has gone", "[alscriptstudiomerging]") { - set_test_name("the world's item moved on: asked for, merged once loaded, and the tab made from its asset; nothing once the window has gone"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door"); const LLUUID was = LLUUID::generateNewID(); const LLUUID moved = LLUUID::generateNewID(); doc.assetId = was; unit->mergeWorld(doc); - ensure_equals("asked", studio.worldAsked, std::string("door")); - ensure_equals("nothing yet", doc.editor->wholeText(), ours); + UNSCOPED_INFO("asked"); + CHECK(studio.worldAsked == std::string("door")); + UNSCOPED_INFO("nothing yet"); + CHECK(doc.editor->wholeText() == ours); studio.world(doc, theirs, moved); - ensure_equals("merged", doc.editor->wholeText(), lines(8, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "mine 6" } })); - ensure("under the world's title, as a merge", studio.titles.back() == said("CompareWorld") && doc.compareView->conflictCount() == 1); - ensure("made from what the world holds", doc.assetId == moved); + UNSCOPED_INFO("merged"); + CHECK(doc.editor->wholeText() == lines(8, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "mine 6" } })); + { + INFO("under the world's title, as a merge"); + CHECK(studio.titles.back() == said("CompareWorld")); + CHECK(doc.compareView->conflictCount() == 1); + } + UNSCOPED_INFO("made from what the world holds"); + CHECK(doc.assetId == moved); Doc& lamp = tab("lamp"); lamp.assetId = was; unit->mergeWorld(lamp); unit.reset(); studio.world(lamp, theirs, moved); - ensure("nothing", lamp.editor->wholeText() == ours && lamp.assetId == was); + { + INFO("nothing"); + CHECK(lamp.editor->wholeText() == ours); + CHECK(lamp.assetId == was); + } } - template<> template<> - void alscriptstudiomerging_object::test<5>() + TEST_CASE_METHOD(alscriptstudiomerging_data, "alscriptstudiomerging: a merge undone before saving brings back the other version and its offer", "[alscriptstudiomerging]") { - set_test_name("a merge undone before it is saved: what was saved elsewhere back, said, and offered again; a step forward leaves it so"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door"); doc.savedThere = theirs; unit->mergeSaved(doc); - ensure("set aside", !doc.savedThere && doc.merged); - ensure("the conflicts said with the comparison to show", services().reports.back().actions == std::vector{ "show_compare" }); + { + INFO("set aside"); + REQUIRE_FALSE(doc.savedThere); + REQUIRE(doc.merged); + } + UNSCOPED_INFO("the conflicts said with the comparison to show"); + CHECK(services().reports.back().actions == std::vector{ "show_compare" }); // Typed in, or any change not a step back: nothing. unit->textChanged(doc); - ensure("still merged", !doc.savedThere && doc.merged); + { + INFO("still merged"); + REQUIRE_FALSE(doc.savedThere); + REQUIRE(doc.merged); + } const S32 notices = studio.notices; doc.editor->undo(); - ensure_equals("back to ours", doc.editor->wholeText(), ours); + UNSCOPED_INFO("back to ours"); + CHECK(doc.editor->wholeText() == ours); unit->textChanged(doc); - ensure("what was saved elsewhere back", doc.savedThere && *doc.savedThere == theirs && !doc.merged); - ensure_equals("said", services().reports.back().text, said("MergeTakenBack", named(doc))); - ensure("take, keep, merge and compare offered again", - services().reports.back().actions == std::vector{ "take_saved", "keep_saved", "merge_saved", "compare_saved" }); - ensure("the notice said again", studio.notices > notices); + { + INFO("what was saved elsewhere back"); + REQUIRE(doc.savedThere); + CHECK(*doc.savedThere == theirs); + REQUIRE_FALSE(doc.merged); + } + UNSCOPED_INFO("said"); + CHECK(services().reports.back().text == said("MergeTakenBack", named(doc))); + UNSCOPED_INFO("take, keep, merge and compare offered again"); + CHECK(services().reports.back().actions == std::vector{ "take_saved", "keep_saved", "merge_saved", "compare_saved" }); + UNSCOPED_INFO("the notice said again"); + CHECK(studio.notices > notices); // Stepped forward: the merge is back in the text, the other version // still stands until it is merged again. doc.editor->redo(); unit->textChanged(doc); - ensure("left so", doc.savedThere && *doc.savedThere == theirs && !doc.merged); + { + INFO("left so"); + REQUIRE(doc.savedThere); + CHECK(*doc.savedThere == theirs); + REQUIRE_FALSE(doc.merged); + } unit->mergeSaved(doc); - ensure("merged again: set aside again", !doc.savedThere && doc.merged); + { + INFO("merged again: set aside again"); + REQUIRE_FALSE(doc.savedThere); + REQUIRE(doc.merged); + } } - template<> template<> - void alscriptstudiomerging_object::test<6>() + TEST_CASE_METHOD(alscriptstudiomerging_data, "alscriptstudiomerging: a world merge undone puts back the old asset so a save stops for the world", "[alscriptstudiomerging]") { - set_test_name("the world's item merged, then undone: the tab made from the asset it was again, so a save stops for the world"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door"); const LLUUID was = LLUUID::generateNewID(); @@ -300,52 +365,68 @@ namespace tut doc.assetId = was; unit->mergeWorld(doc); studio.world(doc, theirs, moved); - ensure("made from what the world holds", doc.assetId == moved && doc.merged); + { + INFO("made from what the world holds"); + CHECK(doc.assetId == moved); + REQUIRE(doc.merged); + } doc.editor->undo(); unit->textChanged(doc); - ensure("made from what it was again", doc.assetId == was && !doc.merged); - ensure("reload, merge and compare offered again", - services().reports.back().actions == std::vector{ "reload_world", "merge_world", "compare_world" }); + { + INFO("made from what it was again"); + CHECK(doc.assetId == was); + REQUIRE_FALSE(doc.merged); + } + UNSCOPED_INFO("reload, merge and compare offered again"); + CHECK(services().reports.back().actions == std::vector{ "reload_world", "merge_world", "compare_world" }); } - template<> template<> - void alscriptstudiomerging_object::test<7>() + TEST_CASE_METHOD(alscriptstudiomerging_data, "alscriptstudiomerging: settle takes the conflict at the caret and the notice goes with the last", "[alscriptstudiomerging]") { - set_test_name("a conflict settled from the keyboard where the caret is in one; the notice says conflicts are left until none are"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door"); doc.savedThere = theirs; unit->mergeSaved(doc); // As the window keeps what was said, and shows the comparison. doc.offer = Doc::Offer{ services().reports.back().text, services().reports.back().actions }; - ensure("not while the comparison is not in front", !ALScriptStudioMerging::canSettle(doc)); + UNSCOPED_INFO("not while the comparison is not in front"); + CHECK_FALSE(ALScriptStudioMerging::canSettle(doc)); doc.view = Doc::View::Compare; ALScriptNoticeBar::Notice notice = ALScriptStudioOrphans::noticeFor(&doc, services()); - ensure("the notice offers the comparison", notice.buttons[0].first == "show_compare" && notice.buttons[1].first.empty()); + { + INFO("the notice offers the comparison"); + CHECK(notice.buttons[0].first == "show_compare"); + REQUIRE(notice.buttons[1].first.empty()); + } doc.compareView->right()->setFocus(true); doc.compareView->right()->goTo(ALTextPos(2, 0)); - ensure("not where the caret is in no conflict", !ALScriptStudioMerging::canSettle(doc)); + UNSCOPED_INFO("not where the caret is in no conflict"); + CHECK_FALSE(ALScriptStudioMerging::canSettle(doc)); doc.compareView->right()->goTo(ALTextPos(6, 0)); - ensure("where it is in one", ALScriptStudioMerging::canSettle(doc)); - ensure("settled with theirs", ALScriptStudioMerging::settle(doc, ALTextMerge::Take::Theirs)); - ensure_equals("theirs in the tab", doc.editor->wholeText(), lines(8, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "theirs 6" } })); - ensure_equals("none left", doc.compareView->conflictCount(), 0); - ensure("nothing left to settle", !ALScriptStudioMerging::canSettle(doc)); + UNSCOPED_INFO("where it is in one"); + CHECK(ALScriptStudioMerging::canSettle(doc)); + UNSCOPED_INFO("settled with theirs"); + CHECK(ALScriptStudioMerging::settle(doc, ALTextMerge::Take::Theirs)); + UNSCOPED_INFO("theirs in the tab"); + CHECK(doc.editor->wholeText() == lines(8, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "theirs 6" } })); + UNSCOPED_INFO("none left"); + CHECK(doc.compareView->conflictCount() == 0); + UNSCOPED_INFO("nothing left to settle"); + CHECK_FALSE(ALScriptStudioMerging::canSettle(doc)); notice = ALScriptStudioOrphans::noticeFor(&doc, services()); - ensure("nor to say", notice.buttons[0].first.empty()); + UNSCOPED_INFO("nor to say"); + REQUIRE(notice.buttons[0].first.empty()); } - template<> template<> - void alscriptstudiomerging_object::test<8>() + TEST_CASE_METHOD(alscriptstudiomerging_data, "alscriptstudiomerging: a merge follows the tab's comparison in letting blank changes go", "[alscriptstudiomerging]") { - set_test_name("a merge begun as the tab's comparison tells lines: blanks let go of there, theirs's change among the lines they re-indented put in, and no conflict said where it finds none"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } // The tab compared before, letting blanks go; then changed line 5 // and re-indented line 7, while what was saved elsewhere re-indented @@ -357,10 +438,17 @@ namespace tut doc.editor->insertText(lines(8, { { 5, "mine 5" }, { 7, " line 7" } })); doc.savedThere = lines(8, { { 2, " line 2" }, { 3, " three" }, { 4, " line 4" }, { 5, " line 5" } }); unit->mergeSaved(doc); - ensure_equals("theirs's line 3 put in, the tab's own kept", doc.editor->wholeText(), + UNSCOPED_INFO("theirs's line 3 put in, the tab's own kept"); + CHECK(doc.editor->wholeText() == lines(8, { { 3, " three" }, { 5, "mine 5" }, { 7, " line 7" } })); - ensure("compared with the tab as merged", doc.compareView->rightText() == doc.editor->wholeText()); - ensure("a merge with no conflict", doc.compareView->merging() && doc.compareView->conflictCount() == 0); - ensure_equals("said", services().reports.back().text, said("MergeClean", named(doc))); + UNSCOPED_INFO("compared with the tab as merged"); + CHECK(doc.compareView->rightText() == doc.editor->wholeText()); + { + INFO("a merge with no conflict"); + REQUIRE(doc.compareView->merging()); + CHECK(doc.compareView->conflictCount() == 0); + } + UNSCOPED_INFO("said"); + CHECK(services().reports.back().text == said("MergeClean", named(doc))); } } diff --git a/indra/newview/tests/alscriptstudioorphans_test.cpp b/indra/newview/tests/alscriptstudioorphans_test.cpp index f458f2b049..207ee7e1fb 100644 --- a/indra/newview/tests/alscriptstudioorphans_test.cpp +++ b/indra/newview/tests/alscriptstudioorphans_test.cpp @@ -31,7 +31,7 @@ #include "llbutton.h" #include "lltextbox.h" -#include "../test/lltut.h" +#include namespace { @@ -94,7 +94,7 @@ namespace } } -namespace tut +namespace { struct alscriptstudioorphans_data { @@ -119,7 +119,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } recovery = std::make_unique(services(), &studio); files = std::make_unique(services()); @@ -148,113 +148,154 @@ namespace tut } }; - typedef test_group alscriptstudioorphans_group; - typedef alscriptstudioorphans_group::object alscriptstudioorphans_object; - alscriptstudioorphans_group alscriptstudioorphans_instance("alscriptstudioorphans"); - - template<> template<> - void alscriptstudioorphans_object::test<1>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: a tab's orphan kind follows what is in reach", "[alscriptstudioorphans]") { - set_test_name("what a tab has become, as what is in reach says: each kind, and a locked or unloaded text kept so while there is an item"); make(); Doc& o = tab("object"); Reach reach = inReach(); - ensure("in reach: nothing", Orphans::seen(o, reach) == Orphan::None); + UNSCOPED_INFO("in reach: nothing"); + CHECK(Orphans::seen(o, reach) == Orphan::None); reach.objectThere = false; - ensure("its object out of sight", Orphans::seen(o, reach) == Orphan::Away); + UNSCOPED_INFO("its object out of sight"); + CHECK(Orphans::seen(o, reach) == Orphan::Away); reach.objectThere = true; reach.heldByPrim = false; - ensure("its prim holds it no more", Orphans::seen(o, reach) == Orphan::Removed); + UNSCOPED_INFO("its prim holds it no more"); + CHECK(Orphans::seen(o, reach) == Orphan::Removed); reach.heldByPrim.reset(); o.orphan->kind = Orphan::Removed; - ensure("while the prim is asked again, gone stays gone", Orphans::seen(o, reach) == Orphan::Removed); + UNSCOPED_INFO("while the prim is asked again, gone stays gone"); + CHECK(Orphans::seen(o, reach) == Orphan::Removed); o.orphan->kind = Orphan::None; - ensure("and nothing stays nothing", Orphans::seen(o, reach) == Orphan::None); + UNSCOPED_INFO("and nothing stays nothing"); + CHECK(Orphans::seen(o, reach) == Orphan::None); reach.heldByPrim = true; o.orphan->kind = Orphan::Locked; - ensure("a locked text stays locked while its item is there", Orphans::seen(o, reach) == Orphan::Locked); + UNSCOPED_INFO("a locked text stays locked while its item is there"); + CHECK(Orphans::seen(o, reach) == Orphan::Locked); reach.heldByPrim = false; - ensure("but not once it is gone", Orphans::seen(o, reach) == Orphan::Removed); + UNSCOPED_INFO("but not once it is gone"); + CHECK(Orphans::seen(o, reach) == Orphan::Removed); reach.offline = true; - ensure("offline", Orphans::seen(o, reach) == Orphan::Offline); + UNSCOPED_INFO("offline"); + CHECK(Orphans::seen(o, reach) == Orphan::Offline); Doc& i = tab("inventory", true); Reach item = inReach(); item.trashed = true; - ensure("in the Trash", Orphans::seen(i, item) == Orphan::Trashed); + UNSCOPED_INFO("in the Trash"); + CHECK(Orphans::seen(i, item) == Orphan::Trashed); i.orphan->kind = Orphan::Unloaded; - ensure("an unloaded text stays so in the Trash", Orphans::seen(i, item) == Orphan::Unloaded); + UNSCOPED_INFO("an unloaded text stays so in the Trash"); + CHECK(Orphans::seen(i, item) == Orphan::Unloaded); item.itemThere = false; - ensure("its item gone", Orphans::seen(i, item) == Orphan::Removed); + UNSCOPED_INFO("its item gone"); + CHECK(Orphans::seen(i, item) == Orphan::Removed); Doc& f = tab("file"); f.ref = ALScriptRef(); f.file = "/somewhere/f.lsl"; Reach file; - ensure("its file gone", Orphans::seen(f, file) == Orphan::FileGone); + UNSCOPED_INFO("its file gone"); + CHECK(Orphans::seen(f, file) == Orphan::FileGone); file.fileThere = true; - ensure("its file there", Orphans::seen(f, file) == Orphan::None); + UNSCOPED_INFO("its file there"); + CHECK(Orphans::seen(f, file) == Orphan::None); f.loaded = false; - ensure("not loaded yet: nothing", Orphans::seen(f, Reach()) == Orphan::None); + UNSCOPED_INFO("not loaded yet: nothing"); + CHECK(Orphans::seen(f, Reach()) == Orphan::None); } - template<> template<> - void alscriptstudioorphans_object::test<2>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: a failed load makes a tab locked or unloaded or gone or away", "[alscriptstudioorphans]") { - set_test_name("what a failed load makes a tab: locked, unloaded, or gone -- from the inventory, its object, or out of sight"); make(); Doc& o = tab("object"); Doc& i = tab("inventory", true); - ensure("not permitted", Orphans::failedAs(o, Failure::NotPermitted, true) == Orphan::Locked); - ensure("unreadable", Orphans::failedAs(o, Failure::Unreadable, true) == Orphan::Unloaded); - ensure("a fetch that failed", Orphans::failedAs(o, Failure::Fetch, true) == Orphan::Unloaded); - ensure("gone from its object", Orphans::failedAs(o, Failure::Missing, true) == Orphan::Removed); - ensure("its object out of sight", Orphans::failedAs(o, Failure::Missing, false) == Orphan::Away); - ensure("gone from the inventory", Orphans::failedAs(i, Failure::Missing, false) == Orphan::Removed); + UNSCOPED_INFO("not permitted"); + CHECK(Orphans::failedAs(o, Failure::NotPermitted, true) == Orphan::Locked); + UNSCOPED_INFO("unreadable"); + CHECK(Orphans::failedAs(o, Failure::Unreadable, true) == Orphan::Unloaded); + UNSCOPED_INFO("a fetch that failed"); + CHECK(Orphans::failedAs(o, Failure::Fetch, true) == Orphan::Unloaded); + UNSCOPED_INFO("gone from its object"); + CHECK(Orphans::failedAs(o, Failure::Missing, true) == Orphan::Removed); + UNSCOPED_INFO("its object out of sight"); + CHECK(Orphans::failedAs(o, Failure::Missing, false) == Orphan::Away); + UNSCOPED_INFO("gone from the inventory"); + CHECK(Orphans::failedAs(i, Failure::Missing, false) == Orphan::Removed); } - template<> template<> - void alscriptstudioorphans_object::test<3>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: the check lets a tab be away a moment and says what was lost or back", "[alscriptstudioorphans]") { - set_test_name("the check: out of sight a moment is not gone; lost with changes, kept and said; back, said; the notice and toolbar told"); Orphans& unit = make(); Doc& a = tab("a"); Doc& b = tab("b"); studio.reaches["a"].objectThere = false; const F64 due = unit.check(); - ensure("each tab's place taken", studio.placed == Names{ "a", "b" }); - ensure("out of sight a moment: not yet away", a.orphan->kind == Orphan::None && a.orphan->awaySince > 0.0); - ensure("and to be looked at again once the moment is past", due > a.orphan->awaySince && due <= a.orphan->awaySince + 3.0); + UNSCOPED_INFO("each tab's place taken"); + CHECK(studio.placed == Names{ "a", "b" }); + { + INFO("out of sight a moment: not yet away"); + REQUIRE(a.orphan->kind == Orphan::None); + CHECK(a.orphan->awaySince > 0.0); + } + { + INFO("and to be looked at again once the moment is past"); + REQUIRE(due > a.orphan->awaySince); + CHECK(due <= a.orphan->awaySince + 3.0); + } a.orphan->awaySince -= 5.0; a.orphan->noticeDismissed = true; unit.check(); - ensure("gone a while: away", a.orphan->kind == Orphan::Away && !a.orphan->noticeDismissed && studio.toolbars == 1); + { + INFO("gone a while: away"); + REQUIRE(a.orphan->kind == Orphan::Away); + CHECK_FALSE(a.orphan->noticeDismissed); + CHECK(studio.toolbars == 1); + } b.editor->setCaret(b.editor->document().end()); b.editor->insertText(" typed"); studio.reaches["b"].heldByPrim = false; unit.check(); - ensure("gone with changes: kept", b.orphan->kind == Orphan::Removed && recovery->keptFor(b.recoveryKey) == 1); - ensure("and said, with what can be done", services().reports.back().text == said("OrphanRemovedKept", "[NAME]", "b") && - services().reports.back().actions == Names{ "copy", "export" }); + { + INFO("gone with changes: kept"); + CHECK(b.orphan->kind == Orphan::Removed); + CHECK(recovery->keptFor(b.recoveryKey) == 1); + } + { + INFO("and said, with what can be done"); + CHECK(services().reports.back().text == said("OrphanRemovedKept", "[NAME]", "b")); + CHECK(services().reports.back().actions == Names{ "copy", "export" }); + } studio.reaches["a"].objectThere = true; unit.check(); - ensure("back: said", a.orphan->kind == Orphan::None && services().reports.back().text == said("OrphanBack", "[NAME]", "a") && - a.orphan->awaySince == 0.0); + { + INFO("back: said"); + REQUIRE(a.orphan->kind == Orphan::None); + CHECK(services().reports.back().text == said("OrphanBack", "[NAME]", "a")); + CHECK(a.orphan->awaySince == 0.0); + } const size_t said = services().reports.size(); unit.check(); - ensure("nothing changed: nothing said", services().reports.size() == said && studio.toolbars == 3); + { + INFO("nothing changed: nothing said"); + REQUIRE(services().reports.size() == said); + CHECK(studio.toolbars == 3); + } Doc& c = tab("c"); c.orphan->kind = Orphan::Away; c.orphan->detached = true; c.orphan->reattachTries = ALRecoveryRetry::TRIES; unit.check(); - ensure("a detached one back: nothing said, its load will", c.orphan->kind == Orphan::None && services().reports.size() == said); + { + INFO("a detached one back: nothing said, its load will"); + CHECK(c.orphan->kind == Orphan::None); + REQUIRE(services().reports.size() == said); + } } - template<> template<> - void alscriptstudioorphans_object::test<4>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: a detached tab reloads under its kept text while tries last and are due", "[alscriptstudioorphans]") { - set_test_name("a detached tab loaded under what it holds once its item is in reach, while its tries last and the next is due"); Orphans& unit = make(); Doc& a = tab("a"); a.orphan->detached = true; @@ -264,283 +305,427 @@ namespace tut a.editor->insertText(" text"); a.orphan->reattachTries = ALRecoveryRetry::TRIES; unit.check(); - ensure("tried out: waits for a person", studio.loads.empty()); + UNSCOPED_INFO("tried out: waits for a person"); + REQUIRE(studio.loads.empty()); a.orphan->reattachTries = 1; a.orphan->nextReattach = LLTimer::getTotalSeconds() + 60.0; const F64 next = unit.check(); - ensure("to be looked at again when its try is due", next == a.orphan->nextReattach); - ensure("not due yet", studio.loads.empty()); + UNSCOPED_INFO("to be looked at again when its try is due"); + CHECK(next == a.orphan->nextReattach); + UNSCOPED_INFO("not due yet"); + REQUIRE(studio.loads.empty()); a.orphan->nextReattach = 0.0; unit.check(); - ensure("loaded", studio.loads.size() == 1 && studio.loads[0] == a.ref); - ensure("what it holds kept first, and carried over", - recovery->keptFor(a.recoveryKey) == 1 && a.carriedText && *a.carriedText == "kept text"); - ensure("not loaded, and not to be typed in, until it is", !a.loaded && a.editor->isReadOnly() && !a.orphan->detached); + { + INFO("loaded"); + REQUIRE(studio.loads.size() == 1); + CHECK(studio.loads[0] == a.ref); + } + { + INFO("what it holds kept first, and carried over"); + REQUIRE(recovery->keptFor(a.recoveryKey) == 1); + REQUIRE(a.carriedText); + CHECK(*a.carriedText == "kept text"); + } + { + INFO("not loaded, and not to be typed in, until it is"); + REQUIRE_FALSE(a.loaded); + REQUIRE(a.editor->isReadOnly()); + CHECK_FALSE(a.orphan->detached); + } Doc& u = tab("u"); u.orphan->detached = true; u.orphan->kind = Orphan::Unloaded; u.loadFailure = Failure::Unreadable; studio.reaches["u"].heldByPrim = true; unit.check(); - ensure("an unreadable one is not tried on its own", studio.loads.size() == 1); + UNSCOPED_INFO("an unreadable one is not tried on its own"); + REQUIRE(studio.loads.size() == 1); u.loadFailure = Failure::Fetch; unit.check(); - ensure("a fetch that failed is", studio.loads.size() == 2); + UNSCOPED_INFO("a fetch that failed is"); + REQUIRE(studio.loads.size() == 2); } - template<> template<> - void alscriptstudioorphans_object::test<5>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: the notice says a kept text first then each kind's words and buttons", "[alscriptstudioorphans]") { - set_test_name("what the notice says: a kept text first, stale where saved since; each kind's words and buttons; nothing once hidden"); make(); const al_studio_test::FakeServices& words = services(); - ensure("no tab: nothing", Orphans::noticeFor(nullptr, words).text.empty()); + UNSCOPED_INFO("no tab: nothing"); + REQUIRE(Orphans::noticeFor(nullptr, words).text.empty()); Doc& a = tab("a"); - ensure("nothing to say", Orphans::noticeFor(&a, words).text.empty()); + UNSCOPED_INFO("nothing to say"); + REQUIRE(Orphans::noticeFor(&a, words).text.empty()); ALRecoveryEntry kept; kept.baseAsset = LLUUID::generateNewID(); a.recoverable = kept; a.orphan->kind = Orphan::Away; ALScriptNoticeBar::Notice notice = Orphans::noticeFor(&a, words); const std::string when = kept.whenSaid(); - ensure("a kept text first", notice.text == said("NoticeRecoverable", "[WHEN]", when) && notice.buttons[0].first == "compare_kept" && - notice.buttons[1].first == "restore" && - notice.buttons[2] == std::make_pair(std::string("discard_left"), std::string("NoticeDiscard"))); + { + INFO("a kept text first"); + CHECK(notice.text == said("NoticeRecoverable", "[WHEN]", when)); + CHECK(notice.buttons[0].first == "compare_kept"); + CHECK(notice.buttons[1].first == "restore"); + CHECK(notice.buttons[2] == std::make_pair(std::string("discard_left"), std::string("NoticeDiscard"))); + } a.assetId = LLUUID::generateNewID(); - ensure("stale where saved since", Orphans::noticeFor(&a, words).text == said("NoticeRecoverableStale", "[WHEN]", when)); + UNSCOPED_INFO("stale where saved since"); + CHECK(Orphans::noticeFor(&a, words).text == said("NoticeRecoverableStale", "[WHEN]", when)); a.recoverable.reset(); notice = Orphans::noticeFor(&a, words); - ensure("away", notice.text == said("NoticeAway") && notice.buttons[0].first == "copy" && notice.buttons[1].first == "export"); + { + INFO("away"); + CHECK(notice.text == said("NoticeAway")); + CHECK(notice.buttons[0].first == "copy"); + CHECK(notice.buttons[1].first == "export"); + } a.orphan->kind = Orphan::Offline; notice = Orphans::noticeFor(&a, words); - ensure("offline: a copy on disk alone", notice.buttons[0].first == "export" && notice.buttons[1].first.empty()); + { + INFO("offline: a copy on disk alone"); + CHECK(notice.buttons[0].first == "export"); + REQUIRE(notice.buttons[1].first.empty()); + } a.orphan->kind = Orphan::Unloaded; a.loadError = "no such asset"; notice = Orphans::noticeFor(&a, words); - ensure("unloaded: why, and to try again", - notice.text.find("no such asset") != std::string::npos && notice.buttons[0].first == "retry_load"); + { + INFO("unloaded: why, and to try again"); + REQUIRE(notice.text.find("no such asset") != std::string::npos); + CHECK(notice.buttons[0].first == "retry_load"); + } a.orphan->kind = Orphan::Trashed; notice = Orphans::noticeFor(&a, words); - ensure("in the Trash: said, nothing to do", notice.text == said("NoticeTrashed") && notice.buttons[0].first.empty()); + { + INFO("in the Trash: said, nothing to do"); + CHECK(notice.text == said("NoticeTrashed")); + REQUIRE(notice.buttons[0].first.empty()); + } a.orphan->kind = Orphan::FileGone; a.file = "/somewhere/a.lsl"; notice = Orphans::noticeFor(&a, words); - ensure("a file gone: saved again", notice.text.find("/somewhere/a.lsl") != std::string::npos && notice.buttons[0].first == "save"); + { + INFO("a file gone: saved again"); + REQUIRE(notice.text.find("/somewhere/a.lsl") != std::string::npos); + CHECK(notice.buttons[0].first == "save"); + } Doc& i = tab("i", true); i.orphan->kind = Orphan::Removed; - ensure("gone from the inventory, said so", Orphans::noticeFor(&i, words).text == said("NoticeRemovedInventory")); + UNSCOPED_INFO("gone from the inventory, said so"); + CHECK(Orphans::noticeFor(&i, words).text == said("NoticeRemovedInventory")); i.orphan->noticeDismissed = true; - ensure("hidden: nothing", Orphans::noticeFor(&i, words).text.empty()); + UNSCOPED_INFO("hidden: nothing"); + REQUIRE(Orphans::noticeFor(&i, words).text.empty()); } - template<> template<> - void alscriptstudioorphans_object::test<6>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: the notice's actions act on the tab in front", "[alscriptstudioorphans]") { - set_test_name("the notice's actions for the tab in front: hide, restore, discard, try again, a copy, a file, a save"); Orphans& unit = make(); Doc& a = tab("a"); services().front = 0; a.recoverable = recovery->leftFor(a, "restored text"); unit.noticeAction("restore"); - ensure("restored, the source in front", studio.did == Names{ "source a", "carried a: restored text" } && !a.recoverable && - services().reports.back().text == said("RecoveryRestored", "[NAME]", "a")); + { + INFO("restored, the source in front"); + CHECK(studio.did == Names{ "source a", "carried a: restored text" }); + REQUIRE_FALSE(a.recoverable); + CHECK(services().reports.back().text == said("RecoveryRestored", "[NAME]", "a")); + } a.recoverable = ALRecoveryEntry(); unit.noticeAction("discard_left"); - ensure("discarded", studio.did.back() == "discard" && !a.recoverable); + { + INFO("discarded"); + CHECK(studio.did.back() == "discard"); + REQUIRE_FALSE(a.recoverable); + } a.recoverable = ALRecoveryEntry(); unit.noticeAction("close"); - ensure("hidden, the kept text let go of here", a.orphan->noticeDismissed && !a.recoverable); + { + INFO("hidden, the kept text let go of here"); + CHECK(a.orphan->noticeDismissed); + REQUIRE_FALSE(a.recoverable); + } unit.noticeAction("copy"); unit.noticeAction("export"); unit.noticeAction("save"); - ensure("a copy, a file, a save", - studio.did == Names{ "source a", "carried a: restored text", "source a", "discard", "copy a", "save a" } && - files->picked == Names{ "a" }); + { + INFO("a copy, a file, a save"); + CHECK(studio.did == Names{ "source a", "carried a: restored text", "source a", "discard", "copy a", "save a" }); + CHECK(files->picked == Names{ "a" }); + } a.orphan->reattachTries = 3; unit.noticeAction("retry_load"); - ensure("not detached: nothing to try", studio.loads.empty()); + UNSCOPED_INFO("not detached: nothing to try"); + REQUIRE(studio.loads.empty()); a.orphan->detached = true; unit.noticeAction("retry_load"); - ensure("tried again, from the first try", studio.loads.size() == 1 && a.orphan->reattachTries == 0); + { + INFO("tried again, from the first try"); + REQUIRE(studio.loads.size() == 1); + CHECK(a.orphan->reattachTries == 0); + } } - template<> template<> - void alscriptstudioorphans_object::test<7>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: the bar shows words and buttons and hides with nothing to say", "[alscriptstudioorphans]") { - set_test_name("the bar: shown with its words and buttons, as wide as their labels; hidden with nothing to say; its buttons the window's"); Orphans& unit = make(); ALScriptNoticeBar* bar = window.find("notice"); - ensure("built from the skin", bar != nullptr); + UNSCOPED_INFO("built from the skin"); + REQUIRE(bar != nullptr); studio.bar = bar; Doc& a = tab("a"); services().front = 0; a.orphan->kind = Orphan::Away; unit.refreshNotice(); LLView* holder = bar->getParent(); - ensure("shown", holder->getVisible()); - ensure_equals("its words", bar->getChild("notice_text")->getText(), said("NoticeAway")); + UNSCOPED_INFO("shown"); + CHECK(holder->getVisible()); + UNSCOPED_INFO("its words"); + CHECK(bar->getChild("notice_text")->getText() == said("NoticeAway")); LLButton* first = bar->getChild("notice_first"); LLButton* second = bar->getChild("notice_second"); - ensure("its buttons, labelled", first->getVisible() && second->getVisible() && first->getLabelSelected() == said("NoticeCopy") && - first->getToolTip() == said("NoticeCopyTip")); - ensure("the first left of the second", first->getRect().mRight < second->getRect().mLeft); + { + INFO("its buttons, labelled"); + REQUIRE(first->getVisible()); + CHECK(second->getVisible()); + REQUIRE(first->getLabelSelected() == said("NoticeCopy")); + CHECK(first->getToolTip() == said("NoticeCopyTip")); + } + UNSCOPED_INFO("the first left of the second"); + CHECK(first->getRect().mRight < second->getRect().mLeft); first->onCommit(); second->onCommit(); bar->getChild("notice_close")->onCommit(); - ensure("the window told", window.pane().pressed == Names{ "copy", "export", "close" }); + UNSCOPED_INFO("the window told"); + CHECK(window.pane().pressed == Names{ "copy", "export", "close" }); a.orphan->kind = Orphan::Offline; unit.refreshNotice(); - ensure("one button", first->getVisible() && !second->getVisible() && bar->action(0) == "export"); + { + INFO("one button"); + CHECK(first->getVisible()); + CHECK_FALSE(second->getVisible()); + CHECK(bar->action(0) == "export"); + } a.orphan->kind = Orphan::None; unit.refreshNotice(); - ensure("hidden", !holder->getVisible()); + UNSCOPED_INFO("hidden"); + CHECK_FALSE(holder->getVisible()); } - template<> template<> - void alscriptstudioorphans_object::test<8>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: a compiled half the source could not make is compared or kept or taken", "[alscriptstudioorphans]") { - set_test_name("a compiled half the source could not have made: said after a kept text and a tab gone, kept as source or taken as it"); Orphans& unit = make(); const al_studio_test::FakeServices& words = services(); Doc& a = tab("a"); services().front = 0; a.compiledDiffers = std::string("default { touch_start(integer n) { llDie(); } }"); ALScriptNoticeBar::Notice notice = Orphans::noticeFor(&a, words); - ensure("said, with its ways", notice.text == said("NoticeCompiledDiffers") && notice.buttons[0].first == "compare_compiled" && - notice.buttons[1].first == "keep_source" && notice.buttons[2].first == "take_compiled"); + { + INFO("said, with its ways"); + CHECK(notice.text == said("NoticeCompiledDiffers")); + CHECK(notice.buttons[0].first == "compare_compiled"); + CHECK(notice.buttons[1].first == "keep_source"); + CHECK(notice.buttons[2].first == "take_compiled"); + } a.uploaded.text = std::make_shared("default { }"); unit.noticeAction("compare_compiled"); - ensure_equals("compared: as saved, beside what the source makes", studio.did.back(), + UNSCOPED_INFO("compared: as saved, beside what the source makes"); + CHECK(studio.did.back() == "compare a: default { touch_start(integer n) { llDie(); } } | default { } (" + said("CompareCompiled") + " | " + said("CompareMade") + ")"); - ensure("the notice stays, to act on after looking", a.compiledDiffers.has_value()); + UNSCOPED_INFO("the notice stays, to act on after looking"); + REQUIRE(a.compiledDiffers.has_value()); studio.did.clear(); a.orphan->kind = Orphan::Away; - ensure("a tab gone first", Orphans::noticeFor(&a, words).text == said("NoticeAway")); + UNSCOPED_INFO("a tab gone first"); + CHECK(Orphans::noticeFor(&a, words).text == said("NoticeAway")); a.orphan->kind = Orphan::None; unit.noticeAction("take_compiled"); - ensure("the source back in front, then taken as the source", - studio.did == Names{ "source a", "carried a: default { touch_start(integer n) { llDie(); } }" } && !a.compiledDiffers); - ensure("and said", services().reports.back().text == said("CompiledTaken", "[NAME]", "a")); + { + INFO("the source back in front, then taken as the source"); + CHECK(studio.did == Names{ "source a", "carried a: default { touch_start(integer n) { llDie(); } }" }); + REQUIRE_FALSE(a.compiledDiffers); + } + UNSCOPED_INFO("and said"); + CHECK(services().reports.back().text == said("CompiledTaken", "[NAME]", "a")); a.compiledDiffers = std::string("x"); unit.noticeAction("keep_source"); - ensure("kept: let go of, the next save replacing it", !a.compiledDiffers && studio.did.back() == "source a"); - ensure("nothing more to say", Orphans::noticeFor(&a, words).text.empty()); + { + INFO("kept: let go of, the next save replacing it"); + REQUIRE_FALSE(a.compiledDiffers); + CHECK(studio.did.back() == "source a"); + } + UNSCOPED_INFO("nothing more to say"); + REQUIRE(Orphans::noticeFor(&a, words).text.empty()); } - template<> template<> - void alscriptstudioorphans_object::test<9>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: a kept text compares with the tab and restores with the source in front", "[alscriptstudioorphans]") { - set_test_name("a kept text compared with what the tab holds now, the notice staying; restoring puts the source back in front"); Orphans& unit = make(); Doc& a = tab("a"); services().front = 0; // As a tab is offered it: the entry's listing, not yet its text. const ALRecoveryEntry kept = recovery->leftFor(a, "default { state_entry() { } }"); a.recoverable = kept; - ensure("offered as listed", !kept.whole); + UNSCOPED_INFO("offered as listed"); + CHECK_FALSE(kept.whole); unit.noticeAction("compare_kept"); - ensure_equals("now beside kept", studio.did.back(), + UNSCOPED_INFO("now beside kept"); + CHECK(studio.did.back() == "compare a: default {} | default { state_entry() { } } (" + said("CompareNow") + " | " + said("CompareKept", "[WHEN]", kept.whenSaid()) + ")"); - ensure("still offered", a.recoverable.has_value()); + UNSCOPED_INFO("still offered"); + REQUIRE(a.recoverable.has_value()); unit.noticeAction("restore"); - ensure("the source in front first", - studio.did[studio.did.size() - 2] == "source a" && studio.did.back() == "carried a: default { state_entry() { } }"); + { + INFO("the source in front first"); + REQUIRE(studio.did[studio.did.size() - 2] == "source a"); + CHECK(studio.did.back() == "carried a: default { state_entry() { } }"); + } } - template<> template<> - void alscriptstudioorphans_object::test<10>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: the last word's offer shows after the tab's state and is taken or hidden", "[alscriptstudioorphans]") { - set_test_name("what the last word offered: said after what the tab is, in the notice's words, a conflict's only while there is another text; " - "taken up as Output would, or hidden"); Orphans& unit = make(); const al_studio_test::FakeServices& words = services(); Doc& a = tab("a"); services().front = 0; a.offer = Doc::Offer{ "Saving a failed.", { "retry", "copy", "export" } }; ALScriptNoticeBar::Notice notice = Orphans::noticeFor(&a, words); - ensure("said with its buttons", notice.text == "Saving a failed." && - notice.buttons[0] == std::make_pair(std::string("retry"), std::string("NoticeRetrySave")) && - notice.buttons[1].first == "copy" && notice.buttons[2].first == "export"); + { + INFO("said with its buttons"); + CHECK(notice.text == "Saving a failed."); + CHECK(notice.buttons[0] == std::make_pair(std::string("retry"), std::string("NoticeRetrySave"))); + CHECK(notice.buttons[1].first == "copy"); + CHECK(notice.buttons[2].first == "export"); + } a.orphan->kind = Orphan::Away; - ensure("what the tab is first", Orphans::noticeFor(&a, words).text == said("NoticeAway")); + UNSCOPED_INFO("what the tab is first"); + CHECK(Orphans::noticeFor(&a, words).text == said("NoticeAway")); a.orphan->noticeDismissed = true; - ensure("then the offer, once that is hidden", Orphans::noticeFor(&a, words).text == "Saving a failed."); + UNSCOPED_INFO("then the offer, once that is hidden"); + CHECK(Orphans::noticeFor(&a, words).text == "Saving a failed."); a.orphan->kind = Orphan::None; a.orphan->noticeDismissed = false; unit.noticeAction("retry"); - ensure("taken up, and let go of", studio.did.back() == "offer a: retry" && !a.offer); + { + INFO("taken up, and let go of"); + CHECK(studio.did.back() == "offer a: retry"); + REQUIRE_FALSE(a.offer); + } a.offer = Doc::Offer{ "Saved elsewhere.", { "take_saved", "keep_saved", "merge_saved", "compare_saved" } }; - ensure("a conflict with nothing to take: not said", Orphans::noticeFor(&a, words).text.empty()); + UNSCOPED_INFO("a conflict with nothing to take: not said"); + REQUIRE(Orphans::noticeFor(&a, words).text.empty()); a.savedThere = std::string("theirs"); notice = Orphans::noticeFor(&a, words); - ensure("with it: said, all four", notice.text == "Saved elsewhere." && notice.buttons[0].second == "NoticeTakeSaved" && - notice.buttons[2].second == "NoticeMerge" && notice.buttons[3].second == "NoticeCompare"); + { + INFO("with it: said, all four"); + CHECK(notice.text == "Saved elsewhere."); + CHECK(notice.buttons[0].second == "NoticeTakeSaved"); + CHECK(notice.buttons[2].second == "NoticeMerge"); + CHECK(notice.buttons[3].second == "NoticeCompare"); + } unit.noticeAction("close"); - ensure("hidden: let go of, and nothing else", !a.offer && !a.orphan->noticeDismissed && studio.did.back() == "offer a: retry"); + { + INFO("hidden: let go of, and nothing else"); + REQUIRE_FALSE(a.offer); + CHECK_FALSE(a.orphan->noticeDismissed); + CHECK(studio.did.back() == "offer a: retry"); + } a.offer = Doc::Offer{ "Held.", { "save_anyway" } }; a.compiledDiffers = std::string("x"); - ensure("said before a compiled half", Orphans::noticeFor(&a, words).text == "Held."); - ensure("a save's, answered by a save; a conflict's not", - a.offer->bySave() && !Doc::Offer{ "x", { "take_external", "keep_here" } }.bySave()); + UNSCOPED_INFO("said before a compiled half"); + CHECK(Orphans::noticeFor(&a, words).text == "Held."); + { + INFO("a save's, answered by a save; a conflict's not"); + CHECK(a.offer->bySave()); + CHECK_FALSE(Doc::Offer{ "x", { "take_external", "keep_here" } }.bySave()); + } a.orphan->kind = Orphan::Removed; a.offer = Doc::Offer{ "Kept.", { "copy", "export" } }; unit.noticeAction("close"); - ensure("what a tab gone says of itself, hidden with it", a.orphan->noticeDismissed && !a.offer); + { + INFO("what a tab gone says of itself, hidden with it"); + CHECK(a.orphan->noticeDismissed); + REQUIRE_FALSE(a.offer); + } a.orphan->noticeDismissed = false; a.offer = Doc::Offer{ "Saving a failed.", { "retry", "copy", "export" } }; unit.noticeAction("close"); - ensure("more than that: said next", a.offer && Orphans::noticeFor(&a, words).text == "Saving a failed."); + { + INFO("more than that: said next"); + REQUIRE(a.offer); + CHECK(Orphans::noticeFor(&a, words).text == "Saving a failed."); + } } - template<> template<> - void alscriptstudioorphans_object::test<11>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: no skin string begins with a quotation mark so code adds vim's quotes", "[alscriptstudioorphans]") { - set_test_name("no string of the skin's begins with a quotation mark, which the skin reads as quoting it: vim's quotes are put in by the code"); make(); - ensure_equals("a name in quotes", said("RenameBadName", "[NAME]", "9lives"), std::string("Not a valid name: \"9lives\".")); + UNSCOPED_INFO("a name in quotes"); + CHECK(said("RenameBadName", "[NAME]", "9lives") == std::string("Not a valid name: \"9lives\".")); LLStringUtil::format_map_t written; written["[QUOTED]"] = "\"a.lsl\""; written["[LINES]"] = "4"; written["[BYTES]"] = "20"; - ensure_equals("vim's written", services().words("VimWritten", written), std::string("\"a.lsl\" 4L, 20B written")); + UNSCOPED_INFO("vim's written"); + CHECK(services().words("VimWritten", written) == std::string("\"a.lsl\" 4L, 20B written")); const std::string vimrc = services().words("VimrcNewFile"); - ensure("the vimrc's words whole", vimrc.rfind("Script Studio's vimrc.", 0) == 0 && std::count(vimrc.begin(), vimrc.end(), '\n') == 3); + { + INFO("the vimrc's words whole"); + CHECK(vimrc.rfind("Script Studio's vimrc.", 0) == 0); + CHECK(std::count(vimrc.begin(), vimrc.end(), '\n') == 3); + } } - template<> template<> - void alscriptstudioorphans_object::test<12>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: a tab's standing changes bring the notice back and space out retries", "[alscriptstudioorphans]") { - set_test_name("a tab's standing as the window and a save change it: the notice back each time, a kept text detached where it is an item's, " - "a failed load tried later and further apart"); make(); Doc& a = tab("a"); a.orphan->noticeDismissed = true; Orphans::become(a, Doc::Orphan::Removed); - ensure("removed, and said", a.orphan->kind == Doc::Orphan::Removed && !a.orphan->noticeDismissed && !a.orphan->detached); + { + INFO("removed, and said"); + REQUIRE(a.orphan->kind == Doc::Orphan::Removed); + REQUIRE_FALSE(a.orphan->noticeDismissed); + CHECK_FALSE(a.orphan->detached); + } a.orphan->noticeDismissed = true; Orphans::showNotice(a); - ensure("the notice back", !a.orphan->noticeDismissed); + UNSCOPED_INFO("the notice back"); + CHECK_FALSE(a.orphan->noticeDismissed); Orphans::detach(a, Doc::Orphan::Unloaded); - ensure("an item's kept text detached", a.orphan->detached && a.orphan->kind == Doc::Orphan::Unloaded); + { + INFO("an item's kept text detached"); + REQUIRE(a.orphan->detached); + CHECK(a.orphan->kind == Doc::Orphan::Unloaded); + } Doc& f = tab("f"); f.file = "/nowhere/f.lsl"; Orphans::detach(f, Doc::Orphan::FileGone); - ensure("a file's not: nothing is loaded under it", !f.orphan->detached && f.orphan->kind == Doc::Orphan::FileGone); + { + INFO("a file's not: nothing is loaded under it"); + REQUIRE_FALSE(f.orphan->detached); + CHECK(f.orphan->kind == Doc::Orphan::FileGone); + } const F64 now = LLTimer::getTotalSeconds(); Orphans::loadFailed(a); const F64 first = a.orphan->nextReattach - now; Orphans::loadFailed(a); const F64 second = a.orphan->nextReattach - now; - ensure("tried later, further apart each time", a.orphan->reattachTries == 2 && first > 0.0 && second > first); + { + INFO("tried later, further apart each time"); + CHECK(a.orphan->reattachTries == 2); + CHECK(first > 0.0); + CHECK(second > first); + } Orphans::loadWentThrough(a); - ensure("from the first try once one goes through", a.orphan->reattachTries == 0); + UNSCOPED_INFO("from the first try once one goes through"); + CHECK(a.orphan->reattachTries == 0); } - template<> template<> - void alscriptstudioorphans_object::test<13>() + TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: a history save offered back is restored as carried text or let go of", "[alscriptstudioorphans]") { - set_test_name("a save of the history offered back: restored as carried text, the comparison ended, said; or let go of with the notice"); Orphans& unit = make(); Doc& a = tab("a"); ALSavedText shown; @@ -548,18 +733,28 @@ namespace tut shown.when = LLDate(1.8e9); a.historyShown = shown; unit.noticeAction("restore_saved"); - ensure("the source back in front, then taken", studio.did == Names{ "source a", "carried a: default { }" } && !a.historyShown); + { + INFO("the source back in front, then taken"); + CHECK(studio.did == Names{ "source a", "carried a: default { }" }); + REQUIRE_FALSE(a.historyShown); + } LLStringUtil::format_map_t args; args["[NAME]"] = "a"; args["[WHEN]"] = ALRecoveryEntry::sayWhen(shown.when); - ensure_equals("and said", services().reports.back().text, services().words("HistoryRestored", args)); + UNSCOPED_INFO("and said"); + CHECK(services().reports.back().text == services().words("HistoryRestored", args)); studio.did.clear(); a.historyShown = shown; a.modifiable = false; unit.noticeAction("restore_saved"); - ensure("not into a tab that may not be changed", studio.did.empty() && a.historyShown); + { + INFO("not into a tab that may not be changed"); + REQUIRE(studio.did.empty()); + REQUIRE(a.historyShown); + } unit.noticeAction("close"); - ensure("let go of with the notice", !a.historyShown); + UNSCOPED_INFO("let go of with the notice"); + REQUIRE_FALSE(a.historyShown); } } diff --git a/indra/newview/tests/alscriptstudiorecovery_test.cpp b/indra/newview/tests/alscriptstudiorecovery_test.cpp index 47d6456630..ab0b489d16 100644 --- a/indra/newview/tests/alscriptstudiorecovery_test.cpp +++ b/indra/newview/tests/alscriptstudiorecovery_test.cpp @@ -33,7 +33,7 @@ #include "fsyspath.h" #include "lltimer.h" -#include "../test/lltut.h" +#include #include #include @@ -106,7 +106,7 @@ namespace }; } -namespace tut +namespace { struct alscriptstudiorecovery_data { @@ -133,7 +133,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } recovery = std::make_unique(services(), studio(), studio()); studio().recovery = recovery.get(); @@ -189,7 +189,8 @@ namespace tut other.write(entry); // What another session left, as this one's store finds it. const std::optional left = store->leftFor(entry.key); - ensure("left by the other session", left.has_value()); + UNSCOPED_INFO("left by the other session"); + REQUIRE(left.has_value()); return *left; } @@ -213,68 +214,118 @@ namespace tut return count; } }; - typedef test_group alscriptstudiorecovery_group; - typedef alscriptstudiorecovery_group::object alscriptstudiorecovery_object; - tut::alscriptstudiorecovery_group alscriptstudiorecovery_instance("alscriptstudiorecovery"); - template<> template<> - void alscriptstudiorecovery_object::test<1>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: restoreHistory brings back an entry's text and steps and caret", "[alscriptstudiorecovery]") { - set_test_name("an entry is the tab as it stands, and put back over a tab of its script holding nothing of its own, brings its text, its history and its caret"); ALScriptStudioRecovery& r = make(); Doc& a = tab("a", "default {}\n"); type(a, "// one"); type(a, " two"); const Entry entry = ALScriptStudioRecovery::entryOf(a); - ensure("the text", entry.text == "default {}\n// one two" && entry.key == a.recoveryKey); - ensure("where it came from", entry.object == a.ref.object && entry.item == a.ref.item && entry.name == "a" && !entry.notecard); - ensure("the caret", entry.caretLine == 1 && entry.caretColumn == 10); - ensure("and the steps, as the journal writes them", entry.historyOf().isMap() && !entry.historyWritten.empty()); + { + INFO("the text"); + CHECK(entry.text == "default {}\n// one two"); + CHECK(entry.key == a.recoveryKey); + } + { + INFO("where it came from"); + CHECK(entry.object == a.ref.object); + CHECK(entry.item == a.ref.item); + CHECK(entry.name == "a"); + CHECK_FALSE(entry.notecard); + } + { + INFO("the caret"); + CHECK(entry.caretLine == 1); + CHECK(entry.caretColumn == 10); + } + { + INFO("and the steps, as the journal writes them"); + REQUIRE(entry.historyOf().isMap()); + REQUIRE_FALSE(entry.historyWritten.empty()); + } Doc& b = tab("b", "default {}\n", a.ref); - ensure("put back", r.restoreHistory(b, entry)); - ensure("its text", b.editor->text() == entry.text && b.editor->isDirty()); - ensure("its caret", b.editor->caret().line == 1 && b.editor->caret().column == 10); + UNSCOPED_INFO("put back"); + CHECK(r.restoreHistory(b, entry)); + { + INFO("its text"); + REQUIRE(b.editor->text() == entry.text); + CHECK(b.editor->isDirty()); + } + { + INFO("its caret"); + REQUIRE(b.editor->caret().line == 1); + CHECK(b.editor->caret().column == 10); + } b.editor->undo(); - ensure("and the steps that led to it, to take back", b.editor->text() != entry.text && b.editor->text().starts_with("default {}\n")); - ensure("the tabs told", studio().tabs == 1); + { + INFO("and the steps that led to it, to take back"); + REQUIRE(b.editor->text() != entry.text); + CHECK(b.editor->text().starts_with("default {}\n")); + } + UNSCOPED_INFO("the tabs told"); + CHECK(studio().tabs == 1); type(b, "x"); - ensure("not over a tab holding something of its own", !r.restoreHistory(b, entry)); + UNSCOPED_INFO("not over a tab holding something of its own"); + CHECK_FALSE(r.restoreHistory(b, entry)); Doc& c = tab("c", "something else\n", a.ref); Entry wrong = entry; wrong.text = "not where the steps lead\n"; - ensure("nor where the history is not of its text", !r.restoreHistory(c, wrong) && c.editor->text() == "something else\n"); + { + INFO("nor where the history is not of its text"); + REQUIRE_FALSE(r.restoreHistory(c, wrong)); + CHECK(c.editor->text() == "something else\n"); + } } - template<> template<> - void alscriptstudiorecovery_object::test<2>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: keep holds unsaved text and forgets it once the tab is clean", "[alscriptstudiorecovery]") { - set_test_name("kept while unsaved and forgotten once clean; what a tab took up is its own to keep from then on"); ALScriptStudioRecovery& r = make(); Doc& doc = tab("a", "x\n"); - ensure("clean: nothing kept", r.keep(doc) && keptFor(doc.recoveryKey) == 0); + { + INFO("clean: nothing kept"); + CHECK(r.keep(doc)); + CHECK(keptFor(doc.recoveryKey) == 0); + } type(doc, "y"); - ensure("kept", r.keep(doc) && keptFor(doc.recoveryKey) == 1); + { + INFO("kept"); + CHECK(r.keep(doc)); + CHECK(keptFor(doc.recoveryKey) == 1); + } doc.editor->resetDirty(); - ensure("clean again: forgotten", r.keep(doc) && keptFor(doc.recoveryKey) == 0); + { + INFO("clean again: forgotten"); + CHECK(r.keep(doc)); + CHECK(keptFor(doc.recoveryKey) == 0); + } doc.recovering = leftFor(doc, "an old session's"); - ensure("the old session's there", keptFor(doc.recoveryKey, "old-session") == 1); + UNSCOPED_INFO("the old session's there"); + CHECK(keptFor(doc.recoveryKey, "old-session") == 1); type(doc, "z"); r.keep(doc); - ensure("taken up, it is this session's alone", keptFor(doc.recoveryKey, "old-session") == 0 && keptFor(doc.recoveryKey) == 1 && !doc.recovering); + { + INFO("taken up, it is this session's alone"); + CHECK(keptFor(doc.recoveryKey, "old-session") == 0); + CHECK(keptFor(doc.recoveryKey) == 1); + REQUIRE_FALSE(doc.recovering); + } Doc& loading = tab("b", "q\n"); type(loading, "w"); loading.loaded = false; - ensure("nothing kept of a tab still loading", r.keep(loading) && keptFor(loading.recoveryKey) == 0); + { + INFO("nothing kept of a tab still loading"); + CHECK(r.keep(loading)); + CHECK(keptFor(loading.recoveryKey) == 0); + } } - template<> template<> - void alscriptstudiorecovery_object::test<3>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: a failing write is reported once whether now or from the store's thread", "[alscriptstudiorecovery]") { - set_test_name("a write that fails is said once, not at every pause in typing, whether now or on the store's thread; one that works again may say it again"); ALScriptStudioRecovery& r = make(); Doc& doc = tab("a", "x\n"); const std::string blocked = folder + "/blocked"; @@ -285,60 +336,99 @@ namespace tut ALRecoveryStore nowhere(blocked, "this-session"); ALRecovery::useStore(&nowhere); type(doc, "y"); - ensure("not kept", !r.keep(doc)); - ensure("said", services().reports.size() == 1 && services().reports[0].failure && services().reports[0].doc == "a" && - services().reports[0].text.find("a") != std::string::npos); + UNSCOPED_INFO("not kept"); + CHECK_FALSE(r.keep(doc)); + { + INFO("said"); + REQUIRE(services().reports.size() == 1); + CHECK(services().reports[0].failure); + CHECK(services().reports[0].doc == "a"); + REQUIRE(services().reports[0].text.find("a") != std::string::npos); + } type(doc, "z"); - ensure("not said again", !r.keep(doc) && services().reports.size() == 1); + { + INFO("not said again"); + CHECK_FALSE(r.keep(doc)); + REQUIRE(services().reports.size() == 1); + } ALRecovery::useStore(store.get()); - ensure("kept, once it can be", r.keep(doc) && !doc.recovery->failed); + { + INFO("kept, once it can be"); + REQUIRE(r.keep(doc)); + CHECK_FALSE(doc.recovery->failed); + } ALRecovery::useStore(&nowhere); type(doc, "w"); r.keepSoon(doc); nowhere.flush(); r.keepSoon(doc); - ensure("from the store's thread, said once", services().reports.size() == 2 && doc.recovery->failed); + { + INFO("from the store's thread, said once"); + REQUIRE(services().reports.size() == 2); + CHECK(doc.recovery->failed); + } nowhere.flush(); r.keepSoon(doc); nowhere.flush(); r.keepSoon(doc); - ensure("and not again", services().reports.size() == 2); + UNSCOPED_INFO("and not again"); + REQUIRE(services().reports.size() == 2); ALRecovery::useStore(store.get()); } - template<> template<> - void alscriptstudiorecovery_object::test<4>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: takeUp waits for the tab to load and goes in as one step to undo", "[alscriptstudiorecovery]") { - set_test_name("a kept text taken up waits for its tab to load, then goes in as one step to undo; over a tab nothing can be saved from, the tab holds it on its own"); ALScriptStudioRecovery& r = make(); Doc& doc = tab("a", "old\n"); const Entry kept = leftFor(doc, "kept\n"); doc.loaded = false; r.takeUp(doc, kept); - ensure("waiting", doc.carriedText == std::optional("kept\n") && doc.recovering && doc.editor->text() == "old\n"); + { + INFO("waiting"); + REQUIRE(doc.carriedText == std::optional("kept\n")); + REQUIRE(doc.recovering); + CHECK(doc.editor->text() == "old\n"); + } doc.loaded = true; doc.carriedText.reset(); doc.recovering.reset(); r.takeUp(doc, kept); - ensure("in", doc.editor->text() == "kept\n" && doc.editor->isDirty() && !doc.carriedText); - ensure("kept by this session, the old entry let go of", keptFor(doc.recoveryKey) == 1 && keptFor(doc.recoveryKey, "old-session") == 0); - ensure("the notice told", studio().notices == 1); + { + INFO("in"); + REQUIRE(doc.editor->text() == "kept\n"); + CHECK(doc.editor->isDirty()); + REQUIRE_FALSE(doc.carriedText); + } + { + INFO("kept by this session, the old entry let go of"); + CHECK(keptFor(doc.recoveryKey) == 1); + CHECK(keptFor(doc.recoveryKey, "old-session") == 0); + } + UNSCOPED_INFO("the notice told"); + CHECK(studio().notices == 1); doc.editor->undo(); - ensure("one step to undo", doc.editor->text() == "old\n"); + UNSCOPED_INFO("one step to undo"); + CHECK(doc.editor->text() == "old\n"); Doc& locked = tab("b", "locked\n"); locked.modifiable = false; r.takeUp(locked, leftFor(locked, "kept too\n")); - ensure("held on its own", studio().became.size() == 1 && studio().became[0] == std::make_pair(std::string("b"), Doc::Orphan::Locked)); - ensure("and said, with what can be done with it", services().reports.size() == 1 && services().reports[0].actions.size() == 2); + { + INFO("held on its own"); + REQUIRE(studio().became.size() == 1); + CHECK(studio().became[0] == std::make_pair(std::string("b"), Doc::Orphan::Locked)); + } + { + INFO("and said, with what can be done with it"); + REQUIRE(services().reports.size() == 1); + REQUIRE(services().reports[0].actions.size() == 2); + } } - template<> template<> - void alscriptstudiorecovery_object::test<5>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: recover takes an entry to where it belongs or to a tab of its own", "[alscriptstudiorecovery]") { - set_test_name("recovered where it belongs: another window that has it; its file, or a tab of its own where the file is gone; its script where it can be had, or a tab of its own"); ALScriptStudioRecovery& r = make(); Entry entry; entry.name = "held"; @@ -348,7 +438,11 @@ namespace tut studio().elsewhere = true; r.recover(entry); - ensure("in the window that has it", studio().tookElsewhere.size() == 1 && studio().orphans.empty()); + { + INFO("in the window that has it"); + REQUIRE(studio().tookElsewhere.size() == 1); + REQUIRE(studio().orphans.empty()); + } studio().elsewhere = false; Entry file = entry; @@ -357,7 +451,11 @@ namespace tut file.file = folder + "/gone.lsl"; file.name = "gone"; r.recover(file); - ensure("a file gone, a tab of its own", studio().orphans.size() == 1 && studio().orphans[0].second == Doc::Orphan::FileGone); + { + INFO("a file gone, a tab of its own"); + REQUIRE(studio().orphans.size() == 1); + CHECK(studio().orphans[0].second == Doc::Orphan::FileGone); + } { llofstream there(folder + "/here.lsl"); there << "on disk\n"; @@ -370,15 +468,27 @@ namespace tut return &doc; }; r.recover(file); - ensure("a file there, opened and taken up", studio().activated.size() == 1 && services().findDoc("disk:" + file.file)->carriedText); + { + INFO("a file there, opened and taken up"); + REQUIRE(studio().activated.size() == 1); + REQUIRE(services().findDoc("disk:" + file.file)->carriedText); + } studio().inHand = false; r.recover(entry); - ensure("an object out of sight, a tab of its own", studio().orphans.size() == 2 && studio().orphans[1].second == Doc::Orphan::Away); + { + INFO("an object out of sight, a tab of its own"); + REQUIRE(studio().orphans.size() == 2); + CHECK(studio().orphans[1].second == Doc::Orphan::Away); + } Entry inventory = entry; inventory.object.setNull(); r.recover(inventory); - ensure("an item gone from the inventory", studio().orphans.size() == 3 && studio().orphans[2].second == Doc::Orphan::Removed); + { + INFO("an item gone from the inventory"); + REQUIRE(studio().orphans.size() == 3); + CHECK(studio().orphans[2].second == Doc::Orphan::Removed); + } studio().inHand = true; services().whenOpened = [this](const ALScriptRef& ref, const std::string&) { @@ -386,17 +496,22 @@ namespace tut doc.loaded = false; }; r.recover(entry); - ensure("its script opened, and the text to go in once loaded", - services().opened.size() == 1 && services().findDoc(ALScriptRef(entry.object, entry.item))->carriedText == std::optional("kept\n")); + { + INFO("its script opened, and the text to go in once loaded"); + REQUIRE(services().opened.size() == 1); + CHECK(services().findDoc(ALScriptRef(entry.object, entry.item))->carriedText == std::optional("kept\n")); + } } - template<> template<> - void alscriptstudiorecovery_object::test<6>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: show offers other sessions' and discarded entries to pick or drop", "[alscriptstudiorecovery]") { - set_test_name("Recover Unsaved Changes offers what other sessions left and what was thrown away, not this session's own; picked, taken up; Shift-Return throws one away, and one thrown away already goes for good"); ALScriptStudioRecovery& r = make(); r.show(); - ensure("nothing to offer, said", services().statuses.size() == 1 && studio().candidates.empty()); + { + INFO("nothing to offer, said"); + REQUIRE(services().statuses.size() == 1); + REQUIRE(studio().candidates.empty()); + } Doc& mine = tab("mine", "a\n"); type(mine, "b"); @@ -405,15 +520,21 @@ namespace tut const Entry left = leftFor(theirs, "left\n"); Doc& gone = tab("gone", "d\n"); type(gone, "e"); - ensure("set aside", r.setAside(gone)); + UNSCOPED_INFO("set aside"); + CHECK(r.setAside(gone)); r.show(); - ensure("theirs and what was set aside", studio().candidates.size() == 2); + UNSCOPED_INFO("theirs and what was set aside"); + REQUIRE(studio().candidates.size() == 2); std::string theirs_value, gone_value; for (const ALQuickOpen::Candidate& one : studio().candidates) { (one.label == "theirs" ? theirs_value : gone_value) = one.value; } - ensure("by name", !theirs_value.empty() && !gone_value.empty()); + { + INFO("by name"); + REQUIRE_FALSE(theirs_value.empty()); + REQUIRE_FALSE(gone_value.empty()); + } studio().dropped(gone_value); bool still = false; @@ -421,7 +542,8 @@ namespace tut { still |= entry.name == "gone"; } - ensure("thrown away already: gone for good", !still); + UNSCOPED_INFO("thrown away already: gone for good"); + CHECK_FALSE(still); studio().dropped(theirs_value); bool discarded = false; @@ -429,43 +551,49 @@ namespace tut { discarded |= entry.name == "theirs" && entry.state == Entry::State::Discarded; } - ensure("thrown away", discarded); + UNSCOPED_INFO("thrown away"); + CHECK(discarded); theirs.carriedText.reset(); theirs.loaded = false; r.show(); studio().chosen(studio().candidates.front().value); - ensure("picked, taken up", theirs.carriedText.has_value()); + UNSCOPED_INFO("picked, taken up"); + REQUIRE(theirs.carriedText.has_value()); } - template<> template<> - void alscriptstudiorecovery_object::test<7>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: schedule writes soon after typing began and forgets a clean tab", "[alscriptstudiorecovery]") { - set_test_name("typing is written a moment after it began, whatever is typed meanwhile; a tab gone clean is forgotten at once"); ALScriptStudioRecovery& r = make(); Doc& doc = tab("a", "x\n"); type(doc, "y"); r.schedule(doc); const F64 due = doc.recovery->due; - ensure("due in a moment", due > LLTimer::getTotalSeconds()); + UNSCOPED_INFO("due in a moment"); + CHECK(due > LLTimer::getTotalSeconds()); type(doc, "z"); r.schedule(doc); - ensure("not put off by more typing", doc.recovery->due == due); + UNSCOPED_INFO("not put off by more typing"); + CHECK(doc.recovery->due == due); r.pump(); - ensure("not yet", keptFor(doc.recoveryKey) == 0); + UNSCOPED_INFO("not yet"); + CHECK(keptFor(doc.recoveryKey) == 0); doc.recovery->due = LLTimer::getTotalSeconds() - 1.0; r.pump(); store->flush(); - ensure("written", keptFor(doc.recoveryKey) == 1 && doc.recovery->due == 0.0); + { + INFO("written"); + REQUIRE(keptFor(doc.recoveryKey) == 1); + CHECK(doc.recovery->due == 0.0); + } doc.editor->resetDirty(); r.schedule(doc); - ensure("clean: forgotten at once", keptFor(doc.recoveryKey) == 0); + UNSCOPED_INFO("clean: forgotten at once"); + CHECK(keptFor(doc.recoveryKey) == 0); } - template<> template<> - void alscriptstudiorecovery_object::test<8>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: a closed window's unsaved tab is offered back when its script reopens", "[alscriptstudiorecovery]") { - set_test_name("a tab whose window went with it unsaved is offered back as its script opens again this session, and not while another tab holds it"); ALScriptStudioRecovery& r = make(); const ALScriptRef ref(LLUUID::generateNewID(), LLUUID::generateNewID()); Doc& was = tab("a", "x\n", ref); @@ -477,38 +605,59 @@ namespace tut // Held by a tab on its way here from another window: that tab's. Doc& moving = tab("b", "x\n", ref); r.offerFor(moving, /*held_elsewhere*/ true); - ensure("not offered while another tab holds it", !moving.recoverable && keptFor(was.recoveryKey) == 1); + { + INFO("not offered while another tab holds it"); + REQUIRE_FALSE(moving.recoverable); + CHECK(keptFor(was.recoveryKey) == 1); + } Doc& again = tab("c", "x\n", ref); r.offerFor(again, false); - ensure("offered back", again.recoverable && again.recoverable->text == "x\ntyped"); - ensure("set aside, out of the way", keptFor(again.recoveryKey) == 0); + { + INFO("offered back"); + REQUIRE(again.recoverable); + CHECK(again.recoverable->text == "x\ntyped"); + } + UNSCOPED_INFO("set aside, out of the way"); + CHECK(keptFor(again.recoveryKey) == 0); // Loaded clean, as a tab opened again is: what it keeps of its own // forgets nothing of that. r.keep(again); - ensure("still there to take", std::filesystem::exists(fsyspath(again.recoverable->path))); + UNSCOPED_INFO("still there to take"); + CHECK(std::filesystem::exists(fsyspath(again.recoverable->path))); const Entry offered = *again.recoverable; r.takeUp(again, offered); - ensure_equals("taken up", again.editor->text(), std::string("x\ntyped")); - ensure("its own from here, the set-aside one let go of", keptFor(again.recoveryKey) == 1 && !std::filesystem::exists(fsyspath(offered.path))); + UNSCOPED_INFO("taken up"); + CHECK(again.editor->text() == std::string("x\ntyped")); + { + INFO("its own from here, the set-aside one let go of"); + CHECK(keptFor(again.recoveryKey) == 1); + CHECK_FALSE(std::filesystem::exists(fsyspath(offered.path))); + } } - template<> template<> - void alscriptstudiorecovery_object::test<9>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: keepAll writes each unsaved tab and reports each failure", "[alscriptstudiorecovery]") { - set_test_name("several tabs kept at once, as the viewer going asks: each unsaved text written, the lot waited on once; a clean tab forgets; one that fails is said"); ALScriptStudioRecovery& r = make(); Doc& a = tab("a", "one\n"); Doc& b = tab("b", "two\n"); Doc& clean = tab("c", "three\n"); type(a, "x"); type(b, "y"); - ensure("kept", r.keepAll({ &a, &b, &clean }, Entry::State::Kept)); - ensure("both written", keptFor(a.recoveryKey) == 1 && keptFor(b.recoveryKey) == 1); - ensure("and nothing of the clean one", keptFor(clean.recoveryKey) == 0); + UNSCOPED_INFO("kept"); + CHECK(r.keepAll({ &a, &b, &clean }, Entry::State::Kept)); + { + INFO("both written"); + CHECK(keptFor(a.recoveryKey) == 1); + CHECK(keptFor(b.recoveryKey) == 1); + } + UNSCOPED_INFO("and nothing of the clean one"); + CHECK(keptFor(clean.recoveryKey) == 0); const std::vector all = store->list(); - ensure("kept for next time", std::all_of(all.begin(), all.end(), [](const Entry& one) { return one.state == Entry::State::Kept; })); - ensure("nothing said", services().reports.empty()); + UNSCOPED_INFO("kept for next time"); + CHECK(std::all_of(all.begin(), all.end(), [](const Entry& one) { return one.state == Entry::State::Kept; })); + UNSCOPED_INFO("nothing said"); + REQUIRE(services().reports.empty()); const std::string blocked = folder + "/blocked"; { @@ -519,65 +668,96 @@ namespace tut ALRecovery::useStore(&nowhere); type(a, "z"); type(b, "w"); - ensure("not kept", !r.keepAll({ &a, &b })); - ensure("each said once", services().reports.size() == 2 && a.recovery->failed && b.recovery->failed); + UNSCOPED_INFO("not kept"); + CHECK_FALSE(r.keepAll({ &a, &b })); + { + INFO("each said once"); + REQUIRE(services().reports.size() == 2); + REQUIRE(a.recovery->failed); + CHECK(b.recovery->failed); + } ALRecovery::useStore(store.get()); } - template<> template<> - void alscriptstudiorecovery_object::test<10>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: keep writes again only when the text or its history has moved", "[alscriptstudiorecovery]") { - set_test_name("nothing is written again where neither the text nor its history has moved; a change, or asking for more, writes it"); ALScriptStudioRecovery& r = make(); Doc& a = tab("a", "one\n"); type(a, "x"); - ensure("kept", r.keep(a) && keptFor(a.recoveryKey) == 1); + { + INFO("kept"); + CHECK(r.keep(a)); + CHECK(keptFor(a.recoveryKey) == 1); + } // Taken away behind its back: not written again while nothing moved. for (const Entry& entry : store->list()) { store->remove(entry); } - ensure("kept again, as nothing moved", r.keep(a) && keptFor(a.recoveryKey) == 0); + { + INFO("kept again, as nothing moved"); + CHECK(r.keep(a)); + CHECK(keptFor(a.recoveryKey) == 0); + } r.keepSoon(a); store->flush(); - ensure("nor as typing asks", keptFor(a.recoveryKey) == 0); + UNSCOPED_INFO("nor as typing asks"); + CHECK(keptFor(a.recoveryKey) == 0); a.editor->undoJournal().label("Named"); r.keepSoon(a); store->flush(); - ensure("its history moved: written", keptFor(a.recoveryKey) == 1); + UNSCOPED_INFO("its history moved: written"); + CHECK(keptFor(a.recoveryKey) == 1); for (const Entry& entry : store->list()) { store->remove(entry); } - ensure("kept for next time is more than was asked", r.keep(a, Entry::State::Kept) && keptFor(a.recoveryKey) == 1); + { + INFO("kept for next time is more than was asked"); + CHECK(r.keep(a, Entry::State::Kept)); + CHECK(keptFor(a.recoveryKey) == 1); + } for (const Entry& entry : store->list()) { store->remove(entry); } type(a, "y"); - ensure("typed in: written", r.keep(a) && keptFor(a.recoveryKey) == 1); + { + INFO("typed in: written"); + CHECK(r.keep(a)); + CHECK(keptFor(a.recoveryKey) == 1); + } } - template<> template<> - void alscriptstudiorecovery_object::test<11>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: at login kept entries are offered only while the studio is closed", "[alscriptstudiorecovery]") { - set_test_name("at login: what sessions left unsaved is offered; what was kept on purpose is offered where the studio is not open to have opened it"); make(); ALRecoveryStore earlier(folder, "earlier"); Entry lost = entry("item:lost", "typed, then a crash"); Entry kept = entry("item:kept", "kept for next time"); kept.state = Entry::State::Kept; - ensure("written", earlier.write(lost) && earlier.write(kept)); + { + INFO("written"); + CHECK(earlier.write(lost)); + CHECK(earlier.write(kept)); + } const ALRecovery::Offers closed = ALRecovery::offersAt(*store, false); - ensure("both offered", closed.unsaved.size() == 1 && closed.kept.size() == 1 && closed.kept.front().key == "item:kept"); + { + INFO("both offered"); + REQUIRE(closed.unsaved.size() == 1); + REQUIRE(closed.kept.size() == 1); + CHECK(closed.kept.front().key == "item:kept"); + } const ALRecovery::Offers open = ALRecovery::offersAt(*store, true); - ensure("the kept not, the studio open having opened it", open.unsaved.size() == 1 && open.kept.empty()); + { + INFO("the kept not, the studio open having opened it"); + REQUIRE(open.unsaved.size() == 1); + REQUIRE(open.kept.empty()); + } } - template<> template<> - void alscriptstudiorecovery_object::test<12>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: a picked target and experience are kept and picked again on takeUp", "[alscriptstudiorecovery]") { - set_test_name("a compile target and an experience picked for the next save are kept with the text, keep a tab on their own, and are picked again as it is taken up"); ALScriptStudioRecovery& r = make(); Doc& a = tab("a", "one\n"); const LLUUID experience = LLUUID::generateNewID(); @@ -585,32 +765,54 @@ namespace tut a.targetChosen = true; a.experience = experience; a.experienceChosen = true; - ensure("a pick alone is unsaved, and kept", r.keep(a) && keptFor(a.recoveryKey) == 1); + { + INFO("a pick alone is unsaved, and kept"); + CHECK(r.keep(a)); + CHECK(keptFor(a.recoveryKey) == 1); + } type(a, "x"); const Entry written = ALScriptStudioRecovery::entryOf(a); - ensure("the picks with the entry", written.pickedTarget == std::optional("lsl2") && written.pickedExperience == std::optional(experience)); - ensure("kept", r.keep(a)); + { + INFO("the picks with the entry"); + CHECK(written.pickedTarget == std::optional("lsl2")); + CHECK(written.pickedExperience == std::optional(experience)); + } + UNSCOPED_INFO("kept"); + CHECK(r.keep(a)); std::optional back = store->leftFor(a.recoveryKey); - ensure("not another session's", !back); + UNSCOPED_INFO("not another session's"); + REQUIRE_FALSE(back); const std::vector listed = store->list(); Entry read = listed.front(); - ensure("read whole, the picks with it", store->load(read) && read.pickedTarget == written.pickedTarget && read.pickedExperience == written.pickedExperience); + { + INFO("read whole, the picks with it"); + CHECK(store->load(read)); + CHECK(read.pickedTarget == written.pickedTarget); + CHECK(read.pickedExperience == written.pickedExperience); + } Doc& loaded = tab("b", "one\n", a.ref); r.takeUp(loaded, read); - ensure("picked again over a tab that has loaded", loaded.targetChosen && loaded.language.compileTarget == "lsl2" && loaded.experienceChosen && - loaded.experience == experience); + { + INFO("picked again over a tab that has loaded"); + CHECK(loaded.targetChosen); + CHECK(loaded.language.compileTarget == "lsl2"); + CHECK(loaded.experienceChosen); + CHECK(loaded.experience == experience); + } Doc& loading = tab("c", "one\n"); loading.loaded = false; r.takeUp(loading, read); - ensure("carried to be picked as a tab loading loads", loading.carriedTarget == std::optional("lsl2") && - loading.carriedExperience == std::optional(experience) && !loading.targetChosen); + { + INFO("carried to be picked as a tab loading loads"); + CHECK(loading.carriedTarget == std::optional("lsl2")); + CHECK(loading.carriedExperience == std::optional(experience)); + CHECK_FALSE(loading.targetChosen); + } } - template<> template<> - void alscriptstudiorecovery_object::test<13>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: a notecard window's entry goes back to it unless it cannot take it", "[alscriptstudiorecovery]") { - set_test_name("what the notecard window kept goes back to it, under a key of its own; where it cannot have the notecard, the studio takes it up"); ALScriptStudioRecovery& r = make(); Entry card; card.name = "card"; @@ -619,8 +821,12 @@ namespace tut card.notecard = true; card.text = "kept\n"; card.key = ALRecoveryStore::windowKeyOf(card.object, card.item); - ensure("a key of its own", ALRecoveryStore::isWindowKey(card.key) && card.key != ALRecoveryStore::keyOf(card.object, card.item, std::string()) && - !ALRecoveryStore::isWindowKey(ALRecoveryStore::keyOf(card.object, card.item, std::string()))); + { + INFO("a key of its own"); + CHECK(ALRecoveryStore::isWindowKey(card.key)); + CHECK(card.key != ALRecoveryStore::keyOf(card.object, card.item, std::string())); + CHECK_FALSE(ALRecoveryStore::isWindowKey(ALRecoveryStore::keyOf(card.object, card.item, std::string()))); + } std::vector taken; bool has = true; @@ -630,39 +836,60 @@ namespace tut }); studio().inHand = false; r.recover(card); - ensure("taken up in the window", taken.size() == 1 && studio().orphans.empty() && services().opened.empty()); + { + INFO("taken up in the window"); + REQUIRE(taken.size() == 1); + REQUIRE(studio().orphans.empty()); + REQUIRE(services().opened.empty()); + } // A studio tab's own entry for the same notecard is the studio's. Entry tab = card; tab.key = ALRecoveryStore::keyOf(card.object, card.item, std::string()); r.recover(tab); - ensure("a tab's entry is not the window's", taken.size() == 1 && studio().orphans.size() == 1); + { + INFO("a tab's entry is not the window's"); + REQUIRE(taken.size() == 1); + REQUIRE(studio().orphans.size() == 1); + } has = false; r.recover(card); - ensure("the window cannot have it: the studio keeps it", taken.size() == 2 && studio().orphans.size() == 2); + { + INFO("the window cannot have it: the studio keeps it"); + REQUIRE(taken.size() == 2); + REQUIRE(studio().orphans.size() == 2); + } ALRecovery::takeWindowsTo(nullptr); } - template<> template<> - void alscriptstudiorecovery_object::test<14>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: rekey lets go of the old key's entry and writes under the new one", "[alscriptstudiorecovery]") { - set_test_name("a tab kept under another key from here on: what the old one kept let go of, and written afresh under the new"); ALScriptStudioRecovery& r = make(); Doc& a = tab("a", "one\n"); type(a, "x"); - ensure("kept", r.keep(a) && keptFor(a.recoveryKey) == 1); + { + INFO("kept"); + CHECK(r.keep(a)); + CHECK(keptFor(a.recoveryKey) == 1); + } const std::string was = a.recoveryKey; ALScriptStudioRecovery::rekey(a, ALRecoveryStore::keyOf(LLUUID::null, LLUUID::null, "/somewhere/a.lsl")); store->flush(); - ensure("the old let go of", a.recoveryKey != was && keptFor(was) == 0); - ensure("written afresh, though nothing moved", r.keep(a) && keptFor(a.recoveryKey) == 1); + { + INFO("the old let go of"); + CHECK(a.recoveryKey != was); + CHECK(keptFor(was) == 0); + } + { + INFO("written afresh, though nothing moved"); + CHECK(r.keep(a)); + CHECK(keptFor(a.recoveryKey) == 1); + } } - template<> template<> - void alscriptstudiorecovery_object::test<15>() + TEST_CASE_METHOD(alscriptstudiorecovery_data, "alscriptstudiorecovery: keepSaved records on the writer's thread and moves saves to a new item", "[alscriptstudiorecovery]") { - set_test_name("a save kept in the history on the writer's thread; one given a new item takes the old one's saves with it"); const std::string folder = fsyspath(std::filesystem::temp_directory_path() / fsyspath("alsavehistory_" + LLUUID::generateNewID().asString())).string(); auto history = std::make_shared(folder); @@ -701,10 +928,13 @@ namespace tut ALRecovery::keepSaved(save("task:p:old", "a", 20.0)); ALRecovery::keepSaved(save("task:p:new", "b", 10.0), "task:p:old"); written(); - ensure_equals("kept", history->list("item:x").size(), 1U); - ensure("the old item's moved", history->list("task:p:old").empty()); + UNSCOPED_INFO("kept"); + REQUIRE(history->list("item:x").size() == 1U); + UNSCOPED_INFO("the old item's moved"); + REQUIRE(history->list("task:p:old").empty()); const std::vector moved = history->list("task:p:new"); - ensure_equals("behind the new one's", moved.size(), 2U); + UNSCOPED_INFO("behind the new one's"); + REQUIRE(moved.size() == 2U); ALRecovery::keepSaved(save("", "nobody's", 5.0)); written(); } diff --git a/indra/newview/tests/alscriptstudiosaving_test.cpp b/indra/newview/tests/alscriptstudiosaving_test.cpp index f5948e6d7c..4dc5d114d4 100644 --- a/indra/newview/tests/alscriptstudiosaving_test.cpp +++ b/indra/newview/tests/alscriptstudiosaving_test.cpp @@ -33,7 +33,7 @@ #include "../alscriptstudiofileio.h" #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include #include @@ -176,7 +176,7 @@ namespace } } -namespace tut +namespace { struct alscriptstudiosaving_data { @@ -197,7 +197,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } studio.services = &services; studio.options.program = "Alchemy Test 1.2.3"; @@ -261,55 +261,73 @@ namespace tut std::string lastStatus() const { return services.statuses.empty() ? std::string() : nameOf(services.statuses.back()); } }; - typedef test_group alscriptstudiosaving_group; - typedef alscriptstudiosaving_group::object alscriptstudiosaving_object; - alscriptstudiosaving_group alscriptstudiosaving_instance("alscriptstudiosaving"); - - template<> template<> - void alscriptstudiosaving_object::test<1>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save writes a file or sends a notecard and holds one away or detached", "[alscriptstudiosaving]") { - set_test_name("a save goes as its tab is: a file written, a notecard sent as it stands, one out of reach said, one detached loaded first"); ALScriptStudioSaving& saving = make(); Doc& file = tab("file", "x = 1"); file.file = files->in("x.luau"); saving.save(file); std::string written; - ensure("a file written, nothing sent", files->settled == Names{ "file" } && ALScriptFileIO::readWholeFile(file.file, written) && written == "x = 1" && - studio.sent.empty()); + { + INFO("a file written, nothing sent"); + CHECK(files->settled == Names{ "file" }); + CHECK(ALScriptFileIO::readWholeFile(file.file, written)); + CHECK(written == "x = 1"); + REQUIRE(studio.sent.empty()); + } Doc& card = tab("card", "some words"); card.notecard = true; // Kept against a crash before, which a save lets go of. recovery->store->write(ALScriptStudioRecovery::entryOf(card)); - ensure("kept before", recovery->keptFor(card.recoveryKey) == 1); + UNSCOPED_INFO("kept before"); + CHECK(recovery->keptFor(card.recoveryKey) == 1); saving.save(card); - ensure("a notecard sent as it stands", studio.notecards == Names{ "some words" }); - ensure("and not tidied", studio.tidied.size() == 1); + UNSCOPED_INFO("a notecard sent as it stands"); + CHECK(studio.notecards == Names{ "some words" }); + UNSCOPED_INFO("and not tidied"); + REQUIRE(studio.tidied.size() == 1); CompileResult saved = answer(card); saved.kind = ALScriptKind::Notecard; saving.compiled(saved); - ensure_equals("its answer said", lastSaid(), std::string("SavedNotecard")); - ensure("and kept as saved: what was kept let go of", recovery->keptFor(card.recoveryKey) == 0 && !card.save.underway()); + UNSCOPED_INFO("its answer said"); + CHECK(lastSaid() == std::string("SavedNotecard")); + { + INFO("and kept as saved: what was kept let go of"); + CHECK(recovery->keptFor(card.recoveryKey) == 0); + CHECK_FALSE(card.save.underway()); + } Doc& away = tab("away", "default {}"); away.orphan->kind = Doc::Orphan::Away; services.front = 2; saving.save(away); - ensure_equals("out of reach, said where", lastStatus(), std::string("SaveBlockedAway")); - ensure("stopped, and the notice back", studio.stops == 1 && studio.notices == 1 && !away.save.underway() && studio.sent.empty()); + UNSCOPED_INFO("out of reach, said where"); + CHECK(lastStatus() == std::string("SaveBlockedAway")); + { + INFO("stopped, and the notice back"); + CHECK(studio.stops == 1); + CHECK(studio.notices == 1); + CHECK_FALSE(away.save.underway()); + REQUIRE(studio.sent.empty()); + } Doc& detached = tab("detached", "default {}"); detached.orphan->detached = true; saving.save(detached); - ensure("loaded under its item first", orphans->loads.size() == 1 && orphans->loads[0] == detached.ref && studio.sent.empty()); - ensure_equals("and said to wait", lastStatus(), std::string("SaveWaitsForLoad")); + { + INFO("loaded under its item first"); + REQUIRE(orphans->loads.size() == 1); + CHECK(orphans->loads[0] == detached.ref); + REQUIRE(studio.sent.empty()); + } + UNSCOPED_INFO("and said to wait"); + CHECK(lastStatus() == std::string("SaveWaitsForLoad")); } - template<> template<> - void alscriptstudiosaving_object::test<2>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save is tidied first with fixes only over the text last checked", "[alscriptstudiosaving]") { - set_test_name("tidied first as the settings say: the safe fixes only over the text last checked, and once a save however many checks it waits on"); ALScriptStudioSaving& saving = make(); studio.options.fix = true; studio.options.format = true; @@ -318,63 +336,97 @@ namespace tut Doc& unchecked = tab("unchecked", "default {}"); saving.save(unchecked); - ensure_equals("no fixes over a text not checked", studio.tidied.back(), std::string("mt")); + UNSCOPED_INFO("no fixes over a text not checked"); + CHECK(studio.tidied.back() == std::string("mt")); Doc& doc = tab("a", "default {}"); checked(doc); saving.save(doc); - ensure_equals("the fixes, over the text checked", studio.tidied.back(), std::string("fmt")); + UNSCOPED_INFO("the fixes, over the text checked"); + CHECK(studio.tidied.back() == std::string("fmt")); // They changed the text: checked again before it goes. - ensure("checked again", studio.analysed.back() == "a" && studio.sent.empty()); + { + INFO("checked again"); + CHECK(studio.analysed.back() == "a"); + REQUIRE(studio.sent.empty()); + } checked(doc); - ensure("the check waited on", doc.save.checked()); + UNSCOPED_INFO("the check waited on"); + CHECK(doc.save.checked()); saving.save(doc); - ensure_equals("not fixed twice", studio.tidied.back(), std::string("mt")); - ensure("sent", studio.sent.size() == 1 && studio.sent.back().doc == "a"); + UNSCOPED_INFO("not fixed twice"); + CHECK(studio.tidied.back() == std::string("mt")); + { + INFO("sent"); + REQUIRE(studio.sent.size() == 1); + CHECK(studio.sent.back().doc == "a"); + } } - template<> template<> - void alscriptstudiosaving_object::test<3>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save held on the analyzers stops at their errors until asked again", "[alscriptstudiosaving]") { - set_test_name("held on the analyzers: checked first, their errors stopping it with Save Anyway and the first in sight; asked again, past them, the offer answered"); ALScriptStudioSaving& saving = make(); studio.options.holdOnErrors = true; Doc& doc = tab("a", "default {}"); saving.save(doc); - ensure("checked first", studio.analysed == Names{ "a" } && studio.sent.empty()); - ensure_equals("and said so", lastStatus(), std::string("Preflight")); + { + INFO("checked first"); + CHECK(studio.analysed == Names{ "a" }); + REQUIRE(studio.sent.empty()); + } + UNSCOPED_INFO("and said so"); + CHECK(lastStatus() == std::string("Preflight")); checked(doc, { anError() }); - ensure("the check waited on", doc.save.checked()); + UNSCOPED_INFO("the check waited on"); + CHECK(doc.save.checked()); saving.save(doc); - ensure_equals("its errors stop it", lastSaid(), std::string("PreflightErrors")); + UNSCOPED_INFO("its errors stop it"); + CHECK(lastSaid() == std::string("PreflightErrors")); const al_studio_test::FakeServices::Said& said = services.reports.back(); - ensure("a failure, of the tab, with Save Anyway", said.failure && said.doc == "a" && said.actions == Names{ "save_anyway" }); - ensure("the first of the checkers' errors in sight", studio.problemsShown == 1 && studio.firstErrors == std::vector{ true }); - ensure("stopped", studio.stops == 1 && studio.sent.empty() && !doc.save.underway()); + { + INFO("a failure, of the tab, with Save Anyway"); + CHECK(said.failure); + CHECK(said.doc == "a"); + CHECK(said.actions == Names{ "save_anyway" }); + } + { + INFO("the first of the checkers' errors in sight"); + CHECK(studio.problemsShown == 1); + CHECK(studio.firstErrors == std::vector{ true }); + } + { + INFO("stopped"); + CHECK(studio.stops == 1); + REQUIRE(studio.sent.empty()); + CHECK_FALSE(doc.save.underway()); + } doc.offer = Doc::Offer{ "held", { "save_anyway" } }; saving.saveAsked(doc); - ensure("asked again over the same text: past them", studio.sent.size() == 1); - ensure("what was offered answered", !doc.offer); + UNSCOPED_INFO("asked again over the same text: past them"); + REQUIRE(studio.sent.size() == 1); + UNSCOPED_INFO("what was offered answered"); + REQUIRE_FALSE(doc.offer); doc.offer = Doc::Offer{ "saved elsewhere", { "take_saved", "keep_saved", "compare_saved" } }; saving.save(doc); - ensure("a conflict's offer stays", doc.offer.has_value()); + UNSCOPED_INFO("a conflict's offer stays"); + REQUIRE(doc.offer.has_value()); // Not held, the errors go with the text, said. studio.options.holdOnErrors = false; Doc& free = tab("free", "default {}"); checked(free, { anError() }); saving.save(free); - ensure("sent", studio.sent.size() == 2); - ensure_equals("with its errors said", lastSaid(), std::string("SentWithErrors")); + UNSCOPED_INFO("sent"); + REQUIRE(studio.sent.size() == 2); + UNSCOPED_INFO("with its errors said"); + CHECK(lastSaid() == std::string("SentWithErrors")); } - template<> template<> - void alscriptstudiosaving_object::test<4>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save sends the tab's own options and stops when too large or refused", "[alscriptstudiosaving]") { - set_test_name("sent as the tab's own -- its target, whether it runs, its experience -- marked saved as it went; too large or refused, said and stopped"); ALScriptStudioSaving& saving = make(); Doc& doc = tab("a", "default {}"); @@ -386,28 +438,45 @@ namespace tut doc.experienceChosen = true; type(doc, "\n// more"); saving.save(doc); - ensure_equals("one sent", studio.sent.size(), size_t(1)); + UNSCOPED_INFO("one sent"); + REQUIRE(studio.sent.size() == size_t(1)); const FakeSavingWindow::Sent& sent = studio.sent.back(); - ensure_equals("the text as it stands", sent.text, std::string("default {}\n// more")); - ensure("its target, not running, its experience", - sent.options.compileTarget == "mono" && sent.options.running == false && sent.options.experience == experience); - ensure("on its way", doc.save.sending()); - ensure_equals("said", lastStatus(), std::string("Saving")); + UNSCOPED_INFO("the text as it stands"); + CHECK(sent.text == std::string("default {}\n// more")); + { + INFO("its target, not running, its experience"); + CHECK(sent.options.compileTarget == "mono"); + CHECK(sent.options.running == false); + CHECK(sent.options.experience == experience); + } + UNSCOPED_INFO("on its way"); + CHECK(doc.save.sending()); + UNSCOPED_INFO("said"); + CHECK(lastStatus() == std::string("Saving")); // Typed while it was on its way: that is still to be saved. type(doc, "\n// later"); saving.compiled(answer(doc)); - ensure_equals("compiled", lastSaid(), std::string("Compiled")); - ensure("what was typed since still unsaved", doc.editor->isDirty()); - ensure("the experience it went with is the one it runs under", !doc.experienceChosen && doc.experienceKnown); - ensure("kept for recovery as it is now", recovery->keptFor(doc.recoveryKey) == 1); + UNSCOPED_INFO("compiled"); + CHECK(lastSaid() == std::string("Compiled")); + UNSCOPED_INFO("what was typed since still unsaved"); + CHECK(doc.editor->isDirty()); + { + INFO("the experience it went with is the one it runs under"); + CHECK_FALSE(doc.experienceChosen); + CHECK(doc.experienceKnown); + } + UNSCOPED_INFO("kept for recovery as it is now"); + CHECK(recovery->keptFor(doc.recoveryKey) == 1); Doc& clean = tab("clean", "default {}"); type(clean, " "); saving.save(clean); - ensure("whether it runs not heard yet: not said, for the save to ask", !studio.sent.back().options.running.has_value()); + UNSCOPED_INFO("whether it runs not heard yet: not said, for the save to ask"); + REQUIRE_FALSE(studio.sent.back().options.running.has_value()); saving.compiled(answer(clean)); - ensure("nothing typed since: saved", !clean.unsaved()); + UNSCOPED_INFO("nothing typed since: saved"); + CHECK_FALSE(clean.unsaved()); std::string too_much; while (too_much.size() <= ALScriptEnvelope::MAX_ASSET_BYTES) @@ -416,71 +485,110 @@ namespace tut } Doc& big = tab("big", too_much); saving.save(big); - ensure_equals("too large: said", lastSaid(), std::string("SaveTooLarge")); - ensure("with what would shrink it", services.reports.back().text.find("SaveTooLargePlain") != std::string::npos); - ensure("its size kept, nothing sent, stopped", - big.weighing->assetBytes == too_much.size() && studio.sent.size() == 2 && !big.save.underway() && studio.stops == 1); + UNSCOPED_INFO("too large: said"); + CHECK(lastSaid() == std::string("SaveTooLarge")); + UNSCOPED_INFO("with what would shrink it"); + REQUIRE(services.reports.back().text.find("SaveTooLargePlain") != std::string::npos); + { + INFO("its size kept, nothing sent, stopped"); + REQUIRE(big.weighing->assetBytes == too_much.size()); + REQUIRE(studio.sent.size() == 2); + CHECK_FALSE(big.save.underway()); + CHECK(studio.stops == 1); + } studio.refuse = "no region"; Doc& refused = tab("refused", "default {}"); saving.save(refused); - ensure_equals("refused: said", lastSaid(), std::string("SaveFailed")); - ensure("with what may be done", services.reports.back().actions == Names{ "retry", "copy", "export" }); - ensure("stopped", !refused.save.underway() && studio.stops == 2); + UNSCOPED_INFO("refused: said"); + CHECK(lastSaid() == std::string("SaveFailed")); + UNSCOPED_INFO("with what may be done"); + CHECK(services.reports.back().actions == Names{ "retry", "copy", "export" }); + { + INFO("stopped"); + CHECK_FALSE(refused.save.underway()); + CHECK(studio.stops == 2); + } } - template<> template<> - void alscriptstudiosaving_object::test<5>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a preprocessed save goes with its errors and what it made enveloped", "[alscriptstudiosaving]") { - set_test_name("preprocessed first: sent with its errors said, what it made in the envelope with its map, and a text moved on is run again"); ALScriptStudioSaving& saving = make(); studio.preprocessor = true; Doc& doc = tab("a", "#include \"x.lsl\"\ndefault {}"); saving.save(doc); - ensure("run first", studio.runs == Names{ "a" } && studio.sent.empty() && doc.preprocessing); + { + INFO("run first"); + CHECK(studio.runs == Names{ "a" }); + REQUIRE(studio.sent.empty()); + CHECK(doc.preprocessing); + } // Its errors do not stop it: the save is what keeps the work. ALPreprocessor::Result wrong; wrong.text = "default {"; wrong.problems.push_back(anError()); studio.answerRun(wrong); - ensure("what waited on the map it made told", studio.known == Names{ "a" }); - ensure_equals("sent all the same", studio.sent.size(), size_t(1)); - ensure_equals("said as it went", lastSaid(), std::string("SavingWithErrors")); - ensure("a failure of the tab, nothing to press", services.reports.back().failure && services.reports.back().actions.empty()); - ensure("not stopped, the problems in sight", doc.save.underway() && studio.stops == 0 && studio.problemsShown == 1); + UNSCOPED_INFO("what waited on the map it made told"); + CHECK(studio.known == Names{ "a" }); + UNSCOPED_INFO("sent all the same"); + REQUIRE(studio.sent.size() == size_t(1)); + UNSCOPED_INFO("said as it went"); + CHECK(lastSaid() == std::string("SavingWithErrors")); + { + INFO("a failure of the tab, nothing to press"); + CHECK(services.reports.back().failure); + REQUIRE(services.reports.back().actions.empty()); + } + { + INFO("not stopped, the problems in sight"); + CHECK(doc.save.underway()); + CHECK(studio.stops == 0); + CHECK(studio.problemsShown == 1); + } saving.compiled(answer(doc)); type(doc, " "); saving.save(doc); - ensure("run again", studio.runs.size() == 2); + UNSCOPED_INFO("run again"); + REQUIRE(studio.runs.size() == 2); ALPreprocessor::Result made; made.text = "default { state_entry() {} }"; studio.answerRun(made); - ensure_equals("sent", studio.sent.size(), size_t(2)); + UNSCOPED_INFO("sent"); + REQUIRE(studio.sent.size() == size_t(2)); const std::optional envelope = ALScriptEnvelope::parse(studio.sent.back().text); - ensure("in the envelope", envelope.has_value()); - ensure_equals("what it made", envelope->expanded, made.text); - ensure_equals("by this viewer", envelope->programVersion, studio.options.program); - ensure("with its map, for the compiler's lines", doc.save.sentMap().has_value()); - ensure("weighed as each went", std::count(weighing->weighs.begin(), weighing->weighs.end(), "sent") == 2); + UNSCOPED_INFO("in the envelope"); + REQUIRE(envelope.has_value()); + UNSCOPED_INFO("what it made"); + CHECK(envelope->expanded == made.text); + UNSCOPED_INFO("by this viewer"); + CHECK(envelope->programVersion == studio.options.program); + UNSCOPED_INFO("with its map, for the compiler's lines"); + REQUIRE(doc.save.sentMap().has_value()); + UNSCOPED_INFO("weighed as each went"); + CHECK(std::count(weighing->weighs.begin(), weighing->weighs.end(), "sent") == 2); saving.compiled(answer(doc)); // The text moved on while the includes came: checked, and run again. type(doc, "\n// a"); saving.save(doc); - ensure("run", studio.runs.size() == 3); + UNSCOPED_INFO("run"); + REQUIRE(studio.runs.size() == 3); type(doc, "\n// b"); studio.answerRun(made); - ensure("checked again", studio.analysed.back() == "a"); - ensure("and run again, nothing sent", studio.runs.size() == 4 && studio.sent.size() == 2); + UNSCOPED_INFO("checked again"); + CHECK(studio.analysed.back() == "a"); + { + INFO("and run again, nothing sent"); + REQUIRE(studio.runs.size() == 4); + REQUIRE(studio.sent.size() == 2); + } } - template<> template<> - void alscriptstudiosaving_object::test<6>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: the compiler's answer keeps its errors and sends a save asked meanwhile", "[alscriptstudiosaving]") { - set_test_name("the compiler's answer: its errors kept and in sight, a save asked meanwhile sent after it, and a tab saved to close let go of"); ALScriptStudioSaving& saving = make(); Doc& doc = tab("a", "default {}"); @@ -494,27 +602,53 @@ namespace tut diagnostic.message = "syntax error"; failed.diagnostics.push_back(diagnostic); saving.compiled(failed); - ensure_equals("said", lastSaid(), std::string("CompileFailed")); - ensure("kept", doc.problems.size() == 1 && doc.problems[0].line == 3 && doc.problems[0].message == "syntax error"); - ensure("in sight, its first error chosen", studio.problemsShown == 1 && studio.firstErrors == std::vector{ false }); - ensure("a close waiting on it stopped", studio.stops == 1); + UNSCOPED_INFO("said"); + CHECK(lastSaid() == std::string("CompileFailed")); + { + INFO("kept"); + REQUIRE(doc.problems.size() == 1); + CHECK(doc.problems[0].line == 3); + CHECK(doc.problems[0].message == "syntax error"); + } + { + INFO("in sight, its first error chosen"); + CHECK(studio.problemsShown == 1); + CHECK(studio.firstErrors == std::vector{ false }); + } + UNSCOPED_INFO("a close waiting on it stopped"); + CHECK(studio.stops == 1); type(doc, " "); saving.save(doc); type(doc, " "); saving.save(doc); - ensure_equals("one on its way at a time", studio.sent.size(), size_t(2)); + UNSCOPED_INFO("one on its way at a time"); + REQUIRE(studio.sent.size() == size_t(2)); saving.compiled(answer(doc)); - ensure("the one asked meanwhile sent after it", studio.sent.size() == 3 && doc.save.sending()); - ensure("what the last said gone with it", doc.problems.empty()); + { + INFO("the one asked meanwhile sent after it"); + REQUIRE(studio.sent.size() == 3); + CHECK(doc.save.sending()); + } + UNSCOPED_INFO("what the last said gone with it"); + REQUIRE(doc.problems.empty()); saving.compiled(answer(doc)); type(doc, " "); saving.saveToClose("a"); - ensure("sent to close", studio.sent.size() == 4 && doc.save.closeAfter()); + { + INFO("sent to close"); + REQUIRE(studio.sent.size() == 4); + CHECK(doc.save.closeAfter()); + } saving.compiled(answer(doc)); - ensure("let go of", studio.closed == Names{ "a" } && !services.findDoc(std::string_view("a"))); - ensure("and a window closing gone on with", studio.continues == 1); + { + INFO("let go of"); + CHECK(studio.closed == Names{ "a" }); + REQUIRE_FALSE(services.findDoc(std::string_view("a"))); + } + UNSCOPED_INFO("and a window closing gone on with"); + CHECK(studio.continues == 1); Doc& card = tab("card", "some words"); card.notecard = true; @@ -523,19 +657,26 @@ namespace tut CompileResult saved = answer(card); saved.kind = ALScriptKind::Notecard; saving.compiled(saved); - ensure("a notecard the same", studio.closed == Names{ "a", "card" } && studio.continues == 2); + { + INFO("a notecard the same"); + CHECK(studio.closed == Names{ "a", "card" }); + CHECK(studio.continues == 2); + } Doc& loading = tab("loading", ""); loading.loaded = false; saving.saveToClose("loading"); - ensure("one that cannot begin is left as it was", services.findDoc(std::string_view("loading")) && !loading.save.closeAfter()); - ensure("and a close waiting on it stops", studio.stops == 2); + { + INFO("one that cannot begin is left as it was"); + REQUIRE(services.findDoc(std::string_view("loading"))); + CHECK_FALSE(loading.save.closeAfter()); + } + UNSCOPED_INFO("and a close waiting on it stops"); + CHECK(studio.stops == 2); } - template<> template<> - void alscriptstudiosaving_object::test<7>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a copy saved closes its original unless that was typed in since", "[alscriptstudiosaving]") { - set_test_name("a copy saved closes the tab it was made of, unless that was typed in since"); ALScriptStudioSaving& saving = make(); Doc& original = tab("original", "default {}"); @@ -545,9 +686,12 @@ namespace tut type(copy, " "); saving.save(copy); saving.compiled(answer(copy)); - ensure("the original let go of", studio.closed == Names{ "original" }); - ensure_equals("said", lastSaid(), std::string("CopiedTo")); - ensure("the copy is no copy now", copy.copyOf.empty()); + UNSCOPED_INFO("the original let go of"); + CHECK(studio.closed == Names{ "original" }); + UNSCOPED_INFO("said"); + CHECK(lastSaid() == std::string("CopiedTo")); + UNSCOPED_INFO("the copy is no copy now"); + REQUIRE(copy.copyOf.empty()); Doc& typed = tab("typed", "default {}"); Doc& other = tab("other", "default {}"); @@ -557,21 +701,26 @@ namespace tut type(other, " "); saving.save(other); saving.compiled(answer(other)); - ensure("typed in since: kept open", studio.closed.size() == 1 && services.findDoc(std::string_view("typed"))); - ensure_equals("and said so", lastSaid(), std::string("CopiedToKeptOpen")); - ensure_equals("of it", services.reports.back().doc, std::string("typed")); + { + INFO("typed in since: kept open"); + REQUIRE(studio.closed.size() == 1); + REQUIRE(services.findDoc(std::string_view("typed"))); + } + UNSCOPED_INFO("and said so"); + CHECK(lastSaid() == std::string("CopiedToKeptOpen")); + UNSCOPED_INFO("of it"); + CHECK(services.reports.back().doc == std::string("typed")); } - template<> template<> - void alscriptstudiosaving_object::test<8>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save over its target's limit is said once and an estimate as one", "[alscriptstudiosaving]") { - set_test_name("what a save sends weighed as it goes, and over its target's limit said once, where the weight is exact; an estimate's said as one"); ALScriptStudioSaving& saving = make(); Doc& doc = tab("a", "default {}"); type(doc, " "); saving.save(doc); - ensure("weighed", weighing->weighs == Names{ "text" }); + UNSCOPED_INFO("weighed"); + CHECK(weighing->weighs == Names{ "text" }); ALScriptWeight weight; weight.target = ALScriptWeight::Target::Mono; weight.total = 70000; @@ -580,11 +729,14 @@ namespace tut doc.weighing->version = doc.editor->document().version(); doc.weighing->exact = true; saving.warnOverWeight(doc); - ensure_equals("over: said", lastSaid(), std::string("SaveOverWeight")); - ensure("as a failure", services.reports.back().failure); + UNSCOPED_INFO("over: said"); + CHECK(lastSaid() == std::string("SaveOverWeight")); + UNSCOPED_INFO("as a failure"); + CHECK(services.reports.back().failure); const size_t said = services.reports.size(); saving.warnOverWeight(doc); - ensure("once", services.reports.size() == said); + UNSCOPED_INFO("once"); + REQUIRE(services.reports.size() == said); Doc& guessed = tab("guessed", "default {}"); type(guessed, " "); @@ -594,37 +746,39 @@ namespace tut guessed.weighing->version = guessed.editor->document().version(); guessed.weighing->exact = true; saving.warnOverWeight(guessed); - ensure_equals("an estimate said as one", lastSaid(), std::string("SaveOverWeightEstimate")); - ensure("once too", services.reports.size() == said + 1); + UNSCOPED_INFO("an estimate said as one"); + CHECK(lastSaid() == std::string("SaveOverWeightEstimate")); + UNSCOPED_INFO("once too"); + REQUIRE(services.reports.size() == said + 1); saving.warnOverWeight(guessed); - ensure("and only once", services.reports.size() == said + 1); + UNSCOPED_INFO("and only once"); + REQUIRE(services.reports.size() == said + 1); } - template<> template<> - void alscriptstudiosaving_object::test<9>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save the external editor made is not tidied but one made here after is", "[alscriptstudiosaving]") { - set_test_name("a save the external editor made is not tidied, and one made here after it is"); ALScriptStudioSaving& saving = make(); studio.options.format = true; studio.options.trim = true; Doc& doc = tab("a", "default {}"); doc.save.fromExternal(doc.editor->document().version()); saving.save(doc); - ensure("not tidied", studio.tidied.empty()); - ensure("sent as it came", studio.sent.size() == 1); + UNSCOPED_INFO("not tidied"); + REQUIRE(studio.tidied.empty()); + UNSCOPED_INFO("sent as it came"); + REQUIRE(studio.sent.size() == 1); saving.compiled(answer(doc)); // Ended as the answer ends it where the editor is watched. doc.save.endExternal(); doc.editor->setCaret(doc.editor->document().end()); doc.editor->insertText(" "); saving.save(doc); - ensure_equals("tidied, made here", studio.tidied.size(), size_t(1)); + UNSCOPED_INFO("tidied, made here"); + REQUIRE(studio.tidied.size() == size_t(1)); } - template<> template<> - void alscriptstudiosaving_object::test<10>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a wrapped script offers a compiled half its source cannot have made", "[alscriptstudiosaving]") { - set_test_name("a wrapped script's first run as it loaded held up to its compiled half: offered where the source could not have made it"); ALScriptStudioSaving& saving = make(); studio.preprocessor = true; const std::string source = "default { state_entry() { llSay(0, \"hi\"); } }"; @@ -649,40 +803,50 @@ namespace tut Doc& here = loaded("here", edited, "Alchemy Release 7.2.0"); ran(here); - ensure("ours, edited outside: offered", here.compiledDiffers && *here.compiledDiffers == edited && !here.compareCompiledAt); + { + INFO("ours, edited outside: offered"); + REQUIRE(here.compiledDiffers); + CHECK(*here.compiledDiffers == edited); + REQUIRE_FALSE(here.compareCompiledAt); + } Doc& same = loaded("same", "default{state_entry(){llSay(0,\"hi\");}}", "Alchemy Release 7.2.0"); ran(same); - ensure("what the source makes, spaced otherwise: nothing", !same.compiledDiffers); + UNSCOPED_INFO("what the source makes, spaced otherwise: nothing"); + REQUIRE_FALSE(same.compiledDiffers); Doc& firestorm = loaded("fs", edited, "Firestorm-Releasex64 7.1.11.76496"); ran(firestorm); - ensure("Firestorm's, untransformed: told", firestorm.compiledDiffers.has_value()); + UNSCOPED_INFO("Firestorm's, untransformed: told"); + REQUIRE(firestorm.compiledDiffers.has_value()); Doc& switched = loaded("sw", edited, "Firestorm-Releasex64 7.1.11.76496"); ran(switched, true); - ensure("Firestorm's, with a transform whose names ours need not share: not told", !switched.compiledDiffers); + UNSCOPED_INFO("Firestorm's, with a transform whose names ours need not share: not told"); + REQUIRE_FALSE(switched.compiledDiffers); Doc& typed = loaded("typed", edited, "Alchemy Release 7.2.0"); type(typed, " "); ran(typed); - ensure("typed in before the run: not the text as it came", !typed.compiledDiffers && !typed.compareCompiledAt); + { + INFO("typed in before the run: not the text as it came"); + REQUIRE_FALSE(typed.compiledDiffers); + REQUIRE_FALSE(typed.compareCompiledAt); + } } - template<> template<> - void alscriptstudiosaving_object::test<11>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a tidy is one step to undo however many of its parts changed the text", "[alscriptstudiosaving]") { - set_test_name("tidied as one step to undo, however many of its parts changed the text"); ALScriptStudioSaving& saving = make(); studio.options.format = true; studio.options.trim = true; studio.changes = true; Doc& doc = tab("a", "default {}"); saving.save(doc); - ensure_equals("each part changed it", doc.editor->text(), std::string("mdefault {}t")); + UNSCOPED_INFO("each part changed it"); + CHECK(doc.editor->text() == std::string("mdefault {}t")); doc.editor->undo(); - ensure_equals("one Undo takes back all of it", doc.editor->text(), std::string("default {}")); + UNSCOPED_INFO("one Undo takes back all of it"); + CHECK(doc.editor->text() == std::string("default {}")); } - template<> template<> - void alscriptstudiosaving_object::test<12>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save goes up without includes missing or pending and names them", "[alscriptstudiosaving]") { - set_test_name("a save goes up without an include not found, or one that never came, saying so by name with the disk's route, and with the other errors said"); ALScriptStudioSaving& saving = make(); studio.preprocessor = true; @@ -698,14 +862,23 @@ namespace tut nowhere.args = { "x.lsl" }; wrong.problems = { missing, nowhere, anError() }; studio.answerRun(wrong); - ensure_equals("sent: the save keeps the work", studio.sent.size(), size_t(1)); + UNSCOPED_INFO("sent: the save keeps the work"); + REQUIRE(studio.sent.size() == size_t(1)); const auto going = std::find_if(services.reports.begin(), services.reports.end(), [](const al_studio_test::FakeServices::Said& s) { return alscriptstudiosaving_data::nameOf(s.text) == "SavingWithout"; }); - ensure("said as it went, by name, a failure of the tab", - going != services.reports.end() && going->text.find("[FILES]=lib.lsl, x.lsl") != std::string::npos && going->failure && going->doc == "a"); - ensure("with where includes come from", going->text.find("PreprocessMissingDiskRoute") != std::string::npos); - ensure_equals("and the error besides them", lastSaid(), std::string("SavingWithErrors")); - ensure("counted without them", services.reports.back().text.find("[COUNT]=1") != std::string::npos); + { + INFO("said as it went, by name, a failure of the tab"); + REQUIRE(going != services.reports.end()); + REQUIRE(going->text.find("[FILES]=lib.lsl, x.lsl") != std::string::npos); + REQUIRE(going->failure); + CHECK(going->doc == "a"); + } + UNSCOPED_INFO("with where includes come from"); + REQUIRE(going->text.find("PreprocessMissingDiskRoute") != std::string::npos); + UNSCOPED_INFO("and the error besides them"); + CHECK(lastSaid() == std::string("SavingWithErrors")); + UNSCOPED_INFO("counted without them"); + REQUIRE(services.reports.back().text.find("[COUNT]=1") != std::string::npos); saving.compiled(answer(doc)); // Only the other errors: those said. @@ -715,7 +888,11 @@ namespace tut plain.text = "default {}"; plain.problems = { anError() }; studio.answerRun(plain); - ensure("sent, its errors said", studio.sent.size() == 2 && lastSaid() == "SavingWithErrors"); + { + INFO("sent, its errors said"); + REQUIRE(studio.sent.size() == 2); + CHECK(lastSaid() == "SavingWithErrors"); + } saving.compiled(answer(doc)); // One that never came: sent without it, and said. @@ -725,38 +902,49 @@ namespace tut waiting.text = "default {}"; waiting.pending = { "far.lsl" }; studio.answerRun(waiting); - ensure_equals("sent without it", studio.sent.size(), size_t(3)); - ensure("and said so", services.reports.back().text.find("SavingWithout") == 0 && - services.reports.back().text.find("[FILES]=far.lsl") != std::string::npos); + UNSCOPED_INFO("sent without it"); + REQUIRE(studio.sent.size() == size_t(3)); + { + INFO("and said so"); + CHECK(services.reports.back().text.find("SavingWithout") == 0); + REQUIRE(services.reports.back().text.find("[FILES]=far.lsl") != std::string::npos); + } } - template<> template<> - void alscriptstudiosaving_object::test<13>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a tab sending takes only its own save's answer and not a recompile's", "[alscriptstudiosaving]") { - set_test_name("a tab sending takes only its own save's answer: another's for the same script, a recompile's, does not land as its own"); ALScriptStudioSaving& saving = make(); Doc& doc = tab("a", "default {}"); type(doc, "\n// mine"); saving.save(doc); - ensure("on its way", doc.save.sending()); + UNSCOPED_INFO("on its way"); + CHECK(doc.save.sending()); const U64 mine = studio.sent.back().options.sender.request; - ensure("sent as a request of the studio's", mine != 0 && studio.sent.back().options.sender.origin == ALScriptOrigin::Studio); + { + INFO("sent as a request of the studio's"); + CHECK(mine != 0); + CHECK(studio.sent.back().options.sender.origin == ALScriptOrigin::Studio); + } // A recompile from the explorer answers first, for the same script. CompileResult other = answer(doc); other.sender = ALScriptSender(ALScriptOrigin::Recompile, mine + 100); saving.compiled(other); - ensure("still on its way", doc.save.sending()); - ensure("not marked saved by another's answer", doc.editor->isDirty()); + UNSCOPED_INFO("still on its way"); + CHECK(doc.save.sending()); + UNSCOPED_INFO("not marked saved by another's answer"); + CHECK(doc.editor->isDirty()); saving.compiled(answer(doc)); - ensure("its own lands", !doc.save.sending() && !doc.editor->isDirty()); + { + INFO("its own lands"); + REQUIRE_FALSE(doc.save.sending()); + CHECK_FALSE(doc.editor->isDirty()); + } } - template<> template<> - void alscriptstudiosaving_object::test<14>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save from elsewhere is taken in or asked about or let be", "[alscriptstudiosaving]") { - set_test_name("a save from elsewhere: taken in by a tab with nothing typed, asked about by one with changes, let be where it saved what the tab last had"); ALScriptStudioSaving& saving = make(); const auto saved = [](const Doc& doc, const std::string& text, ALScriptOrigin origin, U64 request = 0) { ALScriptSaved one; @@ -770,25 +958,42 @@ namespace tut // Nothing typed here: taken in as loaded. Doc& clean = tab("clean", "default {}"); saving.savedElsewhere(saved(clean, "default { touch_start(integer n) {} }", ALScriptOrigin::Bridge)); - ensure("taken in", studio.loadedAgain == Names{ "clean:default { touch_start(integer n) {} }" }); + UNSCOPED_INFO("taken in"); + CHECK(studio.loadedAgain == Names{ "clean:default { touch_start(integer n) {} }" }); // Changed here and there: asked, and nothing taken yet. Doc& dirty = tab("dirty", "default {}"); type(dirty, "\n// mine"); saving.savedElsewhere(saved(dirty, "default {}\n// theirs", ALScriptOrigin::Bridge)); - ensure_equals("asked whose to keep", lastSaid(), std::string("SavedElsewhereConflict")); - ensure("with the four answers", services.reports.back().actions == Names{ "take_saved", "keep_saved", "merge_saved", "compare_saved" }); - ensure("nothing taken yet", dirty.editor->wholeText() == "default {}\n// mine" && dirty.savedThere); + UNSCOPED_INFO("asked whose to keep"); + CHECK(lastSaid() == std::string("SavedElsewhereConflict")); + UNSCOPED_INFO("with the four answers"); + CHECK(services.reports.back().actions == Names{ "take_saved", "keep_saved", "merge_saved", "compare_saved" }); + { + INFO("nothing taken yet"); + CHECK(dirty.editor->wholeText() == "default {}\n// mine"); + REQUIRE(dirty.savedThere); + } saving.takeSaved(dirty); - ensure("theirs taken, and nothing to save", dirty.editor->wholeText() == "default {}\n// theirs" && !dirty.editor->isDirty()); - ensure("asked no more", !dirty.savedThere); + { + INFO("theirs taken, and nothing to save"); + REQUIRE(dirty.editor->wholeText() == "default {}\n// theirs"); + CHECK_FALSE(dirty.editor->isDirty()); + } + UNSCOPED_INFO("asked no more"); + REQUIRE_FALSE(dirty.savedThere); // A recompile of what the tab last had: nothing changes, nothing asked. Doc& kept = tab("kept", "default {}"); type(kept, "\n// typing"); const size_t said = services.reports.size(); saving.savedElsewhere(saved(kept, "default {}", ALScriptOrigin::Recompile)); - ensure("not asked", services.reports.size() == said && !kept.savedThere && kept.editor->isDirty()); + { + INFO("not asked"); + REQUIRE(services.reports.size() == said); + REQUIRE_FALSE(kept.savedThere); + CHECK(kept.editor->isDirty()); + } // In its envelope: read by its source; what went up is what is here. ALScriptEnvelope envelope; @@ -796,7 +1001,11 @@ namespace tut envelope.expanded = "default {}"; envelope.compileTarget = "mono"; saving.savedElsewhere(saved(kept, envelope.wrap(), ALScriptOrigin::Bridge)); - ensure("the same as here: saved", !kept.editor->isDirty() && services.reports.size() == said); + { + INFO("the same as here: saved"); + CHECK_FALSE(kept.editor->isDirty()); + REQUIRE(services.reports.size() == said); + } // Its own save lands as its answer, not as a save from elsewhere. Doc& own = tab("own", "default {}"); @@ -804,26 +1013,35 @@ namespace tut saving.save(own); ALScriptSaved mine = saved(own, "something else", ALScriptOrigin::Studio, own.save.request()); saving.savedElsewhere(mine); - ensure("its own let be", !own.savedThere && own.editor->wholeText() == "default {} "); + { + INFO("its own let be"); + REQUIRE_FALSE(own.savedThere); + CHECK(own.editor->wholeText() == "default {} "); + } // Kept: what is here stays, to be saved. type(dirty, "\n// again"); saving.savedElsewhere(saved(dirty, "default {}\n// third", ALScriptOrigin::Editor)); saving.keepSaved(dirty); - ensure("kept", !dirty.savedThere && dirty.editor->isDirty() && lastStatus() == "SavedElsewhereKept"); + { + INFO("kept"); + REQUIRE_FALSE(dirty.savedThere); + CHECK(dirty.editor->isDirty()); + CHECK(lastStatus() == "SavedElsewhereKept"); + } } - template<> template<> - void alscriptstudiosaving_object::test<15>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save stops where the item was saved elsewhere since until asked again", "[alscriptstudiosaving]") { - set_test_name("a save asks what the item holds now; saved elsewhere since, it stops with Save Anyway, Reload and Compare, and goes when asked again"); ALScriptStudioSaving& saving = make(); Doc& doc = tab("a", "default {}"); doc.assetId.generate(); type(doc, " "); saving.save(doc); - ensure_equals("asked once", studio.worldAsks, 1); - ensure_equals("nothing moved: sent", studio.sent.size(), size_t(1)); + UNSCOPED_INFO("asked once"); + CHECK(studio.worldAsks == 1); + UNSCOPED_INFO("nothing moved: sent"); + REQUIRE(studio.sent.size() == size_t(1)); saving.compiled(answer(doc)); LLUUID elsewhere; @@ -831,17 +1049,22 @@ namespace tut studio.worldHolds = elsewhere; type(doc, "x"); saving.save(doc); - ensure_equals("moved: said", lastSaid(), std::string("SaveWorldMoved")); - ensure("with what can be done", services.reports.back().actions == Names{ "save_anyway", "reload_world", "merge_world", "compare_world" }); - ensure("and not sent", studio.sent.size() == 1 && !doc.save.underway()); + UNSCOPED_INFO("moved: said"); + CHECK(lastSaid() == std::string("SaveWorldMoved")); + UNSCOPED_INFO("with what can be done"); + CHECK(services.reports.back().actions == Names{ "save_anyway", "reload_world", "merge_world", "compare_world" }); + { + INFO("and not sent"); + REQUIRE(studio.sent.size() == 1); + CHECK_FALSE(doc.save.underway()); + } saving.saveAsked(doc); - ensure_equals("asked again: sent over it", studio.sent.size(), size_t(2)); + UNSCOPED_INFO("asked again: sent over it"); + REQUIRE(studio.sent.size() == size_t(2)); } - template<> template<> - void alscriptstudiosaving_object::test<16>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: heard sorts a save from elsewhere and reads the last save only if needed", "[alscriptstudiosaving]") { - set_test_name("a save heard from elsewhere, as every editor of the item decides it: the same text, taken, kept or asked about; what was last saved asked only where it is needed"); using Heard = ALScriptSaved::Heard; S32 asked = 0; auto last_was = [&asked](std::optional text) { @@ -850,19 +1073,24 @@ namespace tut return text; }; }; - ensure("the same text", ALScriptSaved::heard("a", "a", true, last_was("b")) == Heard::Same); - ensure("nothing typed: taken", ALScriptSaved::heard("a", "b", false, last_was("b")) == Heard::Take); - ensure_equals("without asking what was last saved", asked, 0); - ensure("typed, and theirs is what was last saved: kept", ALScriptSaved::heard("a", "b", true, last_was("a")) == Heard::Keep); - ensure("typed, and theirs is new: asked", ALScriptSaved::heard("a", "b", true, last_was("c")) == Heard::Ask); - ensure("typed, nothing known of the last save: asked", ALScriptSaved::heard("a", "b", true, last_was(std::nullopt)) == Heard::Ask); - ensure_equals("asked where it was needed", asked, 3); + UNSCOPED_INFO("the same text"); + CHECK(ALScriptSaved::heard("a", "a", true, last_was("b")) == Heard::Same); + UNSCOPED_INFO("nothing typed: taken"); + CHECK(ALScriptSaved::heard("a", "b", false, last_was("b")) == Heard::Take); + UNSCOPED_INFO("without asking what was last saved"); + CHECK(asked == 0); + UNSCOPED_INFO("typed, and theirs is what was last saved: kept"); + CHECK(ALScriptSaved::heard("a", "b", true, last_was("a")) == Heard::Keep); + UNSCOPED_INFO("typed, and theirs is new: asked"); + CHECK(ALScriptSaved::heard("a", "b", true, last_was("c")) == Heard::Ask); + UNSCOPED_INFO("typed, nothing known of the last save: asked"); + CHECK(ALScriptSaved::heard("a", "b", true, last_was(std::nullopt)) == Heard::Ask); + UNSCOPED_INFO("asked where it was needed"); + CHECK(asked == 3); } - template<> template<> - void alscriptstudiosaving_object::test<17>() + TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a merge is kept for good once a save carrying it is saved", "[alscriptstudiosaving]") { - set_test_name("a merge is kept for good once a save that carries it is saved; a save sent before it leaves it to be undone"); ALScriptStudioSaving& saving = make(); // As ALScriptStudioMerging keeps a merge just put in: the step it // made, and what it set aside. @@ -878,7 +1106,8 @@ namespace tut merged(doc); saving.save(doc); saving.compiled(answer(doc)); - ensure("saved with it: kept for good", !doc.merged); + UNSCOPED_INFO("saved with it: kept for good"); + REQUIRE_FALSE(doc.merged); Doc& early = tab("b", "default {}"); type(early, "\n// typed"); @@ -886,6 +1115,10 @@ namespace tut type(early, "\n// merged while it went"); merged(early); saving.compiled(answer(early)); - ensure("sent before it: still to be undone", early.merged && early.merged->savedThere == std::string("theirs")); + { + INFO("sent before it: still to be undone"); + REQUIRE(early.merged); + CHECK(early.merged->savedThere == std::string("theirs")); + } } } diff --git a/indra/newview/tests/alscriptstudioselections_test.cpp b/indra/newview/tests/alscriptstudioselections_test.cpp index 806aba908d..34acca2524 100644 --- a/indra/newview/tests/alscriptstudioselections_test.cpp +++ b/indra/newview/tests/alscriptstudioselections_test.cpp @@ -29,7 +29,7 @@ #include "aldiffview.h" #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include namespace { @@ -72,7 +72,7 @@ namespace }; } -namespace tut +namespace { struct alscriptstudioselections_data { @@ -136,70 +136,80 @@ namespace tut } }; - typedef test_group alscriptstudioselections_group; - typedef alscriptstudioselections_group::object alscriptstudioselections_object; - tut::alscriptstudioselections_group alscriptstudioselections_test("alscriptstudioselections"); - - template<> template<> - void alscriptstudioselections_object::test<1>() + TEST_CASE_METHOD(alscriptstudioselections_data, "alscriptstudioselections: hold keeps a selection titled by its tab and lines and says so", "[alscriptstudioselections]") { - set_test_name("nothing selected, nothing held; a selection held by its tab's name and its lines, and said"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& door = tab("door", lines(8)); - ensure("nothing to hold", !ALScriptStudioSelections::canHold(door)); + UNSCOPED_INFO("nothing to hold"); + CHECK_FALSE(ALScriptStudioSelections::canHold(door)); unit->hold(door); - ensure("none held", !unit->held()); + UNSCOPED_INFO("none held"); + REQUIRE_FALSE(unit->held()); door.editor->goTo(ALTextRange(ALTextPos(4, 0), ALTextPos(2, 0))); - ensure("something to hold", ALScriptStudioSelections::canHold(door)); + UNSCOPED_INFO("something to hold"); + CHECK(ALScriptStudioSelections::canHold(door)); unit->hold(door); - ensure("held", unit->held().has_value()); - ensure_equals("its text, whichever way it was selected", unit->held()->text, std::string("line 2\nline 3\n")); - ensure_equals("its lines, the last ending at a line's start not counted", unit->held()->title, titled("SelectionLines", "door", 3, 4)); + UNSCOPED_INFO("held"); + REQUIRE(unit->held().has_value()); + UNSCOPED_INFO("its text, whichever way it was selected"); + CHECK(unit->held()->text == std::string("line 2\nline 3\n")); + UNSCOPED_INFO("its lines, the last ending at a line's start not counted"); + CHECK(unit->held()->title == titled("SelectionLines", "door", 3, 4)); LLStringUtil::format_map_t args; args["[TITLE]"] = unit->held()->title; - ensure_equals("said", services().statuses.back(), said("SelectionHeld", args)); + UNSCOPED_INFO("said"); + CHECK(services().statuses.back() == said("SelectionHeld", args)); door.editor->goTo(ALTextRange(ALTextPos(5, 0), ALTextPos(5, 4))); unit->hold(door); - ensure("one line, in place of the other", unit->held()->text == "line" && unit->held()->title == titled("SelectionLine", "door", 6)); + { + INFO("one line, in place of the other"); + REQUIRE(unit->held()->text == "line"); + CHECK(unit->held()->title == titled("SelectionLine", "door", 6)); + } } - template<> template<> - void alscriptstudioselections_object::test<2>() + TEST_CASE_METHOD(alscriptstudioselections_data, "alscriptstudioselections: compare puts the held left of another tab's selection in its place", "[alscriptstudioselections]") { - set_test_name("the held compared with another tab's selection, in that tab's place: the held on the left, each under its title"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& door = tab("door", lines(8)); Doc& lamp = tab("lamp", lines(8, { { 3, "lamp 3" } })); lamp.editor->goTo(ALTextRange(ALTextPos(2, 0), ALTextPos(4, 0))); - ensure("nothing held: nothing to compare", !unit->canCompare(lamp)); + UNSCOPED_INFO("nothing held: nothing to compare"); + CHECK_FALSE(unit->canCompare(lamp)); door.editor->goTo(ALTextRange(ALTextPos(2, 0), ALTextPos(4, 0))); unit->hold(door); - ensure("held, and lamp's selected", unit->canCompare(lamp)); + UNSCOPED_INFO("held, and lamp's selected"); + CHECK(unit->canCompare(lamp)); lamp.editor->goTo(ALTextPos(0, 0)); - ensure("nothing selected in lamp", !unit->canCompare(lamp)); + UNSCOPED_INFO("nothing selected in lamp"); + CHECK_FALSE(unit->canCompare(lamp)); lamp.editor->goTo(ALTextRange(ALTextPos(2, 0), ALTextPos(4, 0))); unit->compare(lamp); - ensure_equals("compared", studio.did.size(), 1U); - ensure_equals("held against lamp's", studio.did[0], + UNSCOPED_INFO("compared"); + REQUIRE(studio.did.size() == 1U); + UNSCOPED_INFO("held against lamp's"); + CHECK(studio.did[0] == "line 2\nline 3\n | line 2\nlamp 3\n (" + titled("SelectionLines", "door", 3, 4) + " | " + titled("SelectionLines", "lamp", 3, 4) + ")"); - ensure("in lamp's place", lamp.compareView && lamp.compareView->changeCount() == 1); + { + INFO("in lamp's place"); + REQUIRE(lamp.compareView); + CHECK(lamp.compareView->changeCount() == 1); + } } - template<> template<> - void alscriptstudioselections_object::test<3>() + TEST_CASE_METHOD(alscriptstudioselections_data, "alscriptstudioselections: typing and taking back edit the source's stretch until it moves", "[alscriptstudioselections]") { - set_test_name("in the source: typing goes on at the selection's place, a change taken back edits that stretch; once the tab moves, neither"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& door = tab("door", lines(10)); door.editor->goTo(ALTextRange(ALTextPos(1, 0), ALTextPos(3, 0))); @@ -207,22 +217,34 @@ namespace tut door.editor->goTo(ALTextRange(ALTextPos(5, 0), ALTextPos(7, 0))); unit->compare(door); ALDiffView& view = *door.compareView; - ensure("its changes may be taken back", view.canTakeBack()); + UNSCOPED_INFO("its changes may be taken back"); + CHECK(view.canTakeBack()); // Typed on the comparison's second line, two in: the source's // seventh line, two in. view.right()->setFocus(true); view.right()->goTo(ALTextPos(1, 2)); view.right()->handleUnicodeChar('x', false); - ensure("sent to the stretch's place", studio.typedAt.size() == 1 && studio.typedAt[0] == ALTextPos(6, 2)); - ensure_equals("typed there", door.editor->text(), lines(10, { { 6, "lixne 6" } })); + { + INFO("sent to the stretch's place"); + REQUIRE(studio.typedAt.size() == 1); + CHECK(studio.typedAt[0] == ALTextPos(6, 2)); + } + UNSCOPED_INFO("typed there"); + CHECK(door.editor->text() == lines(10, { { 6, "lixne 6" } })); // Compared again, a change taken back: the stretch made the held's. door.editor->goTo(ALTextRange(ALTextPos(5, 0), ALTextPos(7, 0))); unit->compare(door); - ensure("taken back", view.takeBack(0)); - ensure_equals("the stretch made the held's", door.editor->text(), lines(10, { { 5, "line 1" }, { 6, "line 2" } })); - ensure("the comparison with it", view.rightText() == "line 1\nline 2\n" && view.changeCount() == 0); + UNSCOPED_INFO("taken back"); + CHECK(view.takeBack(0)); + UNSCOPED_INFO("the stretch made the held's"); + CHECK(door.editor->text() == lines(10, { { 5, "line 1" }, { 6, "line 2" } })); + { + INFO("the comparison with it"); + CHECK(view.rightText() == "line 1\nline 2\n"); + CHECK(view.changeCount() == 0); + } // A stretch whose lines change in number: the next taken back // still lands within it. @@ -230,8 +252,10 @@ namespace tut unit->hold(door); door.editor->goTo(ALTextRange(ALTextPos(5, 0), ALTextPos(7, 0))); unit->compare(door); - ensure("two lines made one", view.takeBack(0)); - ensure_equals("the source", door.editor->text(), lines(9, { { 5, "line 0" }, { 6, "line 7" }, { 7, "line 8" }, { 8, "line 9" } })); + UNSCOPED_INFO("two lines made one"); + CHECK(view.takeBack(0)); + UNSCOPED_INFO("the source"); + CHECK(door.editor->text() == lines(9, { { 5, "line 0" }, { 6, "line 7" }, { 7, "line 8" }, { 8, "line 9" } })); // The source moved under a comparison: nothing taken back, typing // at the stretch's start. @@ -240,20 +264,23 @@ namespace tut door.editor->goTo(ALTextPos(0, 0)); door.editor->insertText("new\n"); const std::string moved = door.editor->text(); - ensure("nothing taken back", !view.takeBack(0) && door.editor->text() == moved); + { + INFO("nothing taken back"); + CHECK_FALSE(view.takeBack(0)); + CHECK(door.editor->text() == moved); + } view.right()->setFocus(true); view.right()->goTo(ALTextPos(1, 3)); view.right()->handleUnicodeChar('y', false); - ensure("typing at the stretch's start", studio.typedAt.back() == ALTextPos(1, 0)); + UNSCOPED_INFO("typing at the stretch's start"); + CHECK(studio.typedAt.back() == ALTextPos(1, 0)); } - template<> template<> - void alscriptstudioselections_object::test<4>() + TEST_CASE_METHOD(alscriptstudioselections_data, "alscriptstudioselections: a selection in the preprocessed view compares as text and edits nothing", "[alscriptstudioselections]") { - set_test_name("a selection in what is not the source -- the preprocessed view -- compared as text alone: nothing taken back, and nothing typed into the script"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& door = tab("door", lines(8)); door.editor->goTo(ALTextRange(ALTextPos(0, 0), ALTextPos(2, 0))); @@ -261,24 +288,29 @@ namespace tut door.expandedEditor = editor("expanded_door", lines(8, { { 1, "expanded 1" } })); door.view = Doc::View::Expanded; door.expandedEditor->goTo(ALTextRange(ALTextPos(0, 0), ALTextPos(2, 0))); - ensure("held from the view in sight", ALScriptStudioSelections::canHold(door) && unit->canCompare(door)); + { + INFO("held from the view in sight"); + CHECK(ALScriptStudioSelections::canHold(door)); + CHECK(unit->canCompare(door)); + } unit->compare(door); - ensure_equals("its text", studio.did.back(), + UNSCOPED_INFO("its text"); + CHECK(studio.did.back() == "line 0\nline 1\n | line 0\nexpanded 1\n (" + titled("SelectionLines", "door", 1, 2) + " | " + titled("SelectionLines", "door", 1, 2) + ")"); - ensure("nothing taken back", !door.compareView->canTakeBack()); + UNSCOPED_INFO("nothing taken back"); + CHECK_FALSE(door.compareView->canTakeBack()); door.compareView->right()->setFocus(true); door.compareView->right()->goTo(ALTextPos(1, 2)); door.compareView->right()->handleUnicodeChar('z', false); - ensure("nothing typed into the script: the expansion is not it", studio.typedAt.empty()); + UNSCOPED_INFO("nothing typed into the script: the expansion is not it"); + REQUIRE(studio.typedAt.empty()); } - template<> template<> - void alscriptstudioselections_object::test<5>() + TEST_CASE_METHOD(alscriptstudioselections_data, "alscriptstudioselections: typing maps a mid-line selection's first line from where it starts", "[alscriptstudioselections]") { - set_test_name("a selection starting within a line: its first line's places counted from where it starts, the rest from their lines' starts"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& door = tab("door", "integer a = alpha;\ninteger b = beta;\ninteger c = 1;"); door.editor->goTo(ALTextRange(ALTextPos(0, 12), ALTextPos(0, 17))); @@ -286,18 +318,22 @@ namespace tut door.editor->goTo(ALTextRange(ALTextPos(1, 12), ALTextPos(2, 9))); unit->compare(door); ALDiffView& view = *door.compareView; - ensure_equals("the stretch", view.rightText(), std::string("beta;\ninteger c")); + UNSCOPED_INFO("the stretch"); + CHECK(view.rightText() == std::string("beta;\ninteger c")); view.right()->setFocus(true); view.right()->goTo(ALTextPos(0, 2)); view.right()->handleUnicodeChar('x', false); - ensure("on its first line, from where it starts", studio.typedAt.back() == ALTextPos(1, 14)); - ensure_equals("typed there", door.editor->text(), std::string("integer a = alpha;\ninteger b = bexta;\ninteger c = 1;")); + UNSCOPED_INFO("on its first line, from where it starts"); + CHECK(studio.typedAt.back() == ALTextPos(1, 14)); + UNSCOPED_INFO("typed there"); + CHECK(door.editor->text() == std::string("integer a = alpha;\ninteger b = bexta;\ninteger c = 1;")); door.editor->goTo(ALTextRange(ALTextPos(1, 12), ALTextPos(2, 9))); unit->compare(door); view.right()->setFocus(true); view.right()->goTo(ALTextPos(1, 3)); view.right()->handleUnicodeChar('y', false); - ensure("on a line after, from its start", studio.typedAt.back() == ALTextPos(2, 3)); + UNSCOPED_INFO("on a line after, from its start"); + CHECK(studio.typedAt.back() == ALTextPos(2, 3)); } } diff --git a/indra/newview/tests/alscriptstudiovim_test.cpp b/indra/newview/tests/alscriptstudiovim_test.cpp index c99588e825..bcd92d0bed 100644 --- a/indra/newview/tests/alscriptstudiovim_test.cpp +++ b/indra/newview/tests/alscriptstudiovim_test.cpp @@ -31,7 +31,7 @@ #include "fsyspath.h" -#include "../test/lltut.h" +#include #include #include @@ -160,7 +160,7 @@ namespace }; } -namespace tut +namespace { struct alscriptstudiovim_data { @@ -221,7 +221,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } for (const char* name : { "save", "close", "save_all", "format", "quick_fix", "fix_all", "back", "forward", "go_to_definition", "reference", "go_to_symbol", "blanks_all", "blanks_none" }) @@ -333,163 +333,253 @@ namespace tut } }; - typedef test_group alscriptstudiovim_group; - typedef alscriptstudiovim_group::object alscriptstudiovim_object; - alscriptstudiovim_group alscriptstudiovim_instance("alscriptstudiovim"); - - template<> template<> - void alscriptstudiovim_object::test<1>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: each : command reaches the menus' table or the window", "[alscriptstudiovim]") { - set_test_name("each : command reaches its command: the menus' through the window's table, the rest through the window"); ALScriptStudioVim& vim = make(); Doc& a = tab("a"); tab("b"); for (const char* name : { "w", "write", "w!" }) { - ensure(name, ex(a, name)); + UNSCOPED_INFO(name); + REQUIRE(ex(a, name)); } - ensure("written by the menus' Save", ran == Names{ "save", "save", "save" }); + UNSCOPED_INFO("written by the menus' Save"); + CHECK(ran == Names{ "save", "save", "save" }); ran.clear(); - ensure("q", ex(a, "q") && ex(a, "wa") && ex(a, "format") && ex(a, "fix") && ex(a, "fixall") && ex(a, "problems")); - ensure("each by its menu name", ran == Names{ "close", "save_all", "format", "quick_fix", "fix_all", "problems" }); + { + INFO("q"); + CHECK(ex(a, "q")); + CHECK(ex(a, "wa")); + CHECK(ex(a, "format")); + CHECK(ex(a, "fix")); + CHECK(ex(a, "fixall")); + CHECK(ex(a, "problems")); + } + UNSCOPED_INFO("each by its menu name"); + CHECK(ran == Names{ "close", "save_all", "format", "quick_fix", "fix_all", "problems" }); ran.clear(); - ensure("one that cannot be done now is taken, and not done", ex(a, "revert") && ran.empty()); + { + INFO("one that cannot be done now is taken, and not done"); + CHECK(ex(a, "revert")); + REQUIRE(ran.empty()); + } - ensure("q! lets it go as it stands", ex(a, "q!") && studio.letGo == Names{ "a" }); - ensure("wq over nothing unsaved closes it", ex(a, "wq") && studio.asked == Names{ "a" } && studio.savedToClose.empty()); + { + INFO("q! lets it go as it stands"); + CHECK(ex(a, "q!")); + CHECK(studio.letGo == Names{ "a" }); + } + { + INFO("wq over nothing unsaved closes it"); + CHECK(ex(a, "wq")); + CHECK(studio.asked == Names{ "a" }); + REQUIRE(studio.savedToClose.empty()); + } a.editor->setCaret(a.editor->document().end()); a.editor->insertText(" "); - ensure("wq over something unsaved saves it to close", ex(a, "x") && studio.savedToClose == Names{ "a" }); - ensure("qa closes them all, asking once", ex(a, "qa") && studio.many == Names{ "a", "b" }); + { + INFO("wq over something unsaved saves it to close"); + CHECK(ex(a, "x")); + CHECK(studio.savedToClose == Names{ "a" }); + } + { + INFO("qa closes them all, asking once"); + CHECK(ex(a, "qa")); + CHECK(studio.many == Names{ "a", "b" }); + } studio.letGo.clear(); - ensure("qa! lets them all go", ex(a, "qa!") && studio.letGo == Names{ "a", "b" }); + { + INFO("qa! lets them all go"); + CHECK(ex(a, "qa!")); + CHECK(studio.letGo == Names{ "a", "b" }); + } - ensure("one it does not know is vim's to say", !ex(a, "frobnicate")); + UNSCOPED_INFO("one it does not know is vim's to say"); + CHECK_FALSE(ex(a, "frobnicate")); ALCodeEditor* stray = editor("stray", "x"); - ensure("nor from an editor of no tab", !vim.command(*stray, "w", std::string()) && ran.empty()); + { + INFO("nor from an editor of no tab"); + CHECK_FALSE(vim.command(*stray, "w", std::string())); + REQUIRE(ran.empty()); + } } - template<> template<> - void alscriptstudiovim_object::test<2>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: :set toggles number and relativenumber only when they differ", "[alscriptstudiovim]") { - set_test_name(":set turns number and relativenumber on or off through their toggles, only where they are not so already"); make(); Doc& a = tab("a"); - ensure("on", ex(a, "set", "number") && lineNumbers && ran == Names{ "line_numbers" }); - ensure("on already: left", ex(a, "set", "nu") && ran.size() == 1); - ensure("off", ex(a, "set", "nonu") && !lineNumbers && ran.size() == 2); - ensure("relative", ex(a, "set", "rnu") && relativeNumbers); - ensure("off already: left", ex(a, "set", "norelativenumber") && !relativeNumbers && ran.size() == 4); - ensure("an option it does not know is vim's", !ex(a, "set", "hlsearch")); + { + INFO("on"); + CHECK(ex(a, "set", "number")); + CHECK(lineNumbers); + CHECK(ran == Names{ "line_numbers" }); + } + { + INFO("on already: left"); + CHECK(ex(a, "set", "nu")); + REQUIRE(ran.size() == 1); + } + { + INFO("off"); + CHECK(ex(a, "set", "nonu")); + CHECK_FALSE(lineNumbers); + REQUIRE(ran.size() == 2); + } + { + INFO("relative"); + CHECK(ex(a, "set", "rnu")); + CHECK(relativeNumbers); + } + { + INFO("off already: left"); + CHECK(ex(a, "set", "norelativenumber")); + CHECK_FALSE(relativeNumbers); + REQUIRE(ran.size() == 4); + } + UNSCOPED_INFO("an option it does not know is vim's"); + CHECK_FALSE(ex(a, "set", "hlsearch")); } - template<> template<> - void alscriptstudiovim_object::test<3>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: :history lists command or search lines or both in Output", "[alscriptstudiovim]") { - set_test_name(":history lists the lines entered in the Output tab: the : ones, the searches, or both"); ALScriptStudioVim& vim = make(); Doc& a = tab("a"); vim.shared().command = { "w", "set nu" }; vim.shared().search = { "foo" }; - ensure("the : ones", ex(a, "history")); - ensure_equals("one entry", studio.entries.size(), size_t(1)); - ensure_equals("numbered", studio.entries[0].text, std::string("cmd history:\n 1 w\n 2 set nu")); - ensure_equals("from vim", studio.entries[0].source, std::string("OutputSourceVim")); - ensure("the tab in sight", studio.outputShown == 1); + UNSCOPED_INFO("the : ones"); + CHECK(ex(a, "history")); + UNSCOPED_INFO("one entry"); + REQUIRE(studio.entries.size() == size_t(1)); + UNSCOPED_INFO("numbered"); + CHECK(studio.entries[0].text == std::string("cmd history:\n 1 w\n 2 set nu")); + UNSCOPED_INFO("from vim"); + CHECK(studio.entries[0].source == std::string("OutputSourceVim")); + UNSCOPED_INFO("the tab in sight"); + CHECK(studio.outputShown == 1); studio.entries.clear(); - ensure("the searches", ex(a, "his", "/") && studio.entries.size() == 1 && studio.entries[0].text == "search history:\n 1 foo"); + { + INFO("the searches"); + CHECK(ex(a, "his", "/")); + REQUIRE(studio.entries.size() == 1); + CHECK(studio.entries[0].text == "search history:\n 1 foo"); + } studio.entries.clear(); - ensure("both", ex(a, "history", "all") && studio.entries.size() == 2); + { + INFO("both"); + CHECK(ex(a, "history", "all")); + REQUIRE(studio.entries.size() == 2); + } } - template<> template<> - void alscriptstudiovim_object::test<4>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: q: lists lines last first to run or to put back on the line", "[alscriptstudiovim]") { - set_test_name("q: lists the lines entered, the last first; Return runs one, Shift-Return puts it back on the line"); ALScriptStudioVim& vim = make(); Doc& a = tab("a"); std::vector> chosen; vim.historyWindow(*a.editor, ':', { "first", "second", "third" }, [&chosen](const std::string& line, bool run) { chosen.emplace_back(line, run); }); - ensure("the last first", studio.offered == Names{ "third", "second", "first" }); - ensure_equals("as tall as they are", studio.pickRows, 3); - ensure_equals("asking of the kind", studio.asking, std::string("VimHistoryPlaceholder [KIND]=:")); + UNSCOPED_INFO("the last first"); + CHECK(studio.offered == Names{ "third", "second", "first" }); + UNSCOPED_INFO("as tall as they are"); + CHECK(studio.pickRows == 3); + UNSCOPED_INFO("asking of the kind"); + CHECK(studio.asking == std::string("VimHistoryPlaceholder [KIND]=:")); studio.pick("second"); studio.shift("first"); - ensure("run, and put back", chosen == std::vector>{ { "second", true }, { "first", false } }); - ensure("none picked is nothing chosen", (studio.cancel(), chosen.size() == 2)); + UNSCOPED_INFO("run, and put back"); + CHECK(chosen == std::vector>{ { "second", true }, { "first", false } }); + UNSCOPED_INFO("none picked is nothing chosen"); + REQUIRE((studio.cancel(), chosen.size() == 2)); vim.historyWindow(*a.editor, '/', Names(20, "x"), [](const std::string&, bool) {}); - ensure_equals("no taller than eight", studio.pickRows, 8); + UNSCOPED_INFO("no taller than eight"); + CHECK(studio.pickRows == 8); vim.historyWindow(*a.editor, '/', Names(), [](const std::string&, bool) {}); - ensure_equals("nor shorter than one", studio.pickRows, 1); + UNSCOPED_INFO("nor shorter than one"); + CHECK(studio.pickRows == 1); } - template<> template<> - void alscriptstudiovim_object::test<5>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: = formats the given lines of a changeable script's source only", "[alscriptstudiovim]") { - set_test_name("= formats the lines given of the source; not of the expansion, a notecard or a tab that cannot change"); ALScriptStudioVim& vim = make(); Doc& a = tab("a", "one\ntwo\nthree\nfour"); vim.format(*a.editor, 1, 2); - ensure("formatted, as a selection", studio.formatted == Names{ "a selection" }); + UNSCOPED_INFO("formatted, as a selection"); + CHECK(studio.formatted == Names{ "a selection" }); const ALTextDocument& text = a.editor->document(); - ensure("of those lines", a.editor->selection() == ALTextRange(text.lineStart(1), text.lineEnd(2))); + UNSCOPED_INFO("of those lines"); + CHECK(a.editor->selection() == ALTextRange(text.lineStart(1), text.lineEnd(2))); vim.format(*a.editor, 2, 99); - ensure("to the last there is", a.editor->selection() == ALTextRange(text.lineStart(2), text.lineEnd(3))); + UNSCOPED_INFO("to the last there is"); + CHECK(a.editor->selection() == ALTextRange(text.lineStart(2), text.lineEnd(3))); a.expandedEditor = editor("expanded_a", "one"); vim.format(*a.expandedEditor, 0, 0); - ensure("not the expansion", studio.formatted.size() == 2); + UNSCOPED_INFO("not the expansion"); + REQUIRE(studio.formatted.size() == 2); Doc& card = tab("card"); card.notecard = true; vim.format(*card.editor, 0, 0); Doc& locked = tab("locked"); locked.modifiable = false; vim.format(*locked.editor, 0, 0); - ensure("nor a notecard, nor one that cannot change", studio.formatted.size() == 2); - ensure("the expansion's editor is its tab's", vim.docOf(*a.expandedEditor) == &a); + UNSCOPED_INFO("nor a notecard, nor one that cannot change"); + REQUIRE(studio.formatted.size() == 2); + UNSCOPED_INFO("the expansion's editor is its tab's"); + CHECK(vim.docOf(*a.expandedEditor) == &a); } - template<> template<> - void alscriptstudiovim_object::test<6>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: a connected keymap shares the window's history and shows the banner", "[alscriptstudiovim]") { - set_test_name("a keymap connected shares the window's history and asks it; the banner says vim where the tab in front has it"); ALScriptStudioVim& vim = make(); Doc& a = tab("a"); vim.pump(); - ensure("no vim, nothing said", vim.banner().empty() && studio.trailers == 0); + { + INFO("no vim, nothing said"); + REQUIRE(vim.banner().empty()); + CHECK(studio.trailers == 0); + } auto keymap = std::make_unique(); vim.connect(*keymap); ALVimKeymap& connected = *keymap; a.editor->setModalKeymap(std::move(keymap)); - ensure("its history the window's", connected.sharedState().get() == &vim.shared()); - ensure("a : command it leaves reaches the table", - connected.hooks().command(*a.editor, "w", std::string()) && ran == Names{ "save" }); + UNSCOPED_INFO("its history the window's"); + CHECK(connected.sharedState().get() == &vim.shared()); + { + INFO("a : command it leaves reaches the table"); + CHECK(connected.hooks().command(*a.editor, "w", std::string())); + CHECK(ran == Names{ "save" }); + } std::vector words; connected.hooks().complete(*a.editor, std::string(), std::string(), words); - ensure("Tab completes the studio's names", std::find(words.begin(), words.end(), "fixall") != words.end()); + UNSCOPED_INFO("Tab completes the studio's names"); + REQUIRE(std::find(words.begin(), words.end(), "fixall") != words.end()); vim.pump(); - ensure_equals("vim, said", vim.banner(), std::string("VimNormal")); - ensure("the strip told", studio.trailers == 1); + UNSCOPED_INFO("vim, said"); + CHECK(vim.banner() == std::string("VimNormal")); + UNSCOPED_INFO("the strip told"); + CHECK(studio.trailers == 1); vim.pump(); - ensure("once", studio.trailers == 1); + UNSCOPED_INFO("once"); + CHECK(studio.trailers == 1); // Gone, the keymap's hooks do nothing. this->vim.reset(); - ensure("asked of nothing", !connected.hooks().command(*a.editor, "w", std::string()) && ran.size() == 1); + { + INFO("asked of nothing"); + CHECK_FALSE(connected.hooks().command(*a.editor, "w", std::string())); + REQUIRE(ran.size() == 1); + } } - template<> template<> - void alscriptstudiovim_object::test<7>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: Tab completes commands and their options and kinds and tab names", "[alscriptstudiovim]") { - set_test_name("Tab completes the command names, :set's options, :history's kinds and the tabs' names"); ALScriptStudioVim& vim = make(); tab("alpha"); tab("beta"); @@ -499,84 +589,128 @@ namespace tut vim.complete("his", std::string(), kinds); vim.complete("bd", std::string(), tabs); vim.complete("q", std::string(), none); - ensure("vim's own and the menus'", std::find(names.begin(), names.end(), "wall") != names.end() && - std::find(names.begin(), names.end(), "go_to_line") != names.end()); - ensure("the options", - options == Names{ "number", "nonumber", "relativenumber", "norelativenumber", "spell", "nospell", "list", "nolist" }); - ensure("the kinds", kinds == Names{ "all", "cmd", "search" }); - ensure("the tabs", tabs == Names{ "alpha", "beta" }); - ensure("nothing after anything else", none.empty()); + { + INFO("vim's own and the menus'"); + REQUIRE(std::find(names.begin(), names.end(), "wall") != names.end()); + REQUIRE(std::find(names.begin(), names.end(), "go_to_line") != names.end()); + } + UNSCOPED_INFO("the options"); + CHECK(options == Names{ "number", "nonumber", "relativenumber", "norelativenumber", "spell", "nospell", "list", "nolist" }); + UNSCOPED_INFO("the kinds"); + CHECK(kinds == Names{ "all", "cmd", "search" }); + UNSCOPED_INFO("the tabs"); + CHECK(tabs == Names{ "alpha", "beta" }); + UNSCOPED_INFO("nothing after anything else"); + REQUIRE(none.empty()); } - template<> template<> - void alscriptstudiovim_object::test<8>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: :b and :tab commands move between tabs round the strip", "[alscriptstudiovim]") { - set_test_name("the tabs are vim's buffers and tab pages: :bn and :bp round the strip, :b by number, name or #, first and last"); make(); ALVimKeymap* vim = fourTabs(); - ensure_equals(":bn", go("bn"), std::string("beta")); - ensure_equals(":bnext 2", go("bnext", "2"), std::string("delta")); - ensure_equals("round past the end", go("bn"), std::string("alpha")); - ensure_equals(":bp round past the start", go("bp"), std::string("delta")); - ensure_equals(":bN 3", go("bN", "3"), std::string("alpha")); - ensure_equals(":b 3", go("b", "3"), std::string("gamma")); - ensure_equals(":b # the one before", go("b", "#"), std::string("alpha")); - ensure_equals("and back", go("buffer", "#"), std::string("gamma")); - ensure_equals(":b by a part of its name, in any case", go("b", "ELT"), std::string("delta")); - ensure_equals(":b by its whole name", go("b", "beta"), std::string("beta")); - ensure_equals(":bf", go("bf"), std::string("alpha")); - ensure_equals(":blast", go("blast"), std::string("delta")); - ensure_equals(":tabfirst", go("tabfirst"), std::string("alpha")); - ensure_equals(":tabl", go("tabl"), std::string("delta")); - ensure_equals(":tabn round past the end", go("tabn"), std::string("alpha")); - ensure_equals(":tabn 3 the third", go("tabn", "3"), std::string("gamma")); - ensure_equals(":tabn +1", go("tabnext", "+1"), std::string("delta")); - ensure_equals(":tabn $", go("tabn", "$"), std::string("delta")); - ensure_equals(":tabp 2", go("tabp", "2"), std::string("beta")); - ensure_equals(":tabN round past the start", go("tabN", "2"), std::string("delta")); - - ensure_equals(":b a -- in every name", go("b", "a"), std::string("delta")); - ensure_equals("said as vim says it", vim->message(), std::string("VimTabsMatch [NAME]=a")); - ensure("an error", vim->messageIsError()); + UNSCOPED_INFO(":bn"); + CHECK(go("bn") == std::string("beta")); + UNSCOPED_INFO(":bnext 2"); + CHECK(go("bnext", "2") == std::string("delta")); + UNSCOPED_INFO("round past the end"); + CHECK(go("bn") == std::string("alpha")); + UNSCOPED_INFO(":bp round past the start"); + CHECK(go("bp") == std::string("delta")); + UNSCOPED_INFO(":bN 3"); + CHECK(go("bN", "3") == std::string("alpha")); + UNSCOPED_INFO(":b 3"); + CHECK(go("b", "3") == std::string("gamma")); + UNSCOPED_INFO(":b # the one before"); + CHECK(go("b", "#") == std::string("alpha")); + UNSCOPED_INFO("and back"); + CHECK(go("buffer", "#") == std::string("gamma")); + UNSCOPED_INFO(":b by a part of its name, in any case"); + CHECK(go("b", "ELT") == std::string("delta")); + UNSCOPED_INFO(":b by its whole name"); + CHECK(go("b", "beta") == std::string("beta")); + UNSCOPED_INFO(":bf"); + CHECK(go("bf") == std::string("alpha")); + UNSCOPED_INFO(":blast"); + CHECK(go("blast") == std::string("delta")); + UNSCOPED_INFO(":tabfirst"); + CHECK(go("tabfirst") == std::string("alpha")); + UNSCOPED_INFO(":tabl"); + CHECK(go("tabl") == std::string("delta")); + UNSCOPED_INFO(":tabn round past the end"); + CHECK(go("tabn") == std::string("alpha")); + UNSCOPED_INFO(":tabn 3 the third"); + CHECK(go("tabn", "3") == std::string("gamma")); + UNSCOPED_INFO(":tabn +1"); + CHECK(go("tabnext", "+1") == std::string("delta")); + UNSCOPED_INFO(":tabn $"); + CHECK(go("tabn", "$") == std::string("delta")); + UNSCOPED_INFO(":tabp 2"); + CHECK(go("tabp", "2") == std::string("beta")); + UNSCOPED_INFO(":tabN round past the start"); + CHECK(go("tabN", "2") == std::string("delta")); + + UNSCOPED_INFO(":b a -- in every name"); + CHECK(go("b", "a") == std::string("delta")); + UNSCOPED_INFO("said as vim says it"); + CHECK(vim->message() == std::string("VimTabsMatch [NAME]=a")); + UNSCOPED_INFO("an error"); + CHECK(vim->messageIsError()); go("b", "zeta"); - ensure_equals("none", vim->message(), std::string("VimNoTabMatch [NAME]=zeta")); + UNSCOPED_INFO("none"); + CHECK(vim->message() == std::string("VimNoTabMatch [NAME]=zeta")); go("b", "9"); - ensure_equals("no ninth", vim->message(), std::string("VimNoSuchTab [NUMBER]=9")); + UNSCOPED_INFO("no ninth"); + CHECK(vim->message() == std::string("VimNoSuchTab [NUMBER]=9")); go("tabn", "9"); - ensure_equals("nor to go to", vim->message(), std::string("VimBadArgument")); - ensure_equals("still where it was", services.frontDoc()->id, std::string("delta")); + UNSCOPED_INFO("nor to go to"); + CHECK(vim->message() == std::string("VimBadArgument")); + UNSCOPED_INFO("still where it was"); + CHECK(services.frontDoc()->id == std::string("delta")); } - template<> template<> - void alscriptstudiovim_object::test<9>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: :bd and :tabclose and :tabonly close tabs and :tabmove moves one", "[alscriptstudiovim]") { - set_test_name(":bd and :tabclose close a tab, asked about or with ! let go of; :tabonly the others; :tabmove moves the one in front"); make(); ALVimKeymap* vim = fourTabs(); go("b", "beta"); - ensure(":bd the one in front, asked about", go("bd") == "beta" && studio.asked == Names{ "beta" }); - ensure(":bd! let go of", (go("bd!"), studio.letGo == Names{ "beta" })); - ensure(":bd by number", (go("bd", "3"), studio.asked == Names{ "beta", "gamma" })); - ensure(":tabclose! by number", (go("tabclose!", "4"), studio.letGo == Names{ "beta", "delta" })); - ensure(":tabonly asks about the others at once", (go("tabonly"), studio.many == Names{ "alpha", "gamma", "delta" })); + { + INFO(":bd the one in front, asked about"); + CHECK(go("bd") == "beta"); + CHECK(studio.asked == Names{ "beta" }); + } + UNSCOPED_INFO(":bd! let go of"); + CHECK((go("bd!"), studio.letGo == Names{ "beta" })); + UNSCOPED_INFO(":bd by number"); + CHECK((go("bd", "3"), studio.asked == Names{ "beta", "gamma" })); + UNSCOPED_INFO(":tabclose! by number"); + CHECK((go("tabclose!", "4"), studio.letGo == Names{ "beta", "delta" })); + UNSCOPED_INFO(":tabonly asks about the others at once"); + CHECK((go("tabonly"), studio.many == Names{ "alpha", "gamma", "delta" })); studio.letGo.clear(); - ensure(":tabonly! lets them go", (go("tabo!"), studio.letGo == Names{ "alpha", "gamma", "delta" })); - - ensure_equals(":tabm 0 to the start", (go("tabm", "0"), order()), std::string("beta alpha gamma delta")); - ensure_equals(":tabm to the end", (go("tabmove"), order()), std::string("alpha gamma delta beta")); - ensure_equals(":tabm 2 after the second", (go("tabm", "2"), order()), std::string("alpha gamma beta delta")); - ensure_equals(":tabm -1", (go("tabm", "-1"), order()), std::string("alpha beta gamma delta")); - ensure_equals(":tabm 3 after the third, past itself", (go("tabm", "3"), order()), std::string("alpha gamma beta delta")); - ensure_equals("still in front", services.frontDoc()->id, std::string("beta")); + UNSCOPED_INFO(":tabonly! lets them go"); + CHECK((go("tabo!"), studio.letGo == Names{ "alpha", "gamma", "delta" })); + + UNSCOPED_INFO(":tabm 0 to the start"); + CHECK((go("tabm", "0"), order()) == std::string("beta alpha gamma delta")); + UNSCOPED_INFO(":tabm to the end"); + CHECK((go("tabmove"), order()) == std::string("alpha gamma delta beta")); + UNSCOPED_INFO(":tabm 2 after the second"); + CHECK((go("tabm", "2"), order()) == std::string("alpha gamma beta delta")); + UNSCOPED_INFO(":tabm -1"); + CHECK((go("tabm", "-1"), order()) == std::string("alpha beta gamma delta")); + UNSCOPED_INFO(":tabm 3 after the third, past itself"); + CHECK((go("tabm", "3"), order()) == std::string("alpha gamma beta delta")); + UNSCOPED_INFO("still in front"); + CHECK(services.frontDoc()->id == std::string("beta")); go("tabm", "+5"); - ensure_equals("not past the end", vim->message(), std::string("VimBadArgument")); - ensure_equals("where it was", order(), std::string("alpha gamma beta delta")); + UNSCOPED_INFO("not past the end"); + CHECK(vim->message() == std::string("VimBadArgument")); + UNSCOPED_INFO("where it was"); + CHECK(order() == std::string("alpha gamma beta delta")); } - template<> template<> - void alscriptstudiovim_object::test<10>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: :ls lists tabs with their flags and lines as vim lists buffers", "[alscriptstudiovim]") { - set_test_name(":ls lists the tabs as vim lists its buffers: the one in front, the one before, unsaved, unchangeable, and their lines"); make(); fourTabs(); go("b", "gamma"); @@ -585,21 +719,23 @@ namespace tut gamma.editor->setCaret(gamma.editor->document().end()); gamma.editor->insertText("\n\n"); services.findDoc(std::string_view("delta"))->modifiable = false; - ensure("taken", ex(*services.docs[0], "ls")); - ensure_equals("one entry", studio.entries.size(), size_t(1)); - ensure_equals("the tabs", studio.entries[0].text, + UNSCOPED_INFO("taken"); + CHECK(ex(*services.docs[0], "ls")); + UNSCOPED_INFO("one entry"); + REQUIRE(studio.entries.size() == size_t(1)); + UNSCOPED_INFO("the tabs"); + CHECK(studio.entries[0].text == std::string("tabs:\n" " 1 h \"alpha\" line 1\n" " 2 %a \"beta\" line 1\n" " 3 #h + \"gamma\" line 3\n" " 4 h- \"delta\" line 1")); - ensure("the tab in sight", studio.outputShown == 1); + UNSCOPED_INFO("the tab in sight"); + CHECK(studio.outputShown == 1); } - template<> template<> - void alscriptstudiovim_object::test<11>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: :e opens a file from the tab's folders or goes to a tab or reverts", "[alscriptstudiovim]") { - set_test_name(":e opens a file where the tab's folders have it, or a tab by its name or file, # the one before; alone, reads the tab again"); ALScriptStudioVim& vim = make(); files(); Doc& a = tab("alpha"); @@ -608,95 +744,141 @@ namespace tut tab("beta"); vim.pump(); - ensure("taken", ex(a, "e", "main.lsl")); - ensure("an LSL file as LSL", studio.openedFiles.size() == 1 && studio.openedFiles.back() == std::make_pair(in("main.lsl"), false)); + UNSCOPED_INFO("taken"); + CHECK(ex(a, "e", "main.lsl")); + { + INFO("an LSL file as LSL"); + REQUIRE(studio.openedFiles.size() == 1); + CHECK(studio.openedFiles.back() == std::make_pair(in("main.lsl"), false)); + } ex(a, "edit", "lib/util.luau"); - ensure("in a folder under it, as SLua", - studio.openedFiles.size() == 2 && studio.openedFiles.back() == std::make_pair(in("lib/util.luau"), true)); + { + INFO("in a folder under it, as SLua"); + REQUIRE(studio.openedFiles.size() == 2); + CHECK(studio.openedFiles.back() == std::make_pair(in("lib/util.luau"), true)); + } ex(a, "e", "notes.txt"); - ensure("anything else as the tab it was named from is", - studio.openedFiles.size() == 3 && studio.openedFiles.back() == std::make_pair(in("notes.txt"), true)); + { + INFO("anything else as the tab it was named from is"); + REQUIRE(studio.openedFiles.size() == 3); + CHECK(studio.openedFiles.back() == std::make_pair(in("notes.txt"), true)); + } ex(a, "e", in("main.lsl")); - ensure("where a whole path says", studio.openedFiles.size() == 4 && studio.openedFiles.back().first == in("main.lsl")); + { + INFO("where a whole path says"); + REQUIRE(studio.openedFiles.size() == 4); + CHECK(studio.openedFiles.back().first == in("main.lsl")); + } ex(a, "tabe", "main.lsl"); - ensure(":tabedit the same", studio.openedFiles.size() == 5); + UNSCOPED_INFO(":tabedit the same"); + REQUIRE(studio.openedFiles.size() == 5); ex(a, "e", "nowhere.lsl"); - ensure_equals("nowhere: said", said->message(), std::string("VimNoFile [FILE]=nowhere.lsl")); - ensure("and nothing opened", studio.openedFiles.size() == 5); + UNSCOPED_INFO("nowhere: said"); + CHECK(said->message() == std::string("VimNoFile [FILE]=nowhere.lsl")); + UNSCOPED_INFO("and nothing opened"); + REQUIRE(studio.openedFiles.size() == 5); ex(a, "tabnew"); - ensure_equals(":tabnew wants a file", said->message(), std::string("VimArgumentRequired")); + UNSCOPED_INFO(":tabnew wants a file"); + CHECK(said->message() == std::string("VimArgumentRequired")); ex(a, "e", "beta"); - ensure_equals("a tab by its name", services.frontDoc()->id, std::string("beta")); + UNSCOPED_INFO("a tab by its name"); + CHECK(services.frontDoc()->id == std::string("beta")); vim.pump(); ex(a, "e", "#"); - ensure_equals("# the one before", services.frontDoc()->id, std::string("alpha")); + UNSCOPED_INFO("# the one before"); + CHECK(services.frontDoc()->id == std::string("alpha")); Doc& main = tab("mainfile"); main.file = in("main.lsl"); ex(a, "e", "main.lsl"); - ensure("a file open already is gone to", services.frontDoc() == &main && studio.openedFiles.size() == 5); + { + INFO("a file open already is gone to"); + CHECK(services.frontDoc() == &main); + REQUIRE(studio.openedFiles.size() == 5); + } ex(a, "e"); - ensure("alone: read again", studio.reverted == Names{ "alpha" }); + UNSCOPED_INFO("alone: read again"); + CHECK(studio.reverted == Names{ "alpha" }); a.editor->setCaret(a.editor->document().end()); a.editor->insertText(" "); ex(a, "e"); - ensure_equals("not over unsaved work", said->message(), std::string("VimNotSaved")); - ensure("left", studio.reverted.size() == 1); + UNSCOPED_INFO("not over unsaved work"); + CHECK(said->message() == std::string("VimNotSaved")); + UNSCOPED_INFO("left"); + REQUIRE(studio.reverted.size() == 1); ex(a, "e!"); - ensure("but with !", studio.reverted == Names{ "alpha", "alpha" }); + UNSCOPED_INFO("but with !"); + CHECK(studio.reverted == Names{ "alpha", "alpha" }); } - template<> template<> - void alscriptstudiovim_object::test<12>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: :r reads a file in and :w and :update and :wqa write", "[alscriptstudiovim]") { - set_test_name(":r puts a file below the caret's line; :w writes the text to one, over one there only with !; :update, :wqa"); make(); files(); Doc& a = tab("alpha", "one\ntwo"); ALVimKeymap* said = vimOver(a); ex(a, "r", "lib/util.luau"); - ensure_equals("below the line, its own last break dropped", a.editor->text(), std::string("one\nlocal x = 1\nreturn x\ntwo")); - ensure("the caret on the first line put in", a.editor->caret() == ALTextPos(1, 0)); + UNSCOPED_INFO("below the line, its own last break dropped"); + CHECK(a.editor->text() == std::string("one\nlocal x = 1\nreturn x\ntwo")); + UNSCOPED_INFO("the caret on the first line put in"); + CHECK(a.editor->caret() == ALTextPos(1, 0)); ex(a, "read", "nowhere"); - ensure_equals("nowhere: said", said->message(), std::string("VimNoFile [FILE]=nowhere")); + UNSCOPED_INFO("nowhere: said"); + CHECK(said->message() == std::string("VimNoFile [FILE]=nowhere")); ex(a, "r"); - ensure_equals("no file of its own", said->message(), std::string("VimNoFileName")); + UNSCOPED_INFO("no file of its own"); + CHECK(said->message() == std::string("VimNoFileName")); a.expandedEditor = editor("expanded_alpha", "x"); - ensure("not into the expansion", vim->command(*a.expandedEditor, "r", "main.lsl") && a.expandedEditor->text() == "x"); + { + INFO("not into the expansion"); + REQUIRE(vim->command(*a.expandedEditor, "r", "main.lsl")); + CHECK(a.expandedEditor->text() == "x"); + } ex(a, "w", "out.lsl"); - ensure_equals("written", contents(in("out.lsl")), a.editor->text()); + UNSCOPED_INFO("written"); + CHECK(contents(in("out.lsl")) == a.editor->text()); const std::string written = "VimWritten [BYTES]=" + std::to_string(a.editor->text().size()) + " [FILE]=" + in("out.lsl") + " [LINES]=4 [QUOTED]=\"" + in("out.lsl") + "\""; - ensure_equals("and said", said->message(), written); - ensure("not as an error", !said->messageIsError()); - ensure("the tab left as it was", ran.empty()); + UNSCOPED_INFO("and said"); + CHECK(said->message() == written); + UNSCOPED_INFO("not as an error"); + CHECK_FALSE(said->messageIsError()); + UNSCOPED_INFO("the tab left as it was"); + REQUIRE(ran.empty()); a.editor->setCaret(a.editor->document().end()); a.editor->insertText("!"); ex(a, "w", "out.lsl"); - ensure_equals("not over one there", said->message(), std::string("VimFileExists")); - ensure("left", contents(in("out.lsl")) != a.editor->text()); + UNSCOPED_INFO("not over one there"); + CHECK(said->message() == std::string("VimFileExists")); + UNSCOPED_INFO("left"); + CHECK(contents(in("out.lsl")) != a.editor->text()); ex(a, "w!", "out.lsl"); - ensure_equals("but with !", contents(in("out.lsl")), a.editor->text()); + UNSCOPED_INFO("but with !"); + CHECK(contents(in("out.lsl")) == a.editor->text()); ex(a, "w", "!ls"); - ensure_equals("no shell", said->message(), std::string("VimBadArgument")); + UNSCOPED_INFO("no shell"); + CHECK(said->message() == std::string("VimBadArgument")); ex(a, "update"); - ensure(":update over unsaved work saves", ran == Names{ "save" }); + UNSCOPED_INFO(":update over unsaved work saves"); + CHECK(ran == Names{ "save" }); a.editor->resetDirty(); ex(a, "up"); - ensure("over none, nothing", ran.size() == 1); + UNSCOPED_INFO("over none, nothing"); + REQUIRE(ran.size() == 1); tab("beta"); type(a, "?"); ex(a, "wqa"); - ensure(":wqa saves the unsaved to close, and closes the rest", - studio.savedToClose == Names{ "alpha" } && studio.asked == Names{ "beta" }); + { + INFO(":wqa saves the unsaved to close, and closes the rest"); + CHECK(studio.savedToClose == Names{ "alpha" }); + CHECK(studio.asked == Names{ "beta" }); + } } - template<> template<> - void alscriptstudiovim_object::test<13>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: Tab after a file command offers files and folders from the tab's folders", "[alscriptstudiovim]") { - set_test_name("Tab after :e, :r and :w offers the files and folders in the tabs' folders, or where a whole path says; hidden ones where asked"); ALScriptStudioVim& vim = make(); files(); tab("alpha"); @@ -706,64 +888,95 @@ namespace tut std::sort(out.begin(), out.end()); return out; }; - ensure("the folder's", offered("e", std::string()) == Names{ "lib/", "main.lsl", "notes.txt" }); - ensure("in a folder under it", offered("edit", "lib/u") == Names{ "lib/util.luau" }); - ensure("by the start of a name", offered("r", "ma") == Names{ "main.lsl" }); - ensure("after :w", offered("w", "n") == Names{ "notes.txt" }); - ensure("hidden where a dot is typed", offered("e", ".") == Names{ ".hidden" }); - ensure("where a whole path says", offered("tabe", folder + "/li") == Names{ folder + "/lib/" }); - ensure("not after anything else", offered("q", std::string()).empty()); + UNSCOPED_INFO("the folder's"); + CHECK(offered("e", std::string()) == Names{ "lib/", "main.lsl", "notes.txt" }); + UNSCOPED_INFO("in a folder under it"); + CHECK(offered("edit", "lib/u") == Names{ "lib/util.luau" }); + UNSCOPED_INFO("by the start of a name"); + CHECK(offered("r", "ma") == Names{ "main.lsl" }); + UNSCOPED_INFO("after :w"); + CHECK(offered("w", "n") == Names{ "notes.txt" }); + UNSCOPED_INFO("hidden where a dot is typed"); + CHECK(offered("e", ".") == Names{ ".hidden" }); + UNSCOPED_INFO("where a whole path says"); + CHECK(offered("tabe", folder + "/li") == Names{ folder + "/lib/" }); + UNSCOPED_INFO("not after anything else"); + REQUIRE(offered("q", std::string()).empty()); } - template<> template<> - void alscriptstudiovim_object::test<14>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: the quickfix and location commands step through the Problems tab", "[alscriptstudiovim]") { - set_test_name("the Problems tab is vim's quickfix and location lists: :cn and :cp step, :cc by number, :cfirst, :clast, :copen, :cclose"); make(); Doc& a = tab("a"); ALVimKeymap* said = vimOver(a); ex(a, "cn"); - ensure_equals("none: said", said->message(), std::string("VimNoErrors")); - ensure("nothing run", ran.empty()); + UNSCOPED_INFO("none: said"); + CHECK(said->message() == std::string("VimNoErrors")); + UNSCOPED_INFO("nothing run"); + REQUIRE(ran.empty()); problemsThere = true; - ensure(":cn, :cnext 2, :lne", ex(a, "cn") && ex(a, "cnext", "2") && ex(a, "lne")); - ensure("each a step", ran == Names(4, "next_problem")); + { + INFO(":cn, :cnext 2, :lne"); + CHECK(ex(a, "cn")); + CHECK(ex(a, "cnext", "2")); + CHECK(ex(a, "lne")); + } + UNSCOPED_INFO("each a step"); + CHECK(ran == Names(4, "next_problem")); ran.clear(); - ensure(":cp, :cN, :lprevious 2", ex(a, "cp") && ex(a, "cN") && ex(a, "lprevious", "2")); - ensure("each a step back", ran == Names(4, "previous_problem")); + { + INFO(":cp, :cN, :lprevious 2"); + CHECK(ex(a, "cp")); + CHECK(ex(a, "cN")); + CHECK(ex(a, "lprevious", "2")); + } + UNSCOPED_INFO("each a step back"); + CHECK(ran == Names(4, "previous_problem")); ex(a, "cn", "x"); - ensure_equals("a count that is none", said->message(), std::string("VimBadArgument")); + UNSCOPED_INFO("a count that is none"); + CHECK(said->message() == std::string("VimBadArgument")); for (const auto& [name, args] : { std::pair{ "cc", "3" }, std::pair{ "cc", "" }, std::pair{ "ll", "2" }, std::pair{ "cfirst", "" }, std::pair{ "cr", "" }, std::pair{ "lfir", "" }, std::pair{ "clast", "" }, std::pair{ "lla", "" } }) { - ensure(name, ex(a, name, args)); + UNSCOPED_INFO(name); + REQUIRE(ex(a, name, args)); } - ensure("by number: 0 at the caret, 1 the first, -1 the last", - studio.problemNumbers == std::vector{ 3, 0, 2, 1, 1, 1, -1, -1 }); + UNSCOPED_INFO("by number: 0 at the caret, 1 the first, -1 the last"); + CHECK(studio.problemNumbers == std::vector{ 3, 0, 2, 1, 1, 1, -1, -1 }); studio.hasProblems = false; ex(a, "cc", "1"); - ensure_equals("none to go to: said", said->message(), std::string("VimNoErrors")); + UNSCOPED_INFO("none to go to: said"); + CHECK(said->message() == std::string("VimNoErrors")); ran.clear(); ex(a, "copen"); - ensure(":copen shows the tab", ran == Names{ "problems" } && problemsShown); + { + INFO(":copen shows the tab"); + CHECK(ran == Names{ "problems" }); + CHECK(problemsShown); + } ex(a, "cw"); - ensure("shown already: left", ran.size() == 1); + UNSCOPED_INFO("shown already: left"); + REQUIRE(ran.size() == 1); ex(a, "ccl"); - ensure(":cclose folds it", ran.size() == 2 && !problemsShown); + { + INFO(":cclose folds it"); + REQUIRE(ran.size() == 2); + CHECK_FALSE(problemsShown); + } ex(a, "lcl"); - ensure("folded already: left", ran.size() == 2); + UNSCOPED_INFO("folded already: left"); + REQUIRE(ran.size() == 2); ex(a, "clist"); - ensure(":clist shows it", problemsShown); + UNSCOPED_INFO(":clist shows it"); + CHECK(problemsShown); } - template<> template<> - void alscriptstudiovim_object::test<15>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: vim's jumps and keys and :file and listings go through the window", "[alscriptstudiovim]") { - set_test_name("vim's jumps are the window's to go back to; Ctrl-O, Ctrl-I, K, :tag and :pop through the table; :file; lists to Output"); make(); Doc& a = tab("a", "one\ntwo\nthree\nfour"); ALVimKeymap* said = vimOver(a); @@ -773,78 +986,125 @@ namespace tut said->hooks().jumped(*a.expandedEditor, ALTextPos(1, 0)); navigation->unit.goBack(false); navigation->unit.goBack(false); - ensure("a jump kept where it began, in the view it was in", navigation->shown == Names{ "a expanded 1", "a 2" }); + UNSCOPED_INFO("a jump kept where it began, in the view it was in"); + CHECK(navigation->shown == Names{ "a expanded 1", "a 2" }); - ensure("Ctrl-O, Ctrl-I, K", said->hooks().command(*a.editor, "back", std::string()) && - said->hooks().command(*a.editor, "forward", std::string()) && - said->hooks().command(*a.editor, "reference", std::string())); - ensure(":tag, :pop", ex(a, "tag") && ex(a, "po")); - ensure("each its command", ran == Names{ "back", "forward", "reference", "go_to_definition", "back" }); + { + INFO("Ctrl-O, Ctrl-I, K"); + REQUIRE(said->hooks().command(*a.editor, "back", std::string())); + REQUIRE(said->hooks().command(*a.editor, "forward", std::string())); + CHECK(said->hooks().command(*a.editor, "reference", std::string())); + } + { + INFO(":tag, :pop"); + CHECK(ex(a, "tag")); + CHECK(ex(a, "po")); + } + UNSCOPED_INFO("each its command"); + CHECK(ran == Names{ "back", "forward", "reference", "go_to_definition", "back" }); ex(a, "tag", "llSay"); - ensure_equals("a name to go to is not taken", said->message(), std::string("VimBadArgument")); + UNSCOPED_INFO("a name to go to is not taken"); + CHECK(said->message() == std::string("VimBadArgument")); a.editor->setCaret(ALTextPos(1, 0)); ex(a, "file"); - ensure_equals(":file", said->message(), std::string("VimFileInfo [LINES]=4 [NAME]=a [PERCENT]=50 [QUOTED]=\"a\" [STATE]=")); - ensure("not as an error", !said->messageIsError()); + UNSCOPED_INFO(":file"); + CHECK(said->message() == std::string("VimFileInfo [LINES]=4 [NAME]=a [PERCENT]=50 [QUOTED]=\"a\" [STATE]=")); + UNSCOPED_INFO("not as an error"); + CHECK_FALSE(said->messageIsError()); a.editor->insertText("!"); ex(a, "f"); - ensure_equals("unsaved", said->message(), std::string("VimFileInfo [LINES]=4 [NAME]=a [PERCENT]=50 [QUOTED]=\"a\" [STATE]=VimStateModified ")); + UNSCOPED_INFO("unsaved"); + CHECK(said->message() == std::string("VimFileInfo [LINES]=4 [NAME]=a [PERCENT]=50 [QUOTED]=\"a\" [STATE]=VimStateModified ")); said->hooks().listing(*a.editor, "mark line col file/text"); - ensure("a listing to Output", - studio.entries.size() == 1 && studio.entries[0].text == "mark line col file/text" && studio.outputShown == 1); + { + INFO("a listing to Output"); + REQUIRE(studio.entries.size() == 1); + CHECK(studio.entries[0].text == "mark line col file/text"); + CHECK(studio.outputShown == 1); + } } - template<> template<> - void alscriptstudiovim_object::test<16>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: :find opens an include or else a file as :e would or says it is nowhere", "[alscriptstudiovim]") { - set_test_name(":find opens an include or a module the script names, else a file as :e finds one, else says it is nowhere"); make(); files(); Doc& a = tab("a"); ALVimKeymap* said = vimOver(a); studio.included = { "lib/util.lsl" }; - ensure("taken", ex(a, "find", "lib/util.lsl")); - ensure("the include, by the name written", studio.includedAsked == Names{ "lib/util.lsl" } && studio.openedFiles.empty()); + UNSCOPED_INFO("taken"); + CHECK(ex(a, "find", "lib/util.lsl")); + { + INFO("the include, by the name written"); + CHECK(studio.includedAsked == Names{ "lib/util.lsl" }); + REQUIRE(studio.openedFiles.empty()); + } ex(a, "fin", "main.lsl"); - ensure("not an include: a file where :e would find it", - studio.openedFiles.size() == 1 && studio.openedFiles.back().first == in("main.lsl")); + { + INFO("not an include: a file where :e would find it"); + REQUIRE(studio.openedFiles.size() == 1); + CHECK(studio.openedFiles.back().first == in("main.lsl")); + } ex(a, "tabfind", "nowhere.lsl"); - ensure_equals("nowhere", said->message(), std::string("VimNotInPath [NAME]=nowhere.lsl")); + UNSCOPED_INFO("nowhere"); + CHECK(said->message() == std::string("VimNotInPath [NAME]=nowhere.lsl")); ex(a, "find"); - ensure_equals("a name wanted", said->message(), std::string("VimArgumentRequired")); + UNSCOPED_INFO("a name wanted"); + CHECK(said->message() == std::string("VimArgumentRequired")); } - template<> template<> - void alscriptstudiovim_object::test<17>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: :set spell and :set list and z= and gO go through the window", "[alscriptstudiovim]") { - set_test_name(":set spell and :set list are the window's; z= picks from a list over the editor; gO the symbols"); make(); Doc& a = tab("a"); ALVimKeymap* said = vimOver(a); - ensure(":set spell", ex(a, "set", "spell") && spellCheck && ran == Names{ "spell_check" }); - ensure("on already: left", ex(a, "set", "spell") && ran.size() == 1); - ensure(":set nospell", ex(a, "set", "nospell") && !spellCheck); - ensure(":set list, :set nolist", ex(a, "set", "list") && ex(a, "set", "nolist")); - ensure("the blanks all, then none", ran == Names{ "spell_check", "spell_check", "blanks_all", "blanks_none" }); + { + INFO(":set spell"); + CHECK(ex(a, "set", "spell")); + CHECK(spellCheck); + CHECK(ran == Names{ "spell_check" }); + } + { + INFO("on already: left"); + CHECK(ex(a, "set", "spell")); + REQUIRE(ran.size() == 1); + } + { + INFO(":set nospell"); + CHECK(ex(a, "set", "nospell")); + CHECK_FALSE(spellCheck); + } + { + INFO(":set list, :set nolist"); + CHECK(ex(a, "set", "list")); + CHECK(ex(a, "set", "nolist")); + } + UNSCOPED_INFO("the blanks all, then none"); + CHECK(ran == Names{ "spell_check", "spell_check", "blanks_all", "blanks_none" }); std::vector chose; said->hooks().pick(*a.editor, "teh", { "the", "ten" }, [&chose](size_t index) { chose.push_back(index); }); - ensure("offered, in order", studio.offered == Names{ "0", "1" }); - ensure_equals("asking of the word", studio.asking, std::string("VimSuggestPlaceholder")); - ensure_equals("as tall as they are", studio.pickRows, 2); + UNSCOPED_INFO("offered, in order"); + CHECK(studio.offered == Names{ "0", "1" }); + UNSCOPED_INFO("asking of the word"); + CHECK(studio.asking == std::string("VimSuggestPlaceholder")); + UNSCOPED_INFO("as tall as they are"); + CHECK(studio.pickRows == 2); studio.pick("1"); - ensure("the one picked", chose == std::vector{ 1 }); + UNSCOPED_INFO("the one picked"); + CHECK(chose == std::vector{ 1 }); ran.clear(); - ensure("gO", said->hooks().command(*a.editor, "go_to_symbol", std::string()) && ran == Names{ "go_to_symbol" }); + { + INFO("gO"); + CHECK(said->hooks().command(*a.editor, "go_to_symbol", std::string())); + CHECK(ran == Names{ "go_to_symbol" }); + } } - template<> template<> - void alscriptstudiovim_object::test<18>() + TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: the vimrc sets the window's toggles and each editor and reports the rest", "[alscriptstudiovim]") { - set_test_name("the vimrc read into the window's vim: the window's options through its toggles, each editor's set on it, what it did not take to Output"); make(); bool wrapped = false; commands.add( @@ -856,34 +1116,77 @@ namespace tut nullptr, [&wrapped]() { return wrapped; }); Doc& a = tab("a"); studio.vimrcText = "set nu wrap ts=2 et\nlet mapleader = ','\ninoremap jk \nbogus\n"; - ensure("not read yet", !vim->sourced()); + UNSCOPED_INFO("not read yet"); + CHECK_FALSE(vim->sourced()); vim->source(); - ensure("read", vim->sourced() && lineNumbers && wrapped); - ensure("the window's editors told", studio.editorsRefreshed == 1); + { + INFO("read"); + CHECK(vim->sourced()); + CHECK(lineNumbers); + CHECK(wrapped); + } + UNSCOPED_INFO("the window's editors told"); + CHECK(studio.editorsRefreshed == 1); const ALVimMappings& maps = vim->shared().mappings; - ensure("its mapping, and its leader", maps.match(ALVimMappings::INSERT, maps.keysOf("jk"), true).full && maps.leader() == ","); - ensure("what it did not take in the Output tab, not brought up", !studio.entries.empty() && - studio.entries.back().text.find("line 4:") != std::string::npos && - studio.entries.back().text.find("the vimrc") != std::string::npos && - studio.outputShown == 0); + { + INFO("its mapping, and its leader"); + REQUIRE(maps.match(ALVimMappings::INSERT, maps.keysOf("jk"), true).full); + CHECK(maps.leader() == ","); + } + { + INFO("what it did not take in the Output tab, not brought up"); + REQUIRE_FALSE(studio.entries.empty()); + REQUIRE(studio.entries.back().text.find("line 4:") != std::string::npos); + REQUIRE(studio.entries.back().text.find("the vimrc") != std::string::npos); + CHECK(studio.outputShown == 0); + } vim->applyViewOptions(*a.editor); - ensure("each editor's own set on it", a.editor->getTabWidth() == 2 && a.editor->getSoftTabs()); + { + INFO("each editor's own set on it"); + REQUIRE(a.editor->getTabWidth() == 2); + CHECK(a.editor->getSoftTabs()); + } // :set's ? shown, and the toggles. ALVimKeymap* said = vimOver(a); - ensure(":set nu?", ex(a, "set", "nu?") && said->message() == " number"); - ensure(":set invwrap", ex(a, "set", "invwrap") && !wrapped); + { + INFO(":set nu?"); + CHECK(ex(a, "set", "nu?")); + CHECK(said->message() == " number"); + } + { + INFO(":set invwrap"); + CHECK(ex(a, "set", "invwrap")); + CHECK_FALSE(wrapped); + } // :source reads it again, or a tab as it; :e $MYVIMRC opens it. studio.vimrcText = "nnoremap Q gq\n"; - ensure(":so", ex(a, "so") && maps.match(ALVimMappings::NORMAL, maps.keysOf("Q"), true).full && - !maps.match(ALVimMappings::INSERT, maps.keysOf("jk"), true).full); + { + INFO(":so"); + CHECK(ex(a, "so")); + REQUIRE(maps.match(ALVimMappings::NORMAL, maps.keysOf("Q"), true).full); + REQUIRE_FALSE(maps.match(ALVimMappings::INSERT, maps.keysOf("jk"), true).full); + } type(a, "\nbad line"); const bool read = ex(a, "source", "%"); const std::string& entry = studio.entries.back().text; - ensure(":so % reads the tab, and brings up what it did not take", - read && studio.outputShown == 1 && entry.find("line 2:") != std::string::npos && entry.find("the vimrc") == std::string::npos); - ensure(":e $MYVIMRC", ex(a, "e", "$MYVIMRC") && studio.vimrcEdited == 1); - ensure(":so of a file that is not there", ex(a, "so", "nowhere.vim") && said->messageIsError()); + { + INFO(":so % reads the tab, and brings up what it did not take"); + CHECK(read); + CHECK(studio.outputShown == 1); + REQUIRE(entry.find("line 2:") != std::string::npos); + REQUIRE(entry.find("the vimrc") == std::string::npos); + } + { + INFO(":e $MYVIMRC"); + CHECK(ex(a, "e", "$MYVIMRC")); + CHECK(studio.vimrcEdited == 1); + } + { + INFO(":so of a file that is not there"); + CHECK(ex(a, "so", "nowhere.vim")); + CHECK(said->messageIsError()); + } } } diff --git a/indra/newview/tests/alscriptstudioweighing_test.cpp b/indra/newview/tests/alscriptstudioweighing_test.cpp index 1d5a4e7c8c..71c0e2573a 100644 --- a/indra/newview/tests/alscriptstudioweighing_test.cpp +++ b/indra/newview/tests/alscriptstudioweighing_test.cpp @@ -30,7 +30,7 @@ #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include namespace { @@ -80,7 +80,7 @@ namespace } } -namespace tut +namespace { struct alscriptstudioweighing_data { @@ -93,7 +93,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } unit = std::make_unique(services, studio, studio, studio); return *unit; @@ -129,125 +129,185 @@ namespace tut } }; - typedef test_group alscriptstudioweighing_group; - typedef alscriptstudioweighing_group::object alscriptstudioweighing_object; - alscriptstudioweighing_group alscriptstudioweighing_instance("alscriptstudioweighing"); - - template<> template<> - void alscriptstudioweighing_object::test<1>() + TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: the target a tab is weighed for and none where it has no weigher", "[alscriptstudioweighing]") { - set_test_name("the target a tab is weighed for, none where it is not; and the others while it is in front and the Weights tab looked at"); ALScriptStudioWeighing& unit = make(); - ensure("Mono", unit.target(tab("mono", "x")) == Target::Mono); - ensure("no target said is Mono", unit.target(tab("none", "x", "")) == Target::Mono); - ensure("LSO", unit.target(tab("lso", "x", "lsl2")) == Target::LSO); - ensure("LSL on Luau", unit.target(tab("ll", "x", "lsl-luau")) == Target::LSLLuau); - ensure("SLua", unit.target(tab("slua", "x", "luau")) == Target::SLua); - ensure("a target with no weigher", !unit.target(tab("odd", "x", "something"))); + UNSCOPED_INFO("Mono"); + CHECK(unit.target(tab("mono", "x")) == Target::Mono); + UNSCOPED_INFO("no target said is Mono"); + CHECK(unit.target(tab("none", "x", "")) == Target::Mono); + UNSCOPED_INFO("LSO"); + CHECK(unit.target(tab("lso", "x", "lsl2")) == Target::LSO); + UNSCOPED_INFO("LSL on Luau"); + CHECK(unit.target(tab("ll", "x", "lsl-luau")) == Target::LSLLuau); + UNSCOPED_INFO("SLua"); + CHECK(unit.target(tab("slua", "x", "luau")) == Target::SLua); + UNSCOPED_INFO("a target with no weigher"); + REQUIRE_FALSE(unit.target(tab("odd", "x", "something"))); Doc& note = tab("note", "x"); note.notecard = true; - ensure("a notecard", !unit.target(note)); + UNSCOPED_INFO("a notecard"); + REQUIRE_FALSE(unit.target(note)); Doc& loading = tab("loading", "x"); loading.loaded = false; - ensure("not loaded", !unit.target(loading)); + UNSCOPED_INFO("not loaded"); + REQUIRE_FALSE(unit.target(loading)); studio.fragment = true; - ensure("a fragment", !unit.target(tab("fragment", "x"))); + UNSCOPED_INFO("a fragment"); + REQUIRE_FALSE(unit.target(tab("fragment", "x"))); studio.fragment = false; services.front = 0; - ensure("its own alone", unit.targets(*services.docs[0]).size() == 1); + UNSCOPED_INFO("its own alone"); + REQUIRE(unit.targets(*services.docs[0]).size() == 1); studio.shown = true; const std::vector all = unit.targets(*services.docs[0]); - ensure("in front, the tab looked at: the other two as well", all.size() == 3 && all[0] == Target::Mono); - ensure("not in front: its own", unit.targets(*services.docs[2]).size() == 1); + { + INFO("in front, the tab looked at: the other two as well"); + REQUIRE(all.size() == 3); + CHECK(all[0] == Target::Mono); + } + UNSCOPED_INFO("not in front: its own"); + REQUIRE(unit.targets(*services.docs[2]).size() == 1); services.front = 4; - ensure("SLua has no others", unit.targets(*services.docs[4]).size() == 1); + UNSCOPED_INFO("SLua has no others"); + REQUIRE(unit.targets(*services.docs[4]).size() == 1); } - template<> template<> - void alscriptstudioweighing_object::test<2>() + TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: a weight with its check is kept and told and an older answer dropped", "[alscriptstudioweighing]") { - set_test_name("weighed with its check: kept, told, and exact where nothing after the check changes it; an answer for older text dropped"); ALScriptStudioWeighing& unit = make(); Doc& a = tab("a", "default {}"); unit.weigh(a); - ensure("asked", a.weighing->asking && studio.asked == Names{ "a" }); + { + INFO("asked"); + CHECK(a.weighing->asking); + CHECK(studio.asked == Names{ "a" }); + } ALScriptAnalysis::Result old = answerFor(a, { weightOf(Target::Mono, 100) }); old.version -= 1; unit.weighed(a, old); - ensure("older: dropped", !a.weighing->asking && !a.weighing->weight && a.weighing->all.empty()); + { + INFO("older: dropped"); + REQUIRE_FALSE(a.weighing->asking); + REQUIRE_FALSE(a.weighing->weight); + REQUIRE(a.weighing->all.empty()); + } unit.weighed(a, answerFor(a, { weightOf(Target::Mono, 100), weightOf(Target::LSO, 200) })); - ensure("kept, its own first", a.weighing->weight && a.weighing->weight->total == 100 && a.weighing->all.size() == 2 && - a.weighing->allVersion == versionOf(a) && a.weighing->version == versionOf(a)); - ensure("exact: no optimizer after the check", a.weighing->exact && !a.weighing->sent); - ensure("the Problems and the save told", studio.problems == Names{ "a" } && studio.warned == Names{ "a" }); + { + INFO("kept, its own first"); + REQUIRE(a.weighing->weight); + REQUIRE(a.weighing->weight->total == 100); + REQUIRE(a.weighing->all.size() == 2); + REQUIRE(a.weighing->allVersion == versionOf(a)); + CHECK(a.weighing->version == versionOf(a)); + } + { + INFO("exact: no optimizer after the check"); + REQUIRE(a.weighing->exact); + CHECK_FALSE(a.weighing->sent); + } + { + INFO("the Problems and the save told"); + CHECK(studio.problems == Names{ "a" }); + CHECK(studio.warned == Names{ "a" }); + } studio.preprocessing = true; studio.optimizer = true; unit.weighed(a, answerFor(a, { weightOf(Target::Mono, 90) })); - ensure("the optimizer after the check: not exact", !a.weighing->exact && a.weighing->weight->total == 90); + { + INFO("the optimizer after the check: not exact"); + REQUIRE_FALSE(a.weighing->exact); + CHECK(a.weighing->weight->total == 90); + } Doc& none = tab("none", "x"); none.notecard = true; none.weighing->weight = weightOf(Target::Mono, 1); unit.weigh(none); - ensure("nothing to weigh it for: its weight let go, nothing asked", !none.weighing->weight && studio.asked.size() == 1); + { + INFO("nothing to weigh it for: its weight let go, nothing asked"); + REQUIRE_FALSE(none.weighing->weight); + REQUIRE(studio.asked.size() == 1); + } } - template<> template<> - void alscriptstudioweighing_object::test<3>() + TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: a sent text's weight stands over the check's of the same text", "[alscriptstudioweighing]") { - set_test_name("what a save sends weighed as sent, which stands over the check's of the same text; an answer for older text dropped"); ALScriptStudioWeighing& unit = make(); Doc& a = tab("a", "default {}"); unit.weighSent(a); - ensure("nothing sent yet: nothing asked", studio.requests.empty()); + UNSCOPED_INFO("nothing sent yet: nothing asked"); + REQUIRE(studio.requests.empty()); a.uploaded.valid = true; a.uploaded.version = versionOf(a); a.uploaded.text = std::make_shared("sent text"); unit.weighSent(a); - ensure("asked of what was sent, for its own target", studio.requests.size() == 1 && *studio.requests[0].text == "sent text" && - studio.requests[0].targets == std::vector{ Target::Mono }); + { + INFO("asked of what was sent, for its own target"); + REQUIRE(studio.requests.size() == 1); + CHECK(*studio.requests[0].text == "sent text"); + CHECK(studio.requests[0].targets == std::vector{ Target::Mono }); + } studio.answers[0](answerFor(a, { weightOf(Target::Mono, 300) })); - ensure("kept as sent, and exact", a.weighing->weight && a.weighing->weight->total == 300 && a.weighing->sent && a.weighing->exact); - ensure("told", studio.problems == Names{ "a" } && studio.warned == Names{ "a" }); + { + INFO("kept as sent, and exact"); + REQUIRE(a.weighing->weight); + REQUIRE(a.weighing->weight->total == 300); + REQUIRE(a.weighing->sent); + CHECK(a.weighing->exact); + } + { + INFO("told"); + CHECK(studio.problems == Names{ "a" }); + CHECK(studio.warned == Names{ "a" }); + } unit.weighed(a, answerFor(a, { weightOf(Target::Mono, 100) })); - ensure("the check's of the same text does not replace it", a.weighing->weight->total == 300 && a.weighing->all.size() == 1); + { + INFO("the check's of the same text does not replace it"); + REQUIRE(a.weighing->weight->total == 300); + REQUIRE(a.weighing->all.size() == 1); + } a.uploaded.disabled = true; unit.weighSent(a); - ensure("the preprocessor off: the text as written", *studio.requests[1].text == "default {}"); + UNSCOPED_INFO("the preprocessor off: the text as written"); + CHECK(*studio.requests[1].text == "default {}"); a.editor->setCaret(a.editor->document().end()); a.editor->insertText(" "); ALScriptAnalysis::Result late = answerFor(a, { weightOf(Target::Mono, 1) }); late.version -= 1; studio.answers[1](late); - ensure("typed on since: dropped", a.weighing->weight->total == 300); + UNSCOPED_INFO("typed on since: dropped"); + CHECK(a.weighing->weight->total == 300); } - template<> template<> - void alscriptstudioweighing_object::test<4>() + TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: the saved text's weight is kept target by target for the change column", "[alscriptstudioweighing]") { - set_test_name("what the text weighs while it is the text saved is kept for the change column, target by target"); ALScriptStudioWeighing& unit = make(); Doc& a = tab("a", "default {}"); a.weighing->all = { weightOf(Target::Mono, 100), weightOf(Target::LSO, 200) }; a.weighing->allVersion = versionOf(a); unit.keepSaved(a); - ensure("kept", a.weighing->saved.size() == 2); + UNSCOPED_INFO("kept"); + REQUIRE(a.weighing->saved.size() == 2); a.weighing->all = { weightOf(Target::Mono, 150) }; unit.keepSaved(a); - ensure("each target's replaced, the others kept", a.weighing->saved.size() == 2 && a.weighing->saved[0].total == 150 && - a.weighing->saved[1].total == 200); + { + INFO("each target's replaced, the others kept"); + REQUIRE(a.weighing->saved.size() == 2); + REQUIRE(a.weighing->saved[0].total == 150); + CHECK(a.weighing->saved[1].total == 200); + } a.editor->setCaret(a.editor->document().end()); a.editor->insertText(" "); a.weighing->allVersion = versionOf(a); a.weighing->all = { weightOf(Target::Mono, 1) }; unit.keepSaved(a); - ensure("not saved: nothing kept", a.weighing->saved[0].total == 150); + UNSCOPED_INFO("not saved: nothing kept"); + CHECK(a.weighing->saved[0].total == 150); } - template<> template<> - void alscriptstudioweighing_object::test<5>() + TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: a weight shows each part's bytes and each line's heat in the editor", "[alscriptstudioweighing]") { - set_test_name("a weight shown in the editor: each part's bytes after its line, each line's heat; neither where it is off or out of date"); ALScriptStudioWeighing& unit = make(); Doc& a = tab("a", "integer f() { return 1; }\ndefault {}\n"); ALScriptWeight weight = weightOf(Target::Mono, 100); @@ -265,42 +325,57 @@ namespace tut a.weighing->version = versionOf(a); a.weighing->exact = true; unit.showInEditor(a); - ensure("its part's bytes after its line", a.editor->noteAt(0).find("WeightNote") != std::string::npos); - ensure("the included file's own not", a.editor->noteAt(1).empty()); - ensure("the warmest line the heat's own colour", a.editor->heatAt(0) == 1.f); - ensure_equals("a quarter as warm by bytes, half by their square root", a.editor->heatAt(1), 0.5f); + UNSCOPED_INFO("its part's bytes after its line"); + REQUIRE(a.editor->noteAt(0).find("WeightNote") != std::string::npos); + UNSCOPED_INFO("the included file's own not"); + REQUIRE(a.editor->noteAt(1).empty()); + UNSCOPED_INFO("the warmest line the heat's own colour"); + CHECK(a.editor->heatAt(0) == 1.f); + UNSCOPED_INFO("a quarter as warm by bytes, half by their square root"); + CHECK(a.editor->heatAt(1) == 0.5f); studio.notes = false; unit.showInEditor(a); - ensure("notes off: gone, the heat kept", a.editor->noteAt(0).empty() && a.editor->heatAt(0) == 1.f); + { + INFO("notes off: gone, the heat kept"); + REQUIRE(a.editor->noteAt(0).empty()); + CHECK(a.editor->heatAt(0) == 1.f); + } studio.heat = false; unit.showInEditor(a); - ensure("heat off: gone", a.editor->heatAt(0) == 0.f); + UNSCOPED_INFO("heat off: gone"); + CHECK(a.editor->heatAt(0) == 0.f); studio.notes = true; studio.heat = true; a.weighing->version -= 1; unit.showInEditor(a); - ensure("out of date: nothing new said", a.editor->noteAt(0).empty() && a.editor->heatAt(0) == 0.f); + { + INFO("out of date: nothing new said"); + REQUIRE(a.editor->noteAt(0).empty()); + CHECK(a.editor->heatAt(0) == 0.f); + } } - template<> template<> - void alscriptstudioweighing_object::test<6>() + TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: a save's size is measured once a text and not for a file on disk", "[alscriptstudioweighing]") { - set_test_name("what a save would send, measured once for each text: a script's, a notecard's, nothing for a file on disk"); ALScriptStudioWeighing& unit = make(); Doc& a = tab("a", "default {}"); unit.measureAsset(a); - ensure_equals("the script's text", a.weighing->assetBytes, size_t(10)); + UNSCOPED_INFO("the script's text"); + CHECK(a.weighing->assetBytes == size_t(10)); a.weighing->assetBytes = 0; unit.measureAsset(a); - ensure("measured once for a text", a.weighing->assetBytes == 0); + UNSCOPED_INFO("measured once for a text"); + CHECK(a.weighing->assetBytes == 0); Doc& n = tab("n", "note text"); n.notecard = true; unit.measureAsset(n); - ensure_equals("a notecard's", n.weighing->assetBytes, size_t(9)); + UNSCOPED_INFO("a notecard's"); + CHECK(n.weighing->assetBytes == size_t(9)); Doc& f = tab("f", "file text"); f.file = "/somewhere/f.lsl"; unit.measureAsset(f); - ensure_equals("a file on disk has no limit", f.weighing->assetBytes, size_t(0)); + UNSCOPED_INFO("a file on disk has no limit"); + CHECK(f.weighing->assetBytes == size_t(0)); // Preprocessed: the envelope a save would send, measured as long as // it would be made. Doc& p = tab("p", "#define X 1\ndefault { /* x */ }"); @@ -310,13 +385,12 @@ namespace tut p.expanded.generation = 1; p.expanded.text = std::make_shared("default { }\n"); unit.measureAsset(p); - ensure_equals("the envelope's length", p.weighing->assetBytes, p.envelopeFor(*p.expanded.text, studio.programVersion()).wrap().size()); + UNSCOPED_INFO("the envelope's length"); + REQUIRE(p.weighing->assetBytes == p.envelopeFor(*p.expanded.text, studio.programVersion()).wrap().size()); } - template<> template<> - void alscriptstudioweighing_object::test<7>() + TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: listed fixes are weighed once settled and told what each would change", "[alscriptstudioweighing]") { - set_test_name("the fixes listed weighed once the list settles, each against the text as it stands; told what each would change"); ALScriptStudioWeighing& unit = make(); Doc& a = tab("a", "integer a = 1\n"); ALCodeEditor& e = *a.editor; @@ -340,27 +414,41 @@ namespace tut e.setFixesShown([&unit, &a](U32 shown, const std::vector& fixes) { unit.fixesShown(a.id, shown, fixes); }); e.setFixable(0, true, true); e.setFocus(true); - ensure("listed", e.handleKeyHere('.', MASK_CONTROL) && e.fixesOpen()); + { + INFO("listed"); + CHECK(e.handleKeyHere('.', MASK_CONTROL)); + CHECK(e.fixesOpen()); + } unit.pump(); - ensure_equals("weighed: the text, and each fix's copy but the suppression's", studio.requests.size(), size_t(1)); + UNSCOPED_INFO("weighed: the text, and each fix's copy but the suppression's"); + REQUIRE(studio.requests.size() == size_t(1)); const ALScriptAnalysis::Request& request = studio.requests[0]; - ensure("the text first, then the copies", request.variants.size() == 3 && request.variants[0] == "integer a = 1\n" && - request.variants[1] == "integer a = 1;\n" && request.variants[2] == "integer b = 1\n"); + { + INFO("the text first, then the copies"); + REQUIRE(request.variants.size() == 3); + CHECK(request.variants[0] == "integer a = 1\n"); + CHECK(request.variants[1] == "integer a = 1;\n"); + CHECK(request.variants[2] == "integer b = 1\n"); + } ALScriptAnalysis::Result result; result.id = a.id; result.version = versionOf(a); result.variantTotals = { 100, 90, 100 }; studio.answers[0](result); - ensure("the lighter one said", e.fixes()[0].note.find("FixLighterEstimate") == 0); - ensure("the same: nothing said", e.fixes()[1].note.empty() && e.fixes()[2].note.empty()); + UNSCOPED_INFO("the lighter one said"); + CHECK(e.fixes()[0].note.find("FixLighterEstimate") == 0); + { + INFO("the same: nothing said"); + REQUIRE(e.fixes()[1].note.empty()); + REQUIRE(e.fixes()[2].note.empty()); + } unit.pump(); - ensure("weighed once", studio.requests.size() == 1); + UNSCOPED_INFO("weighed once"); + REQUIRE(studio.requests.size() == 1); } - template<> template<> - void alscriptstudioweighing_object::test<8>() + TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: the tab in front is weighed once for the targets it lacks", "[alscriptstudioweighing]") { - set_test_name("while the Weights tab is looked at, the tab in front checked as it stands is weighed for the targets it lacks, once"); ALScriptStudioWeighing& unit = make(); Doc& a = tab("a", "default {}"); services.front = 0; @@ -370,23 +458,28 @@ namespace tut a.weighing->allVersion = versionOf(a); a.weighing->askedFor = versionOf(a); unit.pump(); - ensure("the others wanted: weighed", studio.asked == Names{ "a" } && a.weighing->asking); + { + INFO("the others wanted: weighed"); + CHECK(studio.asked == Names{ "a" }); + CHECK(a.weighing->asking); + } unit.pump(); - ensure("once, while it is asked", studio.asked.size() == 1); + UNSCOPED_INFO("once, while it is asked"); + REQUIRE(studio.asked.size() == 1); a.weighing->asking = false; a.weighing->all = { weightOf(Target::Mono, 1), weightOf(Target::LSO, 2), weightOf(Target::LSLLuau, 3) }; unit.pump(); - ensure("all there: nothing more", studio.asked.size() == 1); + UNSCOPED_INFO("all there: nothing more"); + REQUIRE(studio.asked.size() == 1); studio.shown = false; a.weighing->all.clear(); unit.pump(); - ensure("not looked at: nothing", studio.asked.size() == 1); + UNSCOPED_INFO("not looked at: nothing"); + REQUIRE(studio.asked.size() == 1); } - template<> template<> - void alscriptstudioweighing_object::test<9>() + TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: a tab come to the front unweighed is weighed once for its text", "[alscriptstudioweighing]") { - set_test_name("a tab come to the front, checked but not weighed with it, is weighed once for its text; one asked for an older text is not waited on"); ALScriptStudioWeighing& unit = make(); Doc& a = tab("a", "default {}"); Doc& b = tab("b", "default {}"); @@ -395,20 +488,29 @@ namespace tut a.weighing->askedFor = versionOf(a); services.front = 0; unit.pump(); - ensure("weighed with its check already: nothing", studio.asked.empty()); + UNSCOPED_INFO("weighed with its check already: nothing"); + REQUIRE(studio.asked.empty()); services.front = 1; unit.pump(); - ensure("come to the front: weighed", studio.asked == Names{ "b" } && ALScriptStudioWeighing::asking(b)); + { + INFO("come to the front: weighed"); + CHECK(studio.asked == Names{ "b" }); + CHECK(ALScriptStudioWeighing::asking(b)); + } unit.pump(); - ensure("once", studio.asked.size() == 1); + UNSCOPED_INFO("once"); + REQUIRE(studio.asked.size() == 1); // Typed in while it was weighed: the answer for the older text is // passed over, and the check of the new one weighs it again. b.editor->insertText("x"); - ensure("not waited on", !ALScriptStudioWeighing::asking(b)); + UNSCOPED_INFO("not waited on"); + CHECK_FALSE(ALScriptStudioWeighing::asking(b)); unit.pump(); - ensure("not before its check", studio.asked.size() == 1); + UNSCOPED_INFO("not before its check"); + REQUIRE(studio.asked.size() == 1); b.check->analysisVersion = versionOf(b); unit.pump(); - ensure("then, for the new text", studio.asked == (Names{ "b", "b" })); + UNSCOPED_INFO("then, for the new text"); + CHECK(studio.asked == (Names{ "b", "b" })); } } diff --git a/indra/newview/tests/alscriptstudiowords_test.cpp b/indra/newview/tests/alscriptstudiowords_test.cpp index d7d9d913e9..72eb1a0bd5 100644 --- a/indra/newview/tests/alscriptstudiowords_test.cpp +++ b/indra/newview/tests/alscriptstudiowords_test.cpp @@ -28,7 +28,7 @@ #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include #include @@ -72,7 +72,7 @@ namespace } } -namespace tut +namespace { struct alscriptstudiowords_data { @@ -99,7 +99,7 @@ namespace tut { if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } ALCodeEditor::Params p(LLUICtrlFactory::getDefaultParams()); p.name = "editor"; @@ -121,92 +121,143 @@ namespace tut } }; - typedef test_group alscriptstudiowords_group; - typedef alscriptstudiowords_group::object alscriptstudiowords_object; - alscriptstudiowords_group alscriptstudiowords_instance("alscriptstudiowords"); - - template<> template<> - void alscriptstudiowords_object::test<1>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: the vocabulary gives each kind's detail sorted and skips unknown groups", "[alscriptstudiowords]") { - set_test_name("the vocabulary from the definitions: each kind's detail, the deprecated marked, sorted, a group it does not know left out"); const std::vector& words = Words::vocabulary(false); - ensure_equals("six", words.size(), size_t(6)); - ensure("sorted", std::is_sorted(words.begin(), words.end(), [](const Vocab& a, const Vocab& b) { return a.text < b.text; })); + UNSCOPED_INFO("six"); + REQUIRE(words.size() == size_t(6)); + UNSCOPED_INFO("sorted"); + CHECK(std::is_sorted(words.begin(), words.end(), [](const Vocab& a, const Vocab& b) { return a.text < b.text; })); const Vocab* say = Words::word(false, "llSay"); - ensure("a function's call, with its arguments' types", say && say->kind == ALSyntaxKind::Function && - say->detail == "llSay(integer channel, string msg)"); - ensure("and what returns", Words::word(false, "llOld")->detail == "integer llOld()" && Words::word(false, "llOld")->deprecated); - ensure_equals("an event's", Words::word(false, "touch_start")->detail, std::string("touch_start(integer num_detected)")); - ensure_equals("a constant's type and value", Words::word(false, "PI")->detail, std::string("float PI = 3.14159265")); - ensure_equals("a type's tooltip's first line", Words::word(false, "integer")->detail, std::string("A whole number.")); - ensure("a control", Words::word(false, "jump")->kind == ALSyntaxKind::Control); - ensure("not a word", !Words::word(false, "x") && !Words::word(false, "") && !Words::word(false, "nothing")); - ensure_equals("SLua's () returns nothing worth saying", Words::word(true, "ll.Say")->detail, std::string("ll.Say(number channel)")); + { + INFO("a function's call, with its arguments' types"); + REQUIRE(say); + REQUIRE(say->kind == ALSyntaxKind::Function); + CHECK(say->detail == "llSay(integer channel, string msg)"); + } + { + INFO("and what returns"); + CHECK(Words::word(false, "llOld")->detail == "integer llOld()"); + CHECK(Words::word(false, "llOld")->deprecated); + } + UNSCOPED_INFO("an event's"); + CHECK(Words::word(false, "touch_start")->detail == std::string("touch_start(integer num_detected)")); + UNSCOPED_INFO("a constant's type and value"); + CHECK(Words::word(false, "PI")->detail == std::string("float PI = 3.14159265")); + UNSCOPED_INFO("a type's tooltip's first line"); + CHECK(Words::word(false, "integer")->detail == std::string("A whole number.")); + UNSCOPED_INFO("a control"); + CHECK(Words::word(false, "jump")->kind == ALSyntaxKind::Control); + { + INFO("not a word"); + REQUIRE_FALSE(Words::word(false, "x")); + REQUIRE_FALSE(Words::word(false, "")); + REQUIRE_FALSE(Words::word(false, "nothing")); + } + UNSCOPED_INFO("SLua's () returns nothing worth saying"); + CHECK(Words::word(true, "ll.Say")->detail == std::string("ll.Say(number channel)")); } - template<> template<> - void alscriptstudiowords_object::test<2>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: the vocabulary is kept until forgotten and then built again", "[alscriptstudiowords]") { - set_test_name("the vocabulary kept until forgotten, then built again from the definitions as they are, the lookup with it"); - ensure("there", Words::word(false, "llSay") != nullptr); + UNSCOPED_INFO("there"); + REQUIRE(Words::word(false, "llSay") != nullptr); lsl["functions"].erase("llSay"); lsl["functions"]["llShout"] = LLSD().with("return", ""); - ensure("kept", Words::word(false, "llSay") != nullptr && !Words::word(false, "llShout")); + { + INFO("kept"); + REQUIRE(Words::word(false, "llSay") != nullptr); + REQUIRE_FALSE(Words::word(false, "llShout")); + } Words::forget(); - ensure("built again", !Words::word(false, "llSay") && Words::word(false, "llShout") != nullptr); + { + INFO("built again"); + REQUIRE_FALSE(Words::word(false, "llSay")); + REQUIRE(Words::word(false, "llShout") != nullptr); + } viewer.slots.keywords = [](bool) { return LLSD("not a map"); }; Words::forget(); - ensure("definitions that are not: no words", Words::vocabulary(false).empty() && !Words::word(false, "llShout")); + { + INFO("definitions that are not: no words"); + REQUIRE(Words::vocabulary(false).empty()); + REQUIRE_FALSE(Words::word(false, "llShout")); + } } - template<> template<> - void alscriptstudiowords_object::test<3>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: an editor is taught each kind's table and the preprocessor's words", "[alscriptstudiowords]") { - set_test_name("an editor taught the words: each kind's table, the deprecated apart, and LSL's preprocessor words while they are on"); ALCodeEditor& e = editor("default {}", false); extra = { "switch", "case" }; Words::teach(e, false); const ALSyntaxWords& tables = e.highlighter().words(); - ensure("functions", tables.has("function", "llSay") && !tables.has("function", "llOld")); - ensure("the deprecated", tables.has("deprecated", "llOld")); - ensure("events, constants, types, controls", tables.has("event", "touch_start") && tables.has("constant", "PI") && - tables.has("type", "integer") && tables.has("control", "jump")); - ensure("the preprocessor's", tables.has("control", "switch") && tables.has("control", "case")); + { + INFO("functions"); + REQUIRE(tables.has("function", "llSay")); + REQUIRE_FALSE(tables.has("function", "llOld")); + } + UNSCOPED_INFO("the deprecated"); + REQUIRE(tables.has("deprecated", "llOld")); + { + INFO("events, constants, types, controls"); + REQUIRE(tables.has("event", "touch_start")); + REQUIRE(tables.has("constant", "PI")); + REQUIRE(tables.has("type", "integer")); + REQUIRE(tables.has("control", "jump")); + } + { + INFO("the preprocessor's"); + REQUIRE(tables.has("control", "switch")); + REQUIRE(tables.has("control", "case")); + } ALCodeEditor& s = editor("x", true); Words::teach(s, true); - ensure("SLua's own, and none of the preprocessor's", s.highlighter().words().has("function", "ll.Say") && - !s.highlighter().words().has("control", "switch")); + { + INFO("SLua's own, and none of the preprocessor's"); + REQUIRE(s.highlighter().words().has("function", "ll.Say")); + REQUIRE_FALSE(s.highlighter().words().has("control", "switch")); + } } - template<> template<> - void alscriptstudiowords_object::test<4>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: inStateBody finds a state's body past braces in strings and comments", "[alscriptstudiowords]") { - set_test_name("straight inside a state or not, braces in strings and comments passed over"); ALCodeEditor& e = editor("default\n{\n \n touch_start(integer n)\n {\n \n }\n}\n" "state /* named */ two { \"{\" // {\n \n}\n", false); - ensure("in default", Words::inStateBody(e, ALTextPos(2, 4))); - ensure("in a handler: not", !Words::inStateBody(e, ALTextPos(5, 8))); - ensure("after default: not", !Words::inStateBody(e, ALTextPos(8, 0))); - ensure("in a state named, a comment between, past a brace in a string and a comment", Words::inStateBody(e, ALTextPos(9, 2))); + UNSCOPED_INFO("in default"); + CHECK(Words::inStateBody(e, ALTextPos(2, 4))); + UNSCOPED_INFO("in a handler: not"); + CHECK_FALSE(Words::inStateBody(e, ALTextPos(5, 8))); + UNSCOPED_INFO("after default: not"); + CHECK_FALSE(Words::inStateBody(e, ALTextPos(8, 0))); + UNSCOPED_INFO("in a state named, a comment between, past a brace in a string and a comment"); + CHECK(Words::inStateBody(e, ALTextPos(9, 2))); } - template<> template<> - void alscriptstudiowords_object::test<5>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: completions fill in handlers where they go and offer snippets", "[alscriptstudiowords]") { - set_test_name("completions: a word, an event as a handler to fill in in either language; a handler only where one goes; snippets"); const ALCodeEditor::Completion lsl = Words::completionFor(*Words::word(false, "touch_start"), false); - ensure_equals("LSL's handler", lsl.snippet, std::string("touch_start(integer num_detected)\n{\n $0\n}")); + UNSCOPED_INFO("LSL's handler"); + CHECK(lsl.snippet == std::string("touch_start(integer num_detected)\n{\n $0\n}")); const ALCodeEditor::Completion slua = Words::completionFor(*Words::word(true, "touch_start"), true); - ensure_equals("SLua's, a function of LLEvents'", slua.snippet, std::string("function LLEvents.touch_start(detected)\n $0\nend")); - ensure_equals("typed where asked, as the definitions type it", Words::completionFor(*Words::word(true, "touch_start"), true, true).snippet, + UNSCOPED_INFO("SLua's, a function of LLEvents'"); + CHECK(slua.snippet == std::string("function LLEvents.touch_start(detected)\n $0\nend")); + UNSCOPED_INFO("typed where asked, as the definitions type it"); + CHECK(Words::completionFor(*Words::word(true, "touch_start"), true, true).snippet == std::string("function LLEvents.touch_start(detected: {DetectedEvent})\n $0\nend")); - ensure_equals("each parameter typed", Words::completionFor(*Words::word(true, "listen"), true, true).snippet, + UNSCOPED_INFO("each parameter typed"); + CHECK(Words::completionFor(*Words::word(true, "listen"), true, true).snippet == std::string("function LLEvents.listen(channel: number, name: string, id: uuid, msg: string)\n $0\nend")); - ensure_equals("each untyped", Words::completionFor(*Words::word(true, "listen"), true).snippet, + UNSCOPED_INFO("each untyped"); + CHECK(Words::completionFor(*Words::word(true, "listen"), true).snippet == std::string("function LLEvents.listen(channel, name, id, msg)\n $0\nend")); const ALCodeEditor::Completion say = Words::completionFor(*Words::word(false, "llSay"), false); - ensure("a function as itself", say.snippet.empty() && say.text == "llSay" && say.documentation && *say.documentation == "Says msg on channel.\nMore."); + { + INFO("a function as itself"); + REQUIRE(say.snippet.empty()); + REQUIRE(say.text == "llSay"); + REQUIRE(say.documentation); + CHECK(*say.documentation == "Says msg on channel.\nMore."); + } ALCodeEditor& e = editor("default\n{\n t\n}\nt\n", false); ALScriptSnippets::Snippet snippet; @@ -215,137 +266,201 @@ namespace tut snippet.body = "llSetTimerEvent($1);"; std::vector out; Words::complete(false, e, ALTextPos(2, 5), "t", { snippet }, "Snippet", out); - ensure("inside the state: the handler and the snippet", texts(out) == std::vector{ "touch_start", "timer" }); - ensure_equals("the snippet said so", out[1].detail, std::string("Snippet Timer")); + UNSCOPED_INFO("inside the state: the handler and the snippet"); + CHECK(texts(out) == std::vector{ "touch_start", "timer" }); + UNSCOPED_INFO("the snippet said so"); + CHECK(out[1].detail == std::string("Snippet Timer")); out.clear(); Words::complete(false, e, ALTextPos(4, 1), "t", { snippet }, "Snippet", out); - ensure("outside: no handler", texts(out) == std::vector{ "timer" }); + UNSCOPED_INFO("outside: no handler"); + CHECK(texts(out) == std::vector{ "timer" }); out.clear(); ALScriptSnippets::Snippet member = snippet; member.prefix = "ll.Snip"; Words::complete(true, e, ALTextPos(4, 1), "ll.S", { member }, "Snippet", out); - ensure("a member: the vocabulary's alone", texts(out) == std::vector{ "ll.Say" }); + UNSCOPED_INFO("a member: the vocabulary's alone"); + CHECK(texts(out) == std::vector{ "ll.Say" }); } - template<> template<> - void alscriptstudiowords_object::test<6>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: hover text names a member in full and notes the deprecated", "[alscriptstudiowords]") { - set_test_name("the hover card's words: a member asked as the whole name, a word as itself, the deprecated said; a word of the script's none"); ALCodeEditor& s = editor("ll.Say(0)\nx = math.pi\n", true); std::string text; - ensure("ll.Say under Say", Words::hoverText(true, s.document(), ALTextPos(0, 4), "Say", text) && text == "ll.Say(number channel)"); - ensure("math.pi under pi", Words::hoverText(true, s.document(), ALTextPos(1, 10), "pi", text) && text == "number math.pi()"); - ensure("a word of the script's", !Words::hoverText(true, s.document(), ALTextPos(1, 0), "x", text)); + { + INFO("ll.Say under Say"); + REQUIRE(Words::hoverText(true, s.document(), ALTextPos(0, 4), "Say", text)); + CHECK(text == "ll.Say(number channel)"); + } + { + INFO("math.pi under pi"); + CHECK(Words::hoverText(true, s.document(), ALTextPos(1, 10), "pi", text)); + CHECK(text == "number math.pi()"); + } + UNSCOPED_INFO("a word of the script's"); + CHECK_FALSE(Words::hoverText(true, s.document(), ALTextPos(1, 0), "x", text)); ALCodeEditor& e = editor("llOld()\n", false); - ensure("the deprecated", Words::hoverText(false, e.document(), ALTextPos(0, 2), "llOld", text) && - text == "integer llOld()\nGone.\n" + ALCodeEditor::deprecatedNote()); + { + INFO("the deprecated"); + CHECK(Words::hoverText(false, e.document(), ALTextPos(0, 2), "llOld", text)); + CHECK(text == "integer llOld()\nGone.\n" + ALCodeEditor::deprecatedNote()); + } } - template<> template<> - void alscriptstudiowords_object::test<7>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: the Insert menu's lists and each word's reference page", "[alscriptstudiowords]") { - set_test_name("the Insert menu's list and the reference: a word's page on the wiki, SLua's ll names too, the libraries', the portal"); ALScriptSnippets::Snippet snippet; snippet.name = "Timer"; snippet.prefix = "timer"; snippet.detail = "Every so often"; const std::vector snippets = Words::library(false, "snippet", { snippet }, "Deprecated"); - ensure("a snippet, by what it is", snippets.size() == 1 && snippets[0].value == "Timer\ntimer" && snippets[0].also == "timer"); + { + INFO("a snippet, by what it is"); + REQUIRE(snippets.size() == 1); + CHECK(snippets[0].value == "Timer\ntimer"); + CHECK(snippets[0].also == "timer"); + } const std::vector functions = Words::library(false, "function", {}, "Deprecated"); - ensure("the functions alone", functions.size() == 2 && functions[0].label == "llOld" && functions[1].label == "llSay"); - ensure("the deprecated said so, the rest by their tooltip's first line", - functions[0].detail == "Deprecated" && functions[1].detail == "Says msg on channel."); - ensure("the events", Words::library(false, "event", {}, "") .size() == 1); - - ensure_equals("an LSL name", Words::helpUrl(false, "llSay"), std::string("https://wiki.example/llSay")); - ensure_equals("SLua's ll name, as LSL's", Words::helpUrl(true, "ll.Say"), std::string("https://wiki.example/llSay")); - ensure_equals("a library's", Words::helpUrl(true, "math.pi"), std::string("https://luau.org/library")); - ensure_equals("the rest", Words::helpUrl(true, "LLEvents"), std::string("https://wiki.secondlife.com/wiki/Lua_Alpha")); - ensure_equals("nothing: the portal", Words::helpUrl(false, ""), std::string("https://wiki.example/LSL_Portal")); - ensure_equals("the reference's words", Words::referenceText(*Words::word(false, "PI"), false), + { + INFO("the functions alone"); + REQUIRE(functions.size() == 2); + CHECK(functions[0].label == "llOld"); + CHECK(functions[1].label == "llSay"); + } + { + INFO("the deprecated said so, the rest by their tooltip's first line"); + CHECK(functions[0].detail == "Deprecated"); + CHECK(functions[1].detail == "Says msg on channel."); + } + UNSCOPED_INFO("the events"); + REQUIRE(Words::library(false, "event", {}, "") .size() == 1); + + UNSCOPED_INFO("an LSL name"); + CHECK(Words::helpUrl(false, "llSay") == std::string("https://wiki.example/llSay")); + UNSCOPED_INFO("SLua's ll name, as LSL's"); + CHECK(Words::helpUrl(true, "ll.Say") == std::string("https://wiki.example/llSay")); + UNSCOPED_INFO("a library's"); + CHECK(Words::helpUrl(true, "math.pi") == std::string("https://luau.org/library")); + UNSCOPED_INFO("the rest"); + CHECK(Words::helpUrl(true, "LLEvents") == std::string("https://wiki.secondlife.com/wiki/Lua_Alpha")); + UNSCOPED_INFO("nothing: the portal"); + CHECK(Words::helpUrl(false, "") == std::string("https://wiki.example/LSL_Portal")); + UNSCOPED_INFO("the reference's words"); + CHECK(Words::referenceText(*Words::word(false, "PI"), false) == std::string("float PI = 3.14159265\n\nThe ratio.\nhttps://wiki.example/PI")); } - template<> template<> - void alscriptstudiowords_object::test<8>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: a tab's mark follows what it is and a symbol's its kind", "[alscriptstudiowords]") { - set_test_name("the marks: a tab's by what it is, a symbol's by its kind"); ALScriptStudioDoc doc; - ensure_equals("an LSL script", std::string(Words::imageNameOf(doc)), std::string("Inv_Script")); + UNSCOPED_INFO("an LSL script"); + CHECK(std::string(Words::imageNameOf(doc)) == std::string("Inv_Script")); doc.language.lua = true; - ensure_equals("an SLua one", std::string(Words::imageNameOf(doc)), std::string("Inv_Script_Luau")); + UNSCOPED_INFO("an SLua one"); + CHECK(std::string(Words::imageNameOf(doc)) == std::string("Inv_Script_Luau")); doc.notecard = true; - ensure_equals("a notecard", std::string(Words::imageNameOf(doc)), std::string("Inv_Notecard")); + UNSCOPED_INFO("a notecard"); + CHECK(std::string(Words::imageNameOf(doc)) == std::string("Inv_Notecard")); doc.file = "/a/notes.txt"; - ensure_equals("a file", std::string(Words::imageNameOf(doc)), std::string("Studio_File")); + UNSCOPED_INFO("a file"); + CHECK(std::string(Words::imageNameOf(doc)) == std::string("Studio_File")); doc.name = ".luaurc"; - ensure_equals("a config", std::string(Words::imageNameOf(doc)), std::string("Studio_Config")); - ensure_equals("a function", std::string(Words::imageNameOf(ALScriptSymbolKind::Function)), std::string("Symbol_Function")); - ensure_equals("a state as a label", std::string(Words::imageNameOf(ALScriptSymbolKind::State)), std::string("Symbol_Label")); + UNSCOPED_INFO("a config"); + CHECK(std::string(Words::imageNameOf(doc)) == std::string("Studio_Config")); + UNSCOPED_INFO("a function"); + CHECK(std::string(Words::imageNameOf(ALScriptSymbolKind::Function)) == std::string("Symbol_Function")); + UNSCOPED_INFO("a state as a label"); + CHECK(std::string(Words::imageNameOf(ALScriptSymbolKind::State)) == std::string("Symbol_Label")); } - template<> template<> - void alscriptstudiowords_object::test<9>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: each symbol kind has a window word of its own", "[alscriptstudiowords]") { - set_test_name("each kind of symbol called by one of the window's words, a word of its own"); if (!window.floater) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } std::set said; for (S32 kind = static_cast(ALScriptSymbolKind::Keyword); kind <= static_cast(ALScriptSymbolKind::Module); ++kind) { const char* word = Words::kindWordOf(static_cast(kind)); - ensure("a word for each", word != nullptr && window.floater->hasString(word)); + { + INFO("a word for each"); + REQUIRE(word != nullptr); + REQUIRE(window.floater->hasString(word)); + } said.insert(window.floater->getString(word)); } - ensure_equals("each its own", said.size(), size_t(static_cast(ALScriptSymbolKind::Module) + 1)); - ensure_equals("a function", window.floater->getString(Words::kindWordOf(ALScriptSymbolKind::Function)), std::string("function")); + UNSCOPED_INFO("each its own"); + REQUIRE(said.size() == size_t(static_cast(ALScriptSymbolKind::Module) + 1)); + UNSCOPED_INFO("a function"); + CHECK(window.floater->getString(Words::kindWordOf(ALScriptSymbolKind::Function)) == std::string("function")); } - template<> template<> - void alscriptstudiowords_object::test<10>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: a builtin's notes say its delay and god mode and not for a member", "[alscriptstudiowords]") { - set_test_name("what the definitions say of a builtin beyond its declaration: its words, its forced delay, that only a god may call it; a member is no global of its name"); lsl["functions"]["llEmail"] = LLSD().with("return", "").with("sleep", "20.0").with("tooltip", "Sends an email."); lsl["functions"]["llGodLikeRezObject"] = LLSD().with("return", "").with("god-mode", true).with("sleep", "0.0"); slua["functions"]["type"] = LLSD().with("return", "string").with("tooltip", "What a value is."); Words::forget(); const Vocab* email = Words::word(false, "llEmail"); - ensure("the email", email && email->sleep == "20.0" && !email->godMode); + { + INFO("the email"); + REQUIRE(email); + REQUIRE(email->sleep == "20.0"); + CHECK_FALSE(email->godMode); + } const std::string notes = Words::notesOf(*email); - ensure("its words and its delay: " + notes, notes.find("Sends an email.") == 0 && notes.find("20.0") != std::string::npos); + { + INFO("its words and its delay: " + notes); + CHECK(notes.find("Sends an email.") == 0); + REQUIRE(notes.find("20.0") != std::string::npos); + } const Vocab* god = Words::word(false, "llGodLikeRezObject"); - ensure("a god's, no delay said for none", god && god->godMode && god->sleep.empty()); - ensure("said", !Words::notesOf(*god).empty()); + { + INFO("a god's, no delay said for none"); + REQUIRE(god); + REQUIRE(god->godMode); + REQUIRE(god->sleep.empty()); + } + UNSCOPED_INFO("said"); + REQUIRE_FALSE(Words::notesOf(*god).empty()); // `type` under the mouse in `obj.type` is some table's field. ALCodeEditor& s = editor("local t = obj.type\nlocal u = type(t)\n", true); std::string text; - ensure("a member: not the global", !Words::hoverText(true, s.document(), ALTextPos(0, 15), "type", text)); - ensure("the global itself", Words::hoverText(true, s.document(), ALTextPos(1, 11), "type", text) && text.find("What a value is.") != std::string::npos); + UNSCOPED_INFO("a member: not the global"); + REQUIRE_FALSE(Words::hoverText(true, s.document(), ALTextPos(0, 15), "type", text)); + { + INFO("the global itself"); + CHECK(Words::hoverText(true, s.document(), ALTextPos(1, 11), "type", text)); + REQUIRE(text.find("What a value is.") != std::string::npos); + } } - template<> template<> - void alscriptstudiowords_object::test<11>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: linkArgument finds the link-number argument as the definitions name it", "[alscriptstudiowords]") { - set_test_name("a function's link-number argument, as the definitions name it, in LSL and in SLua"); lsl["functions"]["llSetLinkAlpha"] = LLSD().with("return", "").with( "arguments", LLSD().with(0, argument("LinkNumber", "integer")).with(1, argument("Opacity", "float")).with(2, argument("Face", "integer"))); slua["functions"]["ll.MessageLinked"] = LLSD().with("return", "()").with("arguments", LLSD().with(0, argument("link", "number")).with(1, argument("num", "number"))); Words::forget(); - ensure("llSetLinkAlpha's first", Words::linkArgument(false, "llSetLinkAlpha", 0)); - ensure("not its second", !Words::linkArgument(false, "llSetLinkAlpha", 1)); - ensure("nor past its last", !Words::linkArgument(false, "llSetLinkAlpha", 3)); - ensure("llSay has none", !Words::linkArgument(false, "llSay", 0)); - ensure("a word not known, none", !Words::linkArgument(false, "llNothing", 0)); - ensure("SLua's by its name with its library", Words::linkArgument(true, "ll.MessageLinked", 0) && !Words::linkArgument(true, "ll.MessageLinked", 1)); + UNSCOPED_INFO("llSetLinkAlpha's first"); + CHECK(Words::linkArgument(false, "llSetLinkAlpha", 0)); + UNSCOPED_INFO("not its second"); + CHECK_FALSE(Words::linkArgument(false, "llSetLinkAlpha", 1)); + UNSCOPED_INFO("nor past its last"); + CHECK_FALSE(Words::linkArgument(false, "llSetLinkAlpha", 3)); + UNSCOPED_INFO("llSay has none"); + CHECK_FALSE(Words::linkArgument(false, "llSay", 0)); + UNSCOPED_INFO("a word not known, none"); + CHECK_FALSE(Words::linkArgument(false, "llNothing", 0)); + { + INFO("SLua's by its name with its library"); + CHECK(Words::linkArgument(true, "ll.MessageLinked", 0)); + CHECK_FALSE(Words::linkArgument(true, "ll.MessageLinked", 1)); + } } - template<> template<> - void alscriptstudiowords_object::test<12>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: word tables are shared per language and rebuilt when their sources change", "[alscriptstudiowords]") { - set_test_name("a language's tables are made once and shared by every editor of it; new definitions are read once however many ask; new preprocessor words make new tables"); S32 asked = 0; std::string version = "one"; viewer.slots.keywords = [this, &asked](bool lua) { @@ -360,30 +475,39 @@ namespace tut Words::teach(a, false); Words::teach(b, false); Words::teach(s, true); - ensure("one set for both LSL editors", &a.highlighter().words() == &b.highlighter().words()); - ensure("another for SLua's", &s.highlighter().words() != &a.highlighter().words()); + UNSCOPED_INFO("one set for both LSL editors"); + CHECK(&a.highlighter().words() == &b.highlighter().words()); + UNSCOPED_INFO("another for SLua's"); + CHECK(&s.highlighter().words() != &a.highlighter().words()); const S32 first = asked; Words::teach(a, false); - ensure_equals("taught again from what is kept", asked, first); + UNSCOPED_INFO("taught again from what is kept"); + CHECK(asked == first); version = "two"; lsl["functions"]["llShout"] = LLSD().with("return", ""); Words::teach(a, false); Words::teach(b, false); - ensure_equals("new definitions read once for both", asked, first + 1); - ensure("and shared still, with the new word", &a.highlighter().words() == &b.highlighter().words() && - a.highlighter().words().has("function", "llShout")); + UNSCOPED_INFO("new definitions read once for both"); + CHECK(asked == first + 1); + { + INFO("and shared still, with the new word"); + CHECK(&a.highlighter().words() == &b.highlighter().words()); + REQUIRE(a.highlighter().words().has("function", "llShout")); + } const ALSyntaxWords* before = &a.highlighter().words(); extra = { "switch" }; Words::teach(a, false); - ensure("new preprocessor words, new tables", &a.highlighter().words() != before && a.highlighter().words().has("control", "switch")); + { + INFO("new preprocessor words, new tables"); + CHECK(&a.highlighter().words() != before); + REQUIRE(a.highlighter().words().has("control", "switch")); + } } - template<> template<> - void alscriptstudiowords_object::test<13>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: the reference groups each word by category or library or family", "[alscriptstudiowords]") { - set_test_name("the reference files each word: a function by its first category, an SLua ll function by its LSL twin's, other SLua by library, a constant by family"); Words::Categories found; Words::readCategories("constants:\n" " PI:\n" @@ -406,34 +530,53 @@ namespace tut " categories:\n" " - touch\n", found); - ensure_equals("only functions, and those with categories", found.size(), size_t(1)); - ensure_equals("by the first", found["llSay"], std::string("avatar_communication")); + UNSCOPED_INFO("only functions, and those with categories"); + REQUIRE(found.size() == size_t(1)); + UNSCOPED_INFO("by the first"); + CHECK(found["llSay"] == std::string("avatar_communication")); viewer.slots.definitionsYaml = [] { return std::string("functions:\n llSay:\n categories:\n - avatar_communication\n"); }; lsl["constants"]["PRIM_POSITION"] = LLSD().with("type", "integer").with("value", "6"); Words::forget(); - ensure_equals("LSL, in words", Words::word(false, "llSay")->group, std::string("Avatar communication")); - ensure("none where none is said", Words::word(false, "llOld")->group.empty()); - ensure("an event none", Words::word(false, "touch_start")->group.empty()); - ensure_equals("a constant by family", Words::word(false, "PRIM_POSITION")->group, std::string("PRIM_...")); - ensure("one without a family none", Words::word(false, "PI")->group.empty()); - ensure_equals("SLua's ll function as its twin", Words::word(true, "ll.Say")->group, std::string("Avatar communication")); - ensure_equals("another SLua function by library", Words::word(true, "math.pi")->group, std::string("math")); + UNSCOPED_INFO("LSL, in words"); + CHECK(Words::word(false, "llSay")->group == std::string("Avatar communication")); + UNSCOPED_INFO("none where none is said"); + REQUIRE(Words::word(false, "llOld")->group.empty()); + UNSCOPED_INFO("an event none"); + REQUIRE(Words::word(false, "touch_start")->group.empty()); + UNSCOPED_INFO("a constant by family"); + CHECK(Words::word(false, "PRIM_POSITION")->group == std::string("PRIM_...")); + UNSCOPED_INFO("one without a family none"); + REQUIRE(Words::word(false, "PI")->group.empty()); + UNSCOPED_INFO("SLua's ll function as its twin"); + CHECK(Words::word(true, "ll.Say")->group == std::string("Avatar communication")); + UNSCOPED_INFO("another SLua function by library"); + CHECK(Words::word(true, "math.pi")->group == std::string("math")); } - template<> template<> - void alscriptstudiowords_object::test<14>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: the units ask the attached viewer and default what it leaves unsaid", "[alscriptstudiowords]") { - set_test_name("the units ask the viewer attached; what it leaves unsaid is a viewer with nothing's answer"); ALScriptStudioViewer& asked = ALScriptStudioViewer::get(); - ensure("the test's is the one asked", &asked == &viewer); - ensure("its words", asked.lslHelpUrl() == "https://wiki.example/[LSL_STRING]"); - ensure("no definitions as YAML, no version", asked.definitionsYaml().empty() && asked.definitionsVersion().empty()); - ensure("no preprocessor, no transform", !asked.preprocessing() && !asked.transformOn(ALPreprocessor::Transform::Switch)); + UNSCOPED_INFO("the test's is the one asked"); + CHECK(&asked == &viewer); + UNSCOPED_INFO("its words"); + CHECK(asked.lslHelpUrl() == "https://wiki.example/[LSL_STRING]"); + { + INFO("no definitions as YAML, no version"); + REQUIRE(asked.definitionsYaml().empty()); + REQUIRE(asked.definitionsVersion().empty()); + } + { + INFO("no preprocessor, no transform"); + CHECK_FALSE(asked.preprocessing()); + CHECK_FALSE(asked.transformOn(ALPreprocessor::Transform::Switch)); + } ALPreprocessor::Include found; - ensure("no include", asked.lookUp(ALScriptPreprocessor::Request(), ALPreprocessor::Ask(), found) == ALPreprocessor::Found::No); + UNSCOPED_INFO("no include"); + CHECK(asked.lookUp(ALScriptPreprocessor::Request(), ALPreprocessor::Ask(), found) == ALPreprocessor::Found::No); viewer.slots.lslHelpUrl = nullptr; - ensure_equals("the wiki as nothing says it", asked.lslHelpUrl(), std::string("[LSL_STRING]")); + UNSCOPED_INFO("the wiki as nothing says it"); + CHECK(asked.lslHelpUrl() == std::string("[LSL_STRING]")); } // The call a string is an argument of, and what kind of item of the @@ -441,8 +584,7 @@ namespace tut // the string and the bracket or comma before it; SLua's call of a string // alone; nothing for a string that is not an argument's start, nor one // of an argument that names no item. - template<> template<> - void alscriptstudiowords_object::test<15>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: a string argument says its call and the kind of item it names", "[alscriptstudiowords]") { using Item = ALLSLTraits::Item; const auto kind = [this](const std::string& text, bool lua, char* quote = nullptr) { @@ -458,29 +600,48 @@ namespace tut return found; }; char quote = '\0'; - ensure("on its line", kind("llPlaySound(\"do", false, "e) == Item::Sound && quote == '"'); - ensure("a second argument", kind("llGiveInventory(llGetOwner(), \"x", false) == Item::Any); - ensure("lines and comments between", - kind("llGiveInventory(llGetOwner(),\n // what to give\n /* by name */\n \"x", false) == Item::Any); - ensure("many lines between", kind("llRezObject(\n\n\n\n\n\n\"obj", false) == Item::Object); - ensure("SLua's, by its own name", kind("ll.StartAnimation('wa", true, "e) == Item::Animation && quote == '\''); - ensure("SLua's with no brackets", kind("ll.PlaySound \"do", true) == Item::Sound); - ensure("and none in LSL, which has no such call", kind("llPlaySound \"do", false) == Item::None); - ensure("not an argument naming an item", kind("llSay(0, \"x", false) == Item::None); - ensure("not a string that only ends an argument", kind("llPlaySound(prefix + \"x", false) == Item::None); - ensure("not after a keyword", kind("return \"x", true) == Item::None); - ensure("not in a comment", kind("// llPlaySound(\"x", false) == Item::None); + { + INFO("on its line"); + CHECK(kind("llPlaySound(\"do", false, "e) == Item::Sound); + CHECK(quote == '"'); + } + UNSCOPED_INFO("a second argument"); + CHECK(kind("llGiveInventory(llGetOwner(), \"x", false) == Item::Any); + UNSCOPED_INFO("lines and comments between"); + CHECK(kind("llGiveInventory(llGetOwner(),\n // what to give\n /* by name */\n \"x", false) == Item::Any); + UNSCOPED_INFO("many lines between"); + CHECK(kind("llRezObject(\n\n\n\n\n\n\"obj", false) == Item::Object); + { + INFO("SLua's, by its own name"); + CHECK(kind("ll.StartAnimation('wa", true, "e) == Item::Animation); + CHECK(quote == '\''); + } + UNSCOPED_INFO("SLua's with no brackets"); + CHECK(kind("ll.PlaySound \"do", true) == Item::Sound); + UNSCOPED_INFO("and none in LSL, which has no such call"); + CHECK(kind("llPlaySound \"do", false) == Item::None); + UNSCOPED_INFO("not an argument naming an item"); + CHECK(kind("llSay(0, \"x", false) == Item::None); + UNSCOPED_INFO("not a string that only ends an argument"); + CHECK(kind("llPlaySound(prefix + \"x", false) == Item::None); + UNSCOPED_INFO("not after a keyword"); + CHECK(kind("return \"x", true) == Item::None); + UNSCOPED_INFO("not in a comment"); + CHECK(kind("// llPlaySound(\"x", false) == Item::None); std::string callee; S32 argument = -1; ALCodeEditor& e = editor("llSetLinkAlpha(2, ", false); - ensure("the call around a place", Words::callAt(e, ALTextPos(0, 18), callee, argument) && callee == "llSetLinkAlpha" && argument == 1); + { + INFO("the call around a place"); + CHECK(Words::callAt(e, ALTextPos(0, 18), callee, argument)); + CHECK(callee == "llSetLinkAlpha"); + CHECK(argument == 1); + } } - template<> template<> - void alscriptstudiowords_object::test<16>() + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: SLua handler parameters keep their types' own commas and variadics", "[alscriptstudiowords]") { - set_test_name("an SLua handler's parameters split as a signature's are: a type's own commas, colons and arrow its own, a variadic `...` however written"); slua["events"]["mapped"] = LLSD().with("arguments", LLSD().with(0, argument("pairs", "Map")).with(1, argument("n", "number"))); slua["events"]["called"] = LLSD().with("arguments", LLSD().with(0, argument("back", "(number) -> ()")).with(1, argument("data", "{[string]: any}"))); @@ -488,13 +649,20 @@ namespace tut slua["events"]["bare"] = LLSD().with("arguments", LLSD().with(0, argument("...any", ""))); Words::forget(); const auto handler = [](const char* name, bool typed) { return Words::completionFor(*Words::word(true, name), true, typed).snippet; }; - ensure_equals("a generic's comma", handler("mapped", true), std::string("function LLEvents.mapped(pairs: Map, n: number)\n $0\nend")); - ensure_equals("and untyped", handler("mapped", false), std::string("function LLEvents.mapped(pairs, n)\n $0\nend")); - ensure_equals("a function type's arrow, a table type's colon", handler("called", true), + UNSCOPED_INFO("a generic's comma"); + CHECK(handler("mapped", true) == std::string("function LLEvents.mapped(pairs: Map, n: number)\n $0\nend")); + UNSCOPED_INFO("and untyped"); + CHECK(handler("mapped", false) == std::string("function LLEvents.mapped(pairs, n)\n $0\nend")); + UNSCOPED_INFO("a function type's arrow, a table type's colon"); + CHECK(handler("called", true) == std::string("function LLEvents.called(back: (number) -> (), data: {[string]: any})\n $0\nend")); - ensure_equals("a variadic typed", handler("varied", true), std::string("function LLEvents.varied(first: number, ...: any)\n $0\nend")); - ensure_equals("and not", handler("varied", false), std::string("function LLEvents.varied(first, ...)\n $0\nend")); - ensure_equals("one written ...any", handler("bare", true), std::string("function LLEvents.bare(...: any)\n $0\nend")); - ensure_equals("and untyped", handler("bare", false), std::string("function LLEvents.bare(...)\n $0\nend")); + UNSCOPED_INFO("a variadic typed"); + CHECK(handler("varied", true) == std::string("function LLEvents.varied(first: number, ...: any)\n $0\nend")); + UNSCOPED_INFO("and not"); + CHECK(handler("varied", false) == std::string("function LLEvents.varied(first, ...)\n $0\nend")); + UNSCOPED_INFO("one written ...any"); + CHECK(handler("bare", true) == std::string("function LLEvents.bare(...: any)\n $0\nend")); + UNSCOPED_INFO("and untyped"); + CHECK(handler("bare", false) == std::string("function LLEvents.bare(...)\n $0\nend")); } } diff --git a/indra/newview/tests/alscripttheme_test.cpp b/indra/newview/tests/alscripttheme_test.cpp index b7092e39bc..b98048d388 100644 --- a/indra/newview/tests/alscripttheme_test.cpp +++ b/indra/newview/tests/alscripttheme_test.cpp @@ -35,13 +35,13 @@ #include "../../llui/tests/alheadlessui_fixture.h" -#include "../test/lltut.h" +#include #include #include #include -namespace tut +namespace { struct alscripttheme_data { @@ -54,17 +54,11 @@ namespace tut } }; - typedef test_group alscripttheme_test; - typedef alscripttheme_test::object alscripttheme_object; - tut::alscripttheme_test alscripttheme_testgroup("alscripttheme"); - - template<> template<> - void alscripttheme_object::test<1>() + TEST_CASE_METHOD(alscripttheme_data, "alscripttheme: every shipped theme loads and colours only names the editor knows", "[alscripttheme]") { - set_test_name("every theme the viewer ships reads, and colours only what a theme speaks for"); if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } S32 shipped = 0; for (const ALScriptTheme& theme : ALScriptTheme::available()) @@ -74,40 +68,47 @@ namespace tut continue; } ++shipped; - ensure("a name: " + theme.path, !theme.name.empty()); - ensure("colours: " + theme.name, !theme.colors.empty()); + UNSCOPED_INFO("a name: " + theme.path); + REQUIRE_FALSE(theme.name.empty()); + UNSCOPED_INFO("colours: " + theme.name); + REQUIRE_FALSE(theme.colors.empty()); for (const auto& [name, color] : theme.colors) { - ensure(theme.name + " colours " + name + ", which no editor is painted by", spoken(name)); + UNSCOPED_INFO(theme.name + " colours " + name + ", which no editor is painted by"); + REQUIRE(spoken(name)); } } - ensure("the viewer ships themes", shipped > 1); + UNSCOPED_INFO("the viewer ships themes"); + CHECK(shipped > 1); } - template<> template<> - void alscripttheme_object::test<2>() + TEST_CASE_METHOD(alscripttheme_data, "alscripttheme: editor colours come first and every colour name has a label", "[alscripttheme]") { - set_test_name("the editor's own colours come first, and every name reads as words"); const std::vector& names = ALScriptTheme::names(); - ensure("names", !names.empty()); - ensure_equals("the text first", names.front(), std::string("ScriptText")); - ensure("an editor colour", ALScriptTheme::isEditorColor("ScriptBackground")); - ensure_equals("read as a person reads it", ALScriptTheme::labelOf("ScriptBackground"), std::string("Background")); - ensure("a kind is not the editor's", !ALScriptTheme::isEditorColor(names.back())); - ensure_equals("a kind's name spaced", ALScriptTheme::labelOf("ScriptDocComment"), std::string("Doc comment")); + UNSCOPED_INFO("names"); + REQUIRE_FALSE(names.empty()); + UNSCOPED_INFO("the text first"); + CHECK(names.front() == std::string("ScriptText")); + UNSCOPED_INFO("an editor colour"); + CHECK(ALScriptTheme::isEditorColor("ScriptBackground")); + UNSCOPED_INFO("read as a person reads it"); + CHECK(ALScriptTheme::labelOf("ScriptBackground") == std::string("Background")); + UNSCOPED_INFO("a kind is not the editor's"); + CHECK_FALSE(ALScriptTheme::isEditorColor(names.back())); + UNSCOPED_INFO("a kind's name spaced"); + CHECK(ALScriptTheme::labelOf("ScriptDocComment") == std::string("Doc comment")); for (const std::string& name : names) { - ensure("a label for " + name, !ALScriptTheme::labelOf(name).empty()); + UNSCOPED_INFO("a label for " + name); + REQUIRE_FALSE(ALScriptTheme::labelOf(name).empty()); } } - template<> template<> - void alscripttheme_object::test<3>() + TEST_CASE_METHOD(alscripttheme_data, "alscripttheme: the chosen theme is read and written through the UI's setting", "[alscripttheme]") { - set_test_name("the theme chosen is the UI's setting, read and written through it"); if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } LLControlGroup* config = LLUI::getInstance()->mSettingGroups["config"]; if (!config->controlExists("ALScriptStudioTheme")) @@ -122,55 +123,77 @@ namespace tut ~ChosenBack() { ALScriptTheme::setChosen(was); } } chosen_back; ALScriptTheme::setChosen("Monokai"); - ensure_equals("the setting says it", config->getString("ALScriptStudioTheme"), std::string("Monokai")); - ensure_equals("and so does the theme", ALScriptTheme::chosen(), std::string("Monokai")); + UNSCOPED_INFO("the setting says it"); + CHECK(config->getString("ALScriptStudioTheme") == std::string("Monokai")); + UNSCOPED_INFO("and so does the theme"); + CHECK(ALScriptTheme::chosen() == std::string("Monokai")); ALScriptTheme::setChosen(std::string()); - ensure("none", ALScriptTheme::chosen().empty()); + UNSCOPED_INFO("none"); + REQUIRE(ALScriptTheme::chosen().empty()); } - template<> template<> - void alscripttheme_object::test<4>() + TEST_CASE_METHOD(alscripttheme_data, "alscripttheme: illegible reports each colour too faint against its ground", "[alscripttheme]") { - set_test_name("what reads less than it should: code against both grounds, the text against its bands, the line numbers against the gutter"); ALScriptTheme theme; theme.colors["ScriptBackground"] = LLColor4(1.f, 1.f, 1.f, 1.f); theme.colors["ScriptText"] = LLColor4(0.f, 0.f, 0.f, 1.f); theme.colors["ScriptComment"] = LLColor4(0.2f, 0.4f, 0.2f, 1.f); - ensure("black and a dark green on white read", theme.illegible().empty()); + UNSCOPED_INFO("black and a dark green on white read"); + REQUIRE(theme.illegible().empty()); theme.colors["ScriptString"] = LLColor4(0.9f, 0.6f, 0.6f, 1.f); std::vector said = theme.illegible(); - ensure("a pale pink does not", said.size() == 1 && said[0].name == "ScriptString" && said[0].against == "ScriptBackground" && - said[0].contrast < ALSurface::LEGIBLE); + { + INFO("a pale pink does not"); + REQUIRE(said.size() == 1); + CHECK(said[0].name == "ScriptString"); + CHECK(said[0].against == "ScriptBackground"); + CHECK(said[0].contrast < ALSurface::LEGIBLE); + } theme.colors.erase("ScriptString"); theme.colors["ScriptBgReadOnlyColor"] = LLColor4(0.3f, 0.3f, 0.3f, 1.f); said = theme.illegible(); - ensure("a dark read-only ground takes both from the text", said.size() == 2 && said[0].against == "ScriptBgReadOnlyColor"); + { + INFO("a dark read-only ground takes both from the text"); + REQUIRE(said.size() == 2); + CHECK(said[0].against == "ScriptBgReadOnlyColor"); + } theme.colors.erase("ScriptBgReadOnlyColor"); theme.colors["ScriptSelectionColor"] = LLColor4(0.f, 0.f, 0.3f, 0.9f); said = theme.illegible(); - ensure("a selection the text is lost in, as laid over the ground", - said.size() == 1 && said[0].name == "ScriptText" && said[0].against == "ScriptSelectionColor"); + { + INFO("a selection the text is lost in, as laid over the ground"); + REQUIRE(said.size() == 1); + CHECK(said[0].name == "ScriptText"); + CHECK(said[0].against == "ScriptSelectionColor"); + } theme.colors["ScriptSelectionColor"] = LLColor4(0.f, 0.f, 0.3f, 0.2f); - ensure("thin enough, it reads", theme.illegible().empty()); + UNSCOPED_INFO("thin enough, it reads"); + REQUIRE(theme.illegible().empty()); theme.colors["ScriptGutterColor"] = LLColor4(0.95f, 0.95f, 0.95f, 1.f); theme.colors["ScriptLineNumberColor"] = LLColor4(0.75f, 0.75f, 0.75f, 1.f); said = theme.illegible(); - ensure("faint numbers on the gutter", said.size() == 1 && said[0].against == "ScriptGutterColor"); + { + INFO("faint numbers on the gutter"); + REQUIRE(said.size() == 1); + CHECK(said[0].against == "ScriptGutterColor"); + } theme.colors["ScriptLineNumberColor"] = LLColor4(0.5f, 0.5f, 0.5f, 1.f); - ensure("numbers are held to less than the code", theme.illegible().empty() && !theme.illegible(7.f, 4.5f).empty()); + { + INFO("numbers are held to less than the code"); + REQUIRE(theme.illegible().empty()); + REQUIRE_FALSE(theme.illegible(7.f, 4.5f).empty()); + } } - template<> template<> - void alscripttheme_object::test<5>() + TEST_CASE_METHOD(alscripttheme_data, "alscripttheme: every shipped theme reads at its contrast thresholds", "[alscripttheme]") { - set_test_name("every theme the viewer ships reads: the text and each kind of code at 4.5:1, the line numbers at 3:1; the high-contrast ones at 7 and 4.5"); if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } S32 high = 0; for (const ALScriptTheme& theme : ALScriptTheme::available()) @@ -186,28 +209,29 @@ namespace tut { said += "\n " + each.name + " on " + each.against + ": " + std::to_string(each.contrast); } - ensure(theme.name + " reads:" + said, said.empty()); + UNSCOPED_INFO(theme.name + " reads:" + said); + REQUIRE(said.empty()); } - ensure_equals("a dark and a light high-contrast theme", high, 2); + UNSCOPED_INFO("a dark and a light high-contrast theme"); + CHECK(high == 2); } - template<> template<> - void alscripttheme_object::test<6>() + TEST_CASE_METHOD(alscripttheme_data, "alscripttheme: every colour a theme speaks for has its label in strings.xml", "[alscripttheme]") { - set_test_name("every colour a theme speaks for has its label in strings.xml, to be translated"); #ifdef LLUI_TEST_APP_DIR std::ifstream in(std::string(LLUI_TEST_APP_DIR) + "/skins/default/xui/en/strings.xml"); if (!in) { - skip("no source tree: LLUI_TEST_APP_DIR does not point at newview"); + SKIP("no source tree: LLUI_TEST_APP_DIR does not point at newview"); } const std::string strings((std::istreambuf_iterator(in)), std::istreambuf_iterator()); for (const std::string& name : ALScriptTheme::names()) { - ensure("a label for " + name, strings.find("name=\"ScriptColorLabel_" + name + "\"") != std::string::npos); + UNSCOPED_INFO("a label for " + name); + REQUIRE(strings.find("name=\"ScriptColorLabel_" + name + "\"") != std::string::npos); } #else - skip("no LLUI_TEST_APP_DIR"); + SKIP("no LLUI_TEST_APP_DIR"); #endif } @@ -216,15 +240,14 @@ namespace tut // the caret's line and the selection, the line numbers against the // gutter -- the dark skins included, whose defaults were once the // white skin's. - template<> template<> - void alscripttheme_object::test<7>() + TEST_CASE_METHOD(alscripttheme_data, "alscripttheme: every shipped skin's script colours read and its studio parts differ", "[alscripttheme]") { #ifdef LLUI_TEST_APP_DIR const std::string skins = std::string(LLUI_TEST_APP_DIR) + "/skins/"; LLXMLNodePtr default_root; if (!LLXMLNode::parseFile(skins + "default/colors.xml", default_root, nullptr)) { - skip("no source tree: LLUI_TEST_APP_DIR does not point at newview"); + SKIP("no source tree: LLUI_TEST_APP_DIR does not point at newview"); } for (const char* skin : { "default", "alchemy", "gemini", "heretic", "ionic" }) { @@ -233,7 +256,8 @@ namespace tut if (std::string(skin) != "default") { LLXMLNodePtr root; - ensure(std::string(skin) + " parses", LLXMLNode::parseFile(skins + skin + "/colors.xml", root, nullptr)); + UNSCOPED_INFO(std::string(skin) + " parses"); + REQUIRE(LLXMLNode::parseFile(skins + skin + "/colors.xml", root, nullptr)); sheet.read(root, std::string(skin) + "/colors.xml"); } sheet.resolve(); @@ -246,15 +270,21 @@ namespace tut { said += "\n " + each.name + " on " + each.against + ": " + std::to_string(each.contrast); } - ensure(std::string(skin) + "'s script colours read:" + said, said.empty()); + UNSCOPED_INFO(std::string(skin) + "'s script colours read:" + said); + REQUIRE(said.empty()); // And the studios' parts told apart by what they are: a divider // from the panes it divides, a tab not chosen from the chosen // one, the notice and the strips from the panes. const auto apart = [&](const char* a, const char* b, F32 least) { const LLColor4* x = sheet.find(a); const LLColor4* y = sheet.find(b); - ensure(std::string(skin) + " has " + a + " and " + b, x && y); - ensure(std::string(skin) + ": " + a + " apart from " + b, ALSurface::contrast(*x, *y) >= least); + { + INFO(std::string(skin) + " has " + a + " and " + b); + REQUIRE(x); + REQUIRE(y); + } + UNSCOPED_INFO(std::string(skin) + ": " + a + " apart from " + b); + REQUIRE(ALSurface::contrast(*x, *y) >= least); }; apart("StudioDividerColor", "StudioPaneColor", 1.3f); apart("StudioTabColor", "PanelDefaultBackgroundColor", 1.08f); @@ -262,7 +292,7 @@ namespace tut apart("StudioStripColor", "StudioPaneColor", 1.05f); } #else - skip("no LLUI_TEST_APP_DIR"); + SKIP("no LLUI_TEST_APP_DIR"); #endif } } diff --git a/indra/newview/tests/alscripttypes_test.cpp b/indra/newview/tests/alscripttypes_test.cpp index 4df0b597da..6fe94da356 100644 --- a/indra/newview/tests/alscripttypes_test.cpp +++ b/indra/newview/tests/alscripttypes_test.cpp @@ -27,9 +27,9 @@ #include "../alscripttypes.h" #include "alpreprocessor.h" #include "alsourcemap.h" -#include "../test/lltut.h" +#include -namespace tut +namespace { struct alscripttypes_data { @@ -44,17 +44,9 @@ struct alscripttypes_data return out; } }; -typedef test_group alscripttypes_group; -typedef alscripttypes_group::object alscripttypes_object; -alscripttypes_group alscripttypes_test("alscripttypes"); -template<> -template<> -void alscripttypes_object::test<1>() +TEST_CASE_METHOD(alscripttypes_data, "alscripttypes: inSource maps diagnostics back through the envelope and the source map", "[alscripttypes]") { - set_test_name("a compile's diagnostics read back to the source: under the envelope's lines and through the map; an include's and " - "the preprocessor's own at no line, the include named; a client's envelope a line down, without columns; as said " - "with no map"); ALPreprocessor::Options options; options.fileName = "main.lsl"; options.resolve = [](const ALPreprocessor::Ask& ask, ALPreprocessor::Include& out) { @@ -63,7 +55,8 @@ void alscripttypes_object::test<1>() return ALPreprocessor::Found::Yes; }; const ALPreprocessor::Result expanded = ALPreprocessor::run("#include \"lib.lsl\"\ndefault\n{\nstate_entry() { x; }\n}\n", options); - ensure("expanded", expanded.problems.empty()); + UNSCOPED_INFO("expanded"); + REQUIRE(expanded.problems.empty()); // The lines of the expansion that hold each, and the column of `x`. S32 entry = -1, second = -1, column = -1, line = 0; for (size_t at = 0, next; at < expanded.text.size(); at = next + 1, ++line) @@ -81,7 +74,12 @@ void alscripttypes_object::test<1>() break; } } - ensure("found in the expansion", entry >= 0 && second >= 0 && column >= 0); + { + INFO("found in the expansion"); + CHECK(entry >= 0); + CHECK(second >= 0); + CHECK(column >= 0); + } ALScriptCompileResult result; result.codeLine = 7; @@ -95,20 +93,51 @@ void alscripttypes_object::test<1>() result.diagnostics.push_back(unplaced); const std::vector source = result.inSource(); - ensure_equals("four", source.size(), size_t(4)); - ensure("the script's own line and column", source[0].hasLine && source[0].line == 3 && source[0].hasColumn && source[0].column == 16 && - source[0].message == "undefined x"); - ensure("the include's at none, named with its line", !source[1].hasLine && source[1].message == "lib.lsl:2: b again"); - ensure("the preprocessor's own at none", !source[2].hasLine && source[2].message == "somewhere made"); - ensure("none stays none", !source[3].hasLine && source[3].message == "Math Error"); + UNSCOPED_INFO("four"); + REQUIRE(source.size() == size_t(4)); + { + INFO("the script's own line and column"); + CHECK(source[0].hasLine); + CHECK(source[0].line == 3); + CHECK(source[0].hasColumn); + CHECK(source[0].column == 16); + CHECK(source[0].message == "undefined x"); + } + { + INFO("the include's at none, named with its line"); + CHECK_FALSE(source[1].hasLine); + CHECK(source[1].message == "lib.lsl:2: b again"); + } + { + INFO("the preprocessor's own at none"); + CHECK_FALSE(source[2].hasLine); + CHECK(source[2].message == "somewhere made"); + } + { + INFO("none stays none"); + CHECK_FALSE(source[3].hasLine); + CHECK(source[3].message == "Math Error"); + } const std::vector wrapped = result.inSource(1); - ensure("a line down in an envelope, no column", wrapped[0].hasLine && wrapped[0].line == 4 && !wrapped[0].hasColumn); + { + INFO("a line down in an envelope, no column"); + CHECK(wrapped[0].hasLine); + CHECK(wrapped[0].line == 4); + CHECK_FALSE(wrapped[0].hasColumn); + } // Nothing expanded: as the compiler said it, the text having gone as it was. ALScriptCompileResult plain; plain.diagnostics.push_back(alscripttypes_data::said(4, 2, "as is")); const std::vector as_said = plain.inSource(1); - ensure("as said", as_said.size() == 1 && as_said[0].hasLine && as_said[0].line == 4 && as_said[0].hasColumn && as_said[0].column == 2); + { + INFO("as said"); + REQUIRE(as_said.size() == 1); + CHECK(as_said[0].hasLine); + CHECK(as_said[0].line == 4); + CHECK(as_said[0].hasColumn); + CHECK(as_said[0].column == 2); + } } -} // namespace tut +} // anonymous namespace diff --git a/indra/newview/tests/alscriptweightspane_test.cpp b/indra/newview/tests/alscriptweightspane_test.cpp index a25352ceea..cc4928f697 100644 --- a/indra/newview/tests/alscriptweightspane_test.cpp +++ b/indra/newview/tests/alscriptweightspane_test.cpp @@ -36,14 +36,14 @@ #include "alscriptstudio_fixture.h" -#include "../test/lltut.h" +#include #include #include #include #include -namespace tut +namespace { struct alscriptweightspane_data { @@ -58,7 +58,8 @@ namespace tut ALScriptWeightsPane& weights() const { ALScriptWeightsPane* pane = floater->findChild("weights_tab", true); - ensure("the skin builds the tab as the pane", pane != nullptr); + UNSCOPED_INFO("the skin builds the tab as the pane"); + REQUIRE(pane != nullptr); return *pane; } ALPaneList* list(const char* name) const { return floater ? floater->findChild(name, true) : nullptr; } @@ -133,52 +134,67 @@ namespace tut return shown; } }; - typedef test_group alscriptweightspane_group; - typedef alscriptweightspane_group::object alscriptweightspane_object; - alscriptweightspane_group alscriptweightspane_instance("ALScriptWeightsPane"); // The targets side by side, the script's own first and chosen; its // parts listed with their bytes and shares, in the viewer's words; a // target that does not compile says so rather than a number. - template<> template<> - void alscriptweightspane_object::test<1>() + TEST_CASE_METHOD(alscriptweightspane_data, "ALScriptWeightsPane: targets are listed with the script's own first and chosen", "[ALScriptWeightsPane]") { if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } - ensure("the studio's window builds with its Weights tab", tab() != nullptr); + UNSCOPED_INFO("the studio's window builds with its Weights tab"); + REQUIRE(tab() != nullptr); ALScriptWeightsPane& pane = weights(); pane.show(lsl()); ALPaneList* targets = list("weights_targets"); ALPaneList* parts = list("weights_parts"); - ensure_equals("three targets", targets->getItemCount(), 3); - ensure_equals("its own first", cell(targets->getAllData()[0], 0), std::string("LSL (LSO)")); - ensure_equals("its code", cell(targets->getAllData()[0], 1), std::string("4.0 KB")); - ensure_equals("its share", cell(targets->getAllData()[0], 2), std::string("25.0%")); - ensure_equals("an estimate said as one", cell(targets->getAllData()[1], 1), std::string("~5.9 KB")); - ensure_equals("one that does not compile has no number", cell(targets->getAllData()[2], 1), std::string("--")); - ensure("its own chosen", targets->getFirstSelected() && targets->getFirstSelected()->getValue().asInteger() == S32(ALScriptWeight::Target::LSO)); - - ensure_equals("its parts", parts->getItemCount(), 5); + UNSCOPED_INFO("three targets"); + CHECK(targets->getItemCount() == 3); + UNSCOPED_INFO("its own first"); + CHECK(cell(targets->getAllData()[0], 0) == std::string("LSL (LSO)")); + UNSCOPED_INFO("its code"); + CHECK(cell(targets->getAllData()[0], 1) == std::string("4.0 KB")); + UNSCOPED_INFO("its share"); + CHECK(cell(targets->getAllData()[0], 2) == std::string("25.0%")); + UNSCOPED_INFO("an estimate said as one"); + CHECK(cell(targets->getAllData()[1], 1) == std::string("~5.9 KB")); + UNSCOPED_INFO("one that does not compile has no number"); + CHECK(cell(targets->getAllData()[2], 1) == std::string("--")); + { + INFO("its own chosen"); + REQUIRE(targets->getFirstSelected()); + CHECK(targets->getFirstSelected()->getValue().asInteger() == S32(ALScriptWeight::Target::LSO)); + } + + UNSCOPED_INFO("its parts"); + CHECK(parts->getItemCount() == 5); const std::vector names = column(parts, 0); - ensure("the registers in words" + joined(names), std::find(names.begin(), names.end(), "Registers") != names.end()); - ensure("a handler in its state" + joined(names), std::find(names.begin(), names.end(), "touch_start in default") != names.end()); + UNSCOPED_INFO("the registers in words" + joined(names)); + REQUIRE(std::find(names.begin(), names.end(), "Registers") != names.end()); + UNSCOPED_INFO("a handler in its state" + joined(names)); + REQUIRE(std::find(names.begin(), names.end(), "touch_start in default") != names.end()); const std::vector lines = column(parts, 5); - ensure("an include's part at the include's line" + joined(lines), std::find(lines.begin(), lines.end(), "lib.lsl:1") != lines.end()); - ensure("the script's own at its line" + joined(lines), std::find(lines.begin(), lines.end(), "8") != lines.end()); + UNSCOPED_INFO("an include's part at the include's line" + joined(lines)); + REQUIRE(std::find(lines.begin(), lines.end(), "lib.lsl:1") != lines.end()); + UNSCOPED_INFO("the script's own at its line" + joined(lines)); + REQUIRE(std::find(lines.begin(), lines.end(), "8") != lines.end()); const std::string head = floater->findChild("weights_head", true)->getText(); - ensure("the head says whose and on what: " + head, head.find("Door") != std::string::npos && head.find("LSO") != std::string::npos); + { + INFO("the head says whose and on what: " + head); + REQUIRE(head.find("Door") != std::string::npos); + REQUIRE(head.find("LSO") != std::string::npos); + } } // Another target chosen lists its parts; a part chosen says where it // is, in the include where it is one's; one with no place says nothing. - template<> template<> - void alscriptweightspane_object::test<2>() + TEST_CASE_METHOD(alscriptweightspane_data, "ALScriptWeightsPane: another target chosen lists its parts and a part says where it is", "[ALScriptWeightsPane]") { if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } ALScriptWeightsPane& pane = weights(); pane.show(lsl()); @@ -187,35 +203,43 @@ namespace tut parts->selectByValue(LLSD(2)); std::optional place = pane.chosenPlace(parts); - ensure("the include's function has a place", place.has_value()); - ensure_equals("in the include", place->file, std::string("disk:/lib.lsl")); - ensure_equals("by its name", place->fileName, std::string("lib.lsl")); - ensure_equals("at its line", place->line, 0); - ensure_equals("and column", place->column, 4); + UNSCOPED_INFO("the include's function has a place"); + REQUIRE(place.has_value()); + UNSCOPED_INFO("in the include"); + CHECK(place->file == std::string("disk:/lib.lsl")); + UNSCOPED_INFO("by its name"); + CHECK(place->fileName == std::string("lib.lsl")); + UNSCOPED_INFO("at its line"); + CHECK(place->line == 0); + UNSCOPED_INFO("and column"); + CHECK(place->column == 4); parts->selectByValue(LLSD(0)); - ensure("the registers are nowhere", !pane.chosenPlace(parts)); + UNSCOPED_INFO("the registers are nowhere"); + REQUIRE_FALSE(pane.chosenPlace(parts)); targets->selectByValue(LLSD(S32(ALScriptWeight::Target::Mono))); targets->onCommit(); - ensure_equals("Mono's parts", parts->getItemCount(), 2); + UNSCOPED_INFO("Mono's parts"); + CHECK(parts->getItemCount() == 2); // The same script again keeps the target chosen; another starts at // its own. pane.show(lsl()); - ensure_equals("kept through a refill", parts->getItemCount(), 2); + UNSCOPED_INFO("kept through a refill"); + CHECK(parts->getItemCount() == 2); ALScriptWeightsPane::Shown other = lsl(); other.id = "script-2"; pane.show(other); - ensure_equals("another script at its own", parts->getItemCount(), 5); + UNSCOPED_INFO("another script at its own"); + CHECK(parts->getItemCount() == 5); } // Since the save: a part heavier or lighter by so much, one new since, // and the target's whole; nothing where it was not weighed then. - template<> template<> - void alscriptweightspane_object::test<3>() + TEST_CASE_METHOD(alscriptweightspane_data, "ALScriptWeightsPane: changes since the save show for each part and the target's whole", "[ALScriptWeightsPane]") { if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } ALScriptWeightsPane& pane = weights(); ALScriptWeightsPane::Shown shown = lsl(); @@ -230,57 +254,69 @@ namespace tut pane.show(shown); ALPaneList* targets = list("weights_targets"); ALPaneList* parts = list("weights_parts"); - ensure_equals("the target's whole", cell(targets->getAllData()[0], 3), std::string("+96")); - ensure_equals("nothing for a target not weighed then", cell(targets->getAllData()[1], 3), std::string()); + UNSCOPED_INFO("the target's whole"); + CHECK(cell(targets->getAllData()[0], 3) == std::string("+96")); + UNSCOPED_INFO("nothing for a target not weighed then"); + CHECK(cell(targets->getAllData()[1], 3) == std::string()); const std::vector changes = column(parts, 4); - ensure_equals("the handler heavier" + joined(changes), changes[4], std::string("+24")); - ensure_equals("the function new" + joined(changes), changes[2], std::string("new")); - ensure_equals("the global the same where it moved" + joined(changes), changes[1], std::string()); + UNSCOPED_INFO("the handler heavier" + joined(changes)); + CHECK(changes[4] == std::string("+24")); + UNSCOPED_INFO("the function new" + joined(changes)); + CHECK(changes[2] == std::string("new")); + UNSCOPED_INFO("the global the same where it moved" + joined(changes)); + CHECK(changes[1] == std::string()); // Heaviest first, by the number and not the words. parts->sortByColumn("bytes", false); parts->updateSort(); - ensure_equals("the state first", cell(parts->getAllData()[0], 2), std::string("217")); - ensure_equals("the global last", cell(parts->getAllData()[4], 2), std::string("10")); + UNSCOPED_INFO("the state first"); + CHECK(cell(parts->getAllData()[0], 2) == std::string("217")); + UNSCOPED_INFO("the global last"); + CHECK(cell(parts->getAllData()[4], 2) == std::string("10")); parts->sortByColumn("change", false); parts->updateSort(); - ensure_equals("the new function moved most", cell(parts->getAllData()[0], 0), std::string("twice")); + UNSCOPED_INFO("the new function moved most"); + CHECK(cell(parts->getAllData()[0], 0) == std::string("twice")); // By name, as the names are shown. parts->sortByColumn("part", true); parts->updateSort(); const std::vector names = column(parts, 0); for (size_t i = 1; i < names.size(); ++i) { - ensure("in the order of their names" + joined(names), LLStringUtil::compareDict(names[i - 1], names[i]) <= 0); + UNSCOPED_INFO("in the order of their names" + joined(names)); + REQUIRE(LLStringUtil::compareDict(names[i - 1], names[i]) <= 0); } } // Nothing to show says why, and holds nothing to choose. - template<> template<> - void alscriptweightspane_object::test<4>() + TEST_CASE_METHOD(alscriptweightspane_data, "ALScriptWeightsPane: showNothing says why and holds nothing to choose", "[ALScriptWeightsPane]") { if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } ALScriptWeightsPane& pane = weights(); pane.show(lsl()); pane.showNothing("Nothing open to weigh."); - ensure_equals("no targets", list("weights_targets")->getItemCount(), 0); - ensure_equals("no parts", list("weights_parts")->getItemCount(), 0); - ensure("nothing chosen", !pane.chosenPlace(pane.partsList())); - ensure_equals("why", floater->findChild("weights_head", true)->getText(), std::string("Nothing open to weigh.")); - ensure("and whose it is forgotten", pane.shownId().empty()); + UNSCOPED_INFO("no targets"); + CHECK(list("weights_targets")->getItemCount() == 0); + UNSCOPED_INFO("no parts"); + CHECK(list("weights_parts")->getItemCount() == 0); + UNSCOPED_INFO("nothing chosen"); + REQUIRE_FALSE(pane.chosenPlace(pane.partsList())); + UNSCOPED_INFO("why"); + CHECK(floater->findChild("weights_head", true)->getText() == std::string("Nothing open to weigh.")); + UNSCOPED_INFO("and whose it is forgotten"); + REQUIRE(pane.shownId().empty()); } // Anonymous functions share an empty name: each is matched to the one // in its place among them then, not all to their sum. - template<> template<> - void alscriptweightspane_object::test<5>() + TEST_CASE_METHOD(alscriptweightspane_data, "ALScriptWeightsPane: anonymous functions are matched to the saved ones by their place", "[ALScriptWeightsPane]") { if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } using Kind = ALScriptWeight::Part::Kind; ALScriptWeightsPane& pane = weights(); @@ -297,7 +333,8 @@ namespace tut shown.saved = { slua }; pane.show(shown); std::vector changes = column(list("weights_parts"), 4); - ensure_equals("nothing changed" + joined(changes), joined(changes), std::string("|||")); + UNSCOPED_INFO("nothing changed" + joined(changes)); + CHECK(joined(changes) == std::string("|||")); // The middle one heavier, and one added after them. ALScriptWeight now = slua; now.parts[1].bytes = 250; @@ -305,16 +342,15 @@ namespace tut shown.weights = { now }; pane.show(shown); changes = column(list("weights_parts"), 4); - ensure_equals("the middle one, and one new" + joined(changes), joined(changes), std::string("||+50||new")); + UNSCOPED_INFO("the middle one, and one new" + joined(changes)); + CHECK(joined(changes) == std::string("||+50||new")); } - template<> template<> - void alscriptweightspane_object::test<6>() + TEST_CASE_METHOD(alscriptweightspane_data, "ALScriptWeightsPane: an unnamed handler is named by its event and others said to be unnamed", "[ALScriptWeightsPane]") { - set_test_name("a function with no name of its own called by the event it handles, where the outline says so; else said to have none"); if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } using Kind = ALScriptWeight::Part::Kind; ALScriptWeightsPane& pane = weights(); @@ -331,26 +367,28 @@ namespace tut shown.handlers[0] = "touch_start"; pane.show(shown); const std::string names = joined(column(list("weights_parts"), 0)); - ensure("the handler by its event: " + names, names.find("touch_start") != std::string::npos); - ensure("the other with none: " + names, names.find(window.find("weights_tab")->getString("WeightsPartUnnamed")) != std::string::npos); + UNSCOPED_INFO("the handler by its event: " + names); + REQUIRE(names.find("touch_start") != std::string::npos); + UNSCOPED_INFO("the other with none: " + names); + REQUIRE(names.find(window.find("weights_tab")->getString("WeightsPartUnnamed")) != std::string::npos); } // What the region reserves for the script's object, where it has said: // after the code's size, for all of the object's scripts, with its URLs // where it has any; its time, where it told an estate manager; and the // tip saying how the region counts each. - template<> template<> - void alscriptweightspane_object::test<7>() + TEST_CASE_METHOD(alscriptweightspane_data, "ALScriptWeightsPane: the head says what the region reserves for the object where known", "[ALScriptWeightsPane]") { if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } ALScriptWeightsPane& pane = weights(); ALScriptWeightsPane::Shown shown = lsl(); LLTextBox* head = floater->findChild("weights_head", true); pane.show(shown); - ensure("nothing of the region", head->getText().find("region") == std::string::npos); + UNSCOPED_INFO("nothing of the region"); + REQUIRE(head->getText().find("region") == std::string::npos); ALScriptRegionUsage::Usage reserved; reserved.memory = 131072; reserved.when = LLDate(1.8e9); @@ -358,44 +396,63 @@ namespace tut shown.id = "script-2"; pane.show(shown); const std::string said = head->getText(); - ensure("reserved, in KB" + said, said.find("reserves 128 KB for all its scripts") != std::string::npos); - ensure("as of when" + said, said.find(ALRecoveryEntry::sayWhen(reserved.when)) != std::string::npos); - ensure("no URLs said where there are none" + said, said.find("URLs") == std::string::npos); - ensure("the tip says how it counts", head->getToolTip().find("64 KB for Mono") != std::string::npos); - ensure("and nothing of time unasked", head->getToolTip().find("Top Scripts") == std::string::npos); + UNSCOPED_INFO("reserved, in KB" + said); + REQUIRE(said.find("reserves 128 KB for all its scripts") != std::string::npos); + UNSCOPED_INFO("as of when" + said); + REQUIRE(said.find(ALRecoveryEntry::sayWhen(reserved.when)) != std::string::npos); + UNSCOPED_INFO("no URLs said where there are none" + said); + REQUIRE(said.find("URLs") == std::string::npos); + UNSCOPED_INFO("the tip says how it counts"); + REQUIRE(head->getToolTip().find("64 KB for Mono") != std::string::npos); + UNSCOPED_INFO("and nothing of time unasked"); + REQUIRE(head->getToolTip().find("Top Scripts") == std::string::npos); shown.region->urls = 3; shown.id = "script-3"; pane.show(shown); - ensure("and URLs where there are" + head->getText(), head->getText().find("128 KB and 3 URLs") != std::string::npos); - ensure("no time where the region said none" + head->getText(), head->getText().find("ms of the region") == std::string::npos); + UNSCOPED_INFO("and URLs where there are" + head->getText()); + REQUIRE(head->getText().find("128 KB and 3 URLs") != std::string::npos); + UNSCOPED_INFO("no time where the region said none" + head->getText()); + REQUIRE(head->getText().find("ms of the region") == std::string::npos); shown.region->time = 0.125f; shown.region->timeWhen = LLDate(1.8e9); shown.id = "script-4"; pane.show(shown); - ensure("its time, said to an estate manager" + head->getText(), head->getText().find("take 0.125 ms of the region's time") != std::string::npos); - ensure("the tip says how both are counted", head->getToolTip().find("64 KB for Mono") != std::string::npos && head->getToolTip().find("Top Scripts") != std::string::npos); + UNSCOPED_INFO("its time, said to an estate manager" + head->getText()); + REQUIRE(head->getText().find("take 0.125 ms of the region's time") != std::string::npos); + { + INFO("the tip says how both are counted"); + REQUIRE(head->getToolTip().find("64 KB for Mono") != std::string::npos); + REQUIRE(head->getToolTip().find("Top Scripts") != std::string::npos); + } ALScriptRegionUsage::Usage timed; timed.time = 0.5f; timed.timeWhen = LLDate(1.8e9); shown.region = timed; shown.id = "script-5"; pane.show(shown); - ensure("time alone: no memory said" + head->getText(), - head->getText().find("reserves") == std::string::npos && head->getText().find("take 0.500 ms") != std::string::npos); - ensure("and the tip of the time alone", head->getToolTip().find("64 KB for Mono") == std::string::npos && head->getToolTip().find("Top Scripts") != std::string::npos); + { + INFO("time alone: no memory said" + head->getText()); + REQUIRE(head->getText().find("reserves") == std::string::npos); + REQUIRE(head->getText().find("take 0.500 ms") != std::string::npos); + } + { + INFO("and the tip of the time alone"); + REQUIRE(head->getToolTip().find("64 KB for Mono") == std::string::npos); + REQUIRE(head->getToolTip().find("Top Scripts") != std::string::npos); + } } // LSL on Luau's compiler records no lines, so its lines are not // weighed one by one: said, where its heat would show nothing; not of // a target whose lines merely weigh nothing. - template<> template<> - void alscriptweightspane_object::test<8>() + TEST_CASE_METHOD(alscriptweightspane_data, "ALScriptWeightsPane: LSL on Luau's compiler is said to record no lines and LSO is not", "[ALScriptWeightsPane]") { if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } - ensure("the studio's window builds with its Weights tab", tab() != nullptr); + UNSCOPED_INFO("the studio's window builds with its Weights tab"); + REQUIRE(tab() != nullptr); ALScriptWeightsPane& pane = weights(); ALScriptWeightsPane::Shown shown = lsl(); shown.weights[2].compiled = true; @@ -404,22 +461,23 @@ namespace tut std::swap(shown.weights[0], shown.weights[2]); pane.show(shown); const std::string luau = floater->findChild("weights_head", true)->getText(); - ensure("said for LSL on Luau: " + luau, luau.find("records no lines") != std::string::npos); + UNSCOPED_INFO("said for LSL on Luau: " + luau); + REQUIRE(luau.find("records no lines") != std::string::npos); pane.show(lsl()); const std::string lso = floater->findChild("weights_head", true)->getText(); - ensure("not for LSO: " + lso, lso.find("records no lines") == std::string::npos); + UNSCOPED_INFO("not for LSO: " + lso); + REQUIRE(lso.find("records no lines") == std::string::npos); } // A Luau target's strings beside its parts: the starts several share // first, in italics, with what they would save; then each string, the // heaviest first, its uses, and a function's name said as one; each // chosen says where it is first named. No other target has a table. - template<> template<> - void alscriptweightspane_object::test<9>() + TEST_CASE_METHOD(alscriptweightspane_data, "ALScriptWeightsPane: a Luau target lists its strings beside its parts", "[ALScriptWeightsPane]") { if (!ui.ok()) { - skip("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); + SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } ALScriptWeightsPane& pane = weights(); ALScriptWeightsPane::Shown shown; @@ -452,40 +510,73 @@ namespace tut pane.show(shown); ALPaneList* strings = list("weights_strings"); - ensure("the list there", strings && strings->getParent()->getVisible()); - ensure_equals("a start, then each string", strings->getItemCount(), 5); + { + INFO("the list there"); + REQUIRE(strings); + CHECK(strings->getParent()->getVisible()); + } + UNSCOPED_INFO("a start, then each string"); + CHECK(strings->getItemCount() == 5); const std::vector texts = column(strings, 0); - ensure("the start first: " + texts[0], texts[0].find("Shared start") == 0 && texts[0].find("\"You have touched me, \"") != std::string::npos && - texts[0].find("2 strings") != std::string::npos); - ensure_equals("what it saves, as less", column(strings, 1)[0], std::string("-9")); - ensure_equals("its strings' loads", column(strings, 2)[0], std::string("3")); - ensure_equals("at the first of them", column(strings, 4)[0], std::string("3")); - ensure_equals("then the heaviest first, a break shown as one", joined(texts).substr(joined({ texts[0] }).size()), + { + INFO("the start first: " + texts[0]); + CHECK(texts[0].find("Shared start") == 0); + REQUIRE(texts[0].find("\"You have touched me, \"") != std::string::npos); + REQUIRE(texts[0].find("2 strings") != std::string::npos); + } + UNSCOPED_INFO("what it saves, as less"); + CHECK(column(strings, 1)[0] == std::string("-9")); + UNSCOPED_INFO("its strings' loads"); + CHECK(column(strings, 2)[0] == std::string("3")); + UNSCOPED_INFO("at the first of them"); + CHECK(column(strings, 4)[0] == std::string("3")); + UNSCOPED_INFO("then the heaviest first, a break shown as one"); + REQUIRE(joined(texts).substr(joined({ texts[0] }).size()) == std::string("|\"You have touched me, alpha\"|\"You have touched me, bravo\"|\"greet\"|\"x\\ny\"")); - ensure_equals("each one's uses, a function's name said as one", joined(column(strings, 2)), std::string("|3|1|2|name|1")); + UNSCOPED_INFO("each one's uses, a function's name said as one"); + CHECK(joined(column(strings, 2)) == std::string("|3|1|2|name|1")); strings->selectByValue(LLSD(2)); std::optional place = pane.chosenPlace(strings); - ensure("a string chosen: where it is first named", place && place->file.empty() && place->line == 2); + { + INFO("a string chosen: where it is first named"); + REQUIRE(place); + REQUIRE(place->file.empty()); + CHECK(place->line == 2); + } strings->selectByValue(LLSD(0)); place = pane.chosenPlace(strings); - ensure("the start chosen: the first of its strings", place && place->line == 2); - ensure("not the parts' choice", !pane.chosenPlace(list("weights_parts"))); + { + INFO("the start chosen: the first of its strings"); + REQUIRE(place); + CHECK(place->line == 2); + } + UNSCOPED_INFO("not the parts' choice"); + REQUIRE_FALSE(pane.chosenPlace(list("weights_parts"))); // Kept chosen through a refill, by what it is. strings->selectByValue(LLSD(1)); pane.show(shown); - ensure("still chosen", strings->getFirstSelected() && strings->getFirstSelected()->getValue().asInteger() == 1); + { + INFO("still chosen"); + REQUIRE(strings->getFirstSelected()); + CHECK(strings->getFirstSelected()->getValue().asInteger() == 1); + } // A start's tip names its strings; each of them says it shares one. const auto tip = [&](S32 row) { const LLScrollListItem* item = strings->getAllData()[static_cast(row)]; return item->getColumn(0)->getToolTip(); }; - ensure("the start's strings named: " + tip(0), tip(0).find("\"You have touched me, alpha\"") != std::string::npos && - tip(0).find("\"You have touched me, bravo\"") != std::string::npos); - ensure("a string of it says so: " + tip(1), tip(1).find("shares its start") != std::string::npos); - ensure("one that is not, nothing: " + tip(4), tip(4).find("shares its start") == std::string::npos); + { + INFO("the start's strings named: " + tip(0)); + REQUIRE(tip(0).find("\"You have touched me, alpha\"") != std::string::npos); + REQUIRE(tip(0).find("\"You have touched me, bravo\"") != std::string::npos); + } + UNSCOPED_INFO("a string of it says so: " + tip(1)); + REQUIRE(tip(1).find("shares its start") != std::string::npos); + UNSCOPED_INFO("one that is not, nothing: " + tip(4)); + REQUIRE(tip(4).find("shares its start") == std::string::npos); // Since the save: a string not there then, new; a start by how its // saving moved, said as its bytes are, as less: saving more since, @@ -495,7 +586,8 @@ namespace tut then.sharedStarts[0].saved = 4; shown.saved = { then }; pane.show(shown); - ensure_equals("since the save", joined(column(strings, 3)), std::string("|-5||||new")); + UNSCOPED_INFO("since the save"); + CHECK(joined(column(strings, 3)) == std::string("|-5||||new")); // Keeping the start once asks the window, with its strings. std::string kept; @@ -506,25 +598,41 @@ namespace tut }); strings->selectByValue(LLSD(0)); floater->findChild("weights_keep_start", true)->onCommit(); - ensure("asked with the start and its strings", kept == "You have touched me, " && of.size() == 2 && of[1] == "You have touched me, bravo"); + { + INFO("asked with the start and its strings"); + CHECK(kept == "You have touched me, "); + REQUIRE(of.size() == 2); + CHECK(of[1] == "You have touched me, bravo"); + } kept.clear(); strings->selectByValue(LLSD(1)); floater->findChild("weights_keep_start", true)->onCommit(); - ensure("not for a string", kept.empty()); + UNSCOPED_INFO("not for a string"); + REQUIRE(kept.empty()); // Nor in a script that cannot be written to. pane.setKeepStart([&](const std::string& start, const std::vector&) { kept = start; }, []() { return false; }); strings->selectByValue(LLSD(0)); floater->findChild("weights_keep_start", true)->onCommit(); - ensure("not where the script cannot be written to", kept.empty()); + UNSCOPED_INFO("not where the script cannot be written to"); + REQUIRE(kept.empty()); // Nothing to show hides the list with the rest. pane.showNothing("Nothing open to weigh."); - ensure("hidden with nothing shown", !strings->getParent()->getVisible() && strings->getItemCount() == 0); + { + INFO("hidden with nothing shown"); + REQUIRE_FALSE(strings->getParent()->getVisible()); + CHECK(strings->getItemCount() == 0); + } pane.show(shown); - ensure("shown again", strings->getParent()->getVisible()); + UNSCOPED_INFO("shown again"); + CHECK(strings->getParent()->getVisible()); // LSO has no table: no list. pane.show(lsl()); - ensure("hidden for LSO", !strings->getParent()->getVisible() && strings->getItemCount() == 0); + { + INFO("hidden for LSO"); + REQUIRE_FALSE(strings->getParent()->getVisible()); + CHECK(strings->getItemCount() == 0); + } } } diff --git a/indra/newview/tests/alselectionoutline_gl_test.cpp b/indra/newview/tests/alselectionoutline_gl_test.cpp index ca5d9ac9d3..de1f3dee71 100644 --- a/indra/newview/tests/alselectionoutline_gl_test.cpp +++ b/indra/newview/tests/alselectionoutline_gl_test.cpp @@ -42,7 +42,8 @@ #include "../../llrender/tests/llheadlessgl_fixture.h" -#include "../test/lltut.h" +#include +#include #include #include @@ -51,10 +52,8 @@ #include #include -namespace tut +namespace { - namespace - { using Outline = ALSelectionOutline; constexpr S32 W = 64; @@ -258,10 +257,12 @@ namespace tut for (const char* object : { "avatar/objectSkinV.glsl", "deferred/textureUtilV.glsl", "objects/nonindexedTextureV.glsl" }) { S32 level = 1; - ensure(std::string("compiled ") + object, mShaders.loadShaderFile(object, level, GL_VERTEX_SHADER, &defines) != 0); + UNSCOPED_INFO(std::string("compiled ") + object); + REQUIRE(mShaders.loadShaderFile(object, level, GL_VERTEX_SHADER, &defines) != 0); } S32 level = 1; - ensure("compiled deferred/globalF.glsl", mShaders.loadShaderFile("deferred/globalF.glsl", level, GL_FRAGMENT_SHADER, &defines) != 0); + UNSCOPED_INFO("compiled deferred/globalF.glsl"); + REQUIRE(mShaders.loadShaderFile("deferred/globalF.glsl", level, GL_FRAGMENT_SHADER, &defines) != 0); mIdProgram.mName = "Selection Id Shader"; mIdProgram.mShaderFiles.clear(); @@ -270,8 +271,13 @@ namespace tut mIdProgram.mShaderFiles.push_back(std::make_pair("interface/selectionAlphaF.glsl", GL_FRAGMENT_SHADER)); mIdProgram.mShaderFiles.push_back(std::make_pair("interface/selectionUtilF.glsl", GL_FRAGMENT_SHADER)); mIdProgram.mShaderLevel = 1; - ensure("id program builds with its rigged variant", mIdProgram.createShader(LLGLSLShader::VARIANT_RIGGED)); - ensure("id program has a rigged variant", mIdProgram.mRiggedVariant && mIdProgram.mRiggedVariant != &mIdProgram); + UNSCOPED_INFO("id program builds with its rigged variant"); + REQUIRE(mIdProgram.createShader(LLGLSLShader::VARIANT_RIGGED)); + { + INFO("id program has a rigged variant"); + REQUIRE(mIdProgram.mRiggedVariant); + REQUIRE(mIdProgram.mRiggedVariant != &mIdProgram); + } mWireProgram.mName = "Selection Wireframe Shader"; mWireProgram.mShaderFiles.clear(); @@ -281,8 +287,13 @@ namespace tut mWireProgram.mShaderFiles.push_back(std::make_pair("interface/selectionAlphaF.glsl", GL_FRAGMENT_SHADER)); mWireProgram.mShaderFiles.push_back(std::make_pair("interface/selectionUtilF.glsl", GL_FRAGMENT_SHADER)); mWireProgram.mShaderLevel = 1; - ensure("wireframe program builds with its rigged variant", mWireProgram.createShader(LLGLSLShader::VARIANT_RIGGED)); - ensure("wireframe program has a rigged variant", mWireProgram.mRiggedVariant && mWireProgram.mRiggedVariant != &mWireProgram); + UNSCOPED_INFO("wireframe program builds with its rigged variant"); + REQUIRE(mWireProgram.createShader(LLGLSLShader::VARIANT_RIGGED)); + { + INFO("wireframe program has a rigged variant"); + REQUIRE(mWireProgram.mRiggedVariant); + REQUIRE(mWireProgram.mRiggedVariant != &mWireProgram); + } // The final blit's depth copy, as LLViewerShaderMgr builds gCopyDepthProgram. mCopyDepthProgram.mName = "Copy Depth Shader"; @@ -293,7 +304,8 @@ namespace tut mCopyDepthProgram.addPermutation("COPY_DEPTH", "1"); mCopyDepthProgram.addPermutation("DEPTH_ONLY", "1"); mCopyDepthProgram.mShaderLevel = 1; - ensure("copy depth program builds", mCopyDepthProgram.createShader()); + UNSCOPED_INFO("copy depth program builds"); + REQUIRE(mCopyDepthProgram.createShader()); const std::pair passes[] = { { &mJumpProgram, "selectionJumpF.glsl" }, { &mTileProgram, "selectionTileF.glsl" }, @@ -318,31 +330,42 @@ namespace tut // The edge pass searching the disk for the glow too: the full search. program->addPermutation("GLOW_DISK", "1"); } - ensure(std::string(fragment) + "'s program builds", program->createShader()); + UNSCOPED_INFO(std::string(fragment) + "'s program builds"); + REQUIRE(program->createShader()); } const LLRenderTarget::eDepthFormat depth = mReverse ? LLRenderTarget::DEPTH_FMT_32F : LLRenderTarget::DEPTH_FMT_24; - ensure("id target", mIdMap.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); - ensure("jump target", mJumps.allocate(W, H, GL_R8)); - ensure("glow reach target", mGlowReach.allocate(Outline::tileCount(W), Outline::tileCount(H), GL_RGBA16)); - ensure("glow row target", mGlowRows.allocate(W, H, GL_R8)); - ensure("frame target", mFrame.allocate(W, H, GL_RGBA8)); - ensure("window target", mWindow.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); - ensure("tile target", mTiles.allocate(Outline::tileCount(W), Outline::tileCount(H), GL_RGBA16)); + UNSCOPED_INFO("id target"); + REQUIRE(mIdMap.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); + UNSCOPED_INFO("jump target"); + REQUIRE(mJumps.allocate(W, H, GL_R8)); + UNSCOPED_INFO("glow reach target"); + REQUIRE(mGlowReach.allocate(Outline::tileCount(W), Outline::tileCount(H), GL_RGBA16)); + UNSCOPED_INFO("glow row target"); + REQUIRE(mGlowRows.allocate(W, H, GL_R8)); + UNSCOPED_INFO("frame target"); + REQUIRE(mFrame.allocate(W, H, GL_RGBA8)); + UNSCOPED_INFO("window target"); + REQUIRE(mWindow.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); + UNSCOPED_INFO("tile target"); + REQUIRE(mTiles.allocate(Outline::tileCount(W), Outline::tileCount(H), GL_RGBA16)); // Every tile holding every id and a jump: the edge pass searches every pixel's disk, as it did before // the tiles. - ensure("all tiles target", mAllTiles.allocate(Outline::tileCount(W), Outline::tileCount(H), GL_RGBA16)); + UNSCOPED_INFO("all tiles target"); + REQUIRE(mAllTiles.allocate(Outline::tileCount(W), Outline::tileCount(H), GL_RGBA16)); mAllTiles.bindTarget(); gGL.setClearColor(LLColor4(1.f, 1.f, 1.f, 1.f)); mAllTiles.clear(); gGL.setClearColor(LLColor4(0.f, 0.f, 0.f, 0.f)); mAllTiles.flush(); - ensure("far depth", mFar.allocate(W, H, 0, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); + UNSCOPED_INFO("far depth"); + REQUIRE(mFar.allocate(W, H, 0, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); clearDepth(mFar); sceneAt(W, H); mTriangle = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX); - ensure("triangle", mTriangle->allocateBuffer(3, 0)); + UNSCOPED_INFO("triangle"); + REQUIRE(mTriangle->allocateBuffer(3, 0)); LLStrider vert; mTriangle->getVertexStrider(vert); vert[0].set(-1.f, 1.f, 0.f); @@ -363,7 +386,8 @@ namespace tut void sceneAt(S32 width, S32 height) { const LLRenderTarget::eDepthFormat depth = mReverse ? LLRenderTarget::DEPTH_FMT_32F : LLRenderTarget::DEPTH_FMT_24; - ensure("scene depth", mScene.allocate(width, height, 0, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); + UNSCOPED_INFO("scene depth"); + REQUIRE(mScene.allocate(width, height, 0, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); clearDepth(mScene); } @@ -406,7 +430,8 @@ namespace tut const U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | (weights ? LLVertexBuffer::MAP_WEIGHT4 : 0); LLPointer buffer = new LLVertexBuffer(mask); - ensure("quad", buffer->allocateBuffer(4, 6)); + UNSCOPED_INFO("quad"); + REQUIRE(buffer->allocateBuffer(4, 6)); LLStrider vert; LLStrider texcoord; LLStrider index; @@ -626,7 +651,8 @@ namespace tut LLGLSLShader::unbind(); } target.flush(); - ensure("the id program reads the face's texture", texture_read); + UNSCOPED_INFO("the id program reads the face's texture"); + REQUIRE(texture_read); } void idPass(const std::vector& draws, const F32* palette = nullptr) @@ -855,7 +881,8 @@ namespace tut gGL.matrixMode(LLRender::MM_PROJECTION); gGL.loadMatrix(mProjection); gGL.matrixMode(LLRender::MM_MODELVIEW); - ensure("the wireframe program reads the face's texture", texture_read); + UNSCOPED_INFO("the wireframe program reads the face's texture"); + REQUIRE(texture_read); return px; } @@ -870,7 +897,8 @@ namespace tut { const LLVector4a extents[2] = { LLVector4a(-2.f, -1.f, QUAD_Z), LLVector4a(2.f, 1.f, QUAD_Z) }; LLRect rect; - ensure("the quads' box is on screen", Outline::scissorRect(mProjection, extents, W, H, reach, rect)); + UNSCOPED_INFO("the quads' box is on screen"); + REQUIRE(Outline::scissorRect(mProjection, extents, W, H, reach, rect)); return rect; } @@ -913,16 +941,11 @@ namespace tut bool mReverse = false; }; - typedef test_group alselectionoutline_t; - typedef alselectionoutline_t::object alselectionoutline_object_t; - tut::alselectionoutline_t alselectionoutline_testcase("ALSelectionOutline"); - } // Two objects side by side: each is outlined around its outer contour in its own colour, a solid line two // pixels wide at a UI scale of 1. The edge between them is drawn once, thin and faint, on the side of the one // given the lower id. Their insides and the space past the line are left alone. - template<> template<> - void alselectionoutline_object_t::test<1>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: two objects side by side are each outlined in their own colour", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -930,37 +953,66 @@ namespace tut idPass({ { quadA(), ID_A }, { quadB(), ID_B } }); const std::vector ids = read(mIdMap); - ensure_equals(named(reverse, "A's id"), idAt(ids, 20, 32), ID_A); - ensure_equals(named(reverse, "B's id, past one byte"), idAt(ids, 40, 32), ID_B); - ensure_equals(named(reverse, "nothing selected outside"), idAt(ids, 2, 2), 0U); - ensure_equals(named(reverse, "the priority in alpha"), (U32)at(ids, 20, 32).a, (U32)Outline::PRIORITY_ROOT); + UNSCOPED_INFO(named(reverse, "A's id")); + REQUIRE(idAt(ids, 20, 32) == ID_A); + UNSCOPED_INFO(named(reverse, "B's id, past one byte")); + REQUIRE(idAt(ids, 40, 32) == ID_B); + UNSCOPED_INFO(named(reverse, "nothing selected outside")); + REQUIRE(idAt(ids, 2, 2) == 0U); + UNSCOPED_INFO(named(reverse, "the priority in alpha")); + REQUIRE((U32)at(ids, 20, 32).a == (U32)Outline::PRIORITY_ROOT); palette({ { ID_A, RED }, { ID_B, GREEN } }, true); const std::vector px = edgePass(); - ensure_equals(named(reverse, "A outlined at full strength beside its contour"), (U32)at(px, 8, 32).r, 255U); - ensure_equals(named(reverse, "and a pixel further"), (U32)at(px, 7, 32).r, 255U); - ensure(named(reverse, "and in its colour"), red(at(px, 7, 32))); - ensure(named(reverse, "nothing past the line"), black(at(px, 6, 32))); - ensure(named(reverse, "A outlined above"), red(at(px, 20, 45)) && black(at(px, 20, 46))); - ensure(named(reverse, "A outlined below"), red(at(px, 20, 18)) && black(at(px, 20, 17))); - ensure(named(reverse, "B outlined right of its contour"), green(at(px, 56, 32)) && black(at(px, 57, 32))); - ensure(named(reverse, "B outlined above"), green(at(px, 40, 45))); - ensure(named(reverse, "nothing far away"), black(at(px, 2, 2))); + UNSCOPED_INFO(named(reverse, "A outlined at full strength beside its contour")); + REQUIRE((U32)at(px, 8, 32).r == 255U); + UNSCOPED_INFO(named(reverse, "and a pixel further")); + REQUIRE((U32)at(px, 7, 32).r == 255U); + UNSCOPED_INFO(named(reverse, "and in its colour")); + REQUIRE(red(at(px, 7, 32))); + UNSCOPED_INFO(named(reverse, "nothing past the line")); + REQUIRE(black(at(px, 6, 32))); + { + INFO(named(reverse, "A outlined above")); + REQUIRE(red(at(px, 20, 45))); + REQUIRE(black(at(px, 20, 46))); + } + { + INFO(named(reverse, "A outlined below")); + REQUIRE(red(at(px, 20, 18))); + REQUIRE(black(at(px, 20, 17))); + } + { + INFO(named(reverse, "B outlined right of its contour")); + REQUIRE(green(at(px, 56, 32))); + REQUIRE(black(at(px, 57, 32))); + } + UNSCOPED_INFO(named(reverse, "B outlined above")); + REQUIRE(green(at(px, 40, 45))); + UNSCOPED_INFO(named(reverse, "nothing far away")); + REQUIRE(black(at(px, 2, 2))); const Pixel edge = at(px, 31, 32); - ensure(named(reverse, "the shared edge on A's side, in A's colour"), red(edge)); - ensure(named(reverse, "fainter than the contour"), edge.r >= 150 && edge.r <= 156); - ensure(named(reverse, "and not on B's"), black(at(px, 32, 32))); - ensure(named(reverse, "A's inside left alone"), black(at(px, 20, 32))); - ensure(named(reverse, "B's inside left alone"), black(at(px, 44, 32))); + UNSCOPED_INFO(named(reverse, "the shared edge on A's side, in A's colour")); + REQUIRE(red(edge)); + { + INFO(named(reverse, "fainter than the contour")); + REQUIRE(edge.r >= 150); + REQUIRE(edge.r <= 156); + } + UNSCOPED_INFO(named(reverse, "and not on B's")); + REQUIRE(black(at(px, 32, 32))); + UNSCOPED_INFO(named(reverse, "A's inside left alone")); + REQUIRE(black(at(px, 20, 32))); + UNSCOPED_INFO(named(reverse, "B's inside left alone")); + REQUIRE(black(at(px, 44, 32))); } } // The same two quads under one id, as a mask without ids would see them: the contour stays and the edge // between them is gone. This is what the ids buy. - template<> template<> - void alselectionoutline_object_t::test<2>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: two quads under one id keep their contour but lose the edge between", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -969,17 +1021,20 @@ namespace tut palette({ { ID_A, RED } }, true); const std::vector px = edgePass(); - ensure(named(reverse, "contour still outlined"), red(at(px, 8, 32))); - ensure(named(reverse, "contour still outlined on the far side"), red(at(px, 55, 32))); - ensure(named(reverse, "no edge between them on one side"), black(at(px, 31, 32))); - ensure(named(reverse, "no edge between them on the other"), black(at(px, 32, 32))); + UNSCOPED_INFO(named(reverse, "contour still outlined")); + REQUIRE(red(at(px, 8, 32))); + UNSCOPED_INFO(named(reverse, "contour still outlined on the far side")); + REQUIRE(red(at(px, 55, 32))); + UNSCOPED_INFO(named(reverse, "no edge between them on one side")); + REQUIRE(black(at(px, 31, 32))); + UNSCOPED_INFO(named(reverse, "no edge between them on the other")); + REQUIRE(black(at(px, 32, 32))); } } // Behind something nearer in the scene's depth, the surface is marked hidden and its outline drawn dimmed; // with hidden parts off, not at all. Where nothing covers it, the outline is unchanged. - template<> template<> - void alselectionoutline_object_t::test<3>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a surface behind the scene's depth is outlined dimmed or not at all", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -998,35 +1053,46 @@ namespace tut idPass({ { quadA(), ID_A } }); std::vector ids = read(mIdMap); - ensure(named(reverse, "covered part marked hidden and drawn"), drawnHidden(at(ids, 12, 32))); - ensure_equals(named(reverse, "uncovered part marked visible"), (U32)at(ids, 25, 32).b, 255U); - ensure_equals(named(reverse, "hidden parts keep their id"), idAt(ids, 12, 32), ID_A); + UNSCOPED_INFO(named(reverse, "covered part marked hidden and drawn")); + REQUIRE(drawnHidden(at(ids, 12, 32))); + UNSCOPED_INFO(named(reverse, "uncovered part marked visible")); + REQUIRE((U32)at(ids, 25, 32).b == 255U); + UNSCOPED_INFO(named(reverse, "hidden parts keep their id")); + REQUIRE(idAt(ids, 12, 32) == ID_A); palette({ { ID_A, RED } }, true); std::vector px = edgePass(); const U32 hidden = at(px, 8, 32).r; const U32 visible = at(px, 25, 44).r; - ensure_equals(named(reverse, "visible outline at full strength"), visible, 255U); - ensure(named(reverse, "hidden outline dimmed to the hidden alpha"), hidden >= 90 && hidden <= 115); + UNSCOPED_INFO(named(reverse, "visible outline at full strength")); + REQUIRE(visible == 255U); + { + INFO(named(reverse, "hidden outline dimmed to the hidden alpha")); + REQUIRE(hidden >= 90); + REQUIRE(hidden <= 115); + } Draw left_out = { quadA(), ID_A }; left_out.mShowHidden = false; idPass({ left_out }); ids = read(mIdMap); - ensure_equals(named(reverse, "covered part marked not drawn"), (U32)at(ids, 12, 32).b, 0U); - ensure_equals(named(reverse, "uncovered part still visible"), (U32)at(ids, 25, 32).b, 255U); + UNSCOPED_INFO(named(reverse, "covered part marked not drawn")); + REQUIRE((U32)at(ids, 12, 32).b == 0U); + UNSCOPED_INFO(named(reverse, "uncovered part still visible")); + REQUIRE((U32)at(ids, 25, 32).b == 255U); palette({ { ID_A, RED } }, false); px = edgePass(); - ensure(named(reverse, "hidden outline left out"), black(at(px, 8, 32))); - ensure_equals(named(reverse, "visible outline kept"), (U32)at(px, 25, 44).r, 255U); + UNSCOPED_INFO(named(reverse, "hidden outline left out")); + REQUIRE(black(at(px, 8, 32))); + UNSCOPED_INFO(named(reverse, "visible outline kept")); + REQUIRE((U32)at(px, 25, 44).r == 255U); } } // A surface that is itself in the scene is visible, at the window's resolution and at half of it, where the // scene's depth is read by uv from texels twice the size and, on a surface turned away, nearer than the // fragment by up to half a texel of its slope. - template<> template<> - void alselectionoutline_object_t::test<4>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a surface the scene drew is visible at full and at half resolution", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -1057,16 +1123,17 @@ namespace tut } } const std::string at_divisor = " at render resolution / " + std::to_string(divisor); - ensure(named(reverse, "the surface covers pixels" + at_divisor), covered > 200); - ensure_equals(named(reverse, "none of its own pixels hidden by itself" + at_divisor), hidden, size_t(0)); + UNSCOPED_INFO(named(reverse, "the surface covers pixels" + at_divisor)); + REQUIRE(covered > 200); + UNSCOPED_INFO(named(reverse, "none of its own pixels hidden by itself" + at_divisor)); + REQUIRE(hidden == size_t(0)); } } } // The scissor is the objects' projected box grown by the contour's reach: the scissored edge pass draws exactly // what the unscissored one does. Without the growth the line outside the box is clipped. - template<> template<> - void alselectionoutline_object_t::test<5>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the scissor is the objects' projected box grown by the contour's reach", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -1076,46 +1143,60 @@ namespace tut const std::vector full = edgePass(); const S32 reach = Outline::lineReach(view().mWidth); - ensure_equals(named(reverse, "the contour reaches its width and a pixel"), reach, 3); + UNSCOPED_INFO(named(reverse, "the contour reaches its width and a pixel")); + REQUIRE(reach == 3); const LLRect rect = boxRect(reach); - ensure_equals(named(reverse, "left: column 8.57 floored, less the reach"), rect.mLeft, 8 - reach); - ensure_equals(named(reverse, "right: column 55.43 ceiled, plus the reach"), rect.mRight, 56 + reach); - ensure_equals(named(reverse, "bottom: row 20.28 floored, less the reach"), rect.mBottom, 20 - reach); - ensure_equals(named(reverse, "top: row 43.72 ceiled, plus the reach"), rect.mTop, 44 + reach); + UNSCOPED_INFO(named(reverse, "left: column 8.57 floored, less the reach")); + REQUIRE(rect.mLeft == 8 - reach); + UNSCOPED_INFO(named(reverse, "right: column 55.43 ceiled, plus the reach")); + REQUIRE(rect.mRight == 56 + reach); + UNSCOPED_INFO(named(reverse, "bottom: row 20.28 floored, less the reach")); + REQUIRE(rect.mBottom == 20 - reach); + UNSCOPED_INFO(named(reverse, "top: row 43.72 ceiled, plus the reach")); + REQUIRE(rect.mTop == 44 + reach); const std::vector scissored = edgePass(&rect); - ensure(named(reverse, "something is outlined"), lit(full) > 0); - ensure(named(reverse, "the scissored pass draws every outline pixel"), scissored == full); + UNSCOPED_INFO(named(reverse, "something is outlined")); + REQUIRE(lit(full) > 0); + UNSCOPED_INFO(named(reverse, "the scissored pass draws every outline pixel")); + REQUIRE(scissored == full); const LLRect tight = boxRect(0); const std::vector clipped = edgePass(&tight); - ensure(named(reverse, "a box without the reach clips the line"), lit(clipped) < lit(full)); - ensure(named(reverse, "the line's outer pixels are what it loses"), !black(at(full, 7, 32)) && black(at(clipped, 7, 32))); + UNSCOPED_INFO(named(reverse, "a box without the reach clips the line")); + REQUIRE(lit(clipped) < lit(full)); + { + INFO(named(reverse, "the line's outer pixels are what it loses")); + REQUIRE_FALSE(black(at(full, 7, 32))); + REQUIRE(black(at(clipped, 7, 32))); + } } } // Where the scissor gives up: a box reaching behind the eye takes the whole target, and one wholly behind it // touches nothing. - template<> template<> - void alselectionoutline_object_t::test<6>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: scissorRect takes the whole target for a box reaching behind the eye", "[ALSelectionOutline]") { const LLMatrix4a proj = al_perspective(FOV, 1.f, NEAR_PLANE, FORWARD_FAR); LLRect rect; const LLVector4a straddling[2] = { LLVector4a(-1.f, -1.f, -5.f), LLVector4a(1.f, 1.f, 2.f) }; - ensure("a box reaching behind the eye is drawn", Outline::scissorRect(proj, straddling, W, H, 3, rect)); - ensure("over the whole target", rect == LLRect(0, H, W, 0)); + UNSCOPED_INFO("a box reaching behind the eye is drawn"); + REQUIRE(Outline::scissorRect(proj, straddling, W, H, 3, rect)); + UNSCOPED_INFO("over the whole target"); + CHECK(rect == LLRect(0, H, W, 0)); const LLVector4a behind[2] = { LLVector4a(-1.f, -1.f, 2.f), LLVector4a(1.f, 1.f, 5.f) }; - ensure("a box behind the eye is not", !Outline::scissorRect(proj, behind, W, H, 3, rect)); + UNSCOPED_INFO("a box behind the eye is not"); + CHECK_FALSE(Outline::scissorRect(proj, behind, W, H, 3, rect)); const LLVector4a aside[2] = { LLVector4a(30.f, -1.f, -5.f), LLVector4a(32.f, 1.f, -5.f) }; - ensure("a box off to the side is not", !Outline::scissorRect(proj, aside, W, H, 3, rect)); + UNSCOPED_INFO("a box off to the side is not"); + CHECK_FALSE(Outline::scissorRect(proj, aside, W, H, 3, rect)); } // A rigged object's id lands where its joint palette puts it, not at its bind pose, and moves with the pose. - template<> template<> - void alselectionoutline_object_t::test<7>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a rigged object's id lands where its joint palette poses it", "[ALSelectionOutline]") { // Joint 0 moved 1.5 m along +x, then along -x. const F32 right[12] = { 1.f, 0.f, 0.f, 1.5f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f }; @@ -1128,63 +1209,92 @@ namespace tut idPass({ { bound, ID_A } }, right); std::vector ids = read(mIdMap); - ensure_equals(named(reverse, "posed right"), idAt(ids, 49, 32), ID_A); - ensure_equals(named(reverse, "not at the bind pose"), idAt(ids, 32, 32), 0U); - ensure_equals(named(reverse, "not posed left"), idAt(ids, 14, 32), 0U); + UNSCOPED_INFO(named(reverse, "posed right")); + REQUIRE(idAt(ids, 49, 32) == ID_A); + UNSCOPED_INFO(named(reverse, "not at the bind pose")); + REQUIRE(idAt(ids, 32, 32) == 0U); + UNSCOPED_INFO(named(reverse, "not posed left")); + REQUIRE(idAt(ids, 14, 32) == 0U); idPass({ { bound, ID_A } }, left); ids = read(mIdMap); - ensure_equals(named(reverse, "posed left"), idAt(ids, 14, 32), ID_A); - ensure_equals(named(reverse, "gone from the right"), idAt(ids, 49, 32), 0U); + UNSCOPED_INFO(named(reverse, "posed left")); + REQUIRE(idAt(ids, 14, 32) == ID_A); + UNSCOPED_INFO(named(reverse, "gone from the right")); + REQUIRE(idAt(ids, 49, 32) == 0U); // Posed, it covers columns 9 to 20 and rows 26 to 37. palette({ { ID_A, RED } }, true); const std::vector px = edgePass(); - ensure(named(reverse, "outlined above where it is posed"), red(at(px, 14, 39))); - ensure(named(reverse, "outlined below where it is posed"), red(at(px, 14, 24))); - ensure(named(reverse, "not where it is not"), black(at(px, 49, 39)) && black(at(px, 49, 24))); + UNSCOPED_INFO(named(reverse, "outlined above where it is posed")); + REQUIRE(red(at(px, 14, 39))); + UNSCOPED_INFO(named(reverse, "outlined below where it is posed")); + REQUIRE(red(at(px, 14, 24))); + { + INFO(named(reverse, "not where it is not")); + REQUIRE(black(at(px, 49, 39))); + REQUIRE(black(at(px, 49, 24))); + } } } // The palette: an id's visible colour above its hidden one, PALETTE_WIDTH ids to a pair of rows; the hidden // one dimmed, or transparent with hidden parts off. - template<> template<> - void alselectionoutline_object_t::test<8>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the palette holds PALETTE_WIDTH ids to a pair of visible and hidden rows", "[ALSelectionOutline]") { - ensure_equals("one pair of rows up to 255", Outline::paletteRows(255), 2U); - ensure_equals("two from 256", Outline::paletteRows(256), 4U); + UNSCOPED_INFO("one pair of rows up to 255"); + CHECK(Outline::paletteRows(255) == 2U); + UNSCOPED_INFO("two from 256"); + CHECK(Outline::paletteRows(256) == 4U); std::vector texels((size_t)Outline::PALETTE_WIDTH * 4 * 4, 0); Outline::writePalette(texels, 300, LLColor4(1.f, 0.5f, 0.f, 0.8f), true); const size_t visible = ((size_t)2 * Outline::PALETTE_WIDTH + 44) * 4; const size_t hidden = ((size_t)3 * Outline::PALETTE_WIDTH + 44) * 4; - ensure_equals("visible red", (U32)texels[visible], 255U); - ensure_equals("visible green", (U32)texels[visible + 1], 128U); - ensure_equals("visible alpha", (U32)texels[visible + 3], 204U); - ensure_equals("hidden keeps the colour", (U32)texels[hidden + 1], 128U); - ensure_equals("hidden alpha dimmed", (U32)texels[hidden + 3], (U32)ll_round(0.8f * Outline::HIDDEN_ALPHA * 255.f)); + UNSCOPED_INFO("visible red"); + CHECK((U32)texels[visible] == 255U); + UNSCOPED_INFO("visible green"); + CHECK((U32)texels[visible + 1] == 128U); + UNSCOPED_INFO("visible alpha"); + CHECK((U32)texels[visible + 3] == 204U); + UNSCOPED_INFO("hidden keeps the colour"); + CHECK((U32)texels[hidden + 1] == 128U); + UNSCOPED_INFO("hidden alpha dimmed"); + CHECK((U32)texels[hidden + 3] == (U32)ll_round(0.8f * Outline::HIDDEN_ALPHA * 255.f)); Outline::writePalette(texels, 300, LLColor4(1.f, 0.5f, 0.f, 0.8f), false); - ensure_equals("hidden transparent with hidden parts off", (U32)texels[hidden + 3], 0U); + UNSCOPED_INFO("hidden transparent with hidden parts off"); + CHECK((U32)texels[hidden + 3] == 0U); } // The widths: the contour AlchemySelectionOutlineWidth wide, held to 1 to 16, and the edges between objects a // pixel, at a UI scale of 1; both scaled with it and rounded, never under a pixel; the world and the HUD alike. - template<> template<> - void alselectionoutline_object_t::test<9>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: line widths scale with the UI and the contour's is held to 1 to 16", "[ALSelectionOutline]") { - ensure_equals("the setting's default", Outline::contourWidth(Outline::DEFAULT_CONTOUR_WIDTH, 1.f), 2); - ensure_equals("the default at 1.5", Outline::contourWidth(Outline::DEFAULT_CONTOUR_WIDTH, 1.5f), 3); - ensure_equals("the default at 2", Outline::contourWidth(Outline::DEFAULT_CONTOUR_WIDTH, 2.f), 4); - ensure_equals("a setting between pixels rounds", Outline::contourWidth(2.5f, 1.f), 3); - ensure_equals("a setting under 1 held to 1", Outline::contourWidth(0.25f, 1.f), 1); - ensure_equals("a setting over 16 held to 16", Outline::contourWidth(40.f, 1.f), 16); - ensure_equals("and scaled after", Outline::contourWidth(40.f, 2.f), 32); - ensure_equals("a setting that is not a number held to 1", Outline::contourWidth(std::numeric_limits::quiet_NaN(), 1.f), 1); - ensure_equals("never under a pixel", Outline::contourWidth(1.f, 0.2f), 1); - ensure_equals("edges at 1", Outline::lineWidth(Outline::INNER_WIDTH, 1.f), 1); - ensure_equals("edges at 2", Outline::lineWidth(Outline::INNER_WIDTH, 2.f), 2); - ensure_equals("a line reaches its width and a pixel", Outline::lineReach(4), 5); + UNSCOPED_INFO("the setting's default"); + CHECK(Outline::contourWidth(Outline::DEFAULT_CONTOUR_WIDTH, 1.f) == 2); + UNSCOPED_INFO("the default at 1.5"); + CHECK(Outline::contourWidth(Outline::DEFAULT_CONTOUR_WIDTH, 1.5f) == 3); + UNSCOPED_INFO("the default at 2"); + CHECK(Outline::contourWidth(Outline::DEFAULT_CONTOUR_WIDTH, 2.f) == 4); + UNSCOPED_INFO("a setting between pixels rounds"); + CHECK(Outline::contourWidth(2.5f, 1.f) == 3); + UNSCOPED_INFO("a setting under 1 held to 1"); + CHECK(Outline::contourWidth(0.25f, 1.f) == 1); + UNSCOPED_INFO("a setting over 16 held to 16"); + CHECK(Outline::contourWidth(40.f, 1.f) == 16); + UNSCOPED_INFO("and scaled after"); + CHECK(Outline::contourWidth(40.f, 2.f) == 32); + UNSCOPED_INFO("a setting that is not a number held to 1"); + CHECK(Outline::contourWidth(std::numeric_limits::quiet_NaN(), 1.f) == 1); + UNSCOPED_INFO("never under a pixel"); + CHECK(Outline::contourWidth(1.f, 0.2f) == 1); + UNSCOPED_INFO("edges at 1"); + CHECK(Outline::lineWidth(Outline::INNER_WIDTH, 1.f) == 1); + UNSCOPED_INFO("edges at 2"); + CHECK(Outline::lineWidth(Outline::INNER_WIDTH, 2.f) == 2); + UNSCOPED_INFO("a line reaches its width and a pixel"); + CHECK(Outline::lineReach(4) == 5); const LLMatrix4a hud = al_ortho(-0.5f, 0.5f, -0.5f, 0.5f, 0.f, 10.f); const LLMatrix4a world = al_perspective(FOV, 1.f, NEAR_PLANE, FORWARD_FAR); @@ -1195,19 +1305,26 @@ namespace tut const Outline::View in_world = Outline::makeView(identity(), world, setting, ui_scale, false); const Outline::View on_hud = Outline::makeView(identity(), hud, setting, ui_scale, true); const std::string with = " for " + std::to_string(setting) + " at UI scale " + std::to_string(ui_scale); - ensure_equals("the contour" + with, in_world.mWidth, Outline::contourWidth(setting, ui_scale)); - ensure_equals("the edges" + with, in_world.mInnerWidth, Outline::lineWidth(Outline::INNER_WIDTH, ui_scale)); - ensure_equals("the HUD's contour as the world's" + with, on_hud.mWidth, in_world.mWidth); - ensure_equals("the HUD's edges as the world's" + with, on_hud.mInnerWidth, in_world.mInnerWidth); - ensure("the HUD's view is the HUD's" + with, on_hud.mHUD && !in_world.mHUD); + UNSCOPED_INFO("the contour" + with); + REQUIRE(in_world.mWidth == Outline::contourWidth(setting, ui_scale)); + UNSCOPED_INFO("the edges" + with); + REQUIRE(in_world.mInnerWidth == Outline::lineWidth(Outline::INNER_WIDTH, ui_scale)); + UNSCOPED_INFO("the HUD's contour as the world's" + with); + REQUIRE(on_hud.mWidth == in_world.mWidth); + UNSCOPED_INFO("the HUD's edges as the world's" + with); + REQUIRE(on_hud.mInnerWidth == in_world.mInnerWidth); + { + INFO("the HUD's view is the HUD's" + with); + REQUIRE(on_hud.mHUD); + REQUIRE_FALSE(in_world.mHUD); + } } } } // On the HUD the scene's depth is not read: a surface behind something nearer, in a depth bound where the // scene's would be, still counts as visible, and its outline is drawn at full strength with hidden parts off. - template<> template<> - void alselectionoutline_object_t::test<10>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the HUD's id pass does not read the scene's depth", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -1224,7 +1341,8 @@ namespace tut mScene.flush(); idPass({ { quadA(), ID_A } }); - ensure(named(reverse, "the world's pass hides A behind it"), drawnHidden(at(read(mIdMap), 20, 32))); + UNSCOPED_INFO(named(reverse, "the world's pass hides A behind it")); + REQUIRE(drawnHidden(at(read(mIdMap), 20, 32))); idPass(mIdMap, nullptr, { { quadA(), ID_A } }, nullptr, &mScene); const std::vector ids = read(mIdMap); @@ -1241,12 +1359,15 @@ namespace tut } } } - ensure(named(reverse, "the HUD's pass draws A"), covered > 200); - ensure_equals(named(reverse, "and hides none of it"), hidden, size_t(0)); + UNSCOPED_INFO(named(reverse, "the HUD's pass draws A")); + REQUIRE(covered > 200); + UNSCOPED_INFO(named(reverse, "and hides none of it")); + REQUIRE(hidden == size_t(0)); palette({ { ID_A, RED } }, false); const std::vector px = edgePass(); - ensure_equals(named(reverse, "outlined at full strength"), (U32)at(px, 8, 32).r, 255U); + UNSCOPED_INFO(named(reverse, "outlined at full strength")); + REQUIRE((U32)at(px, 8, 32).r == 255U); } } @@ -1254,8 +1375,7 @@ namespace tut // both conventions: al_ortho (gGL.ortho) reverses its depth with reverse-Z, and so does the flattened depth row // get_hud_matrices gives the HUD. An orthographic projection left unreversed under reverse-Z keeps the farthest // instead, which is what the reversal is for. - template<> template<> - void alselectionoutline_object_t::test<11>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the HUD's projections keep the nearest surface in the id target's depth", "[ALSelectionOutline]") { constexpr F32 HUD_DEPTH = 10.f; constexpr U32 ID_NEAR = 1; @@ -1282,8 +1402,10 @@ namespace tut ? projectedIds(*projection, { { nearer, ID_NEAR }, { farther, ID_FAR } }) : projectedIds(*projection, { { farther, ID_FAR }, { nearer, ID_NEAR } }); const std::string order = near_first ? ", nearer drawn first" : ", farther drawn first"; - ensure_equals(named(reverse, which + ": the nearer kept" + order), idAt(ids, 32, 32), ID_NEAR); - ensure_equals(named(reverse, which + ": the farther around it" + order), idAt(ids, 10, 32), ID_FAR); + UNSCOPED_INFO(named(reverse, which + ": the nearer kept" + order)); + REQUIRE(idAt(ids, 32, 32) == ID_NEAR); + UNSCOPED_INFO(named(reverse, which + ": the farther around it" + order)); + REQUIRE(idAt(ids, 10, 32) == ID_FAR); } } @@ -1291,7 +1413,8 @@ namespace tut { const LLMatrix4a unreversed = LLMatrix4a::orthoZO(-0.5f, 0.5f, -0.5f, 0.5f, 0.f, HUD_DEPTH); const std::vector ids = projectedIds(unreversed, { { farther, ID_FAR }, { nearer, ID_NEAR } }); - ensure_equals(named(reverse, "unreversed, the farther wins"), idAt(ids, 32, 32), ID_FAR); + UNSCOPED_INFO(named(reverse, "unreversed, the farther wins")); + REQUIRE(idAt(ids, 32, 32) == ID_FAR); } } } @@ -1299,8 +1422,7 @@ namespace tut // The contour is drawn as wide as the setting and the UI scale make it, held to the setting's range, and as many // pixels wide in the world, through a perspective with the scene's depth read, as on the HUD, through an // orthographic projection with none: its width is in pixels. - template<> template<> - void alselectionoutline_object_t::test<12>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the drawn contour is as wide as contourWidth in the world and on the HUD", "[ALSelectionOutline]") { const std::pair settings[] = { { Outline::DEFAULT_CONTOUR_WIDTH, 1.f }, { Outline::DEFAULT_CONTOUR_WIDTH, 2.f }, { 4.f, 1.f }, { 1.f, 1.f }, { 2.5f, 1.f }, { 0.25f, 1.f }, { 40.f, 1.f } }; @@ -1321,8 +1443,10 @@ namespace tut { ++hud_band; } - ensure_equals(named(reverse, "the HUD's contour is the setting's width" + with), hud_band, width); - ensure(named(reverse, "nothing past it" + with), black(at(px, 19 - width - 1, 32))); + UNSCOPED_INFO(named(reverse, "the HUD's contour is the setting's width" + with)); + REQUIRE(hud_band == width); + UNSCOPED_INFO(named(reverse, "nothing past it" + with)); + REQUIRE(black(at(px, 19 - width - 1, 32))); // The world's: A's left edge is column 9, room for a line eight pixels wide. if (width <= 8) @@ -1334,7 +1458,8 @@ namespace tut { ++world_band; } - ensure_equals(named(reverse, "the world's is the same" + with), world_band, hud_band); + UNSCOPED_INFO(named(reverse, "the world's is the same" + with)); + REQUIRE(world_band == hud_band); } } } @@ -1344,18 +1469,26 @@ namespace tut // through the base colour's transform and the face's texture animation; an opaque face is not cut at all, and // the face's colour, transparent or not, never is. The ramp's alpha is its column, and pixel column c samples // column 4c + 2 of it. - template<> template<> - void alselectionoutline_object_t::test<13>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a face's texture alpha cuts it out of the id target", "[ALSelectionOutline]") { - ensure_equals("a mask at its cutoff", Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_MASK, 64, true), 64.f / 255.f); - ensure_equals("a blend at the blend cutoff", Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_BLEND, 64, true), Outline::BLEND_ALPHA_CUTOFF); - ensure_equals("no material blends", Outline::legacyAlphaCutoff(false, 0, 0, true), Outline::BLEND_ALPHA_CUTOFF); - ensure_equals("opaque", Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_NONE, 64, true), Outline::NO_ALPHA_TEST); - ensure_equals("emissive", Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE, 64, true), Outline::NO_ALPHA_TEST); - ensure_equals("a texture without alpha", Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_MASK, 64, false), Outline::NO_ALPHA_TEST); - ensure_equals("GLTF mask", Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_MASK, 0.25f), 0.25f); - ensure_equals("GLTF blend", Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_BLEND, 0.25f), Outline::BLEND_ALPHA_CUTOFF); - ensure_equals("GLTF opaque", Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_OPAQUE, 0.25f), Outline::NO_ALPHA_TEST); + UNSCOPED_INFO("a mask at its cutoff"); + CHECK(Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_MASK, 64, true) == 64.f / 255.f); + UNSCOPED_INFO("a blend at the blend cutoff"); + CHECK(Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_BLEND, 64, true) == Outline::BLEND_ALPHA_CUTOFF); + UNSCOPED_INFO("no material blends"); + CHECK(Outline::legacyAlphaCutoff(false, 0, 0, true) == Outline::BLEND_ALPHA_CUTOFF); + UNSCOPED_INFO("opaque"); + CHECK(Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_NONE, 64, true) == Outline::NO_ALPHA_TEST); + UNSCOPED_INFO("emissive"); + CHECK(Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE, 64, true) == Outline::NO_ALPHA_TEST); + UNSCOPED_INFO("a texture without alpha"); + CHECK(Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_MASK, 64, false) == Outline::NO_ALPHA_TEST); + UNSCOPED_INFO("GLTF mask"); + CHECK(Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_MASK, 0.25f) == 0.25f); + UNSCOPED_INFO("GLTF blend"); + CHECK(Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_BLEND, 0.25f) == Outline::BLEND_ALPHA_CUTOFF); + UNSCOPED_INFO("GLTF opaque"); + CHECK(Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_OPAQUE, 0.25f) == Outline::NO_ALPHA_TEST); // Halved along u, as a GLTF transform and as a texture animation: column c samples 2c + 1. The transform is // packed as LLGLTFMaterial::TextureTransform::getPacked packs a scale of (0.5, 1). @@ -1377,49 +1510,63 @@ namespace tut // Column 15 samples alpha 62, column 16 alpha 66. std::vector ids = pixelIds({ { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, mask, texture } }); - ensure_equals(named(reverse, "a mask cuts under its cutoff"), idAt(ids, 15, 32), 0U); - ensure_equals(named(reverse, "and keeps over it"), idAt(ids, 16, 32), ID_A); - ensure_equals(named(reverse, "and keeps the opaque end"), idAt(ids, 63, 32), ID_A); + UNSCOPED_INFO(named(reverse, "a mask cuts under its cutoff")); + REQUIRE(idAt(ids, 15, 32) == 0U); + UNSCOPED_INFO(named(reverse, "and keeps over it")); + REQUIRE(idAt(ids, 16, 32) == ID_A); + UNSCOPED_INFO(named(reverse, "and keeps the opaque end")); + REQUIRE(idAt(ids, 63, 32) == ID_A); // Column 5 samples alpha 22, column 6 alpha 26: either side of a tenth. ids = pixelIds({ { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, blend, texture } }); - ensure_equals(named(reverse, "a blend cuts what is all but clear"), idAt(ids, 5, 32), 0U); - ensure_equals(named(reverse, "and keeps the faintest it draws"), idAt(ids, 6, 32), ID_A); + UNSCOPED_INFO(named(reverse, "a blend cuts what is all but clear")); + REQUIRE(idAt(ids, 5, 32) == 0U); + UNSCOPED_INFO(named(reverse, "and keeps the faintest it draws")); + REQUIRE(idAt(ids, 6, 32) == ID_A); ids = pixelIds({ { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, opaque, texture } }); - ensure_equals(named(reverse, "an opaque face keeps its transparent texels"), idAt(ids, 0, 32), ID_A); - ensure_equals(named(reverse, "and the rest"), idAt(ids, 40, 32), ID_A); + UNSCOPED_INFO(named(reverse, "an opaque face keeps its transparent texels")); + REQUIRE(idAt(ids, 0, 32) == ID_A); + UNSCOPED_INFO(named(reverse, "and the rest")); + REQUIRE(idAt(ids, 40, 32) == ID_A); ids = pixelIds({ { pixels(0, W, 16, 48, &invisible), ID_A, Outline::PRIORITY_ROOT, mask, texture } }); - ensure_equals(named(reverse, "a transparent face colour cuts nothing more"), idAt(ids, 16, 32), ID_A); - ensure_equals(named(reverse, "and its texture still cuts"), idAt(ids, 15, 32), 0U); + UNSCOPED_INFO(named(reverse, "a transparent face colour cuts nothing more")); + REQUIRE(idAt(ids, 16, 32) == ID_A); + UNSCOPED_INFO(named(reverse, "and its texture still cuts")); + REQUIRE(idAt(ids, 15, 32) == 0U); // Column 20 samples alpha 41 halved, 82 not; column 40 81 halved. Draw transformed = { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, mask, texture }; transformed.mTransform = &halved_pack; ids = pixelIds({ transformed }); - ensure_equals(named(reverse, "the base colour transform moves the cut"), idAt(ids, 20, 32), 0U); - ensure_equals(named(reverse, "and keeps past it"), idAt(ids, 40, 32), ID_A); + UNSCOPED_INFO(named(reverse, "the base colour transform moves the cut")); + REQUIRE(idAt(ids, 20, 32) == 0U); + UNSCOPED_INFO(named(reverse, "and keeps past it")); + REQUIRE(idAt(ids, 40, 32) == ID_A); Draw animated = { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, mask, texture }; animated.mTextureMatrix = &halved_matrix; ids = pixelIds({ animated }); - ensure_equals(named(reverse, "the texture animation moves the cut"), idAt(ids, 20, 32), 0U); - ensure_equals(named(reverse, "and keeps past it"), idAt(ids, 40, 32), ID_A); + UNSCOPED_INFO(named(reverse, "the texture animation moves the cut")); + REQUIRE(idAt(ids, 20, 32) == 0U); + UNSCOPED_INFO(named(reverse, "and keeps past it")); + REQUIRE(idAt(ids, 40, 32) == ID_A); // A cut-out face shows what is behind it: here another object, which is outlined through the hole. ids = pixelIds({ { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, mask, texture }, { quad(0.f, (F32)W, 0.f, (F32)H, PIXEL_Z - 1.f, PIXEL_Z - 1.f), ID_B } }); - ensure_equals(named(reverse, "the one behind shows through the cut"), idAt(ids, 15, 32), ID_B); - ensure_equals(named(reverse, "and not through the rest"), idAt(ids, 16, 32), ID_A); + UNSCOPED_INFO(named(reverse, "the one behind shows through the cut")); + REQUIRE(idAt(ids, 15, 32) == ID_B); + UNSCOPED_INFO(named(reverse, "and not through the rest")); + REQUIRE(idAt(ids, 16, 32) == ID_A); } } // The contour's anti-aliasing: across a diagonal edge, walking away from it along a row, the line's coverage // never rises, starts solid, takes values between and ends at nothing. Along a row the distance from a // 45-degree edge grows by sqrt(1/2) a pixel a pixel, so the walk takes twice the line's reach. - template<> template<> - void alselectionoutline_object_t::test<14>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the contour's coverage falls smoothly away from a diagonal edge", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -1444,27 +1591,31 @@ namespace tut { first = idAt(ids, x, y) == ID_A ? x : -1; } - ensure_equals(named(reverse, "the diamond's edge" + row), first, 40 - y); + UNSCOPED_INFO(named(reverse, "the diamond's edge" + row)); + REQUIRE(first == 40 - y); U32 last = 255; for (S32 x = first - 1; x >= first - walk; --x) { const U32 r = at(px, x, y).r; - ensure(named(reverse, "coverage never rises away from the edge" + row), r <= last); + UNSCOPED_INFO(named(reverse, "coverage never rises away from the edge" + row)); + REQUIRE(r <= last); between += (r > 0 && r < 255) ? 1 : 0; last = r; } - ensure_equals(named(reverse, "solid beside the edge" + row), (U32)at(px, first - 1, y).r, 255U); - ensure_equals(named(reverse, "nothing past the reach" + row), last, 0U); + UNSCOPED_INFO(named(reverse, "solid beside the edge" + row)); + REQUIRE((U32)at(px, first - 1, y).r == 255U); + UNSCOPED_INFO(named(reverse, "nothing past the reach" + row)); + REQUIRE(last == 0U); } - ensure(named(reverse, "the edge is anti-aliased"), between >= 15); + UNSCOPED_INFO(named(reverse, "the edge is anti-aliased")); + REQUIRE(between >= 15); } } // A feature a pixel across is outlined all the way round: every pixel in the disk the line covers is drawn, // including those no straight or diagonal line from the feature passes through. - template<> template<> - void alselectionoutline_object_t::test<15>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a feature a pixel across is outlined all the way round", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -1488,20 +1639,27 @@ namespace tut const std::string where = " at (" + std::to_string(dx) + ", " + std::to_string(dy) + ")"; if (dist <= (F32)lines.mWidth) { - ensure_equals(named(reverse, "solid within the width" + where), r, 255U); + UNSCOPED_INFO(named(reverse, "solid within the width" + where)); + REQUIRE(r == 255U); } else if (dist < (F32)lines.mWidth + 0.9f) { - ensure(named(reverse, "anti-aliased past it" + where), r > 0 && r < 255); + { + INFO(named(reverse, "anti-aliased past it" + where)); + REQUIRE(r > 0); + REQUIRE(r < 255); + } } else if (dist >= (F32)reach) { - ensure_equals(named(reverse, "nothing at the reach" + where), r, 0U); + UNSCOPED_INFO(named(reverse, "nothing at the reach" + where)); + REQUIRE(r == 0U); } } } // Two across and one up: off every line of taps in eight directions. - ensure(named(reverse, "the knight's move is outlined"), at(px, 34, 33).r > 0); + UNSCOPED_INFO(named(reverse, "the knight's move is outlined")); + REQUIRE(at(px, 34, 33).r > 0); } } @@ -1509,8 +1667,7 @@ namespace tut // Where a root and a child meet, the root's contour is laid over the child's, which shows under it only where // the root's fades; the edge between them is drawn on the root's side, a pixel wide, at INNER_OPACITY, and not // on the child's. - template<> template<> - void alselectionoutline_object_t::test<16>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: priorityOrder ranks ids and the root's contour is laid over the child's", "[ALSelectionOutline]") { const std::vector priorities = { Outline::PRIORITY_CHILD, Outline::PRIORITY_ROOT, Outline::PRIORITY_CONTEXT, Outline::PRIORITY_SUBTRACT, @@ -1518,7 +1675,8 @@ namespace tut Outline::PRIORITY_INSPECT }; std::vector order; Outline::priorityOrder(priorities, order); - ensure("the highest priority first, in the order added within one", order == std::vector({ 3, 5, 6, 1, 0, 4, 2 })); + UNSCOPED_INFO("the highest priority first, in the order added within one"); + CHECK(order == std::vector({ 3, 5, 6, 1, 0, 4, 2 })); constexpr U32 ROOT = 1; constexpr U32 CHILD = 2; @@ -1528,24 +1686,49 @@ namespace tut // The root over columns 16 to 31, the child 32 to 47, both rows 16 to 47. const std::vector ids = pixelIds({ { pixels(16, 32, 16, 48), ROOT, Outline::PRIORITY_ROOT }, { pixels(32, 48, 16, 48), CHILD, Outline::PRIORITY_CHILD } }); - ensure_equals(named(reverse, "the child's priority in alpha"), (U32)at(ids, 40, 32).a, (U32)Outline::PRIORITY_CHILD); + UNSCOPED_INFO(named(reverse, "the child's priority in alpha")); + REQUIRE((U32)at(ids, 40, 32).a == (U32)Outline::PRIORITY_CHILD); palette({ { ROOT, RED }, { CHILD, GREEN } }, true); const std::vector px = edgePass(); // Above the child, a pixel from it and the root's corner a knight's move away. const Pixel over = at(px, 33, 48); - ensure(named(reverse, "the root's contour over the child's"), over.r > over.g && over.r > 200); - ensure(named(reverse, "the child's under it where it fades"), over.g > 0); - ensure(named(reverse, "the root's alone beside it"), red(at(px, 31, 48)) && at(px, 31, 48).r == 255); - ensure(named(reverse, "the child's alone past the root's reach"), green(at(px, 36, 48)) && at(px, 36, 48).g == 255); + { + INFO(named(reverse, "the root's contour over the child's")); + REQUIRE(over.r > over.g); + REQUIRE(over.r > 200); + } + UNSCOPED_INFO(named(reverse, "the child's under it where it fades")); + REQUIRE(over.g > 0); + { + INFO(named(reverse, "the root's alone beside it")); + REQUIRE(red(at(px, 31, 48))); + REQUIRE(at(px, 31, 48).r == 255); + } + { + INFO(named(reverse, "the child's alone past the root's reach")); + REQUIRE(green(at(px, 36, 48))); + REQUIRE(at(px, 36, 48).g == 255); + } const Pixel edge = at(px, 31, 32); const U32 faint = (U32)ll_round(255.f * Outline::INNER_OPACITY); - ensure(named(reverse, "the edge on the root's side, in its colour"), red(edge)); - ensure(named(reverse, "at INNER_OPACITY"), (U32)edge.r + 2 >= faint && (U32)edge.r <= faint + 2); - ensure(named(reverse, "a pixel wide, where the contour is two"), black(at(px, 30, 32))); - ensure(named(reverse, "and not on the child's side"), black(at(px, 32, 32))); - ensure(named(reverse, "the insides left alone"), black(at(px, 20, 32)) && black(at(px, 40, 32))); + UNSCOPED_INFO(named(reverse, "the edge on the root's side, in its colour")); + REQUIRE(red(edge)); + { + INFO(named(reverse, "at INNER_OPACITY")); + REQUIRE((U32)edge.r + 2 >= faint); + REQUIRE((U32)edge.r <= faint + 2); + } + UNSCOPED_INFO(named(reverse, "a pixel wide, where the contour is two")); + REQUIRE(black(at(px, 30, 32))); + UNSCOPED_INFO(named(reverse, "and not on the child's side")); + REQUIRE(black(at(px, 32, 32))); + { + INFO(named(reverse, "the insides left alone")); + REQUIRE(black(at(px, 20, 32))); + REQUIRE(black(at(px, 40, 32))); + } } } @@ -1554,8 +1737,7 @@ namespace tut // inside another, both priorities, and lines from one pixel wide to sixteen, whose reach spans five tiles. A // change along a tile's left or lower border belongs to the tile beyond it, which flags it; a tile inside an // object flags nothing. - template<> template<> - void alselectionoutline_object_t::test<17>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the tile pass's early out draws what searching every disk draws", "[ALSelectionOutline]") { const std::pair line_widths[] = { { 1, 1 }, { 2, 1 }, { 4, 1 }, { 8, 2 }, { 16, 2 } }; for (bool reverse : conventions()) @@ -1604,8 +1786,10 @@ namespace tut const std::string what = name + ", lines " + std::to_string(width) + " and " + std::to_string(inner_width); const std::vector untiled = edgePass(lines, nullptr, true); const std::vector tiled = edgePass(lines); - ensure(named(reverse, what + ": something is drawn"), lit(untiled) > 0); - ensure(named(reverse, what + ": tiled as untiled"), tiled == untiled); + UNSCOPED_INFO(named(reverse, what + ": something is drawn")); + REQUIRE(lit(untiled) > 0); + UNSCOPED_INFO(named(reverse, what + ": tiled as untiled")); + REQUIRE(tiled == untiled); } const std::vector records = tileRecords(); @@ -1614,7 +1798,8 @@ namespace tut { empty += records[i + 1] == 0 ? 1 : 0; } - ensure(named(reverse, name + ": some tiles hold nothing"), empty > 0); + UNSCOPED_INFO(named(reverse, name + ": some tiles hold nothing")); + REQUIRE(empty > 0); } // The first scene again, its edges on tile borders: a tile holds the ids of its own texels, and a tile @@ -1624,18 +1809,40 @@ namespace tut std::vector records = tileRecords(); const S32 columns = (S32)Outline::tileCount(W); auto record = [&](S32 column, S32 row, S32 i) { return (U32)records[((size_t)row * columns + column) * 4 + i]; }; - ensure(named(reverse, "the tile left of the root holds nothing"), record(1, 2, 0) == 0 && record(1, 2, 1) == 0); - ensure(named(reverse, "the tile inside the root holds the root alone"), record(2, 2, 0) == 1 && record(2, 2, 1) == 1); - ensure(named(reverse, "the tile inside the child beside it, the child alone"), record(4, 2, 0) == 2 && record(4, 2, 1) == 2); - ensure(named(reverse, "the tile under the child above, the root alone"), record(2, 4, 0) == 1 && record(2, 4, 1) == 1); - ensure(named(reverse, "no jump in it"), record(2, 2, 2) == 0); - ensure(named(reverse, "a tile far away holds nothing"), record(0, 0, 1) == 0); + { + INFO(named(reverse, "the tile left of the root holds nothing")); + REQUIRE(record(1, 2, 0) == 0); + REQUIRE(record(1, 2, 1) == 0); + } + { + INFO(named(reverse, "the tile inside the root holds the root alone")); + REQUIRE(record(2, 2, 0) == 1); + REQUIRE(record(2, 2, 1) == 1); + } + { + INFO(named(reverse, "the tile inside the child beside it, the child alone")); + REQUIRE(record(4, 2, 0) == 2); + REQUIRE(record(4, 2, 1) == 2); + } + { + INFO(named(reverse, "the tile under the child above, the root alone")); + REQUIRE(record(2, 4, 0) == 1); + REQUIRE(record(2, 4, 1) == 1); + } + UNSCOPED_INFO(named(reverse, "no jump in it")); + REQUIRE(record(2, 2, 2) == 0); + UNSCOPED_INFO(named(reverse, "a tile far away holds nothing")); + REQUIRE(record(0, 0, 1) == 0); // The second, across tile borders: the tile at column and row 3 holds both the root and the child. pixelIds(scenes[1].second); markPasses(view()); records = tileRecords(); - ensure(named(reverse, "a tile across the edge holds both"), record(3, 3, 0) == 1 && record(3, 3, 1) == 2); + { + INFO(named(reverse, "a tile across the edge holds both")); + REQUIRE(record(3, 3, 0) == 1); + REQUIRE(record(3, 3, 1) == 2); + } // The tile pass over the tiles under a rect holding every selected texel and one more around them, as the // viewer runs it under its scissor, draws the same. @@ -1645,15 +1852,15 @@ namespace tut { const Outline::View lines = widths(width, inner_width); const std::string what = "under a rect, lines " + std::to_string(width); - ensure(named(reverse, what), edgePass(lines, nullptr, false, &around) == edgePass(lines, nullptr, true)); + UNSCOPED_INFO(named(reverse, what)); + REQUIRE(edgePass(lines, nullptr, false, &around) == edgePass(lines, nullptr, true)); } } } // Faces are culled as the scene culls them: a single-sided face seen from behind, which the scene does not draw, // takes no pixel from the object behind it, whose contour stays whole; a double-sided one is drawn, and outlined. - template<> template<> - void alselectionoutline_object_t::test<18>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: faces are culled as the scene culls them", "[ALSelectionOutline]") { constexpr U32 FRONT = 1; constexpr U32 REAR = 2; @@ -1668,25 +1875,36 @@ namespace tut LLVertexBuffer* front = quadAt(back_on); std::vector ids = pixelIds({ { rear, REAR, Outline::PRIORITY_CHILD }, { front, FRONT, Outline::PRIORITY_ROOT } }); - ensure_equals(named(reverse, "a single-sided face from behind takes no pixel"), idAt(ids, 32, 32), REAR); + UNSCOPED_INFO(named(reverse, "a single-sided face from behind takes no pixel")); + REQUIRE(idAt(ids, 32, 32) == REAR); std::vector px = edgePass(); - ensure(named(reverse, "nothing traces it"), black(at(px, 23, 32)) && black(at(px, 24, 32)) && black(at(px, 40, 32))); - ensure_equals(named(reverse, "the rear's contour is whole"), (U32)at(px, 15, 32).g, 255U); + { + INFO(named(reverse, "nothing traces it")); + REQUIRE(black(at(px, 23, 32))); + REQUIRE(black(at(px, 24, 32))); + REQUIRE(black(at(px, 40, 32))); + } + UNSCOPED_INFO(named(reverse, "the rear's contour is whole")); + REQUIRE((U32)at(px, 15, 32).g == 255U); Draw double_sided = { front, FRONT, Outline::PRIORITY_ROOT }; double_sided.mDoubleSided = true; ids = pixelIds({ { rear, REAR, Outline::PRIORITY_CHILD }, double_sided }); - ensure_equals(named(reverse, "a double-sided face from behind is drawn"), idAt(ids, 32, 32), FRONT); + UNSCOPED_INFO(named(reverse, "a double-sided face from behind is drawn")); + REQUIRE(idAt(ids, 32, 32) == FRONT); px = edgePass(); - ensure(named(reverse, "and outlined over the rear"), red(at(px, 23, 32)) && at(px, 23, 32).r == 255); + { + INFO(named(reverse, "and outlined over the rear")); + REQUIRE(red(at(px, 23, 32))); + REQUIRE(at(px, 23, 32).r == 255); + } } } // A visible object in front of a selected one the scene hides is outlined in full over it: its contour neither // turns into an edge between the two nor goes on the hidden one's side. With hidden parts drawn, the visible // object's contour is still drawn at full strength, and the hidden one's own dimmed. - template<> template<> - void alselectionoutline_object_t::test<19>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a visible object in front of a hidden one is outlined in full over it", "[ALSelectionOutline]") { constexpr U32 ROOT = 1; constexpr U32 FROND = 2; @@ -1708,19 +1926,39 @@ namespace tut palette({ { ROOT, RED }, { FROND, GREEN } }, show_hidden); const std::vector px = edgePass(); - ensure(named(reverse, "the frond's contour over the root" + hidden_parts), - green(at(px, 24, 32)) && at(px, 24, 32).g == 255 && green(at(px, 23, 32)) && at(px, 23, 32).g == 255); - ensure(named(reverse, "above it too" + hidden_parts), green(at(px, 32, 39)) && at(px, 32, 39).g == 255); - ensure(named(reverse, "as wide as a contour" + hidden_parts), black(at(px, 21, 32))); - ensure(named(reverse, "nothing inside the frond" + hidden_parts), black(at(px, 32, 32)) && black(at(px, 25, 32))); + { + INFO(named(reverse, "the frond's contour over the root" + hidden_parts)); + REQUIRE(green(at(px, 24, 32))); + REQUIRE(at(px, 24, 32).g == 255); + REQUIRE(green(at(px, 23, 32))); + REQUIRE(at(px, 23, 32).g == 255); + } + { + INFO(named(reverse, "above it too" + hidden_parts)); + REQUIRE(green(at(px, 32, 39))); + REQUIRE(at(px, 32, 39).g == 255); + } + UNSCOPED_INFO(named(reverse, "as wide as a contour" + hidden_parts)); + REQUIRE(black(at(px, 21, 32))); + { + INFO(named(reverse, "nothing inside the frond" + hidden_parts)); + REQUIRE(black(at(px, 32, 32))); + REQUIRE(black(at(px, 25, 32))); + } if (show_hidden) { const U32 dimmed = at(px, 11, 32).r; - ensure(named(reverse, "the hidden root's contour dimmed"), red(at(px, 11, 32)) && dimmed >= 90 && dimmed <= 115); + { + INFO(named(reverse, "the hidden root's contour dimmed")); + REQUIRE(red(at(px, 11, 32))); + REQUIRE(dimmed >= 90); + REQUIRE(dimmed <= 115); + } } else { - ensure(named(reverse, "the hidden root's contour left out"), black(at(px, 11, 32))); + UNSCOPED_INFO(named(reverse, "the hidden root's contour left out")); + REQUIRE(black(at(px, 11, 32))); } } } @@ -1729,8 +1967,7 @@ namespace tut // A child in front of another draws its whole contour over it; two surfaces that touch on one plane, here a // wall seen at a slant, whose depth changes by some percent a pixel, draw only the thin edge between them, on // the side of the higher priority. - template<> template<> - void alselectionoutline_object_t::test<20>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a child in front of another draws its whole contour over it", "[ALSelectionOutline]") { const LLColor4 BLUE(0.f, 0.f, 1.f, 1.f); for (bool reverse : conventions()) @@ -1743,9 +1980,19 @@ namespace tut palette({ { 2, GREEN }, { 3, BLUE } }, true); std::vector px = edgePass(); const Pixel over = at(px, 24, 32); - ensure(named(reverse, "the front child's contour over the rear"), over.b == 255 && over.r == 0 && over.g == 0); - ensure(named(reverse, "its full width"), at(px, 23, 32).b == 255 && at(px, 32, 39).b == 255); - ensure(named(reverse, "nothing inside it"), black(at(px, 32, 32))); + { + INFO(named(reverse, "the front child's contour over the rear")); + REQUIRE(over.b == 255); + REQUIRE(over.r == 0); + REQUIRE(over.g == 0); + } + { + INFO(named(reverse, "its full width")); + REQUIRE(at(px, 23, 32).b == 255); + REQUIRE(at(px, 32, 39).b == 255); + } + UNSCOPED_INFO(named(reverse, "nothing inside it")); + REQUIRE(black(at(px, 32, 32))); // A wall from four metres out at the left to twelve at the right, split at eight, columns 31 and 32. idPass({ { quad(-1.6f, 0.f, -1.f, 1.f, -4.f, -8.f), ID_A, Outline::PRIORITY_ROOT }, @@ -1754,17 +2001,26 @@ namespace tut px = edgePass(); const Pixel edge = at(px, 31, 32); const U32 faint = (U32)ll_round(255.f * Outline::INNER_OPACITY); - ensure(named(reverse, "the edge on the root's side"), red(edge) && (U32)edge.r + 2 >= faint && (U32)edge.r <= faint + 2); - ensure(named(reverse, "no contour on the child's side"), black(at(px, 32, 32)) && black(at(px, 33, 32))); - ensure(named(reverse, "none on the root's"), black(at(px, 30, 32))); + { + INFO(named(reverse, "the edge on the root's side")); + REQUIRE(red(edge)); + REQUIRE((U32)edge.r + 2 >= faint); + REQUIRE((U32)edge.r <= faint + 2); + } + { + INFO(named(reverse, "no contour on the child's side")); + REQUIRE(black(at(px, 32, 32))); + REQUIRE(black(at(px, 33, 32))); + } + UNSCOPED_INFO(named(reverse, "none on the root's")); + REQUIRE(black(at(px, 30, 32))); } } // A selected object behind one the scene hides, its hidden parts left out, does not trace the hidden one's shape: // a frond behind a rock, in front of the visible root. And an object not drawn neither draws nor masks the // contour of one that is, though it is the nearer and of the higher priority. - template<> template<> - void alselectionoutline_object_t::test<21>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a hidden object with hidden parts left out traces and masks nothing", "[ALSelectionOutline]") { constexpr U32 ROOT = 1; constexpr U32 FROND = 2; @@ -1778,15 +2034,19 @@ namespace tut frond.mShowHidden = false; idPass({ { quad(-2.f, 2.f, -1.5f, 1.5f, -6.f, -6.f), ROOT, Outline::PRIORITY_ROOT }, frond }); const std::vector ids = read(mIdMap); - ensure_equals(named(reverse, "the frond is over the root"), idAt(ids, 32, 32), FROND); - ensure_equals(named(reverse, "and not drawn"), (U32)at(ids, 32, 32).b, 0U); + UNSCOPED_INFO(named(reverse, "the frond is over the root")); + REQUIRE(idAt(ids, 32, 32) == FROND); + UNSCOPED_INFO(named(reverse, "and not drawn")); + REQUIRE((U32)at(ids, 32, 32).b == 0U); palette({ { ROOT, RED }, { FROND, GREEN } }, false); std::vector px = edgePass(); for (const auto& [x, y] : { std::pair{ 25, 32 }, { 24, 32 }, { 38, 32 }, { 39, 32 }, { 32, 25 }, { 32, 38 }, { 31, 31 } }) { - ensure(named(reverse, "nothing traces the frond at (" + std::to_string(x) + ", " + std::to_string(y) + ")"), black(at(px, x, y))); + UNSCOPED_INFO(named(reverse, "nothing traces the frond at (" + std::to_string(x) + ", " + std::to_string(y) + ")")); + REQUIRE(black(at(px, x, y))); } - ensure_equals(named(reverse, "the root's own contour drawn"), (U32)at(px, 11, 32).r, 255U); + UNSCOPED_INFO(named(reverse, "the root's own contour drawn")); + REQUIRE((U32)at(px, 11, 32).r == 255U); // A root five metres out over columns 9 to 31, hidden, and a child beside it over 32 to 54, visible, both // rows 21 to 43. Above the root, a pixel from it and a knight's move from the child. @@ -1798,14 +2058,24 @@ namespace tut palette({ { ROOT, RED }, { FROND, GREEN } }, false); px = edgePass(); const Pixel above = at(px, 30, 44); - ensure(named(reverse, "the child's contour where the hidden root is nearer"), green(above) && above.g > 200); + { + INFO(named(reverse, "the child's contour where the hidden root is nearer")); + REQUIRE(green(above)); + REQUIRE(above.g > 200); + } // The two touch: the edge between them goes on the drawn side, the child's, though the root's is the // higher priority. const Pixel edge = at(px, 32, 32); const U32 faint = (U32)ll_round(255.f * Outline::INNER_OPACITY); - ensure(named(reverse, "the edge on the drawn side"), green(edge) && (U32)edge.g + 2 >= faint && (U32)edge.g <= faint + 2); - ensure(named(reverse, "not on the hidden root's"), black(at(px, 31, 32))); + { + INFO(named(reverse, "the edge on the drawn side")); + REQUIRE(green(edge)); + REQUIRE((U32)edge.g + 2 >= faint); + REQUIRE((U32)edge.g <= faint + 2); + } + UNSCOPED_INFO(named(reverse, "not on the hidden root's")); + REQUIRE(black(at(px, 31, 32))); } } @@ -1813,8 +2083,7 @@ namespace tut // step, and the edge pass draws the near part's whole contour over the far part from it, as another object's, // and nothing inside the near part. A gap of three percent of the distance is a jump too. The tile holding the // near side records it. - template<> template<> - void alselectionoutline_object_t::test<22>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: an object lying over itself marks the jump and outlines its near part", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -1828,14 +2097,34 @@ namespace tut const std::string at_z = " at " + std::to_string(-near_z) + " m"; idPass({ { quad(-2.f, 2.f, -1.5f, 1.5f, -6.f, -6.f), ID_A }, { quad(-half, half, -half, half, near_z, near_z), ID_A } }); const std::vector px = edgePass(); - ensure(named(reverse, "the near side of the step marked" + at_z), markedAt(25, 32) && markedAt(32, 38)); - ensure(named(reverse, "not the far side, nor inside" + at_z), !markedAt(24, 32) && !markedAt(32, 32)); + { + INFO(named(reverse, "the near side of the step marked" + at_z)); + REQUIRE(markedAt(25, 32)); + REQUIRE(markedAt(32, 38)); + } + { + INFO(named(reverse, "not the far side, nor inside" + at_z)); + REQUIRE_FALSE(markedAt(24, 32)); + REQUIRE_FALSE(markedAt(32, 32)); + } - ensure(named(reverse, "the near part's contour over the far part" + at_z), - red(at(px, 24, 32)) && at(px, 24, 32).r == 255 && at(px, 23, 32).r == 255 && at(px, 32, 39).r == 255); - ensure(named(reverse, "as wide as a contour" + at_z), black(at(px, 21, 32))); - ensure(named(reverse, "nothing inside the near part" + at_z), black(at(px, 25, 32)) && black(at(px, 26, 32)) && black(at(px, 32, 32))); - ensure(named(reverse, "nothing over the far part away from it" + at_z), black(at(px, 15, 32))); + { + INFO(named(reverse, "the near part's contour over the far part" + at_z)); + REQUIRE(red(at(px, 24, 32))); + REQUIRE(at(px, 24, 32).r == 255); + REQUIRE(at(px, 23, 32).r == 255); + REQUIRE(at(px, 32, 39).r == 255); + } + UNSCOPED_INFO(named(reverse, "as wide as a contour" + at_z)); + REQUIRE(black(at(px, 21, 32))); + { + INFO(named(reverse, "nothing inside the near part" + at_z)); + REQUIRE(black(at(px, 25, 32))); + REQUIRE(black(at(px, 26, 32))); + REQUIRE(black(at(px, 32, 32))); + } + UNSCOPED_INFO(named(reverse, "nothing over the far part away from it" + at_z)); + REQUIRE(black(at(px, 15, 32))); } // The near part's edges on tile borders: the tiles holding them record a jump, a tile of the far part alone @@ -1844,16 +2133,17 @@ namespace tut markPasses(view()); const std::vector records = tileRecords(); const S32 columns = (S32)Outline::tileCount(W); - ensure(named(reverse, "a tile on the near side's edge records the jump"), records[((size_t)3 * columns + 3) * 4 + 2] != 0); - ensure(named(reverse, "a tile of the far part alone none"), records[((size_t)1 * columns + 1) * 4 + 2] == 0); + UNSCOPED_INFO(named(reverse, "a tile on the near side's edge records the jump")); + REQUIRE(records[((size_t)3 * columns + 3) * 4 + 2] != 0); + UNSCOPED_INFO(named(reverse, "a tile of the far part alone none")); + REQUIRE(records[((size_t)1 * columns + 1) * 4 + 2] == 0); } } // A surface bending, not stepping, marks no jump and draws nothing across itself: one mesh's inside corner at // 30, 45 and 60 degrees to the view, the outside and the inside of a cylinder out to their rims, and a plane // whose depth changes by three to five percent a pixel, in one piece and in two. - template<> template<> - void alselectionoutline_object_t::test<23>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a bending surface marks no jump and draws nothing across itself", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -1912,9 +2202,12 @@ namespace tut } } } - ensure(named(reverse, name + ": it covers pixels"), covered > 200); - ensure_equals(named(reverse, name + ": no jump marked"), marks, size_t(0)); - ensure_equals(named(reverse, name + ": nothing drawn across it"), drawn, size_t(0)); + UNSCOPED_INFO(named(reverse, name + ": it covers pixels")); + REQUIRE(covered > 200); + UNSCOPED_INFO(named(reverse, name + ": no jump marked")); + REQUIRE(marks == size_t(0)); + UNSCOPED_INFO(named(reverse, name + ": nothing drawn across it")); + REQUIRE(drawn == size_t(0)); } } } @@ -1922,15 +2215,15 @@ namespace tut // The wireframe's lines are as wide in the window wherever they are: along an edge receding from four to twelve // metres, on the same quad four times as far, and twice as wide at twice the width. The width across a line is // read as the sum of its coverage down a column, the line's width over the cosine of its slope. - template<> template<> - void alselectionoutline_object_t::test<24>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the wireframe's lines are as wide in the window wherever they are", "[ALSelectionOutline]") { // The rows a column's runs of drawn pixels cover, bottom up. // The width down column x of the quad's diagonal, the middle of the three lines a column crosses. auto diagonal = [&](const std::vector& px, S32 x) { const std::vector> found = columnRuns(px, x); - ensure_equals("a column crosses the bottom edge, the diagonal and the top edge", found.size(), size_t(3)); + UNSCOPED_INFO("a column crosses the bottom edge, the diagonal and the top edge"); + REQUIRE(found.size() == size_t(3)); return ink(px, x, found[1].first, found[1].second); }; @@ -1946,22 +2239,34 @@ namespace tut const F32 near_end = diagonal(near_px, 26); const F32 far_end = diagonal(near_px, 34); // The line's slope down the screen is about 0.91: a width of 1 reads as about 1.35 down a column. - ensure(named(reverse, "the width down the diagonal, near: " + std::to_string(near_end)), near_end > 1.15f && near_end < 1.55f); - ensure(named(reverse, "the same along the receding edge, far: " + std::to_string(far_end)), fabsf(far_end - near_end) < 0.1f); + { + INFO(named(reverse, "the width down the diagonal, near: " + std::to_string(near_end))); + REQUIRE(near_end > 1.15f); + REQUIRE(near_end < 1.55f); + } + UNSCOPED_INFO(named(reverse, "the same along the receding edge, far: " + std::to_string(far_end))); + REQUIRE(fabsf(far_end - near_end) < 0.1f); const std::vector far_px = worldWireframe({ { quad(-4.f, 6.f, -4.f, 4.f, -12.f, -48.f), ID_A } }); - ensure(named(reverse, "the same four times as far"), fabsf(diagonal(far_px, 26) - near_end) < 0.1f && fabsf(diagonal(far_px, 34) - far_end) < 0.1f); + { + INFO(named(reverse, "the same four times as far")); + REQUIRE(fabsf(diagonal(far_px, 26) - near_end) < 0.1f); + REQUIRE(fabsf(diagonal(far_px, 34) - far_end) < 0.1f); + } const std::vector wide_px = worldWireframe({ { quad(-1.f, 1.5f, -1.f, 1.f, -3.f, -12.f), ID_A } }, 2); const F32 narrow = diagonal(near_px, 30); const F32 wide = diagonal(wide_px, 30); - ensure(named(reverse, "twice as wide at twice the width: " + std::to_string(wide)), wide > 1.8f * narrow && wide < 2.2f * narrow); + { + INFO(named(reverse, "twice as wide at twice the width: " + std::to_string(wide))); + REQUIRE(wide > 1.8f * narrow); + REQUIRE(wide < 2.2f * narrow); + } } } // Across a line, coverage falls from its middle on either side, and is gone within a pixel and a half. - template<> template<> - void alselectionoutline_object_t::test<25>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a line's coverage falls from its middle to nothing on either side", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -1973,17 +2278,20 @@ namespace tut for (S32 y = 16; y < 48; ++y) { const std::string row = ", row " + std::to_string(y); - ensure(named(reverse, "the line is drawn" + row), at(px, y, y).r > 127); + UNSCOPED_INFO(named(reverse, "the line is drawn" + row)); + REQUIRE(at(px, y, y).r > 127); for (S32 step : { -1, 1 }) { U32 last = at(px, y, y).r; for (S32 x = y + step; x != y + 4 * step; x += step) { const U32 r = at(px, x, y).r; - ensure(named(reverse, "coverage falls away from the line" + row), r <= last); + UNSCOPED_INFO(named(reverse, "coverage falls away from the line" + row)); + REQUIRE(r <= last); last = r; } - ensure_equals(named(reverse, "and is gone" + row), last, 0U); + UNSCOPED_INFO(named(reverse, "and is gone" + row)); + REQUIRE(last == 0U); } } } @@ -1991,8 +2299,7 @@ namespace tut // Lines behind something in the scene are drawn in the hidden colour with hidden selections shown, and not at // all without; the lines in front keep their colour. - template<> template<> - void alselectionoutline_object_t::test<26>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: lines behind the scene are dimmed or left out as hidden parts say", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -2014,23 +2321,30 @@ namespace tut windowDepth(nullptr); std::vector px = worldWireframe({ { quadA(), ID_A } }); const U32 open = brightest(px, 25, 11, 18); - ensure(named(reverse, "the line drawn with nothing in front"), open > 127); + UNSCOPED_INFO(named(reverse, "the line drawn with nothing in front")); + REQUIRE(open > 127); // Then with something three metres out over columns 0 to 19, in front of A's left part. occlude(3.f, 0, 0, 20, H); windowDepth(&mScene); px = worldWireframe({ { quadA(), ID_A } }); const U32 hidden = brightest(px, 25, 11, 18); - ensure(named(reverse, "the line in front drawn"), brightest(px, 38, 22, 30) > 127); - ensure(named(reverse, "the line behind dimmed: " + std::to_string(hidden) + " of " + std::to_string(open)), - hidden * 100 >= open * 35 && hidden * 100 <= open * 45); + UNSCOPED_INFO(named(reverse, "the line in front drawn")); + REQUIRE(brightest(px, 38, 22, 30) > 127); + { + INFO(named(reverse, "the line behind dimmed: " + std::to_string(hidden) + " of " + std::to_string(open))); + REQUIRE(hidden * 100 >= open * 35); + REQUIRE(hidden * 100 <= open * 45); + } Draw left_out = { quadA(), ID_A }; left_out.mShowHidden = false; palette({ { ID_A, RED } }, false); px = worldWireframe({ left_out }); - ensure_equals(named(reverse, "the line behind left out"), brightest(px, 25, 11, 18), 0U); - ensure(named(reverse, "the line in front kept"), brightest(px, 38, 22, 30) > 127); + UNSCOPED_INFO(named(reverse, "the line behind left out")); + REQUIRE(brightest(px, 25, 11, 18) == 0U); + UNSCOPED_INFO(named(reverse, "the line in front kept")); + REQUIRE(brightest(px, 38, 22, 30) > 127); } } @@ -2038,8 +2352,7 @@ namespace tut // point-sampled from half the resolution, as with RenderResolutionDivisor 2, nearer than the lines over half // their pixels on a surface turned away, and the polygon offset pulls them in front of it under either depth // convention. None is taken for hidden. - template<> template<> - void alselectionoutline_object_t::test<27>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: lines on their own surface in the scene's depth are all drawn", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -2066,15 +2379,16 @@ namespace tut lost += at(alone, x, y).r != at(on_surface, x, y).r ? 1 : 0; } } - ensure(named(reverse, "lines are drawn"), drawn > 100); - ensure_equals(named(reverse, "every line pixel drawn on its own surface as on nothing"), lost, size_t(0)); + UNSCOPED_INFO(named(reverse, "lines are drawn")); + REQUIRE(drawn > 100); + UNSCOPED_INFO(named(reverse, "every line pixel drawn on its own surface as on nothing")); + REQUIRE(lost == size_t(0)); } } // A face's cut-out texels draw no lines, its kept ones do; a rigged face's lines are where its joints put it; a // face the scene culls draws none. - template<> template<> - void alselectionoutline_object_t::test<28>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a face's lines follow its alpha cut and its pose and its culling", "[ALSelectionOutline]") { // Joint 0 moved 1.5 m along +x. const F32 right[12] = { 1.f, 0.f, 0.f, 1.5f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f }; @@ -2089,33 +2403,42 @@ namespace tut const F32 mask = Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_MASK, 64, true); std::vector px = wireframe({ Outline::WIRE_VISIBLE }, pixelProjection(), { { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, mask, ramp() } }); - ensure_equals(named(reverse, "no line across the cut-out texels"), ink(px, 8, 17, 24), 0.f); - ensure(named(reverse, "nor along their edge"), black(at(px, 8, 16))); - ensure(named(reverse, "lines across the kept ones"), ink(px, 40, 33, 40) > 0.5f && !black(at(px, 40, 16))); + UNSCOPED_INFO(named(reverse, "no line across the cut-out texels")); + REQUIRE(ink(px, 8, 17, 24) == 0.f); + UNSCOPED_INFO(named(reverse, "nor along their edge")); + REQUIRE(black(at(px, 8, 16))); + { + INFO(named(reverse, "lines across the kept ones")); + REQUIRE(ink(px, 40, 33, 40) > 0.5f); + REQUIRE_FALSE(black(at(px, 40, 16))); + } // Posed, the quad covers columns 43 to 54 and rows 26 to 37. LLVertexBuffer* bound = quad(-0.5f, 0.5f, -0.5f, 0.5f, QUAD_Z, QUAD_Z, true); px = worldWireframe({ { bound, ID_A } }, 1, 1.f, right); - ensure(named(reverse, "the rigged face's lines where it is posed"), ink(px, 49, 26, 38) > 0.5f); - ensure(named(reverse, "not at its bind pose"), ink(px, 32, 26, 38) == 0.f); + UNSCOPED_INFO(named(reverse, "the rigged face's lines where it is posed")); + REQUIRE(ink(px, 49, 26, 38) > 0.5f); + UNSCOPED_INFO(named(reverse, "not at its bind pose")); + REQUIRE(ink(px, 32, 26, 38) == 0.f); // A face seen from behind, wound clockwise, as the id pass culls it: no lines unless double-sided. const LLVector3 back_on[4] = { LLVector3(16.f, 16.f, PIXEL_Z), LLVector3(16.f, 48.f, PIXEL_Z), LLVector3(48.f, 48.f, PIXEL_Z), LLVector3(48.f, 16.f, PIXEL_Z) }; Draw back = { quadAt(back_on), ID_A }; px = wireframe({ Outline::WIRE_VISIBLE }, pixelProjection(), { back }); - ensure_equals(named(reverse, "no lines on a face from behind"), lit(px), size_t(0)); + UNSCOPED_INFO(named(reverse, "no lines on a face from behind")); + REQUIRE(lit(px) == size_t(0)); back.mDoubleSided = true; px = wireframe({ Outline::WIRE_VISIBLE }, pixelProjection(), { back }); - ensure(named(reverse, "lines on a double-sided one"), lit(px) > 50); + UNSCOPED_INFO(named(reverse, "lines on a double-sided one")); + REQUIRE(lit(px) > 50); } } // On the HUD the window's depth also holds the scene's, wherever that is the nearer, so the HUD's lines are // tested against the id target's depth instead: drawn whatever the window's depth holds, here the nearest value, // and hidden where they lie behind another selected surface. - template<> template<> - void alselectionoutline_object_t::test<29>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the HUD's lines test the id target's depth and not the window's", "[ALSelectionOutline]") { constexpr U32 REAR = 1; constexpr U32 FRONT = 2; @@ -2147,18 +2470,31 @@ namespace tut } palette({ { REAR, RED }, { FRONT, GREEN } }, show_hidden); const std::vector px = wireframe({ Outline::WIRE_ID_DEPTH }, pixelProjection(), shown); - ensure(named(reverse, "the rear's line in the open" + hidden_parts), red(at(px, 20, 20)) && at(px, 20, 20).r > 200); - ensure(named(reverse, "the front's line" + hidden_parts), green(at(px, 40, 32)) && at(px, 40, 32).g > 200); + { + INFO(named(reverse, "the rear's line in the open" + hidden_parts)); + REQUIRE(red(at(px, 20, 20))); + REQUIRE(at(px, 20, 20).r > 200); + } + { + INFO(named(reverse, "the front's line" + hidden_parts)); + REQUIRE(green(at(px, 40, 32))); + REQUIRE(at(px, 40, 32).g > 200); + } if (show_hidden) { const U32 dimmed = at(px, 32, 32).r; const U32 open = at(px, 20, 20).r; - ensure(named(reverse, "the rear's line behind the front dimmed: " + std::to_string(dimmed)), - red(at(px, 32, 32)) && dimmed * 100 >= open * 35 && dimmed * 100 <= open * 45); + { + INFO(named(reverse, "the rear's line behind the front dimmed: " + std::to_string(dimmed))); + REQUIRE(red(at(px, 32, 32))); + REQUIRE(dimmed * 100 >= open * 35); + REQUIRE(dimmed * 100 <= open * 45); + } } else { - ensure(named(reverse, "the rear's line behind the front left out"), black(at(px, 32, 32))); + UNSCOPED_INFO(named(reverse, "the rear's line behind the front left out")); + REQUIRE(black(at(px, 32, 32))); } } } @@ -2166,26 +2502,30 @@ namespace tut // The wireframe's width, a pixel at a UI scale of 1 and scaled with it, the same for the world and the HUD; and // the polygon offset its lines need over a resampled depth. - template<> template<> - void alselectionoutline_object_t::test<30>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the wireframe is a pixel wide at UI scale 1 and scales with it", "[ALSelectionOutline]") { - ensure_equals("a pixel at 1", Outline::lineWidth(Outline::WIRE_WIDTH, 1.f), 1); - ensure_equals("two at 2", Outline::lineWidth(Outline::WIRE_WIDTH, 2.f), 2); + UNSCOPED_INFO("a pixel at 1"); + CHECK(Outline::lineWidth(Outline::WIRE_WIDTH, 1.f) == 1); + UNSCOPED_INFO("two at 2"); + CHECK(Outline::lineWidth(Outline::WIRE_WIDTH, 2.f) == 2); for (bool hud : { false, true }) { const Outline::View scaled = Outline::makeView(identity(), identity(), 2.f, 2.f, hud); - ensure_equals("its width at the UI scale", scaled.mWireWidth, 2); - } - ensure_equals("a window depth at the scene's resolution", Outline::wireOffsetFactor(1.f), 2.f); - ensure_equals("at half of it", Outline::wireOffsetFactor(2.f), 3.f); - ensure_equals("never under the window's", Outline::wireOffsetFactor(0.5f), 2.f); + UNSCOPED_INFO("its width at the UI scale"); + REQUIRE(scaled.mWireWidth == 2); + } + UNSCOPED_INFO("a window depth at the scene's resolution"); + CHECK(Outline::wireOffsetFactor(1.f) == 2.f); + UNSCOPED_INFO("at half of it"); + CHECK(Outline::wireOffsetFactor(2.f) == 3.f); + UNSCOPED_INFO("never under the window's"); + CHECK(Outline::wireOffsetFactor(0.5f) == 2.f); } // A triangle reaching behind the eye, as a floor or a wall a builder stands at has, is clipped at the near plane // where GL clips it: its edges' parts in front are drawn at their width, the cut along the near plane draws no // line, and its texture coordinates are carried to the cut, so the alpha cut still follows the texture. - template<> template<> - void alselectionoutline_object_t::test<31>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a triangle reaching behind the eye is wireframed as GL clips it", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -2201,12 +2541,21 @@ namespace tut LLVertexBuffer* reaching = quadAt(one_behind); std::vector px = worldWireframe({ { reaching, ID_A } }); std::vector> found = columnRuns(px, 40); - ensure_equals(named(reverse, "column 40 crosses the bottom edge, the diagonal and the top edge"), found.size(), size_t(3)); + UNSCOPED_INFO(named(reverse, "column 40 crosses the bottom edge, the diagonal and the top edge")); + REQUIRE(found.size() == size_t(3)); // The diagonal's slope down the screen is about a third: a width of 1 reads as about 1.05 down a column. const F32 across = ink(px, 40, found[1].first, found[1].second); - ensure(named(reverse, "the diagonal at its width: " + std::to_string(across)), across > 0.9f && across < 1.25f); + { + INFO(named(reverse, "the diagonal at its width: " + std::to_string(across))); + REQUIRE(across > 0.9f); + REQUIRE(across < 1.25f); + } // The top edge, along row 41.8, has one triangle, which draws the half of its line inside the quad. - ensure(named(reverse, "the top edge drawn inside the quad"), at(px, 40, 41).r > 127 && black(at(px, 40, 42))); + { + INFO(named(reverse, "the top edge drawn inside the quad")); + REQUIRE(at(px, 40, 41).r > 127); + REQUIRE(black(at(px, 40, 42))); + } // Two corners behind the eye: a wall crossing the near plane at the middle of the view, column 32, and // reaching ten metres out at column 43. Its edges all run near column 43; the cut at column 32 is no edge. @@ -2224,15 +2573,19 @@ namespace tut at_edges += black(at(px, x, y)) ? 0 : 1; } } - ensure_equals(named(reverse, "no line along the near plane's cut"), at_cut, size_t(0)); - ensure(named(reverse, "the edges in front drawn: " + std::to_string(at_edges)), at_edges > 40); + UNSCOPED_INFO(named(reverse, "no line along the near plane's cut")); + REQUIRE(at_cut == size_t(0)); + UNSCOPED_INFO(named(reverse, "the edges in front drawn: " + std::to_string(at_edges))); + REQUIRE(at_edges > 40); // The first quad textured with the ramp, masked at half: its diagonal's texture coordinate runs from 0 // behind the eye to 1, about 0.43 at column 20 and 0.57 at column 40. const F32 mask = Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_MASK, 128, true); px = worldWireframe({ { reaching, ID_A, Outline::PRIORITY_ROOT, mask, ramp() } }); - ensure_equals(named(reverse, "no line where the clipped triangle's texture is cut"), ink(px, 20, 24, 32), 0.f); - ensure(named(reverse, "a line where it is kept"), ink(px, 40, 32, 38) > 0.5f); + UNSCOPED_INFO(named(reverse, "no line where the clipped triangle's texture is cut")); + REQUIRE(ink(px, 20, 24, 32) == 0.f); + UNSCOPED_INFO(named(reverse, "a line where it is kept")); + REQUIRE(ink(px, 40, 32, 38) > 0.5f); } } @@ -2240,8 +2593,7 @@ namespace tut // objects ask for: the outline and the glow the id pass and the passes after it, the world's wireframe none of // them, since it is tested against the window's depth, and the HUD's the id pass alone, whose depth it is tested // against. What glows asks for nothing else, and a selection's role keeps its object whatever glows. - template<> template<> - void alselectionoutline_object_t::test<32>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the outline and wireframe and glow each run only the passes they need", "[ALSelectionOutline]") { for (bool hud : { false, true }) { @@ -2249,100 +2601,158 @@ namespace tut Outline::Wants wants; wants.mContour = true; Outline::Passes passes = Outline::passesFor(wants, hud, true); - ensure("the outline alone runs the id pass" + where, passes.mIds); - ensure("and the edge passes" + where, passes.mEdges); - ensure("and no wireframe" + where, !passes.mWireframe); + UNSCOPED_INFO("the outline alone runs the id pass" + where); + REQUIRE(passes.mIds); + UNSCOPED_INFO("and the edge passes" + where); + REQUIRE(passes.mEdges); + UNSCOPED_INFO("and no wireframe" + where); + REQUIRE_FALSE(passes.mWireframe); wants.mWireframe = true; passes = Outline::passesFor(wants, hud, true); - ensure("both run everything" + where, passes.mIds && passes.mEdges && passes.mWireframe); + { + INFO("both run everything" + where); + REQUIRE(passes.mIds); + REQUIRE(passes.mEdges); + REQUIRE(passes.mWireframe); + } passes = Outline::passesFor(wants, hud, false); - ensure("a wireframe program that did not load leaves the outline" + where, - passes.mIds && passes.mEdges && !passes.mWireframe); + { + INFO("a wireframe program that did not load leaves the outline" + where); + REQUIRE(passes.mIds); + REQUIRE(passes.mEdges); + REQUIRE_FALSE(passes.mWireframe); + } wants.mContour = false; passes = Outline::passesFor(wants, hud, true); - ensure("the wireframe alone is drawn" + where, passes.mWireframe); - ensure("without the edge passes" + where, !passes.mEdges); - ensure_equals("with the id pass only on the HUD" + where, passes.mIds, hud); + UNSCOPED_INFO("the wireframe alone is drawn" + where); + REQUIRE(passes.mWireframe); + UNSCOPED_INFO("without the edge passes" + where); + REQUIRE_FALSE(passes.mEdges); + UNSCOPED_INFO("with the id pass only on the HUD" + where); + REQUIRE(passes.mIds == hud); passes = Outline::passesFor(wants, hud, false); - ensure("nothing when its program did not load" + where, !passes.any()); + UNSCOPED_INFO("nothing when its program did not load" + where); + REQUIRE_FALSE(passes.any()); wants.mGlow = true; passes = Outline::passesFor(wants, hud, true); - ensure("a glow beside a wireframe runs everything" + where, passes.mIds && passes.mEdges && passes.mWireframe); + { + INFO("a glow beside a wireframe runs everything" + where); + REQUIRE(passes.mIds); + REQUIRE(passes.mEdges); + REQUIRE(passes.mWireframe); + } wants.mWireframe = false; passes = Outline::passesFor(wants, hud, true); - ensure("a glow with the outline and the wireframe off runs the id and edge passes" + where, - passes.mIds && passes.mEdges && !passes.mWireframe); - ensure("and whether or not the wireframe loaded" + where, Outline::passesFor(wants, hud, false).mEdges); + { + INFO("a glow with the outline and the wireframe off runs the id and edge passes" + where); + REQUIRE(passes.mIds); + REQUIRE(passes.mEdges); + REQUIRE_FALSE(passes.mWireframe); + } + UNSCOPED_INFO("and whether or not the wireframe loaded" + where); + REQUIRE(Outline::passesFor(wants, hud, false).mEdges); wants.mGlow = false; - ensure("nothing with all three off" + where, !Outline::passesFor(wants, hud, true).any()); + UNSCOPED_INFO("nothing with all three off" + where); + REQUIRE_FALSE(Outline::passesFor(wants, hud, true).any()); } const U32 both = Outline::PART_CONTOUR | Outline::PART_WIREFRAME; - ensure_equals("what glows has no contour and no wireframe", Outline::partsFor(Outline::PRIORITY_HOVER, both), 0U); - ensure_equals("a selection keeps what it asks for", Outline::partsFor(Outline::PRIORITY_ROOT, both), both); - - ensure("what glows is in the id pass", Outline::inIdPass(0, Outline::PRIORITY_HOVER, false)); - ensure("and drawn there", Outline::outlined(0, Outline::PRIORITY_HOVER)); - ensure("a contour is", Outline::inIdPass(Outline::PART_CONTOUR, Outline::PRIORITY_ROOT, false)); - ensure("a world wireframe alone is not", !Outline::inIdPass(Outline::PART_WIREFRAME, Outline::PRIORITY_ROOT, false)); - ensure("a HUD wireframe alone is, for its depth", Outline::inIdPass(Outline::PART_WIREFRAME, Outline::PRIORITY_ROOT, true)); - ensure("and drawn nowhere", !Outline::outlined(Outline::PART_WIREFRAME, Outline::PRIORITY_ROOT)); + UNSCOPED_INFO("what glows has no contour and no wireframe"); + CHECK(Outline::partsFor(Outline::PRIORITY_HOVER, both) == 0U); + UNSCOPED_INFO("a selection keeps what it asks for"); + CHECK(Outline::partsFor(Outline::PRIORITY_ROOT, both) == both); + + UNSCOPED_INFO("what glows is in the id pass"); + CHECK(Outline::inIdPass(0, Outline::PRIORITY_HOVER, false)); + UNSCOPED_INFO("and drawn there"); + CHECK(Outline::outlined(0, Outline::PRIORITY_HOVER)); + UNSCOPED_INFO("a contour is"); + CHECK(Outline::inIdPass(Outline::PART_CONTOUR, Outline::PRIORITY_ROOT, false)); + UNSCOPED_INFO("a world wireframe alone is not"); + CHECK_FALSE(Outline::inIdPass(Outline::PART_WIREFRAME, Outline::PRIORITY_ROOT, false)); + UNSCOPED_INFO("a HUD wireframe alone is, for its depth"); + CHECK(Outline::inIdPass(Outline::PART_WIREFRAME, Outline::PRIORITY_ROOT, true)); + UNSCOPED_INFO("and drawn nowhere"); + CHECK_FALSE(Outline::outlined(Outline::PART_WIREFRAME, Outline::PRIORITY_ROOT)); for (Outline::EWirePass pass : { Outline::WIRE_VISIBLE, Outline::WIRE_HIDDEN, Outline::WIRE_ID_DEPTH }) { - ensure("what glows has no wireframe in any pass", - !Outline::inWirePass(Outline::partsFor(Outline::PRIORITY_HOVER, both), true, pass)); - ensure("nor an outline alone", !Outline::inWirePass(Outline::PART_CONTOUR, true, pass)); + UNSCOPED_INFO("what glows has no wireframe in any pass"); + REQUIRE_FALSE(Outline::inWirePass(Outline::partsFor(Outline::PRIORITY_HOVER, both), true, pass)); + UNSCOPED_INFO("nor an outline alone"); + REQUIRE_FALSE(Outline::inWirePass(Outline::PART_CONTOUR, true, pass)); + } + UNSCOPED_INFO("a wireframe's visible lines"); + CHECK(Outline::inWirePass(Outline::PART_WIREFRAME, false, Outline::WIRE_VISIBLE)); + { + INFO("its hidden ones only where hidden parts are drawn"); + CHECK_FALSE(Outline::inWirePass(Outline::PART_WIREFRAME, false, Outline::WIRE_HIDDEN)); + CHECK(Outline::inWirePass(Outline::PART_WIREFRAME, true, Outline::WIRE_HIDDEN)); } - ensure("a wireframe's visible lines", Outline::inWirePass(Outline::PART_WIREFRAME, false, Outline::WIRE_VISIBLE)); - ensure("its hidden ones only where hidden parts are drawn", - !Outline::inWirePass(Outline::PART_WIREFRAME, false, Outline::WIRE_HIDDEN) && - Outline::inWirePass(Outline::PART_WIREFRAME, true, Outline::WIRE_HIDDEN)); - ensure("a glow never replaces a selection", !Outline::replaces(Outline::PRIORITY_CONTEXT, Outline::PRIORITY_HOVER)); - ensure("a selection replaces a glow", Outline::replaces(Outline::PRIORITY_HOVER, Outline::PRIORITY_CHILD)); - ensure("what a drag takes out replaces a root", Outline::replaces(Outline::PRIORITY_ROOT, Outline::PRIORITY_SUBTRACT)); - ensure("at one priority the later", Outline::replaces(Outline::PRIORITY_ROOT, Outline::PRIORITY_ROOT)); + UNSCOPED_INFO("a glow never replaces a selection"); + CHECK_FALSE(Outline::replaces(Outline::PRIORITY_CONTEXT, Outline::PRIORITY_HOVER)); + UNSCOPED_INFO("a selection replaces a glow"); + CHECK(Outline::replaces(Outline::PRIORITY_HOVER, Outline::PRIORITY_CHILD)); + UNSCOPED_INFO("what a drag takes out replaces a root"); + CHECK(Outline::replaces(Outline::PRIORITY_ROOT, Outline::PRIORITY_SUBTRACT)); + UNSCOPED_INFO("at one priority the later"); + CHECK(Outline::replaces(Outline::PRIORITY_ROOT, Outline::PRIORITY_ROOT)); } // The glow's reach and profile, the fades of what the pointer is over, and how long the targets are kept: each // object fades in over the fade time while it is named, the one before it fading out as it does, and is dropped // at nothing or when its object is gone. - template<> template<> - void alselectionoutline_object_t::test<33>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the glow's reach and falloff and the hover fades and target lifetimes", "[ALSelectionOutline]") { const F32 nan = std::numeric_limits::quiet_NaN(); - ensure_equals("9 pixels at the default thickness", Outline::glowRadius(Outline::DEFAULT_GLOW_THICKNESS, 1.f), 9); - ensure_equals("scaled with the UI", Outline::glowRadius(Outline::DEFAULT_GLOW_THICKNESS, 2.f), 18); - ensure_equals("held to the widest", Outline::glowRadius(100.f, 1.f), (S32)Outline::MAX_GLOW_RADIUS); - ensure_equals("a pixel at least", Outline::glowRadius(-1.f, 1.f), 1); - ensure_equals("the default where the setting is not a number", Outline::glowRadius(nan, 1.f), 9); + UNSCOPED_INFO("9 pixels at the default thickness"); + CHECK(Outline::glowRadius(Outline::DEFAULT_GLOW_THICKNESS, 1.f) == 9); + UNSCOPED_INFO("scaled with the UI"); + CHECK(Outline::glowRadius(Outline::DEFAULT_GLOW_THICKNESS, 2.f) == 18); + UNSCOPED_INFO("held to the widest"); + CHECK(Outline::glowRadius(100.f, 1.f) == (S32)Outline::MAX_GLOW_RADIUS); + UNSCOPED_INFO("a pixel at least"); + CHECK(Outline::glowRadius(-1.f, 1.f) == 1); + UNSCOPED_INFO("the default where the setting is not a number"); + CHECK(Outline::glowRadius(nan, 1.f) == 9); const Outline::View defaults = Outline::makeView(identity(), identity(), 2.f, 1.f, false); - ensure_equals("a view's glow by default", defaults.mGlowRadius, 9); - ensure_equals("and its brightness", defaults.mGlowBrightness, Outline::DEFAULT_GLOW_BRIGHTNESS); - ensure_equals("a brightness that is not a number is the default", - Outline::makeView(identity(), identity(), 2.f, 1.f, false, 0.6f, nan).mGlowBrightness, + UNSCOPED_INFO("a view's glow by default"); + CHECK(defaults.mGlowRadius == 9); + UNSCOPED_INFO("and its brightness"); + CHECK(defaults.mGlowBrightness == Outline::DEFAULT_GLOW_BRIGHTNESS); + UNSCOPED_INFO("a brightness that is not a number is the default"); + CHECK(Outline::makeView(identity(), identity(), 2.f, 1.f, false, 0.6f, nan).mGlowBrightness == Outline::DEFAULT_GLOW_BRIGHTNESS); - ensure_equals("and one past the brightest held to it", - Outline::makeView(identity(), identity(), 2.f, 1.f, false, 0.6f, 1000.f).mGlowBrightness, + UNSCOPED_INFO("and one past the brightest held to it"); + CHECK(Outline::makeView(identity(), identity(), 2.f, 1.f, false, 0.6f, 1000.f).mGlowBrightness == Outline::MAX_GLOW_BRIGHTNESS); // The silhouette is half a texel out from its texel's centre. - ensure_approximately_equals_range("opaque at the silhouette at the default brightness", - Outline::glowOpacity(0.5f, 9, 4.f), 1.f, 1e-6f); - ensure_approximately_equals_range("half as opaque at half of it", Outline::glowOpacity(0.5f, 9, 2.f), 0.5f, 1e-6f); - ensure_approximately_equals_range("half way out, half of the silhouette's", Outline::glowOpacity(5.f, 9, 4.f), 0.5f, - 1e-6f); - ensure_equals("nothing at its reach", Outline::glowOpacity(9.5f, 9, 4.f), 0.f); - ensure_equals("nor past it", Outline::glowOpacity(30.f, 9, 4.f), 0.f); - ensure_equals("held to opaque", Outline::glowOpacity(2.f, 9, Outline::MAX_GLOW_BRIGHTNESS), 1.f); + UNSCOPED_INFO("opaque at the silhouette at the default brightness"); + CHECK_THAT(Outline::glowOpacity(0.5f, 9, 4.f), Catch::Matchers::WithinAbs(1.f, 1e-6f)); + UNSCOPED_INFO("half as opaque at half of it"); + CHECK_THAT(Outline::glowOpacity(0.5f, 9, 2.f), Catch::Matchers::WithinAbs(0.5f, 1e-6f)); + UNSCOPED_INFO("half way out, half of the silhouette's"); + CHECK_THAT(Outline::glowOpacity(5.f, 9, 4.f), Catch::Matchers::WithinAbs(0.5f, + 1e-6f)); + UNSCOPED_INFO("nothing at its reach"); + CHECK(Outline::glowOpacity(9.5f, 9, 4.f) == 0.f); + UNSCOPED_INFO("nor past it"); + CHECK(Outline::glowOpacity(30.f, 9, 4.f) == 0.f); + UNSCOPED_INFO("held to opaque"); + CHECK(Outline::glowOpacity(2.f, 9, Outline::MAX_GLOW_BRIGHTNESS) == 1.f); const F32 last_step = Outline::glowOpacity(9.25f, 9, 4.f); - ensure("fading smoothly into nothing: " + std::to_string(last_step), last_step > 0.f && last_step < 0.01f); + { + INFO("fading smoothly into nothing: " + std::to_string(last_step)); + CHECK(last_step > 0.f); + CHECK(last_step < 0.01f); + } F32 previous = 2.f; bool falling = true; for (S32 step = 0; step <= 40; ++step) @@ -2351,16 +2761,24 @@ namespace tut falling = falling && opacity <= previous; previous = opacity; } - ensure("falling all the way out", falling); - - ensure_approximately_equals_range("half way in half the fade time", ALHoverGlow::stepFade(0.f, 0.05f, 0.1f, true), - 0.5f, 1e-6f); - ensure_approximately_equals_range("out as fast", ALHoverGlow::stepFade(0.5f, 0.05f, 0.1f, false), 0.f, 1e-6f); - ensure_equals("held to one", ALHoverGlow::stepFade(0.9f, 1.f, 0.1f, true), 1.f); - ensure_equals("and to nothing", ALHoverGlow::stepFade(0.1f, 1.f, 0.1f, false), 0.f); - ensure_equals("at once with no fade time", ALHoverGlow::stepFade(0.f, 0.f, 0.f, true), 1.f); - ensure_equals("or one that is not a number", ALHoverGlow::stepFade(1.f, 0.f, nan, false), 0.f); - ensure_equals("time running back moves nothing", ALHoverGlow::stepFade(0.5f, -1.f, 0.1f, true), 0.5f); + UNSCOPED_INFO("falling all the way out"); + CHECK(falling); + + UNSCOPED_INFO("half way in half the fade time"); + CHECK_THAT(ALHoverGlow::stepFade(0.f, 0.05f, 0.1f, true), + Catch::Matchers::WithinAbs(0.5f, 1e-6f)); + UNSCOPED_INFO("out as fast"); + CHECK_THAT(ALHoverGlow::stepFade(0.5f, 0.05f, 0.1f, false), Catch::Matchers::WithinAbs(0.f, 1e-6f)); + UNSCOPED_INFO("held to one"); + CHECK(ALHoverGlow::stepFade(0.9f, 1.f, 0.1f, true) == 1.f); + UNSCOPED_INFO("and to nothing"); + CHECK(ALHoverGlow::stepFade(0.1f, 1.f, 0.1f, false) == 0.f); + UNSCOPED_INFO("at once with no fade time"); + CHECK(ALHoverGlow::stepFade(0.f, 0.f, 0.f, true) == 1.f); + UNSCOPED_INFO("or one that is not a number"); + CHECK(ALHoverGlow::stepFade(1.f, 0.f, nan, false) == 0.f); + UNSCOPED_INFO("time running back moves nothing"); + CHECK(ALHoverGlow::stepFade(0.5f, -1.f, 0.1f, true) == 0.5f); // Steps of an eighth of a second over a quarter: halves, exactly. const LLUUID a("c0ffee00-0000-4000-8000-00000000000a"); @@ -2387,8 +2805,11 @@ namespace tut }; // A frame an eighth of a second long, the settle time between one and two of them. const F32 fade_time = 0.25f; - ensure("the settle time lies between one frame and two", - ALHoverGlow::SETTLE_SECONDS > 0.125 && ALHoverGlow::SETTLE_SECONDS <= 0.25); + { + INFO("the settle time lies between one frame and two"); + CHECK(ALHoverGlow::SETTLE_SECONDS > 0.125); + CHECK(ALHoverGlow::SETTLE_SECONDS <= 0.25); + } U32 frame = 0; auto at = [&](const LLUUID& id, F64 now) { @@ -2398,71 +2819,97 @@ namespace tut }; at(a, 10.0); - ensure("named, nothing glows yet", glow.glows().empty()); + UNSCOPED_INFO("named, nothing glows yet"); + REQUIRE(glow.glows().empty()); at(a, 10.125); - ensure("nor before the name has settled", glow.glows().empty()); + UNSCOPED_INFO("nor before the name has settled"); + REQUIRE(glow.glows().empty()); at(a, 10.25); - ensure_equals("settled, it fades in", fade(a), 0.5f); + UNSCOPED_INFO("settled, it fades in"); + CHECK(fade(a) == 0.5f); glow.update(10.25, frame, fade_time, is_alive); - ensure_equals("a second update in a frame moves nothing", fade(a), 0.5f); + UNSCOPED_INFO("a second update in a frame moves nothing"); + CHECK(fade(a) == 0.5f); at(a, 10.375); - ensure_equals("in over the fade time", fade(a), 1.f); + UNSCOPED_INFO("in over the fade time"); + CHECK(fade(a) == 1.f); at(b, 10.5); at(b, 10.625); - ensure_equals("the glow stays while the next name settles", fade(a), 1.f); - ensure_equals("which does not glow yet", fade(b), -1.f); + UNSCOPED_INFO("the glow stays while the next name settles"); + CHECK(fade(a) == 1.f); + UNSCOPED_INFO("which does not glow yet"); + CHECK(fade(b) == -1.f); at(b, 10.75); - ensure_equals("then the one before fades out", fade(a), 0.5f); - ensure_equals("while the next fades in", fade(b), 0.5f); + UNSCOPED_INFO("then the one before fades out"); + CHECK(fade(a) == 0.5f); + UNSCOPED_INFO("while the next fades in"); + CHECK(fade(b) == 0.5f); at(b, 10.875); - ensure_equals("dropped at nothing", fade(a), -1.f); - ensure_equals("one glows", glow.glows().size(), size_t(1)); + UNSCOPED_INFO("dropped at nothing"); + CHECK(fade(a) == -1.f); + UNSCOPED_INFO("one glows"); + REQUIRE(glow.glows().size() == size_t(1)); at(LLUUID::null, 11.0); at(b, 11.125); - ensure_equals("a frame off it, at its edge or a seam, does not put it out", fade(b), 1.f); + UNSCOPED_INFO("a frame off it, at its edge or a seam, does not put it out"); + CHECK(fade(b) == 1.f); at(LLUUID::null, 11.25); at(LLUUID::null, 11.375); - ensure_equals("nor does leaving it, until that settles", fade(b), 1.f); + UNSCOPED_INFO("nor does leaving it, until that settles"); + CHECK(fade(b) == 1.f); at(LLUUID::null, 11.5); - ensure_equals("then it fades out", fade(b), 0.5f); + UNSCOPED_INFO("then it fades out"); + CHECK(fade(b) == 0.5f); at(a, 11.625); at(b, 11.75); at(a, 11.875); at(LLUUID::null, 12.0); - ensure("a sweep across objects lights none of them", glow.glows().empty()); + UNSCOPED_INFO("a sweep across objects lights none of them"); + REQUIRE(glow.glows().empty()); at(a, 12.125); at(a, 12.25); at(a, 12.375); - ensure_equals("one rested on lights", fade(a), 0.5f); + UNSCOPED_INFO("one rested on lights"); + CHECK(fade(a) == 0.5f); alive.clear(); at(a, 12.5); - ensure("dropped when its object is gone, named or not", glow.glows().empty()); + UNSCOPED_INFO("dropped when its object is gone, named or not"); + REQUIRE(glow.glows().empty()); at(LLUUID::null, 12.625); at(LLUUID::null, 12.75); - ensure("nothing named, nothing glows", glow.glows().empty()); + UNSCOPED_INFO("nothing named, nothing glows"); + REQUIRE(glow.glows().empty()); glow.hover(b, 100); - ensure("named a frame ago, it is still named", glow.hovered(101) == b); - ensure("unnamed for longer, the name lapses", glow.hovered(102).isNull()); + UNSCOPED_INFO("named a frame ago, it is still named"); + CHECK(glow.hovered(101) == b); + UNSCOPED_INFO("unnamed for longer, the name lapses"); + CHECK(glow.hovered(102).isNull()); const F64 kept = Outline::TARGET_KEEP_SECONDS; - ensure("a target drawn with this frame is kept", !Outline::stale(5, 100.0, 5, 100.0 + kept * 2.0)); - ensure("and the next, however long it took", !Outline::stale(5, 100.0, 6, 100.0 + kept * 2.0)); - ensure("and for its time, however many frames pass", !Outline::stale(5, 100.0, 500, 100.0 + kept * 0.5)); - ensure("given up after both", Outline::stale(5, 100.0, 7, 100.0 + kept)); - ensure("across the frame counter's wrap", - !Outline::stale(0xFFFFFFFFu, 100.0, 0u, 200.0) && Outline::stale(0xFFFFFFFEu, 100.0, 1u, 200.0)); + UNSCOPED_INFO("a target drawn with this frame is kept"); + CHECK_FALSE(Outline::stale(5, 100.0, 5, 100.0 + kept * 2.0)); + UNSCOPED_INFO("and the next, however long it took"); + CHECK_FALSE(Outline::stale(5, 100.0, 6, 100.0 + kept * 2.0)); + UNSCOPED_INFO("and for its time, however many frames pass"); + CHECK_FALSE(Outline::stale(5, 100.0, 500, 100.0 + kept * 0.5)); + UNSCOPED_INFO("given up after both"); + CHECK(Outline::stale(5, 100.0, 7, 100.0 + kept)); + { + INFO("across the frame counter's wrap"); + CHECK_FALSE(Outline::stale(0xFFFFFFFFu, 100.0, 0u, 200.0)); + CHECK(Outline::stale(0xFFFFFFFEu, 100.0, 1u, 200.0)); + } } // A glowing object draws a halo around its silhouette in its colour, falling off from the silhouette as // glowOpacity says, as bright as asked, to nothing at its reach; and nothing over itself, its own folds included, // whose jumps the jump pass leaves unmarked. - template<> template<> - void alselectionoutline_object_t::test<34>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a glowing object draws a halo around its silhouette in its colour", "[ALSelectionOutline]") { constexpr S32 RADIUS = 6; for (bool reverse : conventions()) @@ -2472,7 +2919,11 @@ namespace tut // 34: selected, the near side of a jump in its own surface. pixelIds({ { pixels(20, 40, 20, 44), ID_A }, { quad(25.f, 35.f, 25.f, 39.f, -1.f, -1.f), ID_A } }); markPasses(glowView(RADIUS)); - ensure(named(reverse, "selected, the fold's edge is the near side of a jump"), markedAt(25, 32) && markedAt(34, 32)); + { + INFO(named(reverse, "selected, the fold's edge is the near side of a jump")); + REQUIRE(markedAt(25, 32)); + REQUIRE(markedAt(34, 32)); + } pixelIds({ hoverDraw(pixels(20, 40, 20, 44), ID_A), hoverDraw(quad(25.f, 35.f, 25.f, 39.f, -1.f, -1.f), ID_A) }); palette({ { ID_A, GREEN } }, false); @@ -2481,30 +2932,48 @@ namespace tut { const std::string at_brightness = " at brightness " + std::to_string(brightness); const std::vector px = edgePass(glowView(RADIUS, brightness), nullptr, false, nullptr, true); - ensure(named(reverse, "glowing, its fold's edge is not marked"), !markedAt(25, 32) && !markedAt(34, 32)); + { + INFO(named(reverse, "glowing, its fold's edge is not marked")); + REQUIRE_FALSE(markedAt(25, 32)); + REQUIRE_FALSE(markedAt(34, 32)); + } for (S32 k = 0; k <= RADIUS + 2; ++k) { // Column 40 + k is k + 1 from the centre of the nearest texel, in column 39. const F32 expected = 255.f * Outline::glowOpacity((F32)(k + 1), RADIUS, brightness); const Pixel p = at(px, 40 + k, 32); - ensure(named(reverse, "the glow " + std::to_string(k + 1) + " pixels out" + at_brightness + ": " + - std::to_string(p.g) + " for " + std::to_string(expected)), - std::fabs((F32)p.g - expected) <= 2.f && p.r == 0 && p.b == 0); + { + INFO(named(reverse, "the glow " + std::to_string(k + 1) + " pixels out" + at_brightness + ": " + + std::to_string(p.g) + " for " + std::to_string(expected))); + REQUIRE(std::fabs((F32)p.g - expected) <= 2.f); + REQUIRE(p.r == 0); + REQUIRE(p.b == 0); + } } const U8 between = at(px, 43, 32).g; - ensure(named(reverse, "soft, not a solid band" + at_brightness), between > 10 && between < 245); - ensure(named(reverse, "nothing over the object" + at_brightness), - black(at(px, 30, 32)) && black(at(px, 39, 32)) && black(at(px, 20, 20))); - ensure(named(reverse, "nor over its far side beside its fold" + at_brightness), - black(at(px, 24, 32)) && black(at(px, 35, 32))); + { + INFO(named(reverse, "soft, not a solid band" + at_brightness)); + REQUIRE(between > 10); + REQUIRE(between < 245); + } + { + INFO(named(reverse, "nothing over the object" + at_brightness)); + REQUIRE(black(at(px, 30, 32))); + REQUIRE(black(at(px, 39, 32))); + REQUIRE(black(at(px, 20, 20))); + } + { + INFO(named(reverse, "nor over its far side beside its fold" + at_brightness)); + REQUIRE(black(at(px, 24, 32))); + REQUIRE(black(at(px, 35, 32))); + } } } } // A selection's contour and the edges between selected objects are laid over the glow; and beside a glowing // object a selection is outlined as though it were not there, except where it stands in front. - template<> template<> - void alselectionoutline_object_t::test<35>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a selection's contour and edges are laid over the glow", "[ALSelectionOutline]") { constexpr U32 ID_GLOW = 400; for (bool reverse : conventions()) @@ -2518,10 +2987,17 @@ namespace tut for (S32 x : { 38, 39 }) { const Pixel p = at(px, x, 32); - ensure(named(reverse, "the contour opaque over the glow at column " + std::to_string(x)), - p.r == 255 && p.g == 0); + { + INFO(named(reverse, "the contour opaque over the glow at column " + std::to_string(x))); + REQUIRE(p.r == 255); + REQUIRE(p.g == 0); + } + } + { + INFO(named(reverse, "the glow past the contour")); + REQUIRE(green(at(px, 37, 32))); + REQUIRE(green(at(px, 36, 32))); } - ensure(named(reverse, "the glow past the contour"), green(at(px, 37, 32)) && green(at(px, 36, 32))); // Touching it, at column 40: the selection's contour drawn over the glowing object as over nothing, and // no edge between them. @@ -2533,8 +3009,13 @@ namespace tut { const Pixel p = at(px, x, 32); const Pixel q = at(alone, x, 32); - ensure(named(reverse, "the contour beside it as without it at column " + std::to_string(x)), - p.r == q.r && p.g == q.g && p.b == q.b && p.a == q.a); + { + INFO(named(reverse, "the contour beside it as without it at column " + std::to_string(x))); + REQUIRE(p.r == q.r); + REQUIRE(p.g == q.g); + REQUIRE(p.b == q.b); + REQUIRE(p.a == q.a); + } } // Two selected objects touching at column 30, their edge on A's side, and a glowing one nearer below @@ -2545,17 +3026,17 @@ namespace tut // Pixel (29, 20) is a pixel from B and three from the glowing object's top row. const F32 glow = Outline::glowOpacity(3.f, 9, Outline::DEFAULT_GLOW_BRIGHTNESS); const Pixel edge = at(px, 29, 20); - ensure(named(reverse, "the edge over the glow: red " + std::to_string(edge.r)), - std::fabs((F32)edge.r - 255.f * Outline::INNER_OPACITY) <= 2.f); - ensure(named(reverse, "the glow under it: green " + std::to_string(edge.g)), - std::fabs((F32)edge.g - 255.f * glow * (1.f - Outline::INNER_OPACITY)) <= 2.f); - ensure(named(reverse, "the glow over A's surface, which lies behind it"), green(at(px, 20, 21))); + UNSCOPED_INFO(named(reverse, "the edge over the glow: red " + std::to_string(edge.r))); + REQUIRE(std::fabs((F32)edge.r - 255.f * Outline::INNER_OPACITY) <= 2.f); + UNSCOPED_INFO(named(reverse, "the glow under it: green " + std::to_string(edge.g))); + REQUIRE(std::fabs((F32)edge.g - 255.f * glow * (1.f - Outline::INNER_OPACITY)) <= 2.f); + UNSCOPED_INFO(named(reverse, "the glow over A's surface, which lies behind it")); + REQUIRE(green(at(px, 20, 21))); } } // A glowing object's hidden parts do not glow: its halo follows the part the scene shows. - template<> template<> - void alselectionoutline_object_t::test<36>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a glowing object's halo follows only the part the scene shows", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -2564,19 +3045,29 @@ namespace tut occlude(3.f, 0, 0, 21, H); idPass({ hoverDraw(quadA(), ID_A) }); const std::vector ids = read(mIdMap); - ensure_equals(named(reverse, "its hidden part left out"), (U32)at(ids, 12, 32).b, 0U); + UNSCOPED_INFO(named(reverse, "its hidden part left out")); + REQUIRE((U32)at(ids, 12, 32).b == 0U); palette({ { ID_A, GREEN } }, false); const std::vector px = edgePass(glowView(6), nullptr, false, nullptr, true); - ensure(named(reverse, "a glow past its visible side"), green(at(px, 32, 32)) && at(px, 32, 32).g > 200); - ensure(named(reverse, "none past its hidden one"), black(at(px, 8, 32)) && black(at(px, 5, 32))); - ensure(named(reverse, "nor above it"), black(at(px, 12, 46))); - ensure(named(reverse, "but above the part shown"), green(at(px, 26, 45))); + { + INFO(named(reverse, "a glow past its visible side")); + REQUIRE(green(at(px, 32, 32))); + REQUIRE(at(px, 32, 32).g > 200); + } + { + INFO(named(reverse, "none past its hidden one")); + REQUIRE(black(at(px, 8, 32))); + REQUIRE(black(at(px, 5, 32))); + } + UNSCOPED_INFO(named(reverse, "nor above it")); + REQUIRE(black(at(px, 12, 46))); + UNSCOPED_INFO(named(reverse, "but above the part shown")); + REQUIRE(green(at(px, 26, 45))); } } // The wireframe draws no lines for what glows, beside a selection whose lines it draws. - template<> template<> - void alselectionoutline_object_t::test<37>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the wireframe draws no lines for what glows beside a selection", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -2595,15 +3086,16 @@ namespace tut glowing += p.g > 0 ? 1 : 0; } } - ensure(named(reverse, "the selection's lines"), selected > 20); - ensure_equals(named(reverse, "none for what glows"), glowing, size_t(0)); + UNSCOPED_INFO(named(reverse, "the selection's lines")); + REQUIRE(selected > 20); + UNSCOPED_INFO(named(reverse, "none for what glows")); + REQUIRE(glowing == size_t(0)); } } // The tiles change nothing the glow draws, where it reaches past the lines; and a glowing object's glow lies in // its box grown by the glow's reach, which drawObject grows the scissor by. - template<> template<> - void alselectionoutline_object_t::test<38>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the tiles and the scissor change nothing the glow draws", "[ALSelectionOutline]") { constexpr U32 ID_GLOW = 400; constexpr U32 ID_FRONT = 401; @@ -2617,34 +3109,41 @@ namespace tut hoverDraw(quad(44.f, 58.f, 22.f, 36.f, -1.f, -1.f), ID_FRONT) }); const std::vector tiled = edgePass(glowView(RADIUS), nullptr, false, nullptr, true); const std::vector untiled = edgePass(glowView(RADIUS), nullptr, true, nullptr, true); - ensure(named(reverse, "the glow reaches past the lines"), green(at(tiled, 28, 15))); - ensure(named(reverse, "the tiles change nothing it draws"), tiled == untiled); + UNSCOPED_INFO(named(reverse, "the glow reaches past the lines")); + REQUIRE(green(at(tiled, 28, 15))); + UNSCOPED_INFO(named(reverse, "the tiles change nothing it draws")); + REQUIRE(tiled == untiled); const LLVector4a extents[2] = { LLVector4a(6.f, 6.f, PIXEL_Z), LLVector4a(22.f, 24.f, PIXEL_Z) }; LLRect rect; - ensure(named(reverse, "its box is on screen"), - Outline::scissorRect(pixelProjection(), extents, W, H, Outline::lineReach(RADIUS), rect)); + UNSCOPED_INFO(named(reverse, "its box is on screen")); + REQUIRE(Outline::scissorRect(pixelProjection(), extents, W, H, Outline::lineReach(RADIUS), rect)); pixelIds({ hoverDraw(pixels(6, 22, 6, 24), ID_GLOW) }); const std::vector whole = edgePass(glowView(RADIUS), nullptr, false, nullptr, true); const std::vector scissored = edgePass(glowView(RADIUS), &rect, false, &rect, true); - ensure(named(reverse, "its glow is drawn"), lit(whole) > 100); - ensure(named(reverse, "and lies in its box grown by its reach"), whole == scissored); + UNSCOPED_INFO(named(reverse, "its glow is drawn")); + REQUIRE(lit(whole) > 100); + UNSCOPED_INFO(named(reverse, "and lies in its box grown by its reach")); + REQUIRE(whole == scissored); } } // A face wearing the library's transparent texture is drawn whole, legacy or GLTF, whatever its alpha mode, so // the invisible prims builders hide roots and touch areas with are outlined; any other texture keeps its alpha cut. - template<> template<> - void alselectionoutline_object_t::test<39>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a face wearing the library's transparent texture is drawn whole", "[ALSelectionOutline]") { const LLUUID other("c0ffee00-0000-4000-8000-0000000000aa"); const F32 blend = Outline::legacyAlphaCutoff(false, 0, 0, true); const F32 mask = Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_MASK, 0.5f); - ensure_equals("the transparent texture is drawn whole", Outline::faceAlphaCutoff(IMG_TRANSPARENT, blend), + UNSCOPED_INFO("the transparent texture is drawn whole"); + CHECK(Outline::faceAlphaCutoff(IMG_TRANSPARENT, blend) == Outline::NO_ALPHA_TEST); - ensure_equals("as a GLTF base colour too", Outline::faceAlphaCutoff(IMG_TRANSPARENT, mask), Outline::NO_ALPHA_TEST); - ensure_equals("any other keeps its cut", Outline::faceAlphaCutoff(other, blend), blend); - ensure_equals("a GLTF one too", Outline::faceAlphaCutoff(other, mask), mask); + UNSCOPED_INFO("as a GLTF base colour too"); + CHECK(Outline::faceAlphaCutoff(IMG_TRANSPARENT, mask) == Outline::NO_ALPHA_TEST); + UNSCOPED_INFO("any other keeps its cut"); + CHECK(Outline::faceAlphaCutoff(other, blend) == blend); + UNSCOPED_INFO("a GLTF one too"); + CHECK(Outline::faceAlphaCutoff(other, mask) == mask); for (bool reverse : conventions()) { @@ -2656,19 +3155,19 @@ namespace tut const std::string which = whole ? "the transparent texture" : "another clear texture"; idPass({ { quadA(), ID_A, Outline::PRIORITY_ROOT, Outline::faceAlphaCutoff(texture, blend), clearTexture() } }); const std::vector ids = read(mIdMap); - ensure_equals(named(reverse, which + (whole ? " drawn whole" : " cut away")), idAt(ids, 20, 32), - whole ? ID_A : 0U); + UNSCOPED_INFO(named(reverse, which + (whole ? " drawn whole" : " cut away"))); + REQUIRE(idAt(ids, 20, 32) == + (whole ? ID_A : 0U)); const std::vector px = edgePass(); - ensure(named(reverse, which + (whole ? " outlined" : " not outlined")), - whole ? red(at(px, 8, 32)) : black(at(px, 8, 32))); + UNSCOPED_INFO(named(reverse, which + (whole ? " outlined" : " not outlined"))); + REQUIRE((whole ? red(at(px, 8, 32)) : black(at(px, 8, 32)))); } } } // On the HUD, an object in the id pass for its wireframe's depth alone is drawn nowhere there: its id is in the // target, hiding what lies behind it from the lines, and it has no contour while another object's is drawn. - template<> template<> - void alselectionoutline_object_t::test<40>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a HUD object in the id pass only for its wireframe's depth is not drawn", "[ALSelectionOutline]") { for (bool reverse : conventions()) { @@ -2676,21 +3175,32 @@ namespace tut Draw wire_only{ pixels(36, 50, 20, 44), ID_B }; wire_only.mParts = Outline::PART_WIREFRAME; const std::vector ids = pixelIds({ { pixels(10, 26, 20, 44), ID_A }, wire_only }); - ensure_equals(named(reverse, "its id is in the target"), idAt(ids, 40, 32), ID_B); - ensure_equals(named(reverse, "drawn nowhere"), (U32)at(ids, 40, 32).b, 0U); - ensure_equals(named(reverse, "the other drawn"), (U32)at(ids, 20, 32).b, 255U); + UNSCOPED_INFO(named(reverse, "its id is in the target")); + REQUIRE(idAt(ids, 40, 32) == ID_B); + UNSCOPED_INFO(named(reverse, "drawn nowhere")); + REQUIRE((U32)at(ids, 40, 32).b == 0U); + UNSCOPED_INFO(named(reverse, "the other drawn")); + REQUIRE((U32)at(ids, 20, 32).b == 255U); palette({ { ID_A, RED }, { ID_B, GREEN } }, true); const std::vector px = edgePass(Outline::makeView(identity(), pixelProjection(), TEST_WIDTH, 1.f, true)); - ensure(named(reverse, "the other's contour"), red(at(px, 9, 32)) && red(at(px, 26, 32))); - ensure(named(reverse, "none around it"), black(at(px, 35, 32)) && black(at(px, 50, 32)) && black(at(px, 43, 45))); + { + INFO(named(reverse, "the other's contour")); + REQUIRE(red(at(px, 9, 32))); + REQUIRE(red(at(px, 26, 32))); + } + { + INFO(named(reverse, "none around it")); + REQUIRE(black(at(px, 35, 32))); + REQUIRE(black(at(px, 50, 32))); + REQUIRE(black(at(px, 43, 45))); + } } } // A blended face is cut only where its texture is all but clear: one translucent all over, as a pane of glass is, // is drawn whole, outlined and wireframed, where the same texture under a cutoff of a half is cut away. - template<> template<> - void alselectionoutline_object_t::test<41>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: a blended face is cut only where its texture is all but clear", "[ALSelectionOutline]") { const F32 blend = Outline::legacyAlphaCutoff(false, 0, 0, true); const F32 half = Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_MASK, 0.5f); @@ -2702,21 +3212,27 @@ namespace tut idPass({ { quadA(), ID_A, Outline::PRIORITY_ROOT, blend, glass } }); std::vector ids = read(mIdMap); - ensure_equals(named(reverse, "a blended pane of glass drawn whole"), idAt(ids, 20, 32), ID_A); + UNSCOPED_INFO(named(reverse, "a blended pane of glass drawn whole")); + REQUIRE(idAt(ids, 20, 32) == ID_A); std::vector px = edgePass(); - ensure(named(reverse, "and outlined"), red(at(px, 8, 32))); + UNSCOPED_INFO(named(reverse, "and outlined")); + REQUIRE(red(at(px, 8, 32))); windowDepth(nullptr); px = worldWireframe({ { quadA(), ID_A, Outline::PRIORITY_ROOT, blend, glass } }); - ensure(named(reverse, "and wireframed"), lit(px) > 0); + UNSCOPED_INFO(named(reverse, "and wireframed")); + REQUIRE(lit(px) > 0); idPass({ { quadA(), ID_A, Outline::PRIORITY_ROOT, half, glass } }); ids = read(mIdMap); - ensure_equals(named(reverse, "under a cutoff of a half it is cut away"), idAt(ids, 20, 32), 0U); + UNSCOPED_INFO(named(reverse, "under a cutoff of a half it is cut away")); + REQUIRE(idAt(ids, 20, 32) == 0U); px = edgePass(); - ensure(named(reverse, "and not outlined"), black(at(px, 8, 32))); + UNSCOPED_INFO(named(reverse, "and not outlined")); + REQUIRE(black(at(px, 8, 32))); px = worldWireframe({ { quadA(), ID_A, Outline::PRIORITY_ROOT, half, glass } }); - ensure_equals(named(reverse, "nor wireframed"), lit(px), size_t(0)); + UNSCOPED_INFO(named(reverse, "nor wireframed")); + REQUIRE(lit(px) == size_t(0)); } } @@ -2724,8 +3240,7 @@ namespace tut // around shapes thin, slanted and cut off by the target's edges, between two glowing objects, where the lower id's // colour is drawn where both are as near, beside selections and with one in front of it, and around an object // partly hidden. - template<> template<> - void alselectionoutline_object_t::test<42>() + TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the glow reach and row passes draw what the full search draws", "[ALSelectionOutline]") { constexpr U32 ID_GLOW = 400; constexpr U32 ID_OTHER = 401; @@ -2758,19 +3273,24 @@ namespace tut const std::string at_radius = name + ", a reach of " + std::to_string(radius); const std::vector rows = edgePass(glowView(radius), nullptr, false, nullptr, true); const std::vector full = edgePass(glowView(radius), nullptr, true, nullptr, true); - ensure(named(reverse, at_radius + ": it glows"), lit(rows) > 0); - ensure(named(reverse, at_radius + ": as the full search draws it"), rows == full); + UNSCOPED_INFO(named(reverse, at_radius + ": it glows")); + REQUIRE(lit(rows) > 0); + UNSCOPED_INFO(named(reverse, at_radius + ": as the full search draws it")); + REQUIRE(rows == full); } } // Column 24 is five columns from each of the first scene's objects, column 23 four from the one on the left. pixelIds(scenes[0].second); const std::vector between = edgePass(glowView(9), nullptr, false, nullptr, true); - ensure(named(reverse, "as near both along a row, the lower id's colour"), green(at(between, 24, 32))); - ensure(named(reverse, "nearer the left, its colour"), blue(at(between, 23, 32))); + UNSCOPED_INFO(named(reverse, "as near both along a row, the lower id's colour")); + REQUIRE(green(at(between, 24, 32))); + UNSCOPED_INFO(named(reverse, "nearer the left, its colour")); + REQUIRE(blue(at(between, 23, 32))); pixelIds(scenes[4].second); const std::vector across = edgePass(glowView(9), nullptr, false, nullptr, true); - ensure(named(reverse, "as near both along a column and a row, the lower id's colour"), green(at(across, 30, 30))); + UNSCOPED_INFO(named(reverse, "as near both along a column and a row, the lower id's colour")); + REQUIRE(green(at(across, 30, 30))); // Behind something in the scene over columns 0 to 20, its hidden part drawing no glow. occlude(3.f, 0, 0, 21, H); @@ -2780,8 +3300,10 @@ namespace tut const std::string at_radius = "partly hidden, a reach of " + std::to_string(radius); const std::vector rows = edgePass(glowView(radius), nullptr, false, nullptr, true); const std::vector full = edgePass(glowView(radius), nullptr, true, nullptr, true); - ensure(named(reverse, at_radius + ": it glows"), lit(rows) > 0); - ensure(named(reverse, at_radius + ": as the full search draws it"), rows == full); + UNSCOPED_INFO(named(reverse, at_radius + ": it glows")); + REQUIRE(lit(rows) > 0); + UNSCOPED_INFO(named(reverse, at_radius + ": as the full search draws it")); + REQUIRE(rows == full); } } } diff --git a/indra/newview/tests/alterrainsurfacemaps_test.cpp b/indra/newview/tests/alterrainsurfacemaps_test.cpp index 1c224de1ee..7beb304fb2 100644 --- a/indra/newview/tests/alterrainsurfacemaps_test.cpp +++ b/indra/newview/tests/alterrainsurfacemaps_test.cpp @@ -26,14 +26,15 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include +#include "altestmatchers.h" #include "../alterrainsurfacemaps.h" #include #include -namespace tut +namespace { struct alterrainsurfacemaps_data { @@ -54,140 +55,171 @@ namespace tut } }; - typedef test_group alterrainsurfacemaps_test; - typedef alterrainsurfacemaps_test::object alterrainsurfacemaps_object; - tut::alterrainsurfacemaps_test alterrainsurfacemaps_testcase("ALTerrainSurfaceMaps"); - // fill() visits every grid coordinate from -APRON to gpe + APRON - 1 on // both axes, once, rows along y, and lands each at (gx + APRON, gy + APRON). - template<> template<> - void alterrainsurfacemaps_object::test<1>() + TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: fill() lays the grid out APRON in with rows along y", "[ALTerrainSurfaceMaps]") { std::vector out; ALTerrainSurfaceMaps::fill(out, GPE, 1, [](S32 gx, S32 gy, F32* t) { t[0] = (F32)(gx * 100 + gy); }); - ensure_equals("size", out.size(), static_cast(SIZE) * SIZE); - ensure_equals("first texel is the south-west apron corner", out[texel(-APRON, -APRON)], (F32)(-APRON * 100 - APRON)); - ensure_equals("grid origin sits APRON in", out[texel(0, 0)], 0.f); - ensure_equals("buffer column", out[texel(GPE - 1, 3)], (F32)((GPE - 1) * 100 + 3)); - ensure_equals("last texel is the north-east apron corner", - out[texel(GPE + APRON - 1, GPE + APRON - 1)], (F32)((GPE + APRON - 1) * 100 + GPE + APRON - 1)); - ensure_equals("row stride is the map width", out[texel(0, 1)] - out[texel(0, 0)], 1.f); - ensure_equals("column stride is one texel", out[texel(1, 0)] - out[texel(0, 0)], 100.f); + UNSCOPED_INFO("size"); + REQUIRE(out.size() == static_cast(SIZE) * SIZE); + UNSCOPED_INFO("first texel is the south-west apron corner"); + CHECK(out[texel(-APRON, -APRON)] == (F32)(-APRON * 100 - APRON)); + UNSCOPED_INFO("grid origin sits APRON in"); + CHECK(out[texel(0, 0)] == 0.f); + UNSCOPED_INFO("buffer column"); + CHECK(out[texel(GPE - 1, 3)] == (F32)((GPE - 1) * 100 + 3)); + UNSCOPED_INFO("last texel is the north-east apron corner"); + CHECK(out[texel(GPE + APRON - 1, GPE + APRON - 1)] == (F32)((GPE + APRON - 1) * 100 + GPE + APRON - 1)); + UNSCOPED_INFO("row stride is the map width"); + CHECK(out[texel(0, 1)] - out[texel(0, 0)] == 1.f); + UNSCOPED_INFO("column stride is one texel"); + CHECK(out[texel(1, 0)] - out[texel(0, 0)] == 100.f); } // Two channels interleave, and a second fill of a buffer already the // right size keeps the channel the sampler does not write. - template<> template<> - void alterrainsurfacemaps_object::test<2>() + TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: two channels interleave and a refill keeps the channel it does not write", "[ALTerrainSurfaceMaps]") { std::vector out; ALTerrainSurfaceMaps::fill(out, GPE, 2, [](S32 gx, S32 gy, F32* t) { t[0] = (F32)gx; t[1] = (F32)gy; }); - ensure_equals("size", out.size(), static_cast(SIZE) * SIZE * 2); - ensure_equals("channel 0", out[texel(3, 5, 2)], 3.f); - ensure_equals("channel 1", out[texel(3, 5, 2) + 1], 5.f); + UNSCOPED_INFO("size"); + REQUIRE(out.size() == static_cast(SIZE) * SIZE * 2); + UNSCOPED_INFO("channel 0"); + CHECK(out[texel(3, 5, 2)] == 3.f); + UNSCOPED_INFO("channel 1"); + CHECK(out[texel(3, 5, 2) + 1] == 5.f); ALTerrainSurfaceMaps::fill(out, GPE, 2, [](S32 gx, S32, F32* t) { t[0] = (F32)(gx + 1000); }); - ensure_equals("channel 0 rewritten", out[texel(3, 5, 2)], 1003.f); - ensure_equals("channel 1 kept", out[texel(3, 5, 2) + 1], 5.f); + UNSCOPED_INFO("channel 0 rewritten"); + CHECK(out[texel(3, 5, 2)] == 1003.f); + UNSCOPED_INFO("channel 1 kept"); + CHECK(out[texel(3, 5, 2) + 1] == 5.f); } // Inside the region nothing moves. - template<> template<> - void alterrainsurfacemaps_object::test<3>() + TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: resolve moves nothing inside the region", "[ALTerrainSurfaceMaps]") { bool has[8]; allSet(true, has); S32 gx = 4, gy = GPE - 1; - ensure_equals("interior is this surface", ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has), MIDDLE); - ensure_equals("gx unchanged", gx, 4); - ensure_equals("gy unchanged, the buffer row is ours", gy, GPE - 1); + UNSCOPED_INFO("interior is this surface"); + CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == MIDDLE); + UNSCOPED_INFO("gx unchanged"); + CHECK(gx == 4); + UNSCOPED_INFO("gy unchanged, the buffer row is ours"); + CHECK(gy == GPE - 1); } // One axis out, neighbour present: the neighbour's grid 0 is our last // column, so our -1 is their gpe - 2 and our gpe is their 1. - template<> template<> - void alterrainsurfacemaps_object::test<4>() + TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: one axis out resolves to that neighbour's grid", "[ALTerrainSurfaceMaps]") { bool has[8]; allSet(true, has); S32 gx = -1, gy = 3; - ensure_equals("west", ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has), WEST); - ensure_equals("west gx", gx, GPE - 2); - ensure_equals("west gy", gy, 3); + UNSCOPED_INFO("west"); + CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == WEST); + UNSCOPED_INFO("west gx"); + CHECK(gx == GPE - 2); + UNSCOPED_INFO("west gy"); + CHECK(gy == 3); gx = -APRON; gy = 3; ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has); - ensure_equals("west, two out", gx, GPE - 3); + UNSCOPED_INFO("west, two out"); + CHECK(gx == GPE - 3); gx = GPE; gy = 3; - ensure_equals("east", ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has), EAST); - ensure_equals("east gx", gx, 1); + UNSCOPED_INFO("east"); + CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == EAST); + UNSCOPED_INFO("east gx"); + CHECK(gx == 1); gx = GPE + 1; gy = 3; ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has); - ensure_equals("east, two out", gx, 2); + UNSCOPED_INFO("east, two out"); + CHECK(gx == 2); gx = 3; gy = -1; - ensure_equals("south", ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has), SOUTH); - ensure_equals("south gy", gy, GPE - 2); + UNSCOPED_INFO("south"); + CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == SOUTH); + UNSCOPED_INFO("south gy"); + CHECK(gy == GPE - 2); gx = 3; gy = GPE + 1; - ensure_equals("north", ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has), NORTH); - ensure_equals("north gy", gy, 2); + UNSCOPED_INFO("north"); + CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == NORTH); + UNSCOPED_INFO("north gy"); + CHECK(gy == 2); } // Both axes out: the diagonal neighbour when it is there. - template<> template<> - void alterrainsurfacemaps_object::test<5>() + TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: both axes out resolve to the diagonal neighbour when it is there", "[ALTerrainSurfaceMaps]") { bool has[8]; allSet(true, has); S32 gx = -1, gy = -APRON; - ensure_equals("south-west", ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has), SOUTHWEST); - ensure_equals("south-west gx", gx, GPE - 2); - ensure_equals("south-west gy", gy, GPE - 3); + UNSCOPED_INFO("south-west"); + CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == SOUTHWEST); + UNSCOPED_INFO("south-west gx"); + CHECK(gx == GPE - 2); + UNSCOPED_INFO("south-west gy"); + CHECK(gy == GPE - 3); gx = GPE + 1; gy = GPE; - ensure_equals("north-east", ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has), NORTHEAST); - ensure_equals("north-east gx", gx, 2); - ensure_equals("north-east gy", gy, 1); + UNSCOPED_INFO("north-east"); + CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == NORTHEAST); + UNSCOPED_INFO("north-east gx"); + CHECK(gx == 2); + UNSCOPED_INFO("north-east gy"); + CHECK(gy == 1); } // A missing neighbour clamps the axis that needed it and keeps the rest of // the walk: no west means gx clamps to 0 and y still resolves north. - template<> template<> - void alterrainsurfacemaps_object::test<6>() + TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: a missing neighbour clamps its axis and the other still resolves", "[ALTerrainSurfaceMaps]") { bool has[8]; allSet(true, has); has[WEST] = false; S32 gx = -1, gy = 3; - ensure_equals("no west: this surface", ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has), MIDDLE); - ensure_equals("no west: gx clamped", gx, 0); + UNSCOPED_INFO("no west: this surface"); + CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == MIDDLE); + UNSCOPED_INFO("no west: gx clamped"); + CHECK(gx == 0); gx = -1; gy = GPE; - ensure_equals("no west, north present: north", ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has), NORTH); - ensure_equals("north with gx clamped", gx, 0); - ensure_equals("north gy", gy, 1); + UNSCOPED_INFO("no west, north present: north"); + CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == NORTH); + UNSCOPED_INFO("north with gx clamped"); + CHECK(gx == 0); + UNSCOPED_INFO("north gy"); + CHECK(gy == 1); allSet(true, has); has[NORTHWEST] = false; gx = -1; gy = GPE; - ensure_equals("west present, north-west missing: west", ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has), WEST); - ensure_equals("west gx", gx, GPE - 2); - ensure_equals("west gy clamped to its last row", gy, GPE - 1); + UNSCOPED_INFO("west present, north-west missing: west"); + CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == WEST); + UNSCOPED_INFO("west gx"); + CHECK(gx == GPE - 2); + UNSCOPED_INFO("west gy clamped to its last row"); + CHECK(gy == GPE - 1); allSet(false, has); gx = GPE + 1; gy = -1; - ensure_equals("no neighbours: this surface", ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has), MIDDLE); - ensure_equals("gx clamped to the buffer column", gx, GPE - 1); - ensure_equals("gy clamped to 0", gy, 0); + UNSCOPED_INFO("no neighbours: this surface"); + CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == MIDDLE); + UNSCOPED_INFO("gx clamped to the buffer column"); + CHECK(gx == GPE - 1); + UNSCOPED_INFO("gy clamped to 0"); + CHECK(gy == 0); } // The smooth surface passes through every sample: at an integer grid point the // value is the sample, whatever the neighbours do. - template<> template<> - void alterrainsurfacemaps_object::test<7>() + TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: smoothHeight passes through every sample", "[ALTerrainSurfaceMaps]") { auto field = [](S32 gx, S32 gy) { return (F32)(gx * gx - 3 * gy + (gx * gy) % 5); }; for (S32 gy = 0; gy < 6; ++gy) @@ -195,7 +227,8 @@ namespace tut for (S32 gx = 0; gx < 6; ++gx) { const F32 h = ALTerrainSurfaceMaps::smoothHeight((F32)gx, (F32)gy, field, nullptr, nullptr); - ensure_equals("value at a sample is the sample", h, field(gx, gy)); + UNSCOPED_INFO("value at a sample is the sample"); + REQUIRE(h == field(gx, gy)); } } } @@ -205,30 +238,38 @@ namespace tut // drop inside the cell's range; a Catmull-Rom would put metres of bump // above the crease. And a monotone run stays monotone, so a ramp is a // ramp with no ripple ahead of or behind the step. - template<> template<> - void alterrainsurfacemaps_object::test<8>() + TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: smoothHeight grows no lip at a step and stays monotone down it", "[ALTerrainSurfaceMaps]") { auto cliff = [](S32 gx, S32) { return gx <= 2 ? 30.f : 0.f; }; for (F32 x = 0.f; x < 2.f; x += 0.125f) { F32 dzdx = 1.f, dzdy = 1.f; - ensure_approximately_equals("level up to the edge", ALTerrainSurfaceMaps::smoothHeight(x, 3.f, cliff, &dzdx, &dzdy), 30.f, 12); + UNSCOPED_INFO("level up to the edge"); + REQUIRE_THAT(ALTerrainSurfaceMaps::smoothHeight(x, 3.f, cliff, &dzdx, &dzdy), ll_test::WithinBits(30.f, 12)); // The tangent at the crease sample is zeroed, not averaged with the drop: the // level run has no slope at all, so it does not lean toward the edge. - ensure_approximately_equals("no slope on the level run", dzdx, 0.f, 12); + UNSCOPED_INFO("no slope on the level run"); + REQUIRE_THAT(dzdx, ll_test::WithinBits(0.f, 12)); } F32 previous = 30.f; for (F32 x = 2.f; x <= 3.f; x += 0.0625f) { const F32 h = ALTerrainSurfaceMaps::smoothHeight(x, 3.f, cliff, nullptr, nullptr); - ensure("inside the cell's range", h <= 30.f && h >= 0.f); - ensure("monotone down the face", h <= previous); + { + INFO("inside the cell's range"); + REQUIRE(h <= 30.f); + REQUIRE(h >= 0.f); + } + UNSCOPED_INFO("monotone down the face"); + REQUIRE(h <= previous); previous = h; } - ensure_approximately_equals("mid-cell is the midpoint of the step", ALTerrainSurfaceMaps::smoothHeight(2.5f, 3.f, cliff, nullptr, nullptr), 15.f, 12); + UNSCOPED_INFO("mid-cell is the midpoint of the step"); + CHECK_THAT(ALTerrainSurfaceMaps::smoothHeight(2.5f, 3.f, cliff, nullptr, nullptr), ll_test::WithinBits(15.f, 12)); for (F32 x = 3.f; x < 5.f; x += 0.125f) { - ensure_approximately_equals("level past the foot", ALTerrainSurfaceMaps::smoothHeight(x, 3.f, cliff, nullptr, nullptr), 0.f, 12); + UNSCOPED_INFO("level past the foot"); + REQUIRE_THAT(ALTerrainSurfaceMaps::smoothHeight(x, 3.f, cliff, nullptr, nullptr), ll_test::WithinBits(0.f, 12)); } // Off the axis too: a corner of the plateau, evaluated across the @@ -239,27 +280,30 @@ namespace tut for (F32 x = 2.f; x <= 3.f; x += 0.25f) { const F32 h = ALTerrainSurfaceMaps::smoothHeight(x, y, corner, nullptr, nullptr); - ensure("plateau corner within its cell's range", h >= 0.f && h <= 30.f); + { + INFO("plateau corner within its cell's range"); + REQUIRE(h >= 0.f); + REQUIRE(h <= 30.f); + } } } } // A field symmetric in x and y gives a surface symmetric in x and y. - template<> template<> - void alterrainsurfacemaps_object::test<9>() + TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: a field symmetric in x and y gives a surface symmetric in x and y", "[ALTerrainSurfaceMaps]") { auto field = [](S32 gx, S32 gy) { return (F32)(gx * gx + gy * gy) * 0.1f + (F32)((gx + gy) % 3); }; for (F32 v = 0.f; v < 4.f; v += 0.37f) { const F32 a = ALTerrainSurfaceMaps::smoothHeight(1.2f, v, field, nullptr, nullptr); const F32 b = ALTerrainSurfaceMaps::smoothHeight(v, 1.2f, field, nullptr, nullptr); - ensure_approximately_equals("h(x, y) == h(y, x)", a, b, 5); + UNSCOPED_INFO("h(x, y) == h(y, x)"); + REQUIRE_THAT(a, ll_test::WithinBits(b, 5)); } } // The analytic gradient is the derivative of the value. - template<> template<> - void alterrainsurfacemaps_object::test<10>() + TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: the analytic gradient matches a central difference of the value", "[ALTerrainSurfaceMaps]") { auto field = [](S32 gx, S32 gy) { return sinf(0.7f * gx) * 2.f + cosf(0.4f * gy) + 0.1f * gx * gy; }; const F32 eps = 1e-2f; @@ -273,8 +317,10 @@ namespace tut - ALTerrainSurfaceMaps::smoothHeight(x - eps, y, field, nullptr, nullptr)) / (2.f * eps); const F32 fdy = (ALTerrainSurfaceMaps::smoothHeight(x, y + eps, field, nullptr, nullptr) - ALTerrainSurfaceMaps::smoothHeight(x, y - eps, field, nullptr, nullptr)) / (2.f * eps); - ensure_approximately_equals("dz/dx", dzdx, fdx, 8); - ensure_approximately_equals("dz/dy", dzdy, fdy, 8); + UNSCOPED_INFO("dz/dx"); + REQUIRE_THAT(dzdx, ll_test::WithinBits(fdx, 8)); + UNSCOPED_INFO("dz/dy"); + REQUIRE_THAT(dzdy, ll_test::WithinBits(fdy, 8)); } } } diff --git a/indra/newview/tests/altexturetable_test.cpp b/indra/newview/tests/altexturetable_test.cpp index 56e4018bc9..fc0b360bc2 100644 --- a/indra/newview/tests/altexturetable_test.cpp +++ b/indra/newview/tests/altexturetable_test.cpp @@ -24,7 +24,7 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include #include "../altexturetable.h" @@ -71,7 +71,7 @@ namespace using Table = ALTextureTable; } -namespace tut +namespace { struct texturetable_data { @@ -87,7 +87,8 @@ namespace tut for (U32 i = 1; i <= count; ++i) { Item* item = new Item(i); - ensure("fill insert", mTable.insert(key(i), item)); + UNSCOPED_INFO("fill insert"); + REQUIRE(mTable.insert(key(i), item)); items.push_back(item); } return items; @@ -103,232 +104,293 @@ namespace tut static std::vector ids(std::initializer_list in) { return std::vector(in); } }; - typedef test_group texturetable_group; - typedef texturetable_group::object texturetable_object; - tut::texturetable_group tg("ALTextureTable"); - // --- membership ---------------------------------------------------------- // An empty table answers every query without touching anything. - template<> template<> - void texturetable_object::test<1>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: an empty table answers every query without touching anything", "[ALTextureTable]") { - ensure_equals("size", mTable.size(), (size_t)0); - ensure("empty", mTable.empty()); - ensure("find", mTable.find(key(1)) == nullptr); - ensure("erase", mTable.erase(key(1)).isNull()); - ensure_equals("window", window(4).size(), (size_t)0); + UNSCOPED_INFO("size"); + REQUIRE(mTable.size() == (size_t)0); + UNSCOPED_INFO("empty"); + REQUIRE(mTable.empty()); + UNSCOPED_INFO("find"); + REQUIRE(mTable.find(key(1)) == nullptr); + UNSCOPED_INFO("erase"); + REQUIRE(mTable.erase(key(1)).isNull()); + UNSCOPED_INFO("window"); + REQUIRE(window(4).size() == (size_t)0); mTable.rewind(3); - ensure_equals("cursor", mTable.cursor(), 0u); - ensure("consistent", mTable.consistent()); + UNSCOPED_INFO("cursor"); + CHECK(mTable.cursor() == 0u); + UNSCOPED_INFO("consistent"); + CHECK(mTable.consistent()); } // Insert records each item's position, find answers by key, iteration is // insertion order, and the table holds exactly one reference per item. - template<> template<> - void texturetable_object::test<2>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: insert records positions and iteration is insertion order", "[ALTextureTable]") { mTable.reserve(8); std::vector items = fill(3); - ensure_equals("size", mTable.size(), (size_t)3); - ensure("find 2", mTable.find(key(2)) == items[1]); - ensure("find type", mTable.find(key(2, 1)) == nullptr); - ensure("contains", mTable.contains(key(3))); + UNSCOPED_INFO("size"); + REQUIRE(mTable.size() == (size_t)3); + UNSCOPED_INFO("find 2"); + CHECK(mTable.find(key(2)) == items[1]); + UNSCOPED_INFO("find type"); + REQUIRE(mTable.find(key(2, 1)) == nullptr); + UNSCOPED_INFO("contains"); + CHECK(mTable.contains(key(3))); for (S32 i = 0; i < 3; ++i) { - ensure_equals("index", items[i]->getListIndex(), i); - ensure("position", mTable[i] == items[i]); - ensure_equals("one ref", items[i]->getNumRefs(), 1); + UNSCOPED_INFO("index"); + REQUIRE(items[i]->getListIndex() == i); + UNSCOPED_INFO("position"); + REQUIRE(mTable[i] == items[i]); + UNSCOPED_INFO("one ref"); + REQUIRE(items[i]->getNumRefs() == 1); } U32 expected = 1; for (const LLPointer& item : mTable) { - ensure_equals("iteration order", item->mId, expected++); + UNSCOPED_INFO("iteration order"); + REQUIRE(item->mId == expected++); } - ensure_equals("live", Item::sLive, 3); - ensure("consistent", mTable.consistent()); + UNSCOPED_INFO("live"); + CHECK(Item::sLive == 3); + UNSCOPED_INFO("consistent"); + CHECK(mTable.consistent()); } // A key already present, or an item already in a table, is refused and // nothing changes; the refused item keeps its own state. - template<> template<> - void texturetable_object::test<3>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: a duplicate key or an item already in a table is refused", "[ALTextureTable]") { std::vector items = fill(3); LLPointer other = new Item(9); - ensure("duplicate key refused", !mTable.insert(key(2), other)); - ensure_equals("size after key refusal", mTable.size(), (size_t)3); - ensure("original kept", mTable.find(key(2)) == items[1]); - ensure_equals("refused item index", other->getListIndex(), -1); - ensure_equals("refused item refs", other->getNumRefs(), 1); - - ensure("second key refused", !mTable.insert(key(9), items[0])); - ensure("second key absent", mTable.find(key(9)) == nullptr); - ensure_equals("size after item refusal", mTable.size(), (size_t)3); - ensure("consistent", mTable.consistent()); + UNSCOPED_INFO("duplicate key refused"); + CHECK_FALSE(mTable.insert(key(2), other)); + UNSCOPED_INFO("size after key refusal"); + REQUIRE(mTable.size() == (size_t)3); + UNSCOPED_INFO("original kept"); + CHECK(mTable.find(key(2)) == items[1]); + UNSCOPED_INFO("refused item index"); + CHECK(other->getListIndex() == -1); + UNSCOPED_INFO("refused item refs"); + CHECK(other->getNumRefs() == 1); + + UNSCOPED_INFO("second key refused"); + CHECK_FALSE(mTable.insert(key(9), items[0])); + UNSCOPED_INFO("second key absent"); + REQUIRE(mTable.find(key(9)) == nullptr); + UNSCOPED_INFO("size after item refusal"); + REQUIRE(mTable.size() == (size_t)3); + UNSCOPED_INFO("consistent"); + CHECK(mTable.consistent()); } // Erasing the last item needs no patching and hands the reference back. - template<> template<> - void texturetable_object::test<4>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: erasing the last item needs no patching and hands the reference back", "[ALTextureTable]") { std::vector items = fill(3); { LLPointer removed = mTable.erase(key(3)); - ensure("returned item", removed == items[2]); - ensure_equals("returned ref is the only one", removed->getNumRefs(), 1); - ensure_equals("removed index", removed->getListIndex(), -1); - ensure_equals("size", mTable.size(), (size_t)2); - ensure("gone", mTable.find(key(3)) == nullptr); - ensure_equals("others untouched 0", items[0]->getListIndex(), 0); - ensure_equals("others untouched 1", items[1]->getListIndex(), 1); - ensure_equals("still live", Item::sLive, 3); + UNSCOPED_INFO("returned item"); + CHECK(removed == items[2]); + UNSCOPED_INFO("returned ref is the only one"); + CHECK(removed->getNumRefs() == 1); + UNSCOPED_INFO("removed index"); + CHECK(removed->getListIndex() == -1); + UNSCOPED_INFO("size"); + REQUIRE(mTable.size() == (size_t)2); + UNSCOPED_INFO("gone"); + REQUIRE(mTable.find(key(3)) == nullptr); + UNSCOPED_INFO("others untouched 0"); + CHECK(items[0]->getListIndex() == 0); + UNSCOPED_INFO("others untouched 1"); + CHECK(items[1]->getListIndex() == 1); + UNSCOPED_INFO("still live"); + CHECK(Item::sLive == 3); } - ensure_equals("destroyed with the last ref", Item::sLive, 2); - ensure("consistent", mTable.consistent()); + UNSCOPED_INFO("destroyed with the last ref"); + CHECK(Item::sLive == 2); + UNSCOPED_INFO("consistent"); + CHECK(mTable.consistent()); } // Erasing a middle item moves the last item into the hole and the moved // item's recorded position follows it. - template<> template<> - void texturetable_object::test<5>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: erasing a middle item moves the last into the hole with its position", "[ALTextureTable]") { std::vector items = fill(5); LLPointer removed = mTable.erase(key(2)); - ensure("returned item", removed == items[1]); - ensure_equals("size", mTable.size(), (size_t)4); - ensure("last item fills the hole", mTable[1] == items[4]); - ensure_equals("moved index follows", items[4]->getListIndex(), 1); - ensure("moved item still found", mTable.find(key(5)) == items[4]); - ensure("erased key gone", mTable.find(key(2)) == nullptr); - ensure_equals("unmoved 0", items[0]->getListIndex(), 0); - ensure_equals("unmoved 2", items[2]->getListIndex(), 2); - ensure_equals("unmoved 3", items[3]->getListIndex(), 3); - ensure("consistent", mTable.consistent()); + UNSCOPED_INFO("returned item"); + CHECK(removed == items[1]); + UNSCOPED_INFO("size"); + REQUIRE(mTable.size() == (size_t)4); + UNSCOPED_INFO("last item fills the hole"); + CHECK(mTable[1] == items[4]); + UNSCOPED_INFO("moved index follows"); + CHECK(items[4]->getListIndex() == 1); + UNSCOPED_INFO("moved item still found"); + CHECK(mTable.find(key(5)) == items[4]); + UNSCOPED_INFO("erased key gone"); + REQUIRE(mTable.find(key(2)) == nullptr); + UNSCOPED_INFO("unmoved 0"); + CHECK(items[0]->getListIndex() == 0); + UNSCOPED_INFO("unmoved 2"); + CHECK(items[2]->getListIndex() == 2); + UNSCOPED_INFO("unmoved 3"); + CHECK(items[3]->getListIndex() == 3); + UNSCOPED_INFO("consistent"); + CHECK(mTable.consistent()); } // An absent key erases nothing. - template<> template<> - void texturetable_object::test<6>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: an absent key erases nothing", "[ALTextureTable]") { std::vector items = fill(3); - ensure("null", mTable.erase(key(42)).isNull()); - ensure("null by type", mTable.erase(key(2, 1)).isNull()); - ensure_equals("size", mTable.size(), (size_t)3); - ensure_equals("live", Item::sLive, 3); - ensure("consistent", mTable.consistent()); + UNSCOPED_INFO("null"); + REQUIRE(mTable.erase(key(42)).isNull()); + UNSCOPED_INFO("null by type"); + REQUIRE(mTable.erase(key(2, 1)).isNull()); + UNSCOPED_INFO("size"); + REQUIRE(mTable.size() == (size_t)3); + UNSCOPED_INFO("live"); + CHECK(Item::sLive == 3); + UNSCOPED_INFO("consistent"); + CHECK(mTable.consistent()); } // An insert after an erase lands at the end, not in the hole the erase // already filled. - template<> template<> - void texturetable_object::test<7>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: an insert after an erase lands at the end", "[ALTextureTable]") { std::vector items = fill(4); mTable.erase(key(2)); Item* added = new Item(6); - ensure("insert", mTable.insert(key(6), added)); - ensure_equals("at the end", added->getListIndex(), 3); - ensure_equals("size", mTable.size(), (size_t)4); - ensure("find", mTable.find(key(6)) == added); - ensure("consistent", mTable.consistent()); + UNSCOPED_INFO("insert"); + CHECK(mTable.insert(key(6), added)); + UNSCOPED_INFO("at the end"); + CHECK(added->getListIndex() == 3); + UNSCOPED_INFO("size"); + REQUIRE(mTable.size() == (size_t)4); + UNSCOPED_INFO("find"); + CHECK(mTable.find(key(6)) == added); + UNSCOPED_INFO("consistent"); + CHECK(mTable.consistent()); } // --- the round-robin window ---------------------------------------------- // Consecutive windows continue from the cursor and wrap. - template<> template<> - void texturetable_object::test<8>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: consecutive windows continue from the cursor and wrap", "[ALTextureTable]") { fill(5); - ensure("first", window(2) == ids({ 1, 2 })); - ensure("second", window(2) == ids({ 3, 4 })); - ensure("wraps", window(2) == ids({ 5, 1 })); - ensure_equals("cursor", mTable.cursor(), 1u); + UNSCOPED_INFO("first"); + CHECK(window(2) == ids({ 1, 2 })); + UNSCOPED_INFO("second"); + CHECK(window(2) == ids({ 3, 4 })); + UNSCOPED_INFO("wraps"); + CHECK(window(2) == ids({ 5, 1 })); + UNSCOPED_INFO("cursor"); + CHECK(mTable.cursor() == 1u); } // A window larger than the table visits every item once. - template<> template<> - void texturetable_object::test<9>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: a window larger than the table visits every item once", "[ALTextureTable]") { fill(5); std::vector seen; U32 visited = mTable.visitWindow(10, [&](Item* item) { seen.push_back(item->mId); }); - ensure_equals("visited", visited, 5u); - ensure("each once", seen == ids({ 1, 2, 3, 4, 5 })); - ensure_equals("cursor back at start", mTable.cursor(), 0u); + UNSCOPED_INFO("visited"); + CHECK(visited == 5u); + UNSCOPED_INFO("each once"); + CHECK(seen == ids({ 1, 2, 3, 4, 5 })); + UNSCOPED_INFO("cursor back at start"); + CHECK(mTable.cursor() == 0u); } // When erases leave the cursor past the end, the next window starts over // instead of reading past the vector. - template<> template<> - void texturetable_object::test<10>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: a cursor left past the end by erases starts the next window over", "[ALTextureTable]") { fill(5); window(4); - ensure_equals("cursor", mTable.cursor(), 4u); + UNSCOPED_INFO("cursor"); + CHECK(mTable.cursor() == 4u); mTable.erase(key(1)); mTable.erase(key(2)); - ensure_equals("size", mTable.size(), (size_t)3); - ensure("consistent", mTable.consistent()); - - ensure("restarts", window(1) == ids({ 5 })); - ensure_equals("cursor after restart", mTable.cursor(), 1u); + UNSCOPED_INFO("size"); + REQUIRE(mTable.size() == (size_t)3); + UNSCOPED_INFO("consistent"); + CHECK(mTable.consistent()); + + UNSCOPED_INFO("restarts"); + CHECK(window(1) == ids({ 5 })); + UNSCOPED_INFO("cursor after restart"); + CHECK(mTable.cursor() == 1u); } // Rewind steps the cursor back so unprocessed items come around again, // and clamps at one full turn. - template<> template<> - void texturetable_object::test<11>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: rewind steps the cursor back and clamps at one full turn", "[ALTextureTable]") { fill(5); window(4); mTable.rewind(2); - ensure_equals("cursor", mTable.cursor(), 2u); - ensure("revisits", window(1) == ids({ 3 })); + UNSCOPED_INFO("cursor"); + CHECK(mTable.cursor() == 2u); + UNSCOPED_INFO("revisits"); + CHECK(window(1) == ids({ 3 })); mTable.rewind(99); - ensure_equals("clamped to one turn", mTable.cursor(), 3u); - ensure("continues", window(1) == ids({ 4 })); + UNSCOPED_INFO("clamped to one turn"); + CHECK(mTable.cursor() == 3u); + UNSCOPED_INFO("continues"); + CHECK(window(1) == ids({ 4 })); } // An erase between windows changes who sits where, but every item the // next window hands out is a member, and the moved item is reached on the // following turn. - template<> template<> - void texturetable_object::test<12>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: after an erase between windows the moved item still comes around", "[ALTextureTable]") { fill(6); - ensure("first", window(3) == ids({ 1, 2, 3 })); + UNSCOPED_INFO("first"); + CHECK(window(3) == ids({ 1, 2, 3 })); mTable.erase(key(2)); - ensure("consistent", mTable.consistent()); + UNSCOPED_INFO("consistent"); + CHECK(mTable.consistent()); std::vector second = window(3); - ensure("second", second == ids({ 4, 5, 1 })); + UNSCOPED_INFO("second"); + CHECK(second == ids({ 4, 5, 1 })); for (U32 id : second) { - ensure("member", mTable.find(key(id)) != nullptr); + UNSCOPED_INFO("member"); + REQUIRE(mTable.find(key(id)) != nullptr); } - ensure("moved item comes around", window(3) == ids({ 6, 3, 4 })); + UNSCOPED_INFO("moved item comes around"); + CHECK(window(3) == ids({ 6, 3, 4 })); } // Visiting hands out raw pointers and takes no references. - template<> template<> - void texturetable_object::test<13>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: visiting hands out raw pointers and takes no references", "[ALTextureTable]") { std::vector items = fill(3); window(3); for (Item* item : items) { - ensure_equals("refs after visit", item->getNumRefs(), 1); + UNSCOPED_INFO("refs after visit"); + REQUIRE(item->getNumRefs() == 1); } } @@ -336,28 +398,34 @@ namespace tut // Clear resets every index before releasing, so an item that outlives the // table reads as in no table. - template<> template<> - void texturetable_object::test<14>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: clear leaves an item that outlives the table in no table", "[ALTextureTable]") { std::vector items = fill(3); LLPointer kept = items[1]; window(2); mTable.clear(); - ensure_equals("size", mTable.size(), (size_t)0); - ensure_equals("cursor", mTable.cursor(), 0u); - ensure_equals("kept index", kept->getListIndex(), -1); - ensure_equals("kept refs", kept->getNumRefs(), 1); - ensure_equals("others destroyed", Item::sLive, 1); - ensure("consistent", mTable.consistent()); - - ensure("reinsert after clear", mTable.insert(key(2), kept)); - ensure_equals("reinserted index", kept->getListIndex(), 0); + UNSCOPED_INFO("size"); + REQUIRE(mTable.size() == (size_t)0); + UNSCOPED_INFO("cursor"); + CHECK(mTable.cursor() == 0u); + UNSCOPED_INFO("kept index"); + CHECK(kept->getListIndex() == -1); + UNSCOPED_INFO("kept refs"); + CHECK(kept->getNumRefs() == 1); + UNSCOPED_INFO("others destroyed"); + CHECK(Item::sLive == 1); + UNSCOPED_INFO("consistent"); + CHECK(mTable.consistent()); + + UNSCOPED_INFO("reinsert after clear"); + CHECK(mTable.insert(key(2), kept)); + UNSCOPED_INFO("reinserted index"); + CHECK(kept->getListIndex() == 0); } // Destroying the table releases its references. - template<> template<> - void texturetable_object::test<15>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: destroying the table releases its references", "[ALTextureTable]") { { Table local; @@ -365,9 +433,11 @@ namespace tut { local.insert(key(i), new Item(i)); } - ensure_equals("live", Item::sLive, 3); + UNSCOPED_INFO("live"); + CHECK(Item::sLive == 3); } - ensure_equals("released", Item::sLive, 0); + UNSCOPED_INFO("released"); + CHECK(Item::sLive == 0); } // --- scale --------------------------------------------------------------- @@ -375,38 +445,46 @@ namespace tut // Growth through several rehashes keeps every item findable and every // recorded position right, and a reservation up front changes nothing // but the allocations. - template<> template<> - void texturetable_object::test<16>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: growth through several rehashes keeps every item findable and placed", "[ALTextureTable]") { const U32 count = 20000; std::vector items = fill(count); - ensure("consistent after growth", mTable.consistent()); + UNSCOPED_INFO("consistent after growth"); + CHECK(mTable.consistent()); for (U32 i = 1; i <= count; i += 997) { - ensure("found after growth", mTable.find(key(i)) == items[i - 1]); + UNSCOPED_INFO("found after growth"); + REQUIRE(mTable.find(key(i)) == items[i - 1]); } // erase every third item, then look for all of them for (U32 i = 3; i <= count; i += 3) { - ensure("erase", mTable.erase(key(i)).notNull()); + UNSCOPED_INFO("erase"); + REQUIRE(mTable.erase(key(i)).notNull()); } - ensure_equals("size after erases", mTable.size(), (size_t)(count - count / 3)); - ensure("consistent after erases", mTable.consistent()); + UNSCOPED_INFO("size after erases"); + REQUIRE(mTable.size() == (size_t)(count - count / 3)); + UNSCOPED_INFO("consistent after erases"); + CHECK(mTable.consistent()); for (U32 i = 1; i <= count; ++i) { Item* found = mTable.find(key(i)); - ensure("erased gone, kept found", (i % 3 == 0) ? found == nullptr : found == items[i - 1]); + UNSCOPED_INFO("erased gone, kept found"); + REQUIRE(((i % 3 == 0) ? found == nullptr : found == items[i - 1])); } Table reserved; reserved.reserve(count); for (U32 i = 1; i <= 100; ++i) { - ensure("reserved insert", reserved.insert(key(i), new Item(i))); + UNSCOPED_INFO("reserved insert"); + REQUIRE(reserved.insert(key(i), new Item(i))); } - ensure_equals("reserved size", reserved.size(), (size_t)100); - ensure("reserved consistent", reserved.consistent()); + UNSCOPED_INFO("reserved size"); + REQUIRE(reserved.size() == (size_t)100); + UNSCOPED_INFO("reserved consistent"); + CHECK(reserved.consistent()); } // --- find-or-insert ------------------------------------------------------ @@ -414,34 +492,50 @@ namespace tut // A hit hands back the existing item without calling the maker; a miss // calls it once and takes one reference to what it made; a maker that // returns nothing, or an item already in a table, leaves no trace. - template<> template<> - void texturetable_object::test<17>() + TEST_CASE_METHOD(texturetable_data, "ALTextureTable: findOrInsert makes only on a miss and leaves no trace on a refusal", "[ALTextureTable]") { std::vector items = fill(2); U32 made = 0; Item* hit = mTable.findOrInsert(key(2), [&]() { ++made; return new Item(99); }); - ensure("hit returns existing", hit == items[1]); - ensure_equals("maker not called on hit", made, 0u); + UNSCOPED_INFO("hit returns existing"); + CHECK(hit == items[1]); + UNSCOPED_INFO("maker not called on hit"); + CHECK(made == 0u); Item* fresh = mTable.findOrInsert(key(3), [&]() { ++made; return new Item(3); }); - ensure("miss inserts", fresh != nullptr && fresh->mId == 3); - ensure_equals("maker called once", made, 1u); - ensure_equals("one ref from the table", fresh->getNumRefs(), 1); - ensure_equals("position", fresh->getListIndex(), 2); - ensure("found afterwards", mTable.find(key(3)) == fresh); - ensure_equals("size", mTable.size(), (size_t)3); + { + INFO("miss inserts"); + REQUIRE(fresh != nullptr); + CHECK(fresh->mId == 3); + } + UNSCOPED_INFO("maker called once"); + CHECK(made == 1u); + UNSCOPED_INFO("one ref from the table"); + CHECK(fresh->getNumRefs() == 1); + UNSCOPED_INFO("position"); + CHECK(fresh->getListIndex() == 2); + UNSCOPED_INFO("found afterwards"); + CHECK(mTable.find(key(3)) == fresh); + UNSCOPED_INFO("size"); + REQUIRE(mTable.size() == (size_t)3); Item* none = mTable.findOrInsert(key(4), [&]() -> Item* { ++made; return nullptr; }); - ensure("null maker yields null", none == nullptr); - ensure("null maker leaves no key", !mTable.contains(key(4))); - ensure_equals("size after null maker", mTable.size(), (size_t)3); + UNSCOPED_INFO("null maker yields null"); + REQUIRE(none == nullptr); + UNSCOPED_INFO("null maker leaves no key"); + CHECK_FALSE(mTable.contains(key(4))); + UNSCOPED_INFO("size after null maker"); + REQUIRE(mTable.size() == (size_t)3); LLPointer other = new Item(5); mTable.insert(key(5), other); Item* dup = mTable.findOrInsert(key(6), [&]() { return other.get(); }); - ensure("item already in a table refused", dup == nullptr); - ensure("refused key absent", !mTable.contains(key(6))); - ensure("consistent", mTable.consistent()); + UNSCOPED_INFO("item already in a table refused"); + REQUIRE(dup == nullptr); + UNSCOPED_INFO("refused key absent"); + CHECK_FALSE(mTable.contains(key(6))); + UNSCOPED_INFO("consistent"); + CHECK(mTable.consistent()); } } diff --git a/indra/newview/tests/alwhitebalancesolver_test.cpp b/indra/newview/tests/alwhitebalancesolver_test.cpp index 9b062e967d..6805b61688 100644 --- a/indra/newview/tests/alwhitebalancesolver_test.cpp +++ b/indra/newview/tests/alwhitebalancesolver_test.cpp @@ -14,13 +14,14 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include +#include "altestmatchers.h" #include "../alwhitebalancesolver.h" #include -namespace tut +namespace { struct wb_data { @@ -35,33 +36,31 @@ namespace tut } }; - typedef test_group wb_group; - typedef wb_group::object wb_object; - tut::wb_group wbg("ALWhiteBalanceSolver"); - // Neutral in, neutral out. The shader's identity fast path tests the gain // against exactly vec3(1), so anything else here would leave the default // settings paying for a colour transform that does nothing. - template<> template<> - void wb_object::test<1>() + TEST_CASE_METHOD(wb_data, "ALWhiteBalanceSolver: neutral in gives a gain of one", "[ALWhiteBalanceSolver]") { const LLVector3 g = ALWhiteBalanceSolver::gain(0.f, 0.f); - ensure_approximately_equals("neutral red", g.mV[VX], 1.f, 6); - ensure_approximately_equals("neutral green", g.mV[VY], 1.f, 6); - ensure_approximately_equals("neutral blue", g.mV[VZ], 1.f, 6); + UNSCOPED_INFO("neutral red"); + CHECK_THAT(g.mV[VX], ll_test::WithinBits(1.f, 6)); + UNSCOPED_INFO("neutral green"); + CHECK_THAT(g.mV[VY], ll_test::WithinBits(1.f, 6)); + UNSCOPED_INFO("neutral blue"); + CHECK_THAT(g.mV[VZ], ll_test::WithinBits(1.f, 6)); } // Green is pinned across the whole range, which is what makes temperature // a colour control rather than an exposure one. - template<> template<> - void wb_object::test<2>() + TEST_CASE_METHOD(wb_data, "ALWhiteBalanceSolver: the green gain stays pinned at one across the whole range", "[ALWhiteBalanceSolver]") { for (S32 i = -5; i <= 5; ++i) { for (S32 j = -2; j <= 2; ++j) { const LLVector3 g = ALWhiteBalanceSolver::gain(i * 1000.f, j * 0.5f); - ensure_approximately_equals("green stays pinned", g.mV[VY], 1.f, 6); + UNSCOPED_INFO("green stays pinned"); + REQUIRE_THAT(g.mV[VY], ll_test::WithinBits(1.f, 6)); } } } @@ -69,19 +68,19 @@ namespace tut // The direction of the temperature control. A negative offset asks for a // warmer scene, which the renderer delivers by pushing red up relative to // blue -- if this ever inverts, every tooltip in the Basic panel is wrong. - template<> template<> - void wb_object::test<3>() + TEST_CASE_METHOD(wb_data, "ALWhiteBalanceSolver: a negative temperature offset warms and a positive one cools", "[ALWhiteBalanceSolver]") { const LLVector3 warm = ALWhiteBalanceSolver::gain(-2500.f, 0.f); const LLVector3 cool = ALWhiteBalanceSolver::gain( 2500.f, 0.f); - ensure("warm lifts red above blue", warm.mV[VX] > warm.mV[VZ]); - ensure("cool lifts blue above red", cool.mV[VZ] > cool.mV[VX]); + UNSCOPED_INFO("warm lifts red above blue"); + CHECK(warm.mV[VX] > warm.mV[VZ]); + UNSCOPED_INFO("cool lifts blue above red"); + CHECK(cool.mV[VZ] > cool.mV[VX]); } // The round trip the eyedropper depends on: every usable pair is recovered // from the gain it produces. - template<> template<> - void wb_object::test<4>() + TEST_CASE_METHOD(wb_data, "ALWhiteBalanceSolver: solve recovers every usable pair from the gain it produces", "[ALWhiteBalanceSolver]") { S32 tested = 0; for (S32 i = -4; i <= 4; ++i) @@ -110,19 +109,21 @@ namespace tut // or unachievable where it does not. What has to round-trip is // the colour the renderer will actually apply. const LLVector3 back = ALWhiteBalanceSolver::gain(got.mCCTOffset, got.mDuv); - ensure("gain round-trips", gainDistance(want, back) < 1e-3f); - ensure("and the solver knows it did", got.mResidual < 1e-3f); + UNSCOPED_INFO("gain round-trips"); + REQUIRE(gainDistance(want, back) < 1e-3f); + UNSCOPED_INFO("and the solver knows it did"); + REQUIRE(got.mResidual < 1e-3f); } } // Guards against the skip above quietly emptying the sweep. - ensure("the sweep covered most of the range", tested > 60); + UNSCOPED_INFO("the sweep covered most of the range"); + CHECK(tested > 60); } // A solution never escapes the sliders' range, whatever it is asked for. // Out here the answer is a best effort against the edge of the box, and // the residual is how the caller finds out. - template<> template<> - void wb_object::test<5>() + TEST_CASE_METHOD(wb_data, "ALWhiteBalanceSolver: a solution stays in the sliders' range whatever it is asked for", "[ALWhiteBalanceSolver]") { // Both free channels pulled well below green: "make it much greener // than any light source is". Temperature trades red against blue and @@ -132,40 +133,49 @@ namespace tut const LLVector3 absurd(0.3f, 1.f, 0.3f); const ALWhiteBalanceSolver::Result got = ALWhiteBalanceSolver::solve(absurd); - ensure("cct stays in range", - got.mCCTOffset >= ALWhiteBalanceSolver::CCT_MIN && - got.mCCTOffset <= ALWhiteBalanceSolver::CCT_MAX); - ensure("duv stays in range", - got.mDuv >= ALWhiteBalanceSolver::DUV_MIN && - got.mDuv <= ALWhiteBalanceSolver::DUV_MAX); - ensure("and it reports that it could not get there", got.mResidual > 0.1f); + { + INFO("cct stays in range"); + CHECK(got.mCCTOffset >= ALWhiteBalanceSolver::CCT_MIN); + CHECK(got.mCCTOffset <= ALWhiteBalanceSolver::CCT_MAX); + } + { + INFO("duv stays in range"); + CHECK(got.mDuv >= ALWhiteBalanceSolver::DUV_MIN); + CHECK(got.mDuv <= ALWhiteBalanceSolver::DUV_MAX); + } + UNSCOPED_INFO("and it reports that it could not get there"); + CHECK(got.mResidual > 0.1f); } // The gain that neutralises a colour, and the sign of what it does. - template<> template<> - void wb_object::test<6>() + TEST_CASE_METHOD(wb_data, "ALWhiteBalanceSolver: neutralisingGain pins green and scales red and blue to meet it", "[ALWhiteBalanceSolver]") { const LLVector3 g = ALWhiteBalanceSolver::neutralisingGain(LLColor3(0.4f, 0.5f, 0.8f)); - ensure_approximately_equals("green pinned", g.mV[VY], 1.f, 6); - ensure_approximately_equals("red is lifted to meet green", g.mV[VX], 1.25f, 5); - ensure_approximately_equals("blue is pulled down to it", g.mV[VZ], 0.625f, 5); + UNSCOPED_INFO("green pinned"); + CHECK_THAT(g.mV[VY], ll_test::WithinBits(1.f, 6)); + UNSCOPED_INFO("red is lifted to meet green"); + CHECK_THAT(g.mV[VX], ll_test::WithinBits(1.25f, 5)); + UNSCOPED_INFO("blue is pulled down to it"); + CHECK_THAT(g.mV[VZ], ll_test::WithinBits(0.625f, 5)); // Applying it does what it says. const LLColor3 sample(0.4f, 0.5f, 0.8f); - ensure_approximately_equals("corrected red equals green", sample.mV[0] * g.mV[VX], sample.mV[1], 5); - ensure_approximately_equals("corrected blue equals green", sample.mV[2] * g.mV[VZ], sample.mV[1], 5); + UNSCOPED_INFO("corrected red equals green"); + CHECK_THAT(sample.mV[0] * g.mV[VX], ll_test::WithinBits(sample.mV[1], 5)); + UNSCOPED_INFO("corrected blue equals green"); + CHECK_THAT(sample.mV[2] * g.mV[VZ], ll_test::WithinBits(sample.mV[1], 5)); // Scale-invariant: the eyedropper cares about the colour of a sample, // never how brightly it was lit. const LLVector3 dim = ALWhiteBalanceSolver::neutralisingGain(LLColor3(0.04f, 0.05f, 0.08f)); - ensure("brightness does not change the answer", gainDistance(g, dim) < 1e-4f); + UNSCOPED_INFO("brightness does not change the answer"); + CHECK(gainDistance(g, dim) < 1e-4f); } // The whole eyedropper, end to end: take a neutral surface, light it the // way some (cct, duv) pair would, and the solver should recover the pair // that undoes it. - template<> template<> - void wb_object::test<7>() + TEST_CASE_METHOD(wb_data, "ALWhiteBalanceSolver: solveForColor recovers the light that tinted a grey surface", "[ALWhiteBalanceSolver]") { for (S32 i = -3; i <= 3; ++i) { @@ -179,26 +189,30 @@ namespace tut const ALWhiteBalanceSolver::Result got = ALWhiteBalanceSolver::solveForColor(lit); const LLVector3 back = ALWhiteBalanceSolver::gain(got.mCCTOffset, got.mDuv); - ensure("recovers the light's own correction", - gainDistance(correction, back) < 1e-3f); + UNSCOPED_INFO("recovers the light's own correction"); + REQUIRE(gainDistance(correction, back) < 1e-3f); // And the sample really does come out neutral. const LLColor3 fixed(lit.mV[0] * back.mV[VX], lit.mV[1], lit.mV[2] * back.mV[VZ]); - ensure_approximately_equals("neutralised red", fixed.mV[0], fixed.mV[1], 4); - ensure_approximately_equals("neutralised blue", fixed.mV[2], fixed.mV[1], 4); + UNSCOPED_INFO("neutralised red"); + REQUIRE_THAT(fixed.mV[0], ll_test::WithinBits(fixed.mV[1], 4)); + UNSCOPED_INFO("neutralised blue"); + REQUIRE_THAT(fixed.mV[2], ll_test::WithinBits(fixed.mV[1], 4)); } } // An already-neutral sample asks for nothing, so clicking a grey wall in // a correctly balanced scene must not nudge the sliders off zero. - template<> template<> - void wb_object::test<8>() + TEST_CASE_METHOD(wb_data, "ALWhiteBalanceSolver: an already-neutral sample asks for no correction", "[ALWhiteBalanceSolver]") { const ALWhiteBalanceSolver::Result got = ALWhiteBalanceSolver::solveForColor(LLColor3(0.5f, 0.5f, 0.5f)); - ensure("cct stays put", std::fabs(got.mCCTOffset) < 1.f); - ensure("duv stays put", std::fabs(got.mDuv) < 1e-3f); - ensure("exactly reachable", got.mResidual < 1e-4f); + UNSCOPED_INFO("cct stays put"); + CHECK(std::fabs(got.mCCTOffset) < 1.f); + UNSCOPED_INFO("duv stays put"); + CHECK(std::fabs(got.mDuv) < 1e-3f); + UNSCOPED_INFO("exactly reachable"); + CHECK(got.mResidual < 1e-4f); } // The warm end of the Temperature slider leaves the sRGB gamut: below @@ -207,23 +221,30 @@ namespace tut // sign. That is the renderer's existing behaviour and this fixes none of // it; what is pinned here is that the solver stays out of the region, so // the eyedropper can never hand a user a balance that does that. - template<> template<> - void wb_object::test<9>() + TEST_CASE_METHOD(wb_data, "ALWhiteBalanceSolver: the solver stays out of the out-of-gamut warm end", "[ALWhiteBalanceSolver]") { - ensure("neutral is usable", ALWhiteBalanceSolver::isUsable(0.f, 0.f)); - ensure("the cool end is usable", ALWhiteBalanceSolver::isUsable(5000.f, 0.f)); - ensure("the warm extreme is not", !ALWhiteBalanceSolver::isUsable(-5000.f, 0.f)); + UNSCOPED_INFO("neutral is usable"); + CHECK(ALWhiteBalanceSolver::isUsable(0.f, 0.f)); + UNSCOPED_INFO("the cool end is usable"); + CHECK(ALWhiteBalanceSolver::isUsable(5000.f, 0.f)); + UNSCOPED_INFO("the warm extreme is not"); + CHECK_FALSE(ALWhiteBalanceSolver::isUsable(-5000.f, 0.f)); // Tint moves the boundary: pushing green costs gamut at the warm end. - ensure("-4000 is usable at neutral tint", ALWhiteBalanceSolver::isUsable(-4000.f, 0.f)); - ensure("but not at full green tint", !ALWhiteBalanceSolver::isUsable(-4000.f, 1.f)); + UNSCOPED_INFO("-4000 is usable at neutral tint"); + CHECK(ALWhiteBalanceSolver::isUsable(-4000.f, 0.f)); + UNSCOPED_INFO("but not at full green tint"); + CHECK_FALSE(ALWhiteBalanceSolver::isUsable(-4000.f, 1.f)); // Ask for something only the out-of-gamut region could match, and the // answer must still be a balance that works. const LLVector3 want = ALWhiteBalanceSolver::gain(-5000.f, 0.f); const ALWhiteBalanceSolver::Result got = ALWhiteBalanceSolver::solve(want); - ensure("the solution is usable", ALWhiteBalanceSolver::isUsable(got.mCCTOffset, got.mDuv)); + UNSCOPED_INFO("the solution is usable"); + CHECK(ALWhiteBalanceSolver::isUsable(got.mCCTOffset, got.mDuv)); const LLVector3 back = ALWhiteBalanceSolver::gain(got.mCCTOffset, got.mDuv); - ensure("its red gain is positive", back.mV[VX] > 0.f); - ensure("and so is its blue", back.mV[VZ] > 0.f); + UNSCOPED_INFO("its red gain is positive"); + CHECK(back.mV[VX] > 0.f); + UNSCOPED_INFO("and so is its blue"); + CHECK(back.mV[VZ] > 0.f); } } diff --git a/indra/newview/tests/cppfeatures_test.cpp b/indra/newview/tests/cppfeatures_test.cpp index 82d697f332..c14963dd6a 100644 --- a/indra/newview/tests/cppfeatures_test.cpp +++ b/indra/newview/tests/cppfeatures_test.cpp @@ -29,29 +29,23 @@ // Tests related to newer C++ features, for verifying support across compilers and platforms #include "linden_common.h" -#include "../test/lltut.h" +#include -namespace tut +namespace { -struct cpp_features_test {}; -typedef test_group cpp_features_test_t; -typedef cpp_features_test_t::object cpp_features_test_object_t; -tut::cpp_features_test_t tut_cpp_features_test("LLCPPFeatures"); - // bracket initializers // Can initialize containers or values using curly brackets -template<> template<> -void cpp_features_test_object_t::test<1>() +TEST_CASE("LLCPPFeatures: bracket initializers set values and containers", "[LLCPPFeatures]") { S32 explicit_val{3}; - ensure(explicit_val==3); + CHECK(explicit_val==3); S32 default_val{}; - ensure(default_val==0); + CHECK(default_val==0); std::vector fibs{1,1,2,3,5}; - ensure(fibs[4]==5); + CHECK(fibs[4]==5); } // auto @@ -59,20 +53,21 @@ void cpp_features_test_object_t::test<1>() // https://en.cppreference.com/w/cpp/language/auto // // Can use auto in place of a more complex type specification, if the compiler can infer the type -template<> template<> -void cpp_features_test_object_t::test<2>() +TEST_CASE("LLCPPFeatures: auto deduces an element and an iterator type", "[LLCPPFeatures]") { std::vector numbers{3,6,9}; // auto element auto& aval = numbers[1]; - ensure("auto element", aval==6); + UNSCOPED_INFO("auto element"); + CHECK(aval==6); // auto iterator (non-const) auto it = numbers.rbegin(); *it += 1; S32 val = *it; - ensure("auto iterator", val==10); + UNSCOPED_INFO("auto iterator"); + CHECK(val==10); } // range for @@ -80,8 +75,7 @@ void cpp_features_test_object_t::test<2>() // https://en.cppreference.com/w/cpp/language/range-for // // Can iterate over containers without explicit iterator -template<> template<> -void cpp_features_test_object_t::test<3>() +TEST_CASE("LLCPPFeatures: range for walks a container or a C array", "[LLCPPFeatures]") { // Traditional iterator for with container @@ -95,7 +89,8 @@ void cpp_features_test_object_t::test<3>() auto& n = *it; n *= 2; } - ensure("iterator for vector", numbers[2]==18); + UNSCOPED_INFO("iterator for vector"); + CHECK(numbers[2]==18); // Range for with container // @@ -107,7 +102,8 @@ void cpp_features_test_object_t::test<3>() { n *= 2; } - ensure("range for vector", numbersb[2]==18); + UNSCOPED_INFO("range for vector"); + CHECK(numbersb[2]==18); // Range for over a C-style array. // @@ -119,7 +115,8 @@ void cpp_features_test_object_t::test<3>() { sum += v; } - ensure("for C-array", sum==31); + UNSCOPED_INFO("for C-array"); + CHECK(sum==31); } // override specifier @@ -134,8 +131,6 @@ void cpp_features_test_object_t::test<3>() // * Some compilers require that any class using override must use it consistently for all functions. // This makes switching a class to use override a lot more work. -namespace -{ class Foo { @@ -153,13 +148,12 @@ class Bar: public Foo // bool is_happx() override { return true; } }; -} // anonymous namespace -template<> template<> -void cpp_features_test_object_t::test<4>() +TEST_CASE("LLCPPFeatures: an override specifier marks a virtual override", "[LLCPPFeatures]") { Bar b; - ensure("override", b.is_happy()); + UNSCOPED_INFO("override"); + CHECK(b.is_happy()); } // final @@ -168,8 +162,6 @@ void cpp_features_test_object_t::test<4>() // virtual function cannot be overridden in a derived class or that a // class cannot be inherited from." -namespace -{ class Vehicle { @@ -190,13 +182,12 @@ class Bicycle: public WheeledVehicle // virtual bool has_wheels() override const { return true; } }; -} // anonymous namespace -template<> template<> -void cpp_features_test_object_t::test<5>() +TEST_CASE("LLCPPFeatures: a class derives from one with a final override", "[LLCPPFeatures]") { Bicycle bi; - ensure("final", bi.has_wheels()); + UNSCOPED_INFO("final"); + CHECK(bi.has_wheels()); } // deleted function declaration @@ -213,8 +204,6 @@ void cpp_features_test_object_t::test<5>() // * Makes the intention clear // * Creates an error sooner, at compile time -namespace -{ class DoNotCopy { @@ -223,10 +212,8 @@ class DoNotCopy DoNotCopy(const DoNotCopy& ref) = delete; }; -} // anonymous namespace -template<> template<> -void cpp_features_test_object_t::test<6>() +TEST_CASE("LLCPPFeatures: a deleted copy constructor leaves default construction", "[LLCPPFeatures]") { DoNotCopy nc; // OK, default constructor //DoNotCopy nc2(nc); // No, can't copy @@ -241,8 +228,6 @@ void cpp_features_test_object_t::test<6>() // and are happy with the default implementation the compiler will make (memberwise copy). // Now you can explicitly declare that too. // Usage: I guess it makes the intent clearer, but otherwise not obviously useful. -namespace -{ class DefaultCopyOK { @@ -254,17 +239,18 @@ class DefaultCopyOK S32 mVal; }; -} // anonymous namespace -template<> template<> -void cpp_features_test_object_t::test<7>() +TEST_CASE("LLCPPFeatures: a defaulted copy constructor copies the members", "[LLCPPFeatures]") { DefaultCopyOK d; // OK DefaultCopyOK d2(d); // OK DefaultCopyOK d3 = d; // OK - ensure("default copy d", d.val()==123); - ensure("default copy d2", d.val()==d2.val()); - ensure("default copy d3", d.val()==d3.val()); + UNSCOPED_INFO("default copy d"); + CHECK(d.val()==123); + UNSCOPED_INFO("default copy d2"); + CHECK(d.val()==d2.val()); + UNSCOPED_INFO("default copy d3"); + CHECK(d.val()==d3.val()); } // initialize class members inline @@ -276,8 +262,6 @@ void cpp_features_test_object_t::test<7>() // It is preferred to skip creating a constructor if all the work can be done by inline initialization: // http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines.html#c45-dont-define-a-default-constructor-that-only-initializes-data-members-use-in-class-member-initializers-instead // -namespace -{ class InitInline { @@ -299,17 +283,18 @@ class InitInlineWithConstructor S32 mBar = 20; }; -} // anonymous namespace -template<> template<> -void cpp_features_test_object_t::test<8>() +TEST_CASE("LLCPPFeatures: inline member initializers give defaults a constructor overrides", "[LLCPPFeatures]") { InitInline ii; - ensure("init member inline 1", ii.mFoo==10); + UNSCOPED_INFO("init member inline 1"); + CHECK(ii.mFoo==10); InitInlineWithConstructor iici; - ensure("init member inline 2", iici.mFoo==10); - ensure("init member inline 3", iici.mBar==25); + UNSCOPED_INFO("init member inline 2"); + CHECK(iici.mFoo==10); + UNSCOPED_INFO("init member inline 3"); + CHECK(iici.mBar==25); } // constexpr @@ -317,8 +302,6 @@ void cpp_features_test_object_t::test<8>() // https://en.cppreference.com/w/cpp/language/constexpr // // Various things can be computed at compile time, and flagged as constexpr. -namespace -{ constexpr S32 compute2() { return 2; } @@ -334,17 +317,17 @@ constexpr S32 ce_factorial(S32 n) } } -} // anonymous namespace -template<> template<> -void cpp_features_test_object_t::test<9>() +TEST_CASE("LLCPPFeatures: constexpr functions compute values", "[LLCPPFeatures]") { S32 val = compute2(); - ensure("constexpr 1", val==2); + UNSCOPED_INFO("constexpr 1"); + CHECK(val==2); // Compile-time factorial. You used to need complex templates to do something this useless. S32 fac5 = ce_factorial(5); - ensure("constexpr 2", fac5==120); + UNSCOPED_INFO("constexpr 2"); + CHECK(fac5==120); } // static assert @@ -358,8 +341,7 @@ void cpp_features_test_object_t::test<9>() // // Currently only the 2-parameter form works on windows. The 1-parameter form needs a flag we don't set. -template<> template<> -void cpp_features_test_object_t::test<10>() +TEST_CASE("LLCPPFeatures: static_assert checks a constexpr at compile time", "[LLCPPFeatures]") { // static_assert(ce_factorial(6)==720); No, needs a flag we don't currently set. static_assert(ce_factorial(6)==720, "bad factorial"); // OK @@ -376,11 +358,11 @@ void cpp_features_test_object_t::test<10>() template using stringmap = std::map; -template<> template<> -void cpp_features_test_object_t::test<11>() +TEST_CASE("LLCPPFeatures: a template type alias names a map type", "[LLCPPFeatures]") { stringmap name_counts{ {"alice", 3}, {"bob", 2} }; - ensure("type alias", name_counts["bob"]==2); + UNSCOPED_INFO("type alias"); + CHECK(name_counts["bob"]==2); } // Other possibilities: @@ -413,4 +395,4 @@ void cpp_features_test_object_t::test<11>() // string_view -} // namespace tut +} // anonymous namespace diff --git a/indra/newview/tests/llagentaccess_test.cpp b/indra/newview/tests/llagentaccess_test.cpp index 747157a808..29e1ea374c 100644 --- a/indra/newview/tests/llagentaccess_test.cpp +++ b/indra/newview/tests/llagentaccess_test.cpp @@ -25,7 +25,7 @@ */ #include "linden_common.h" -#include "../test/lltut.h" +#include #include "../llagentaccess.h" @@ -34,18 +34,9 @@ #include -namespace tut +namespace { - struct agentaccess - { - }; - - typedef test_group agentaccess_t; - typedef agentaccess_t::object agentaccess_object_t; - tut::agentaccess_t tut_agentaccess("LLAgentAccess"); - - template<> template<> - void agentaccess_object_t::test<1>() + TEST_CASE("LLAgentAccess: the prefers queries follow the PreferredMaturity setting", "[LLAgentAccess]") { LLControlGroup cgr("llagentaccess"); cgr.declareU32("PreferredMaturity", SIM_ACCESS_PG, "declared_for_test", LLControlVariable::PERSIST_NO); @@ -53,28 +44,36 @@ namespace tut cgr.setU32("PreferredMaturity", SIM_ACCESS_PG); #ifndef HACKED_GODLIKE_VIEWER - ensure("1 prefersPG", aa.prefersPG()); - ensure("1 prefersMature", !aa.prefersMature()); - ensure("1 prefersAdult", !aa.prefersAdult()); + UNSCOPED_INFO("1 prefersPG"); + CHECK(aa.prefersPG()); + UNSCOPED_INFO("1 prefersMature"); + CHECK_FALSE(aa.prefersMature()); + UNSCOPED_INFO("1 prefersAdult"); + CHECK_FALSE(aa.prefersAdult()); #endif // HACKED_GODLIKE_VIEWER cgr.setU32("PreferredMaturity", SIM_ACCESS_MATURE); #ifndef HACKED_GODLIKE_VIEWER - ensure("2 prefersPG", !aa.prefersPG()); - ensure("2 prefersMature", aa.prefersMature()); - ensure("2 prefersAdult", !aa.prefersAdult()); + UNSCOPED_INFO("2 prefersPG"); + CHECK_FALSE(aa.prefersPG()); + UNSCOPED_INFO("2 prefersMature"); + CHECK(aa.prefersMature()); + UNSCOPED_INFO("2 prefersAdult"); + CHECK_FALSE(aa.prefersAdult()); #endif // HACKED_GODLIKE_VIEWER cgr.setU32("PreferredMaturity", SIM_ACCESS_ADULT); #ifndef HACKED_GODLIKE_VIEWER - ensure("3 prefersPG", !aa.prefersPG()); - ensure("3 prefersMature", aa.prefersMature()); - ensure("3 prefersAdult", aa.prefersAdult()); + UNSCOPED_INFO("3 prefersPG"); + CHECK_FALSE(aa.prefersPG()); + UNSCOPED_INFO("3 prefersMature"); + CHECK(aa.prefersMature()); + UNSCOPED_INFO("3 prefersAdult"); + CHECK(aa.prefersAdult()); #endif // HACKED_GODLIKE_VIEWER } - template<> template<> - void agentaccess_object_t::test<2>() + TEST_CASE("LLAgentAccess: maturity starts PG and setMaturity takes the P M and A letters", "[LLAgentAccess]") { LLControlGroup cgr("llagentaccess"); cgr.declareU32("PreferredMaturity", SIM_ACCESS_PG, "declared_for_test", LLControlVariable::PERSIST_NO); @@ -82,146 +81,193 @@ namespace tut // make sure default is PG #ifndef HACKED_GODLIKE_VIEWER - ensure("1 isTeen", aa.isTeen()); - ensure("1 isMature", !aa.isMature()); - ensure("1 isAdult", !aa.isAdult()); + UNSCOPED_INFO("1 isTeen"); + CHECK(aa.isTeen()); + UNSCOPED_INFO("1 isMature"); + CHECK_FALSE(aa.isMature()); + UNSCOPED_INFO("1 isAdult"); + CHECK_FALSE(aa.isAdult()); #endif // HACKED_GODLIKE_VIEWER // check the conversion routine #ifndef HACKED_GODLIKE_VIEWER - ensure_equals("1 conversion", SIM_ACCESS_PG, aa.convertTextToMaturity('P')); - ensure_equals("2 conversion", SIM_ACCESS_MATURE, aa.convertTextToMaturity('M')); - ensure_equals("3 conversion", SIM_ACCESS_ADULT, aa.convertTextToMaturity('A')); - ensure_equals("4 conversion", SIM_ACCESS_MIN, aa.convertTextToMaturity('Q')); + UNSCOPED_INFO("1 conversion"); + CHECK(SIM_ACCESS_PG == aa.convertTextToMaturity('P')); + UNSCOPED_INFO("2 conversion"); + CHECK(SIM_ACCESS_MATURE == aa.convertTextToMaturity('M')); + UNSCOPED_INFO("3 conversion"); + CHECK(SIM_ACCESS_ADULT == aa.convertTextToMaturity('A')); + UNSCOPED_INFO("4 conversion"); + CHECK(SIM_ACCESS_MIN == aa.convertTextToMaturity('Q')); #endif // HACKED_GODLIKE_VIEWER // now try the other method of setting it - PG aa.setMaturity('P'); - ensure("2 isTeen", aa.isTeen()); + UNSCOPED_INFO("2 isTeen"); + CHECK(aa.isTeen()); #ifndef HACKED_GODLIKE_VIEWER - ensure("2 isMature", !aa.isMature()); - ensure("2 isAdult", !aa.isAdult()); + UNSCOPED_INFO("2 isMature"); + CHECK_FALSE(aa.isMature()); + UNSCOPED_INFO("2 isAdult"); + CHECK_FALSE(aa.isAdult()); #endif // HACKED_GODLIKE_VIEWER // Mature aa.setMaturity('M'); #ifndef HACKED_GODLIKE_VIEWER - ensure("3 isTeen", !aa.isTeen()); - ensure("3 isMature", aa.isMature()); - ensure("3 isAdult", !aa.isAdult()); + UNSCOPED_INFO("3 isTeen"); + CHECK_FALSE(aa.isTeen()); + UNSCOPED_INFO("3 isMature"); + CHECK(aa.isMature()); + UNSCOPED_INFO("3 isAdult"); + CHECK_FALSE(aa.isAdult()); #endif // HACKED_GODLIKE_VIEWER // Adult aa.setMaturity('A'); #ifndef HACKED_GODLIKE_VIEWER - ensure("4 isTeen", !aa.isTeen()); - ensure("4 isMature", aa.isMature()); - ensure("4 isAdult", aa.isAdult()); + UNSCOPED_INFO("4 isTeen"); + CHECK_FALSE(aa.isTeen()); + UNSCOPED_INFO("4 isMature"); + CHECK(aa.isMature()); + UNSCOPED_INFO("4 isAdult"); + CHECK(aa.isAdult()); #endif // HACKED_GODLIKE_VIEWER } - template<> template<> - void agentaccess_object_t::test<3>() + TEST_CASE("LLAgentAccess: isGodlike follows the god level and the admin override", "[LLAgentAccess]") { LLControlGroup cgr("llagentaccess"); cgr.declareU32("PreferredMaturity", SIM_ACCESS_PG, "declared_for_test", LLControlVariable::PERSIST_NO); LLAgentAccess aa(cgr); #ifndef HACKED_GODLIKE_VIEWER - ensure("starts normal", !aa.isGodlike()); + UNSCOPED_INFO("starts normal"); + CHECK_FALSE(aa.isGodlike()); #endif // HACKED_GODLIKE_VIEWER aa.setGodLevel(GOD_NOT); #ifndef HACKED_GODLIKE_VIEWER - ensure("stays normal", !aa.isGodlike()); + UNSCOPED_INFO("stays normal"); + CHECK_FALSE(aa.isGodlike()); #endif // HACKED_GODLIKE_VIEWER aa.setGodLevel(GOD_FULL); #ifndef HACKED_GODLIKE_VIEWER - ensure("sets full", aa.isGodlike()); + UNSCOPED_INFO("sets full"); + CHECK(aa.isGodlike()); #endif // HACKED_GODLIKE_VIEWER aa.setGodLevel(GOD_NOT); #ifndef HACKED_GODLIKE_VIEWER - ensure("resets normal", !aa.isGodlike()); + UNSCOPED_INFO("resets normal"); + CHECK_FALSE(aa.isGodlike()); #endif // HACKED_GODLIKE_VIEWER aa.setAdminOverride(true); #ifndef HACKED_GODLIKE_VIEWER - ensure("admin true", aa.getAdminOverride()); - ensure("overrides 1", aa.isGodlike()); + UNSCOPED_INFO("admin true"); + CHECK(aa.getAdminOverride()); + UNSCOPED_INFO("overrides 1"); + CHECK(aa.isGodlike()); #endif // HACKED_GODLIKE_VIEWER aa.setGodLevel(GOD_FULL); #ifndef HACKED_GODLIKE_VIEWER - ensure("overrides 2", aa.isGodlike()); + UNSCOPED_INFO("overrides 2"); + CHECK(aa.isGodlike()); #endif // HACKED_GODLIKE_VIEWER aa.setAdminOverride(false); #ifndef HACKED_GODLIKE_VIEWER - ensure("admin false", !aa.getAdminOverride()); - ensure("overrides 3", aa.isGodlike()); + UNSCOPED_INFO("admin false"); + CHECK_FALSE(aa.getAdminOverride()); + UNSCOPED_INFO("overrides 3"); + CHECK(aa.isGodlike()); #endif // HACKED_GODLIKE_VIEWER } - template<> template<> - void agentaccess_object_t::test<4>() + TEST_CASE("LLAgentAccess: access needs both rating and preference unless god or admin", "[LLAgentAccess]") { LLControlGroup cgr("llagentaccess"); cgr.declareU32("PreferredMaturity", SIM_ACCESS_PG, "declared_for_test", LLControlVariable::PERSIST_NO); LLAgentAccess aa(cgr); #ifndef HACKED_GODLIKE_VIEWER - ensure("1 pg to start", aa.wantsPGOnly()); - ensure("2 pg to start", !aa.canAccessMature()); - ensure("3 pg to start", !aa.canAccessAdult()); + UNSCOPED_INFO("1 pg to start"); + CHECK(aa.wantsPGOnly()); + UNSCOPED_INFO("2 pg to start"); + CHECK_FALSE(aa.canAccessMature()); + UNSCOPED_INFO("3 pg to start"); + CHECK_FALSE(aa.canAccessAdult()); #endif // HACKED_GODLIKE_VIEWER aa.setGodLevel(GOD_FULL); #ifndef HACKED_GODLIKE_VIEWER - ensure("1 full god", !aa.wantsPGOnly()); - ensure("2 full god", aa.canAccessMature()); - ensure("3 full god", aa.canAccessAdult()); + UNSCOPED_INFO("1 full god"); + CHECK_FALSE(aa.wantsPGOnly()); + UNSCOPED_INFO("2 full god"); + CHECK(aa.canAccessMature()); + UNSCOPED_INFO("3 full god"); + CHECK(aa.canAccessAdult()); #endif // HACKED_GODLIKE_VIEWER aa.setGodLevel(GOD_NOT); aa.setAdminOverride(true); #ifndef HACKED_GODLIKE_VIEWER - ensure("1 admin mode", !aa.wantsPGOnly()); - ensure("2 admin mode", aa.canAccessMature()); - ensure("3 admin mode", aa.canAccessAdult()); + UNSCOPED_INFO("1 admin mode"); + CHECK_FALSE(aa.wantsPGOnly()); + UNSCOPED_INFO("2 admin mode"); + CHECK(aa.canAccessMature()); + UNSCOPED_INFO("3 admin mode"); + CHECK(aa.canAccessAdult()); #endif // HACKED_GODLIKE_VIEWER aa.setAdminOverride(false); aa.setMaturity('M'); // preferred is still pg by default #ifndef HACKED_GODLIKE_VIEWER - ensure("1 mature pref pg", aa.wantsPGOnly()); - ensure("2 mature pref pg", !aa.canAccessMature()); - ensure("3 mature pref pg", !aa.canAccessAdult()); + UNSCOPED_INFO("1 mature pref pg"); + CHECK(aa.wantsPGOnly()); + UNSCOPED_INFO("2 mature pref pg"); + CHECK_FALSE(aa.canAccessMature()); + UNSCOPED_INFO("3 mature pref pg"); + CHECK_FALSE(aa.canAccessAdult()); #endif // HACKED_GODLIKE_VIEWER cgr.setU32("PreferredMaturity", SIM_ACCESS_MATURE); #ifndef HACKED_GODLIKE_VIEWER - ensure("1 mature", !aa.wantsPGOnly()); - ensure("2 mature", aa.canAccessMature()); - ensure("3 mature", !aa.canAccessAdult()); + UNSCOPED_INFO("1 mature"); + CHECK_FALSE(aa.wantsPGOnly()); + UNSCOPED_INFO("2 mature"); + CHECK(aa.canAccessMature()); + UNSCOPED_INFO("3 mature"); + CHECK_FALSE(aa.canAccessAdult()); #endif // HACKED_GODLIKE_VIEWER cgr.setU32("PreferredMaturity", SIM_ACCESS_PG); #ifndef HACKED_GODLIKE_VIEWER - ensure("1 mature pref pg", aa.wantsPGOnly()); - ensure("2 mature pref pg", !aa.canAccessMature()); - ensure("3 mature pref pg", !aa.canAccessAdult()); + UNSCOPED_INFO("1 mature pref pg"); + CHECK(aa.wantsPGOnly()); + UNSCOPED_INFO("2 mature pref pg"); + CHECK_FALSE(aa.canAccessMature()); + UNSCOPED_INFO("3 mature pref pg"); + CHECK_FALSE(aa.canAccessAdult()); #endif // HACKED_GODLIKE_VIEWER aa.setMaturity('A'); #ifndef HACKED_GODLIKE_VIEWER - ensure("1 adult pref pg", aa.wantsPGOnly()); - ensure("2 adult pref pg", !aa.canAccessMature()); - ensure("3 adult pref pg", !aa.canAccessAdult()); + UNSCOPED_INFO("1 adult pref pg"); + CHECK(aa.wantsPGOnly()); + UNSCOPED_INFO("2 adult pref pg"); + CHECK_FALSE(aa.canAccessMature()); + UNSCOPED_INFO("3 adult pref pg"); + CHECK_FALSE(aa.canAccessAdult()); #endif // HACKED_GODLIKE_VIEWER cgr.setU32("PreferredMaturity", SIM_ACCESS_ADULT); #ifndef HACKED_GODLIKE_VIEWER - ensure("1 adult", !aa.wantsPGOnly()); - ensure("2 adult", aa.canAccessMature()); - ensure("3 adult", aa.canAccessAdult()); + UNSCOPED_INFO("1 adult"); + CHECK_FALSE(aa.wantsPGOnly()); + UNSCOPED_INFO("2 adult"); + CHECK(aa.canAccessMature()); + UNSCOPED_INFO("3 adult"); + CHECK(aa.canAccessAdult()); #endif // HACKED_GODLIKE_VIEWER // make sure that even if pref is high, if access is low we block access @@ -229,15 +275,17 @@ namespace tut cgr.setU32("PreferredMaturity", SIM_ACCESS_ADULT); aa.setMaturity('P'); #ifndef HACKED_GODLIKE_VIEWER - ensure("1 pref adult, actual pg", aa.wantsPGOnly()); - ensure("2 pref adult, actual pg", !aa.canAccessMature()); - ensure("3 pref adult, actual pg", !aa.canAccessAdult()); + UNSCOPED_INFO("1 pref adult, actual pg"); + CHECK(aa.wantsPGOnly()); + UNSCOPED_INFO("2 pref adult, actual pg"); + CHECK_FALSE(aa.canAccessMature()); + UNSCOPED_INFO("3 pref adult, actual pg"); + CHECK_FALSE(aa.canAccessAdult()); #endif // HACKED_GODLIKE_VIEWER } - template<> template<> - void agentaccess_object_t::test<5>() + TEST_CASE("LLAgentAccess: setMaturity lowers a higher preferred maturity to match", "[LLAgentAccess]") { LLControlGroup cgr("llagentaccess"); cgr.declareU32("PreferredMaturity", SIM_ACCESS_PG, "declared_for_test", LLControlVariable::PERSIST_NO); @@ -246,12 +294,14 @@ namespace tut cgr.setU32("PreferredMaturity", SIM_ACCESS_ADULT); aa.setMaturity('M'); #ifndef HACKED_GODLIKE_VIEWER - ensure("1 preferred maturity pegged to M when maturity is M", cgr.getU32("PreferredMaturity") == SIM_ACCESS_MATURE); + UNSCOPED_INFO("1 preferred maturity pegged to M when maturity is M"); + CHECK(cgr.getU32("PreferredMaturity") == SIM_ACCESS_MATURE); #endif // HACKED_GODLIKE_VIEWER aa.setMaturity('P'); #ifndef HACKED_GODLIKE_VIEWER - ensure("1 preferred maturity pegged to P when maturity is P", cgr.getU32("PreferredMaturity") == SIM_ACCESS_PG); + UNSCOPED_INFO("1 preferred maturity pegged to P when maturity is P"); + CHECK(cgr.getU32("PreferredMaturity") == SIM_ACCESS_PG); #endif // HACKED_GODLIKE_VIEWER } } diff --git a/indra/newview/tests/lldateutil_test.cpp b/indra/newview/tests/lldateutil_test.cpp index cbe8b250a7..d2a84acca7 100644 --- a/indra/newview/tests/lldateutil_test.cpp +++ b/indra/newview/tests/lldateutil_test.cpp @@ -25,7 +25,7 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include #include "../lldateutil.h" @@ -75,7 +75,7 @@ std::string LLUI::getLanguage() return "en"; } -namespace tut +namespace { struct dateutil { @@ -109,87 +109,73 @@ namespace tut LLDate mNow; }; - typedef test_group dateutil_t; - typedef dateutil_t::object dateutil_object_t; - tut::dateutil_t tut_dateutil("LLDateUtil"); - - template<> template<> - void dateutil_object_t::test<1>() + TEST_CASE_METHOD(dateutil, "LLDateUtil: an age of a year or more reads in years and whole months", "[LLDateUtil]") { - set_test_name("Years"); - ensure_equals("years + months", - LLDateUtil::ageFromDate("10/30/2007", mNow), - "2 years 2 months old" ); - ensure_equals("years", - LLDateUtil::ageFromDate("12/31/2007", mNow), - "2 years old" ); - ensure_equals("years", - LLDateUtil::ageFromDate("1/1/2008", mNow), - "1 year 11 months old" ); - ensure_equals("single year + one month", - LLDateUtil::ageFromDate("11/30/2008", mNow), - "1 year 1 month old" ); - ensure_equals("single year + a bit", - LLDateUtil::ageFromDate("12/12/2008", mNow), - "1 year old" ); - ensure_equals("single year", - LLDateUtil::ageFromDate("12/31/2008", mNow), - "1 year old" ); + UNSCOPED_INFO("years + months"); + CHECK(LLDateUtil::ageFromDate("10/30/2007", mNow) == + "2 years 2 months old"); + UNSCOPED_INFO("years"); + CHECK(LLDateUtil::ageFromDate("12/31/2007", mNow) == + "2 years old"); + UNSCOPED_INFO("years"); + CHECK(LLDateUtil::ageFromDate("1/1/2008", mNow) == + "1 year 11 months old"); + UNSCOPED_INFO("single year + one month"); + CHECK(LLDateUtil::ageFromDate("11/30/2008", mNow) == + "1 year 1 month old"); + UNSCOPED_INFO("single year + a bit"); + CHECK(LLDateUtil::ageFromDate("12/12/2008", mNow) == + "1 year old"); + UNSCOPED_INFO("single year"); + CHECK(LLDateUtil::ageFromDate("12/31/2008", mNow) == + "1 year old"); } - template<> template<> - void dateutil_object_t::test<2>() + TEST_CASE_METHOD(dateutil, "LLDateUtil: an age of a month to a year reads in whole months", "[LLDateUtil]") { - set_test_name("Months"); - ensure_equals("months", - LLDateUtil::ageFromDate("10/30/2009", mNow), - "2 months old" ); - ensure_equals("months 2", - LLDateUtil::ageFromDate("10/31/2009", mNow), - "2 months old" ); - ensure_equals("single month", - LLDateUtil::ageFromDate("11/30/2009", mNow), - "1 month old" ); + UNSCOPED_INFO("months"); + CHECK(LLDateUtil::ageFromDate("10/30/2009", mNow) == + "2 months old"); + UNSCOPED_INFO("months 2"); + CHECK(LLDateUtil::ageFromDate("10/31/2009", mNow) == + "2 months old"); + UNSCOPED_INFO("single month"); + CHECK(LLDateUtil::ageFromDate("11/30/2009", mNow) == + "1 month old"); } - template<> template<> - void dateutil_object_t::test<3>() + TEST_CASE_METHOD(dateutil, "LLDateUtil: an age under a month reads in whole weeks", "[LLDateUtil]") { - set_test_name("Weeks"); - ensure_equals("4 weeks", - LLDateUtil::ageFromDate("12/1/2009", mNow), - "4 weeks old" ); - ensure_equals("weeks", - LLDateUtil::ageFromDate("12/17/2009", mNow), - "2 weeks old" ); - ensure_equals("single week", - LLDateUtil::ageFromDate("12/24/2009", mNow), - "1 week old" ); + UNSCOPED_INFO("4 weeks"); + CHECK(LLDateUtil::ageFromDate("12/1/2009", mNow) == + "4 weeks old"); + UNSCOPED_INFO("weeks"); + CHECK(LLDateUtil::ageFromDate("12/17/2009", mNow) == + "2 weeks old"); + UNSCOPED_INFO("single week"); + CHECK(LLDateUtil::ageFromDate("12/24/2009", mNow) == + "1 week old"); } - template<> template<> - void dateutil_object_t::test<4>() + TEST_CASE_METHOD(dateutil, "LLDateUtil: an age under a week reads in days or as joined today", "[LLDateUtil]") { - set_test_name("Days"); - ensure_equals("days", - LLDateUtil::ageFromDate("12/29/2009", mNow), - "2 days old" ); - ensure_equals("single day", - LLDateUtil::ageFromDate("12/30/2009", mNow), - "1 day old" ); - ensure_equals("today", - LLDateUtil::ageFromDate("12/31/2009", mNow), - "Joined today" ); + UNSCOPED_INFO("days"); + CHECK(LLDateUtil::ageFromDate("12/29/2009", mNow) == + "2 days old"); + UNSCOPED_INFO("single day"); + CHECK(LLDateUtil::ageFromDate("12/30/2009", mNow) == + "1 day old"); + UNSCOPED_INFO("today"); + CHECK(LLDateUtil::ageFromDate("12/31/2009", mNow) == + "Joined today"); } - template<> template<> - void dateutil_object_t::test<5>() + TEST_CASE_METHOD(dateutil, "LLDateUtil: an age that spans the new year still reads in weeks", "[LLDateUtil]") { - set_test_name("2010 rollover"); LLDate now(std::string("2010-01-04T12:00:00Z")); - ensure_equals("days", - LLDateUtil::ageFromDate("12/13/2009", now), - "3 weeks old" ); + UNSCOPED_INFO("days"); + CHECK(LLDateUtil::ageFromDate("12/13/2009", now) == + "3 weeks old"); } //template<> template<> diff --git a/indra/newview/tests/llhttpretrypolicy_test.cpp b/indra/newview/tests/llhttpretrypolicy_test.cpp index a261ec8699..9dc5b26cfc 100644 --- a/indra/newview/tests/llhttpretrypolicy_test.cpp +++ b/indra/newview/tests/llhttpretrypolicy_test.cpp @@ -26,35 +26,29 @@ #include "../llviewerprecompiledheaders.h" #include "../llhttpretrypolicy.h" -#include "lltut.h" +#include +#include +#include "altestmatchers.h" -namespace tut +namespace { -struct llhttpretrypolicy_data -{ -}; - -typedef test_group RetryPolicyTestGroup; -typedef RetryPolicyTestGroup::object RetryPolicyTestObject; -RetryPolicyTestGroup retryPolicyTestGroup("retry_policy"); - -template<> template<> -void RetryPolicyTestObject::test<1>() +TEST_CASE("retry_policy: a policy of zero retries never retries", "[retry_policy]") { LLAdaptiveRetryPolicy never_retry(1.0,1.0,1.0,0); LLSD headers; F32 wait_seconds; // No retry until we've failed a try. - ensure("never retry 0", !never_retry.shouldRetry(wait_seconds)); + UNSCOPED_INFO("never retry 0"); + REQUIRE_FALSE(never_retry.shouldRetry(wait_seconds)); // 0 retries max. never_retry.onFailure(500,headers); - ensure("never retry 1", !never_retry.shouldRetry(wait_seconds)); + UNSCOPED_INFO("never retry 1"); + CHECK_FALSE(never_retry.shouldRetry(wait_seconds)); } -template<> template<> -void RetryPolicyTestObject::test<2>() +TEST_CASE("retry_policy: a 404 is retried only when 4xx retries are enabled", "[retry_policy]") { LLSD headers; F32 wait_seconds; @@ -62,17 +56,18 @@ void RetryPolicyTestObject::test<2>() // Normally only retry on server error (5xx) LLAdaptiveRetryPolicy noRetry404(1.0,2.0,3.0,10); noRetry404.onFailure(404,headers); - ensure("no retry on 404", !noRetry404.shouldRetry(wait_seconds)); + UNSCOPED_INFO("no retry on 404"); + REQUIRE_FALSE(noRetry404.shouldRetry(wait_seconds)); // Can retry on 4xx errors if enabled by flag. bool do_retry_4xx = true; LLAdaptiveRetryPolicy doRetry404(1.0,2.0,3.0,10,do_retry_4xx); doRetry404.onFailure(404,headers); - ensure("do retry on 404", doRetry404.shouldRetry(wait_seconds)); + UNSCOPED_INFO("do retry on 404"); + CHECK(doRetry404.shouldRetry(wait_seconds)); } -template<> template<> -void RetryPolicyTestObject::test<3>() +TEST_CASE("retry_policy: waits double to a cap and retries stop at the limit until a success", "[retry_policy]") { // Should retry after 1.0, 2.0, 3.0, 3.0 seconds. LLAdaptiveRetryPolicy basic_retry(1.0,3.0,2.0,4); @@ -82,64 +77,79 @@ void RetryPolicyTestObject::test<3>() U32 frac_bits = 6; // No retry until we've failed a try. - ensure("basic_retry 0", !basic_retry.shouldRetry(wait_seconds)); + UNSCOPED_INFO("basic_retry 0"); + REQUIRE_FALSE(basic_retry.shouldRetry(wait_seconds)); // Starting wait 1.0 basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 1", should_retry); - ensure_approximately_equals("basic_retry 1", wait_seconds, 1.0F, frac_bits); + UNSCOPED_INFO("basic_retry 1"); + CHECK(should_retry); + UNSCOPED_INFO("basic_retry 1"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(1.0F, frac_bits)); // Double wait to 2.0 basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 2", should_retry); - ensure_approximately_equals("basic_retry 2", wait_seconds, 2.0F, frac_bits); + UNSCOPED_INFO("basic_retry 2"); + CHECK(should_retry); + UNSCOPED_INFO("basic_retry 2"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(2.0F, frac_bits)); // Hit max wait of 3.0 (4.0 clamped to max 3) basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 3", should_retry); - ensure_approximately_equals("basic_retry 3", wait_seconds, 3.0F, frac_bits); + UNSCOPED_INFO("basic_retry 3"); + CHECK(should_retry); + UNSCOPED_INFO("basic_retry 3"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(3.0F, frac_bits)); // At max wait, should stay at 3.0 basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 4", should_retry); - ensure_approximately_equals("basic_retry 4", wait_seconds, 3.0F, frac_bits); + UNSCOPED_INFO("basic_retry 4"); + CHECK(should_retry); + UNSCOPED_INFO("basic_retry 4"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(3.0F, frac_bits)); // Max retries, should fail now. basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 5", !should_retry); + UNSCOPED_INFO("basic_retry 5"); + CHECK_FALSE(should_retry); // Max retries, should fail now. basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 5", !should_retry); + UNSCOPED_INFO("basic_retry 5"); + CHECK_FALSE(should_retry); // After a success, should reset to the starting state. basic_retry.onSuccess(); // No retry until we've failed a try. - ensure("basic_retry 6", !basic_retry.shouldRetry(wait_seconds)); + UNSCOPED_INFO("basic_retry 6"); + CHECK_FALSE(basic_retry.shouldRetry(wait_seconds)); // Starting wait 1.0 basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 7", should_retry); - ensure_approximately_equals("basic_retry 7", wait_seconds, 1.0F, frac_bits); + UNSCOPED_INFO("basic_retry 7"); + CHECK(should_retry); + UNSCOPED_INFO("basic_retry 7"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(1.0F, frac_bits)); // Double wait to 2.0 basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 8", should_retry); - ensure_approximately_equals("basic_retry 8", wait_seconds, 2.0F, frac_bits); + UNSCOPED_INFO("basic_retry 8"); + CHECK(should_retry); + UNSCOPED_INFO("basic_retry 8"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(2.0F, frac_bits)); } // Retries should stop as soon as a non-5xx error is received. -template<> template<> -void RetryPolicyTestObject::test<4>() +TEST_CASE("retry_policy: retries stop for good at the first non-5xx error", "[retry_policy]") { // Should retry after 1.0, 2.0, 3.0, 3.0 seconds. LLAdaptiveRetryPolicy killer404(1.0,3.0,2.0,4); @@ -151,24 +161,30 @@ void RetryPolicyTestObject::test<4>() // Starting wait 1.0 killer404.onFailure(500,headers); should_retry = killer404.shouldRetry(wait_seconds); - ensure("killer404 1", should_retry); - ensure_approximately_equals("killer404 1", wait_seconds, 1.0F, frac_bits); + UNSCOPED_INFO("killer404 1"); + CHECK(should_retry); + UNSCOPED_INFO("killer404 1"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(1.0F, frac_bits)); // Double wait to 2.0 killer404.onFailure(500,headers); should_retry = killer404.shouldRetry(wait_seconds); - ensure("killer404 2", should_retry); - ensure_approximately_equals("killer404 2", wait_seconds, 2.0F, frac_bits); + UNSCOPED_INFO("killer404 2"); + CHECK(should_retry); + UNSCOPED_INFO("killer404 2"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(2.0F, frac_bits)); // Should fail on non-5xx killer404.onFailure(404,headers); should_retry = killer404.shouldRetry(wait_seconds); - ensure("killer404 3", !should_retry); + UNSCOPED_INFO("killer404 3"); + CHECK_FALSE(should_retry); // After a non-5xx, should keep failing. killer404.onFailure(500,headers); should_retry = killer404.shouldRetry(wait_seconds); - ensure("killer404 4", !should_retry); + UNSCOPED_INFO("killer404 4"); + CHECK_FALSE(should_retry); } // Test handling of "retry-after" header. If present, this header @@ -176,8 +192,7 @@ void RetryPolicyTestObject::test<4>() // progression of delay values. For example, if the normal // progression of delays would be 1,2,4,8..., but the 2nd and 3rd calls // get a retry header of 33, the pattern would become 1,33,33,8... -template<> template<> -void RetryPolicyTestObject::test<5>() +TEST_CASE("retry_policy: a retry-after header overrides the wait but not its progression", "[retry_policy]") { LLAdaptiveRetryPolicy policy(1.0,25.0,2.0,6); LLSD headers_with_retry; @@ -189,45 +204,57 @@ void RetryPolicyTestObject::test<5>() policy.onFailure(500,headers_without_retry); should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 1", should_retry); - ensure_approximately_equals("retry header 1", wait_seconds, 1.0F, frac_bits); + UNSCOPED_INFO("retry header 1"); + CHECK(should_retry); + UNSCOPED_INFO("retry header 1"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(1.0F, frac_bits)); policy.onFailure(500,headers_without_retry); should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 2", should_retry); - ensure_approximately_equals("retry header 2", wait_seconds, 2.0F, frac_bits); + UNSCOPED_INFO("retry header 2"); + CHECK(should_retry); + UNSCOPED_INFO("retry header 2"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(2.0F, frac_bits)); policy.onFailure(500,headers_with_retry); should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 3", should_retry); + UNSCOPED_INFO("retry header 3"); + CHECK(should_retry); // 4.0 overrides by header -> 666.0 - ensure_approximately_equals("retry header 3", wait_seconds, 666.0F, frac_bits); + UNSCOPED_INFO("retry header 3"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(666.0F, frac_bits)); policy.onFailure(500,headers_with_retry); should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 4", should_retry); + UNSCOPED_INFO("retry header 4"); + CHECK(should_retry); // 8.0 overrides by header -> 666.0 - ensure_approximately_equals("retry header 4", wait_seconds, 666.0F, frac_bits); + UNSCOPED_INFO("retry header 4"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(666.0F, frac_bits)); policy.onFailure(500,headers_without_retry); should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 5", should_retry); - ensure_approximately_equals("retry header 5", wait_seconds, 16.0F, frac_bits); + UNSCOPED_INFO("retry header 5"); + CHECK(should_retry); + UNSCOPED_INFO("retry header 5"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(16.0F, frac_bits)); policy.onFailure(500,headers_without_retry); should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 6", should_retry); - ensure_approximately_equals("retry header 6", wait_seconds, 25.0F, frac_bits); + UNSCOPED_INFO("retry header 6"); + CHECK(should_retry); + UNSCOPED_INFO("retry header 6"); + CHECK_THAT(wait_seconds, ll_test::WithinBits(25.0F, frac_bits)); policy.onFailure(500,headers_with_retry); should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 7", !should_retry); + UNSCOPED_INFO("retry header 7"); + CHECK_FALSE(should_retry); } // Test getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait), // used by header parsing of the retry policy. -template<> template<> -void RetryPolicyTestObject::test<6>() +TEST_CASE("retry_policy: getSecondsUntilRetryAfter parses seconds and an HTTP date", "[retry_policy]") { F32 seconds_to_wait; bool success; @@ -235,14 +262,18 @@ void RetryPolicyTestObject::test<6>() std::string str1("0"); seconds_to_wait = F32_MAX; success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str1, seconds_to_wait); - ensure("parse 1", success); - ensure_equals("parse 1", seconds_to_wait, 0.0); + UNSCOPED_INFO("parse 1"); + CHECK(success); + UNSCOPED_INFO("parse 1"); + CHECK(seconds_to_wait == 0.0); std::string str2("999.9"); seconds_to_wait = F32_MAX; success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str2, seconds_to_wait); - ensure("parse 2", success); - ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8); + UNSCOPED_INFO("parse 2"); + CHECK(success); + UNSCOPED_INFO("parse 2"); + CHECK_THAT(seconds_to_wait, ll_test::WithinBits(999.9F, 8)); time_t nowseconds; time(&nowseconds); @@ -250,13 +281,14 @@ void RetryPolicyTestObject::test<6>() seconds_to_wait = F32_MAX; success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str3, seconds_to_wait); std::cerr << " str3 [" << str3 << "]" << std::endl; - ensure("parse 3", success); - ensure_approximately_equals_range("parse 3", seconds_to_wait, 44.0F, 2.0F); + UNSCOPED_INFO("parse 3"); + CHECK(success); + UNSCOPED_INFO("parse 3"); + CHECK_THAT(seconds_to_wait, Catch::Matchers::WithinAbs(44.0F, 2.0F)); } // Test retry-after field in both llmessage and CoreHttp headers. -template<> template<> -void RetryPolicyTestObject::test<7>() +TEST_CASE("retry_policy: retry-after is honoured in both llmessage and CoreHttp headers", "[retry_policy]") { std::cerr << "7 starts" << std::endl; @@ -268,21 +300,26 @@ void RetryPolicyTestObject::test<7>() bool should_retry; // No retry until we've failed a try. - ensure("header 0", !policy.shouldRetry(seconds_to_wait)); + UNSCOPED_INFO("header 0"); + REQUIRE_FALSE(policy.shouldRetry(seconds_to_wait)); // no retry header, use default. policy.onFailure(500,LLSD()); should_retry = policy.shouldRetry(seconds_to_wait); - ensure("header 1", should_retry); - ensure_approximately_equals("header 1", seconds_to_wait, 17.0F, 6); + UNSCOPED_INFO("header 1"); + CHECK(should_retry); + UNSCOPED_INFO("header 1"); + CHECK_THAT(seconds_to_wait, ll_test::WithinBits(17.0F, 6)); // retry header should override, give delay of 0 std::string date_string = LLDate((F64)(nowseconds+7)).asRFC1123(); sd_headers[HTTP_IN_HEADER_RETRY_AFTER] = date_string; policy.onFailure(503,sd_headers); should_retry = policy.shouldRetry(seconds_to_wait); - ensure("header 2", should_retry); - ensure_approximately_equals_range("header 2", seconds_to_wait, 7.0F, 2.0F); + UNSCOPED_INFO("header 2"); + CHECK(should_retry); + UNSCOPED_INFO("header 2"); + CHECK_THAT(seconds_to_wait, Catch::Matchers::WithinAbs(7.0F, 2.0F)); LLCore::HttpResponse *response; LLCore::HttpHeaders::ptr_t headers; @@ -294,8 +331,10 @@ void RetryPolicyTestObject::test<7>() headers->append(HTTP_IN_HEADER_RETRY_AFTER, std::string("600")); policy.onFailure(response); should_retry = policy.shouldRetry(seconds_to_wait); - ensure("header 3",should_retry); - ensure_approximately_equals("header 3", seconds_to_wait, 600.0F, 6); + UNSCOPED_INFO("header 3"); + CHECK(should_retry); + UNSCOPED_INFO("header 3"); + CHECK_THAT(seconds_to_wait, ll_test::WithinBits(600.0F, 6)); response->release(); response = new LLCore::HttpResponse(); @@ -308,20 +347,25 @@ void RetryPolicyTestObject::test<7>() headers->append(HTTP_IN_HEADER_RETRY_AFTER,date_string); policy.onFailure(response); should_retry = policy.shouldRetry(seconds_to_wait); - ensure("header 4",should_retry); - ensure_approximately_equals_range("header 4", seconds_to_wait, 77.0F, 2.0F); + UNSCOPED_INFO("header 4"); + CHECK(should_retry); + UNSCOPED_INFO("header 4"); + CHECK_THAT(seconds_to_wait, Catch::Matchers::WithinAbs(77.0F, 2.0F)); response->release(); // Timeout should be clamped at max. policy.onFailure(500,LLSD()); should_retry = policy.shouldRetry(seconds_to_wait); - ensure("header 5", should_retry); - ensure_approximately_equals("header 5", seconds_to_wait, 644.0F, 6); + UNSCOPED_INFO("header 5"); + CHECK(should_retry); + UNSCOPED_INFO("header 5"); + CHECK_THAT(seconds_to_wait, ll_test::WithinBits(644.0F, 6)); // No more retries. policy.onFailure(500,LLSD()); should_retry = policy.shouldRetry(seconds_to_wait); - ensure("header 6", !should_retry); + UNSCOPED_INFO("header 6"); + CHECK_FALSE(should_retry); } } diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index b1a2db7065..273fcb0152 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -38,7 +38,7 @@ // std headers // external library headers // other Linden headers -#include "../test/lltut.h" +#include #include "llevents.h" #include "llnotificationsutil.h" #include "lltrans.h" @@ -338,7 +338,7 @@ std::string xml_escape_string(const std::string& in) /***************************************************************************** * TUT *****************************************************************************/ -namespace tut +namespace { struct lllogininstance_data { @@ -394,19 +394,13 @@ namespace tut MockNotifications notifications; }; - typedef test_group lllogininstance_group; - typedef lllogininstance_group::object lllogininstance_object; - lllogininstance_group llsdmgr("LLLoginInstance"); - - template<> template<> - void lllogininstance_object::test<1>() + TEST_CASE_METHOD(lllogininstance_data, "LLLoginInstance: a successful connect keeps the response until a disconnect", "[LLLoginInstance]") { - set_test_name("Test Simple Success And Disconnect"); - // Test default connect. logininstance->connect(agentCredential); - ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); + UNSCOPED_INFO("Default connect uri"); + CHECK(gLoginURI == VIEWERLOGIN_URI); // Dummy success response. LLSD response; @@ -418,12 +412,15 @@ namespace tut testPump().post(response); - ensure("Success response", logininstance->authSuccess()); - ensure_equals("Test Response Data", logininstance->getResponse().asString(), "test_data"); + UNSCOPED_INFO("Success response"); + CHECK(logininstance->authSuccess()); + UNSCOPED_INFO("Test Response Data"); + CHECK(logininstance->getResponse().asString() == "test_data"); logininstance->disconnect(); - ensure_equals("Called Login Module Disconnect", gDisconnectCalled, true); + UNSCOPED_INFO("Called Login Module Disconnect"); + CHECK(gDisconnectCalled == true); response.clear(); response["state"] = "offline"; @@ -434,23 +431,24 @@ namespace tut testPump().post(response); - ensure("Disconnected", !(logininstance->authSuccess())); + UNSCOPED_INFO("Disconnected"); + CHECK_FALSE(logininstance->authSuccess()); } - template<> template<> - void lllogininstance_object::test<2>() + TEST_CASE_METHOD(lllogininstance_data, "LLLoginInstance: accepting the TOS or a critical message reconnects with it agreed", "[LLLoginInstance]") { - set_test_name("Test User TOS/Critical message Interaction"); - const std::string test_uri = "testing-uri"; // Test default connect. logininstance->connect(test_uri, agentCredential); // connect should call LLLogin::connect to init gLoginURI and gLoginCreds. - ensure_equals("Default connect uri", gLoginURI, "testing-uri"); - ensure_equals("Default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false); - ensure_equals("Default for read critical", gLoginCreds["params"]["read_critical"].asBoolean(), false); + UNSCOPED_INFO("Default connect uri"); + CHECK(gLoginURI == "testing-uri"); + UNSCOPED_INFO("Default for agree to tos"); + CHECK(gLoginCreds["params"]["agree_to_tos"].asBoolean() == false); + UNSCOPED_INFO("Default for read critical"); + CHECK(gLoginCreds["params"]["read_critical"].asBoolean() == false); // TOS failure response. LLSD response; @@ -461,43 +459,62 @@ namespace tut response["data"]["reason"] = "tos"; testPump().post(response); - ensure_equals("TOS Dialog type", gTOSType, "message_tos"); - ensure("TOS callback given", gTOSReplyPump != 0); + UNSCOPED_INFO("TOS Dialog type"); + CHECK(gTOSType == "message_tos"); + UNSCOPED_INFO("TOS callback given"); + REQUIRE(gTOSReplyPump != 0); gTOSReplyPump->post(false); // Call callback denying TOS. - ensure("No TOS, failed auth", logininstance->authFailure()); + UNSCOPED_INFO("No TOS, failed auth"); + CHECK(logininstance->authFailure()); // Start again. logininstance->connect(test_uri, agentCredential); testPump().post(response); // Fail for tos again. gTOSReplyPump->post(true); // Accept tos, should reconnect w/ agree_to_tos. - ensure_equals("Accepted agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), true); - ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess()); + UNSCOPED_INFO("Accepted agree to tos"); + CHECK(gLoginCreds["params"]["agree_to_tos"].asBoolean() == true); + { + INFO("Incomplete login status"); + REQUIRE_FALSE(logininstance->authFailure()); + CHECK_FALSE(logininstance->authSuccess()); + } // Fail connection, attempt connect again. // The new request should have reset agree to tos to default. response["data"]["reason"] = "key"; // bad creds. testPump().post(response); - ensure("TOS auth failure", logininstance->authFailure()); + UNSCOPED_INFO("TOS auth failure"); + CHECK(logininstance->authFailure()); logininstance->connect(test_uri, agentCredential); - ensure_equals("Reset to default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false); + UNSCOPED_INFO("Reset to default for agree to tos"); + CHECK(gLoginCreds["params"]["agree_to_tos"].asBoolean() == false); // Critical Message failure response. logininstance->connect(test_uri, agentCredential); response["data"]["reason"] = "critical"; // Change response to "critical message" testPump().post(response); - ensure_equals("TOS Dialog type", gTOSType, "message_critical"); - ensure("TOS callback given", gTOSReplyPump != 0); + UNSCOPED_INFO("TOS Dialog type"); + CHECK(gTOSType == "message_critical"); + UNSCOPED_INFO("TOS callback given"); + REQUIRE(gTOSReplyPump != 0); gTOSReplyPump->post(true); - ensure_equals("Accepted read critical message", gLoginCreds["params"]["read_critical"].asBoolean(), true); - ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess()); + UNSCOPED_INFO("Accepted read critical message"); + CHECK(gLoginCreds["params"]["read_critical"].asBoolean() == true); + { + INFO("Incomplete login status"); + REQUIRE_FALSE(logininstance->authFailure()); + CHECK_FALSE(logininstance->authSuccess()); + } // Fail then attempt new connection response["data"]["reason"] = "key"; // bad creds. testPump().post(response); - ensure("TOS auth failure", logininstance->authFailure()); + UNSCOPED_INFO("TOS auth failure"); + CHECK(logininstance->authFailure()); logininstance->connect(test_uri, agentCredential); - ensure_equals("Default for agree to tos", gLoginCreds["params"]["read_critical"].asBoolean(), false); + UNSCOPED_INFO("Default for agree to tos"); + CHECK(gLoginCreds["params"]["read_critical"].asBoolean() == false); } } diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index d1eae88f46..6c12cb68c1 100644 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -26,7 +26,7 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include #include "../llremoteparcelrequest.h" @@ -52,8 +52,6 @@ void LLAgent::sendReliableMessage(void) { } LLUUID gAgentSessionID; LLUUID gAgentID; -namespace tut -{ namespace { struct TestObserver : public LLRemoteParcelInfoObserver { @@ -70,7 +68,6 @@ namespace bool mProcessed; }; -} // anonymous namespace struct RemoteParcelRequestData { @@ -79,15 +76,8 @@ namespace } }; - typedef test_group remoteparcelrequest_t; - typedef remoteparcelrequest_t::object remoteparcelrequest_object_t; - tut::remoteparcelrequest_t tut_remoteparcelrequest("LLRemoteParcelRequest"); - - template<> template<> - void remoteparcelrequest_object_t::test<1>() + TEST_CASE_METHOD(RemoteParcelRequestData, "LLRemoteParcelRequest: an observer is told of the reply for its parcel", "[LLRemoteParcelRequest]") { - set_test_name("observer pointer"); - std::unique_ptr observer(new TestObserver()); LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance(); @@ -95,14 +85,11 @@ namespace processor.processParcelData(testParcelData()); - ensure(observer->mProcessed); + CHECK(observer->mProcessed); } - template<> template<> - void remoteparcelrequest_object_t::test<2>() + TEST_CASE_METHOD(RemoteParcelRequestData, "LLRemoteParcelRequest: a reply after its observer is deleted does not crash", "[LLRemoteParcelRequest]") { - set_test_name("CHOP-220: dangling observer pointer"); - LLRemoteParcelInfoObserver * observer = new TestObserver(); LLRemoteParcelInfoProcessor & processor = LLRemoteParcelInfoProcessor::instance(); diff --git a/indra/newview/tests/llsecapi_test.cpp b/indra/newview/tests/llsecapi_test.cpp index f065d29458..44e1f448fd 100644 --- a/indra/newview/tests/llsecapi_test.cpp +++ b/indra/newview/tests/llsecapi_test.cpp @@ -27,7 +27,7 @@ */ #include "../llviewerprecompiledheaders.h" #include "../llviewernetwork.h" -#include "../test/lltut.h" +#include #include "../llsecapi.h" #include "../llsechandler_basic.h" #include "../../llxml/llcontrol.h" @@ -81,7 +81,7 @@ void LLSecAPIBasicHandler::removeCredentialMap(const std::string& storage, const // ------------------------------------------------------------------------------------------- // TUT // ------------------------------------------------------------------------------------------- -namespace tut +namespace { // Test wrapper declaration : wrapping nothing for the moment struct secapiTest @@ -95,39 +95,36 @@ namespace tut } }; - // Tut templating thingamagic: test group, object and test instance - typedef test_group secapiTestFactory; - typedef secapiTestFactory::object secapiTestObject; - tut::secapiTestFactory tut_secapi("LLSecAPI"); - // --------------------------------------------------------------------------------------- // Test functions // --------------------------------------------------------------------------------------- // registration - template<> template<> - void secapiTestObject::test<1>() + TEST_CASE_METHOD(secapiTest, "LLSecAPI: getSecHandler finds registered handlers by name and no others", "[LLSecAPI]") { // retrieve an unknown handler - ensure("'Unknown' handler should be NULL", getSecHandler("unknown") == nullptr); + UNSCOPED_INFO("'Unknown' handler should be NULL"); + REQUIRE(getSecHandler("unknown") == nullptr); LLPointer test1_handler = new LLSecAPIBasicHandler(); registerSecHandler("sectest1", test1_handler); - ensure("'Unknown' handler should be NULL", getSecHandler("unknown") == nullptr); + UNSCOPED_INFO("'Unknown' handler should be NULL"); + REQUIRE(getSecHandler("unknown") == nullptr); LLPointer retrieved_test1_handler = getSecHandler("sectest1"); - ensure("Retrieved sectest1 handler should be the same", - retrieved_test1_handler == test1_handler); + UNSCOPED_INFO("Retrieved sectest1 handler should be the same"); + CHECK(retrieved_test1_handler == test1_handler); // insert a second handler LLPointer test2_handler = new LLSecAPIBasicHandler(); registerSecHandler("sectest2", test2_handler); - ensure("'Unknown' handler should be NULL", getSecHandler("unknown") == nullptr); + UNSCOPED_INFO("'Unknown' handler should be NULL"); + REQUIRE(getSecHandler("unknown") == nullptr); retrieved_test1_handler = getSecHandler("sectest1"); - ensure("Retrieved sectest1 handler should be the same", - retrieved_test1_handler == test1_handler); + UNSCOPED_INFO("Retrieved sectest1 handler should be the same"); + CHECK(retrieved_test1_handler == test1_handler); LLPointer retrieved_test2_handler = getSecHandler("sectest2"); - ensure("Retrieved sectest1 handler should be the same", - retrieved_test2_handler == test2_handler); + UNSCOPED_INFO("Retrieved sectest1 handler should be the same"); + CHECK(retrieved_test2_handler == test2_handler); } } diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp index b9a51c67b3..819eaba5cb 100644 --- a/indra/newview/tests/llsechandler_basic_test.cpp +++ b/indra/newview/tests/llsechandler_basic_test.cpp @@ -26,7 +26,8 @@ * $/LicenseInfo$ */ #include "../llviewerprecompiledheaders.h" -#include "../test/lltut.h" +#include +#include "altestmatchers.h" #include "../llsecapi.h" #include "../llsechandler_basic.h" #include "../../llxml/llcontrol.h" @@ -55,14 +56,12 @@ #define ensure_throws(str, exc_type, cert, func, ...) \ try \ { \ -func(__VA_ARGS__); \ -fail("throws, " str); \ +func(__VA_ARGS__); FAIL(("throws, " str)); \ } \ catch(exc_type& except) \ { \ LLSD cert_data; \ -cert->getLLSD(cert_data); \ -ensure("Exception cert is incorrect for " str, valueCompareLLSD(except.getCertData(), cert_data)); \ +cert->getLLSD(cert_data); UNSCOPED_INFO(("Exception cert is incorrect for " str)); REQUIRE((valueCompareLLSD(except.getCertData(), cert_data))); \ } extern bool _cert_hostname_wildcard_match(const std::string& hostname, const std::string& wildcard_string); @@ -140,7 +139,7 @@ LLCertException::LLCertException(const LLSD& cert_data, const std::string& msg) // ------------------------------------------------------------------------------------------- // TUT // ------------------------------------------------------------------------------------------- -namespace tut +namespace { const std::string mPemTestCert( "Certificate:\n" @@ -702,17 +701,11 @@ namespace tut } }; - // Tut templating thingamagic: test group, object and test instance - typedef test_group sechandler_basic_test_factory; - typedef sechandler_basic_test_factory::object sechandler_basic_test_object; - tut::sechandler_basic_test_factory tut_sechandler_basic("LLSecHandler"); - // --------------------------------------------------------------------------------------- // Test functions // --------------------------------------------------------------------------------------- // test cert data retrieval - template<> template<> - void sechandler_basic_test_object::test<1>() + TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: a certificate is made from PEM without throwing", "[LLSecHandler]") { try { @@ -722,17 +715,16 @@ namespace tut catch (LLCertException& cert_exception) { LL_INFOS() << "cert ex: " << cert_exception.getCertData() << LL_ENDL; - fail("cert exception"); + FAIL("cert exception"); } catch (...) { LOG_UNHANDLED_EXCEPTION("test 1"); - fail("other exception"); + FAIL("other exception"); } } - template<> template<> - void sechandler_basic_test_object::test<2>() + TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: a certificate's LLSD describes its issuer and subject and validity", "[LLSecHandler]") { LLPointer test_cert(new LLBasicCertificate(mPemChildCert, &mValidationDate)); @@ -741,41 +733,57 @@ namespace tut //std::ostringstream llsd_value; //llsd_value << LLSDOStreamer(llsd_cert) << std::endl; LL_DEBUGS() << "test 1 cert " << llsd_cert << LL_ENDL; - ensure_equals("Issuer Name/commonName", (std::string)llsd_cert["issuer_name"]["commonName"], "Integration Test Intermediate CA"); - ensure_equals("Issuer Name/countryName", (std::string)llsd_cert["issuer_name"]["countryName"], "US"); - ensure_equals("Issuer Name/state", (std::string)llsd_cert["issuer_name"]["stateOrProvinceName"], "California"); - ensure_equals("Issuer Name/org name", (std::string)llsd_cert["issuer_name"]["organizationName"], "Linden Lab"); - ensure_equals("Issuer Name/org unit", (std::string)llsd_cert["issuer_name"]["organizationalUnitName"], "Second Life Engineering"); - ensure_equals("Issuer name string", (std::string)llsd_cert["issuer_name_string"], + UNSCOPED_INFO("Issuer Name/commonName"); + CHECK((std::string)llsd_cert["issuer_name"]["commonName"] == "Integration Test Intermediate CA"); + UNSCOPED_INFO("Issuer Name/countryName"); + CHECK((std::string)llsd_cert["issuer_name"]["countryName"] == "US"); + UNSCOPED_INFO("Issuer Name/state"); + CHECK((std::string)llsd_cert["issuer_name"]["stateOrProvinceName"] == "California"); + UNSCOPED_INFO("Issuer Name/org name"); + CHECK((std::string)llsd_cert["issuer_name"]["organizationName"] == "Linden Lab"); + UNSCOPED_INFO("Issuer Name/org unit"); + CHECK((std::string)llsd_cert["issuer_name"]["organizationalUnitName"] == "Second Life Engineering"); + UNSCOPED_INFO("Issuer name string"); + CHECK((std::string)llsd_cert["issuer_name_string"] == "emailAddress=noreply@lindenlab.com,CN=Integration Test Intermediate CA,OU=Second Life Engineering,O=Linden Lab,L=San Francisco,ST=California,C=US"); - ensure_equals("subject Name/commonName", (std::string)llsd_cert["subject_name"]["commonName"], + UNSCOPED_INFO("subject Name/commonName"); + CHECK((std::string)llsd_cert["subject_name"]["commonName"] == "Integration Test Server Cert"); - ensure_equals("subject Name/countryName", (std::string)llsd_cert["subject_name"]["countryName"], "US"); - ensure_equals("subject Name/state", (std::string)llsd_cert["subject_name"]["stateOrProvinceName"], "California"); - ensure_equals("subject Name/localityName", (std::string)llsd_cert["subject_name"]["localityName"], "San Francisco"); - ensure_equals("subject Name/org name", (std::string)llsd_cert["subject_name"]["organizationName"], "Linden Lab"); - ensure_equals("subjectName/org unit", - (std::string)llsd_cert["subject_name"]["organizationalUnitName"], "Second Life Engineering"); - - ensure_equals("subject name string", - (std::string)llsd_cert["subject_name_string"], + UNSCOPED_INFO("subject Name/countryName"); + CHECK((std::string)llsd_cert["subject_name"]["countryName"] == "US"); + UNSCOPED_INFO("subject Name/state"); + CHECK((std::string)llsd_cert["subject_name"]["stateOrProvinceName"] == "California"); + UNSCOPED_INFO("subject Name/localityName"); + CHECK((std::string)llsd_cert["subject_name"]["localityName"] == "San Francisco"); + UNSCOPED_INFO("subject Name/org name"); + CHECK((std::string)llsd_cert["subject_name"]["organizationName"] == "Linden Lab"); + UNSCOPED_INFO("subjectName/org unit"); + CHECK((std::string)llsd_cert["subject_name"]["organizationalUnitName"] == "Second Life Engineering"); + + UNSCOPED_INFO("subject name string"); + CHECK((std::string)llsd_cert["subject_name_string"] == "emailAddress=noreply@lindenlab.com,CN=Integration Test Server Cert,OU=Second Life Engineering,O=Linden Lab,L=San Francisco,ST=California,C=US"); - ensure_equals("serial number", (std::string)llsd_cert["serial_number"], "9E8D3413E79BF931"); - ensure_equals("valid from", (std::string)llsd_cert["valid_from"], "2024-07-23T11:46:39Z"); - ensure_equals("valid to", (std::string)llsd_cert["valid_to"], "2034-07-21T11:46:39Z"); + UNSCOPED_INFO("serial number"); + CHECK((std::string)llsd_cert["serial_number"] == "9E8D3413E79BF931"); + UNSCOPED_INFO("valid from"); + CHECK((std::string)llsd_cert["valid_from"] == "2024-07-23T11:46:39Z"); + UNSCOPED_INFO("valid to"); + CHECK((std::string)llsd_cert["valid_to"] == "2034-07-21T11:46:39Z"); LLSD expectedKeyUsage = LLSD::emptyArray(); expectedKeyUsage.append(LLSD((std::string)"digitalSignature")); expectedKeyUsage.append(LLSD((std::string)"keyEncipherment")); - ensure("key usage", valueCompareLLSD(llsd_cert["keyUsage"], expectedKeyUsage)); - ensure_equals("basic constraints", llsd_cert["basicConstraints"]["CA"].asInteger(), 0); + UNSCOPED_INFO("key usage"); + CHECK(valueCompareLLSD(llsd_cert["keyUsage"], expectedKeyUsage)); + UNSCOPED_INFO("basic constraints"); + CHECK(llsd_cert["basicConstraints"]["CA"].asInteger() == 0); - ensure("x509 is equal", !X509_cmp(mX509ChildCert, test_cert->getOpenSSLX509())); + UNSCOPED_INFO("x509 is equal"); + CHECK_FALSE(X509_cmp(mX509ChildCert, test_cert->getOpenSSLX509())); } // test protected data - template<> template<> - void sechandler_basic_test_object::test<3>() + TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: protected data is kept by type and id and survives a reload", "[LLSecHandler]") { std::string protected_data = "sUSh3wj77NG9oAMyt3XIhaej3KLZhLZWFZvI6rIGmwUUOmmelrRg0NI9rkOj8ZDpTPxpwToaBT5u" "GQhakdaGLJznr9bHr4/6HIC1bouKj4n2rs4TL6j2WSjto114QdlNfLsE8cbbE+ghww58g8SeyLQO" @@ -789,7 +797,7 @@ namespace tut simdutf::result r = simdutf::base64_to_binary(protected_data.data(), protected_data.size(), (char*)binary_data.data()); if (r.error != simdutf::error_code::SUCCESS) { - fail("base64 decode failed"); + FAIL("base64 decode failed"); } else { @@ -813,9 +821,12 @@ namespace tut LLSD data = handler->getProtectedData("test_data_type", "test_data_id"); - ensure_equals("retrieve existing data1", (std::string)data["data1"], "test_data_1"); - ensure_equals("retrieve existing data2", (std::string)data["data2"], "test_data_2"); - ensure_equals("retrieve existing data3", (std::string)data["data3"]["elem1"], "test element1"); + UNSCOPED_INFO("retrieve existing data1"); + CHECK((std::string)data["data1"] == "test_data_1"); + UNSCOPED_INFO("retrieve existing data2"); + CHECK((std::string)data["data2"] == "test_data_2"); + UNSCOPED_INFO("retrieve existing data3"); + CHECK((std::string)data["data3"]["elem1"] == "test element1"); // data storage LLSD store_data = LLSD::emptyMap(); @@ -829,22 +840,31 @@ namespace tut data = handler->getProtectedData("test_data_type", "test_data_id"); // verify no overwrite of existing data - ensure_equals("verify no overwrite 1", (std::string)data["data1"], "test_data_1"); - ensure_equals("verify no overwrite 2", (std::string)data["data2"], "test_data_2"); - ensure_equals("verify no overwrite 3", (std::string)data["data3"]["elem1"], "test element1"); + UNSCOPED_INFO("verify no overwrite 1"); + CHECK((std::string)data["data1"] == "test_data_1"); + UNSCOPED_INFO("verify no overwrite 2"); + CHECK((std::string)data["data2"] == "test_data_2"); + UNSCOPED_INFO("verify no overwrite 3"); + CHECK((std::string)data["data3"]["elem1"] == "test element1"); // verify written data is good data = handler->getProtectedData("test_data_type", "test_data_id1"); - ensure_equals("verify stored data1", (std::string)data["store_data1"], "test_store_data1"); - ensure_equals("verify stored data2", (int)data["store_data2"], 27); - ensure_equals("verify stored data3", (std::string)data["store_data3"]["subelem1"], "test_subelem1"); + UNSCOPED_INFO("verify stored data1"); + CHECK((std::string)data["store_data1"] == "test_store_data1"); + UNSCOPED_INFO("verify stored data2"); + CHECK((int)data["store_data2"] == 27); + UNSCOPED_INFO("verify stored data3"); + CHECK((std::string)data["store_data3"]["subelem1"] == "test_subelem1"); // verify overwrite works handler->setProtectedData("test_data_type", "test_data_id", store_data); data = handler->getProtectedData("test_data_type", "test_data_id"); - ensure_equals("verify overwrite stored data1", (std::string)data["store_data1"], "test_store_data1"); - ensure_equals("verify overwrite stored data2", (int)data["store_data2"], 27); - ensure_equals("verify overwrite stored data3", (std::string)data["store_data3"]["subelem1"], "test_subelem1"); + UNSCOPED_INFO("verify overwrite stored data1"); + CHECK((std::string)data["store_data1"] == "test_store_data1"); + UNSCOPED_INFO("verify overwrite stored data2"); + CHECK((int)data["store_data2"] == 27); + UNSCOPED_INFO("verify overwrite stored data3"); + CHECK((std::string)data["store_data3"]["subelem1"] == "test_subelem1"); // verify other datatype doesn't conflict store_data["store_data3"] = "test_store_data3"; @@ -854,14 +874,18 @@ namespace tut handler->setProtectedData("test_data_type1", "test_data_id", store_data); data = handler->getProtectedData("test_data_type1", "test_data_id"); - ensure_equals("verify datatype stored data3", (std::string)data["store_data3"], "test_store_data3"); - ensure_equals("verify datatype stored data4", (int)data["store_data4"], 28); - ensure_equals("verify datatype stored data5", (std::string)data["store_data5"]["subelem2"], "test_subelem2"); + UNSCOPED_INFO("verify datatype stored data3"); + CHECK((std::string)data["store_data3"] == "test_store_data3"); + UNSCOPED_INFO("verify datatype stored data4"); + CHECK((int)data["store_data4"] == 28); + UNSCOPED_INFO("verify datatype stored data5"); + CHECK((std::string)data["store_data5"]["subelem2"] == "test_subelem2"); // test data not found data = handler->getProtectedData("test_data_type1", "test_data_not_found"); - ensure("not found", data.isUndefined()); + UNSCOPED_INFO("not found"); + REQUIRE(data.isUndefined()); // cause a 'write' by using 'LLPointer' to delete then instantiate a handler handler = NULL; @@ -869,9 +893,12 @@ namespace tut handler->init(); data = handler->getProtectedData("test_data_type1", "test_data_id"); - ensure_equals("verify datatype stored data3a", (std::string)data["store_data3"], "test_store_data3"); - ensure_equals("verify datatype stored data4a", (int)data["store_data4"], 28); - ensure_equals("verify datatype stored data5a", (std::string)data["store_data5"]["subelem2"], "test_subelem2"); + UNSCOPED_INFO("verify datatype stored data3a"); + CHECK((std::string)data["store_data3"] == "test_store_data3"); + UNSCOPED_INFO("verify datatype stored data4a"); + CHECK((int)data["store_data4"] == 28); + UNSCOPED_INFO("verify datatype stored data5a"); + CHECK((std::string)data["store_data5"]["subelem2"] == "test_subelem2"); // rewrite the initial file to verify reloads handler = NULL; @@ -883,24 +910,26 @@ namespace tut handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat"); handler->init(); data = handler->getProtectedData("test_data_type1", "test_data_id"); - ensure("not found", data.isUndefined()); + UNSCOPED_INFO("not found"); + REQUIRE(data.isUndefined()); handler->deleteProtectedData("test_data_type", "test_data_id"); - ensure("Deleted data not found", handler->getProtectedData("test_data_type", "test_data_id").isUndefined()); + UNSCOPED_INFO("Deleted data not found"); + REQUIRE(handler->getProtectedData("test_data_type", "test_data_id").isUndefined()); LLFile::remove("sechandler_settings.tmp"); handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat"); handler->init(); data = handler->getProtectedData("test_data_type1", "test_data_id"); - ensure("not found", data.isUndefined()); + UNSCOPED_INFO("not found"); + REQUIRE(data.isUndefined()); handler = NULL; - ensure(LLFile::isfile("sechandler_settings.tmp")); + CHECK(LLFile::isfile("sechandler_settings.tmp")); } // test credenitals - template<> template<> - void sechandler_basic_test_object::test<4>() + TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: credentials save and load and delete and fall back to legacy logins", "[LLSecHandler]") { LLPointer handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat"); handler->init(); @@ -916,9 +945,12 @@ namespace tut LLPointer my_cred = handler->createCredential("my_grid", my_id, my_authenticator); // test retrieval of credential components - ensure_equals("basic credential creation: identifier", my_id, my_cred->getIdentifier()); - ensure_equals("basic credential creation: authenticator", my_authenticator, my_cred->getAuthenticator()); - ensure_equals("basic credential creation: grid", "my_grid", my_cred->getGrid()); + UNSCOPED_INFO("basic credential creation: identifier"); + CHECK_THAT(my_id, ll_test::LLSDEquals(my_cred->getIdentifier())); + UNSCOPED_INFO("basic credential creation: authenticator"); + CHECK_THAT(my_authenticator, ll_test::LLSDEquals(my_cred->getAuthenticator())); + UNSCOPED_INFO("basic credential creation: grid"); + CHECK("my_grid" == my_cred->getGrid()); // test setting/overwriting of credential components my_id["first_name"] = "firstname"; @@ -927,53 +959,71 @@ namespace tut my_authenticator["hash"] = "6563245"; my_cred->setCredentialData(my_id, my_authenticator); - ensure_equals("set credential data: identifier", my_id, my_cred->getIdentifier()); - ensure_equals("set credential data: authenticator", my_authenticator, my_cred->getAuthenticator()); - ensure_equals("set credential data: grid", "my_grid", my_cred->getGrid()); + UNSCOPED_INFO("set credential data: identifier"); + CHECK_THAT(my_id, ll_test::LLSDEquals(my_cred->getIdentifier())); + UNSCOPED_INFO("set credential data: authenticator"); + CHECK_THAT(my_authenticator, ll_test::LLSDEquals(my_cred->getAuthenticator())); + UNSCOPED_INFO("set credential data: grid"); + CHECK("my_grid" == my_cred->getGrid()); // test loading of a credential, that hasn't been saved, without // any legacy saved credential data LLPointer my_new_cred = handler->loadCredential("my_grid2"); - ensure("unknown credential load test", my_new_cred->getIdentifier().isMap()); - ensure("unknown credential load test", !my_new_cred->getIdentifier().has("type")); - ensure("unknown credential load test", my_new_cred->getAuthenticator().isMap()); - ensure("unknown credential load test", !my_new_cred->getAuthenticator().has("type")); + UNSCOPED_INFO("unknown credential load test"); + REQUIRE(my_new_cred->getIdentifier().isMap()); + UNSCOPED_INFO("unknown credential load test"); + REQUIRE_FALSE(my_new_cred->getIdentifier().has("type")); + UNSCOPED_INFO("unknown credential load test"); + REQUIRE(my_new_cred->getAuthenticator().isMap()); + UNSCOPED_INFO("unknown credential load test"); + REQUIRE_FALSE(my_new_cred->getAuthenticator().has("type")); // test saving of a credential handler->saveCredential(my_cred, true); // test loading of a known credential my_new_cred = handler->loadCredential("my_grid"); - ensure_equals("load a known credential: identifier", my_id, my_new_cred->getIdentifier()); - ensure_equals("load a known credential: authenticator",my_authenticator, my_new_cred->getAuthenticator()); - ensure_equals("load a known credential: grid", "my_grid", my_cred->getGrid()); + UNSCOPED_INFO("load a known credential: identifier"); + CHECK_THAT(my_id, ll_test::LLSDEquals(my_new_cred->getIdentifier())); + UNSCOPED_INFO("load a known credential: authenticator"); + CHECK_THAT(my_authenticator, ll_test::LLSDEquals(my_new_cred->getAuthenticator())); + UNSCOPED_INFO("load a known credential: grid"); + CHECK("my_grid" == my_cred->getGrid()); // test deletion of a credential handler->deleteCredential(my_new_cred); - ensure("delete credential: identifier", my_new_cred->getIdentifier().isUndefined()); - ensure("delete credentialt: authenticator", my_new_cred->getIdentifier().isUndefined()); - ensure_equals("delete credential: grid", "my_grid", my_cred->getGrid()); + UNSCOPED_INFO("delete credential: identifier"); + REQUIRE(my_new_cred->getIdentifier().isUndefined()); + UNSCOPED_INFO("delete credentialt: authenticator"); + REQUIRE(my_new_cred->getIdentifier().isUndefined()); + UNSCOPED_INFO("delete credential: grid"); + CHECK("my_grid" == my_cred->getGrid()); // load unknown cred my_new_cred = handler->loadCredential("my_grid"); - ensure("deleted credential load test", my_new_cred->getIdentifier().isMap()); - ensure("deleted credential load test", !my_new_cred->getIdentifier().has("type")); - ensure("deleted credential load test", my_new_cred->getAuthenticator().isMap()); - ensure("deleted credential load test", !my_new_cred->getAuthenticator().has("type")); + UNSCOPED_INFO("deleted credential load test"); + REQUIRE(my_new_cred->getIdentifier().isMap()); + UNSCOPED_INFO("deleted credential load test"); + REQUIRE_FALSE(my_new_cred->getIdentifier().has("type")); + UNSCOPED_INFO("deleted credential load test"); + REQUIRE(my_new_cred->getAuthenticator().isMap()); + UNSCOPED_INFO("deleted credential load test"); + REQUIRE_FALSE(my_new_cred->getAuthenticator().has("type")); // test loading of an unknown credential with legacy saved username, but without // saved password gFirstName = "myfirstname"; gLastName = "mylastname"; my_new_cred = handler->loadCredential("my_legacy_grid"); - ensure_equals("legacy credential with no password: type", - (const std::string)my_new_cred->getIdentifier()["type"], "agent"); - ensure_equals("legacy credential with no password: first_name", - (const std::string)my_new_cred->getIdentifier()["first_name"], "myfirstname"); - ensure_equals("legacy credential with no password: last_name", - (const std::string)my_new_cred->getIdentifier()["last_name"], "mylastname"); + UNSCOPED_INFO("legacy credential with no password: type"); + CHECK((const std::string)my_new_cred->getIdentifier()["type"] == "agent"); + UNSCOPED_INFO("legacy credential with no password: first_name"); + CHECK((const std::string)my_new_cred->getIdentifier()["first_name"] == "myfirstname"); + UNSCOPED_INFO("legacy credential with no password: last_name"); + CHECK((const std::string)my_new_cred->getIdentifier()["last_name"] == "mylastname"); - ensure("legacy credential with no password: no authenticator", my_new_cred->getAuthenticator().isUndefined()); + UNSCOPED_INFO("legacy credential with no password: no authenticator"); + REQUIRE(my_new_cred->getAuthenticator().isUndefined()); // test loading of an unknown credential with legacy saved password and username @@ -986,7 +1036,7 @@ namespace tut simdutf::result r = simdutf::base64_to_binary(hashed_password.data(), hashed_password.size(), decoded_password.data()); if (r.error != simdutf::error_code::SUCCESS) { - fail("base64 decode failed"); + FAIL("base64 decode failed"); } else { @@ -1005,22 +1055,22 @@ namespace tut password_file.close(); my_new_cred = handler->loadCredential("my_legacy_grid2"); - ensure_equals("legacy credential with password: type", - (const std::string)my_new_cred->getIdentifier()["type"], "agent"); - ensure_equals("legacy credential with password: first_name", - (const std::string)my_new_cred->getIdentifier()["first_name"], "myfirstname"); - ensure_equals("legacy credential with password: last_name", - (const std::string)my_new_cred->getIdentifier()["last_name"], "mylastname"); + UNSCOPED_INFO("legacy credential with password: type"); + CHECK((const std::string)my_new_cred->getIdentifier()["type"] == "agent"); + UNSCOPED_INFO("legacy credential with password: first_name"); + CHECK((const std::string)my_new_cred->getIdentifier()["first_name"] == "myfirstname"); + UNSCOPED_INFO("legacy credential with password: last_name"); + CHECK((const std::string)my_new_cred->getIdentifier()["last_name"] == "mylastname"); LLSD legacy_authenticator = my_new_cred->getAuthenticator(); - ensure_equals("legacy credential with password: type", - (std::string)legacy_authenticator["type"], + UNSCOPED_INFO("legacy credential with password: type"); + CHECK((std::string)legacy_authenticator["type"] == "hash"); - ensure_equals("legacy credential with password: algorithm", - (std::string)legacy_authenticator["algorithm"], + UNSCOPED_INFO("legacy credential with password: algorithm"); + CHECK((std::string)legacy_authenticator["algorithm"] == "md5"); - ensure_equals("legacy credential with password: algorithm", - (std::string)legacy_authenticator["secret"], + UNSCOPED_INFO("legacy credential with password: algorithm"); + CHECK((std::string)legacy_authenticator["secret"] == "01234567890123456789012345678901"); // test creation of credentials @@ -1028,35 +1078,41 @@ namespace tut // test save without saving authenticator. handler->saveCredential(my_cred, false); my_new_cred = handler->loadCredential("mysavedgrid"); - ensure_equals("saved credential without auth", - (const std::string)my_new_cred->getIdentifier()["type"], "test_type"); - ensure("no authenticator values were saved", my_new_cred->getAuthenticator().isUndefined()); + UNSCOPED_INFO("saved credential without auth"); + CHECK((const std::string)my_new_cred->getIdentifier()["type"] == "test_type"); + UNSCOPED_INFO("no authenticator values were saved"); + REQUIRE(my_new_cred->getAuthenticator().isUndefined()); } // test cert vector - template<> template<> - void sechandler_basic_test_object::test<5>() + TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: a certificate vector adds once and iterates and inserts and finds", "[LLSecHandler]") { // validate create from empty vector LLPointer test_vector = new LLBasicCertificateVector(); - ensure_equals("when loading with nothing, we should result in no certs in vector", test_vector->size(), 0); + UNSCOPED_INFO("when loading with nothing, we should result in no certs in vector"); + REQUIRE(test_vector->size() == 0); test_vector->add(new LLBasicCertificate(mPemTestCert, &mValidationDate)); - ensure_equals("one element in vector", test_vector->size(), 1); + UNSCOPED_INFO("one element in vector"); + REQUIRE(test_vector->size() == 1); test_vector->add(new LLBasicCertificate(mPemChildCert, &mValidationDate)); - ensure_equals("two elements in vector after add", test_vector->size(), 2); + UNSCOPED_INFO("two elements in vector after add"); + REQUIRE(test_vector->size() == 2); // add duplicate; should be a no-op (and log at DEBUG level) test_vector->add(new LLBasicCertificate(mPemChildCert, &mValidationDate)); - ensure_equals("two elements in vector after re-add", test_vector->size(), 2); + UNSCOPED_INFO("two elements in vector after re-add"); + REQUIRE(test_vector->size() == 2); // validate order X509* test_cert = (*test_vector)[0]->getOpenSSLX509(); - ensure("first cert added remains first cert", !X509_cmp(test_cert, mX509TestCert)); + UNSCOPED_INFO("first cert added remains first cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509TestCert)); X509_free(test_cert); test_cert = (*test_vector)[1]->getOpenSSLX509(); - ensure("second cert is second cert", !X509_cmp(test_cert, mX509ChildCert)); + UNSCOPED_INFO("second cert is second cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); // @@ -1065,71 +1121,91 @@ namespace tut LLBasicCertificateVector::iterator current_cert = test_vector->begin(); LLBasicCertificateVector::iterator copy_current_cert = current_cert; // operator++(int) - ensure("validate iterator++ element in vector is expected cert", *current_cert++ == (*test_vector)[0]); - ensure("validate 2nd iterator++ element in vector is expected cert", *current_cert++ == (*test_vector)[1]); - ensure("validate end iterator++", current_cert == test_vector->end()); + UNSCOPED_INFO("validate iterator++ element in vector is expected cert"); + CHECK(*current_cert++ == (*test_vector)[0]); + UNSCOPED_INFO("validate 2nd iterator++ element in vector is expected cert"); + CHECK(*current_cert++ == (*test_vector)[1]); + UNSCOPED_INFO("validate end iterator++"); + REQUIRE(current_cert == test_vector->end()); // copy - ensure("validate copy iterator element in vector is expected cert", *copy_current_cert == (*test_vector)[0]); + UNSCOPED_INFO("validate copy iterator element in vector is expected cert"); + CHECK(*copy_current_cert == (*test_vector)[0]); // operator--(int) current_cert--; - ensure("validate iterator-- element in vector is expected cert", *current_cert-- == (*test_vector)[1]); - ensure("validate iterator-- element in vector is expected cert", *current_cert == (*test_vector)[0]); + UNSCOPED_INFO("validate iterator-- element in vector is expected cert"); + CHECK(*current_cert-- == (*test_vector)[1]); + UNSCOPED_INFO("validate iterator-- element in vector is expected cert"); + CHECK(*current_cert == (*test_vector)[0]); - ensure("begin iterator is equal", current_cert == test_vector->begin()); + UNSCOPED_INFO("begin iterator is equal"); + CHECK(current_cert == test_vector->begin()); // operator++ - ensure("validate ++iterator element in vector is expected cert", *++current_cert == (*test_vector)[1]); - ensure("end of cert vector after ++iterator", ++current_cert == test_vector->end()); + UNSCOPED_INFO("validate ++iterator element in vector is expected cert"); + CHECK(*++current_cert == (*test_vector)[1]); + UNSCOPED_INFO("end of cert vector after ++iterator"); + REQUIRE(++current_cert == test_vector->end()); // operator-- - ensure("validate --iterator element in vector is expected cert", *--current_cert == (*test_vector)[1]); - ensure("validate 2nd --iterator element in vector is expected cert", *--current_cert == (*test_vector)[0]); + UNSCOPED_INFO("validate --iterator element in vector is expected cert"); + CHECK(*--current_cert == (*test_vector)[1]); + UNSCOPED_INFO("validate 2nd --iterator element in vector is expected cert"); + CHECK(*--current_cert == (*test_vector)[0]); test_vector->erase(test_vector->begin()); - ensure_equals("one element in store after remove", test_vector->size(), 1); + UNSCOPED_INFO("one element in store after remove"); + REQUIRE(test_vector->size() == 1); test_cert = (*test_vector)[0]->getOpenSSLX509(); - ensure("Child cert remains", !X509_cmp(test_cert, mX509ChildCert)); + UNSCOPED_INFO("Child cert remains"); + CHECK_FALSE(X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); // validate insert test_vector->insert(test_vector->begin(), new LLBasicCertificate(mPemIntermediateCert, &mValidationDate)); test_cert = (*test_vector)[0]->getOpenSSLX509(); - ensure_equals("two elements in store after insert", test_vector->size(), 2); - ensure("validate intermediate cert was inserted at first position", !X509_cmp(test_cert, mX509IntermediateCert)); + UNSCOPED_INFO("two elements in store after insert"); + REQUIRE(test_vector->size() == 2); + UNSCOPED_INFO("validate intermediate cert was inserted at first position"); + CHECK_FALSE(X509_cmp(test_cert, mX509IntermediateCert)); X509_free(test_cert); test_cert = (*test_vector)[1]->getOpenSSLX509(); - ensure("validate child cert still there", !X509_cmp(test_cert, mX509ChildCert)); + UNSCOPED_INFO("validate child cert still there"); + CHECK_FALSE(X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); //validate find LLSD find_info = LLSD::emptyMap(); find_info["subjectKeyIdentifier"] = "7b:1a:f9:2b:c4:b2:f6:ae:d6:f2:8e:b1:73:fb:dd:11:ca:db:f8:87"; LLBasicCertificateVector::iterator found_cert = test_vector->find(find_info); - ensure("found some cert", found_cert != test_vector->end()); + UNSCOPED_INFO("found some cert"); + REQUIRE(found_cert != test_vector->end()); X509* found_x509 = (*found_cert).get()->getOpenSSLX509(); - ensure("child cert was found", !X509_cmp(found_x509, mX509ChildCert)); + UNSCOPED_INFO("child cert was found"); + CHECK_FALSE(X509_cmp(found_x509, mX509ChildCert)); X509_free(found_x509); find_info["subjectKeyIdentifier"] = "00:00:00:00"; // bogus current_cert =test_vector->find(find_info); - ensure("didn't find cert", current_cert == test_vector->end()); + UNSCOPED_INFO("didn't find cert"); + REQUIRE(current_cert == test_vector->end()); } // test cert store - template<> template<> - void sechandler_basic_test_object::test<6>() + TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: a certificate store loads from and saves to its file", "[LLSecHandler]") { // validate load with nothing LLFile::remove("mycertstore.pem"); LLPointer test_store = new LLBasicCertificateStore("mycertstore.pem"); - ensure_equals("when loading with nothing, we should result in no certs in store", test_store->size(), 0); + UNSCOPED_INFO("when loading with nothing, we should result in no certs in store"); + REQUIRE(test_store->size() == 0); // validate load with empty file test_store->save(); test_store = NULL; test_store = new LLBasicCertificateStore("mycertstore.pem"); - ensure_equals("when loading with nothing, we should result in no certs in store", test_store->size(), 0); + UNSCOPED_INFO("when loading with nothing, we should result in no certs in store"); + REQUIRE(test_store->size() == 0); test_store=NULL; // instantiate a cert store from a file @@ -1138,15 +1214,18 @@ namespace tut certstorefile.close(); // validate loaded certs test_store = new LLBasicCertificateStore("mycertstore.pem"); - ensure_equals("two elements in store", test_store->size(), 2); + UNSCOPED_INFO("two elements in store"); + REQUIRE(test_store->size() == 2); // operator[] X509* test_cert = (*test_store)[0]->getOpenSSLX509(); - ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); + UNSCOPED_INFO("validate first element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); test_cert = (*test_store)[1]->getOpenSSLX509(); - ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509TestCert)); + UNSCOPED_INFO("validate second element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509TestCert)); X509_free(test_cert); @@ -1155,131 +1234,134 @@ namespace tut test_store->save(); test_store = NULL; test_store = new LLBasicCertificateStore("mycertstore.pem"); - ensure_equals("two elements in store after save", test_store->size(), 2); + UNSCOPED_INFO("two elements in store after save"); + REQUIRE(test_store->size() == 2); LLCertificateStore::iterator current_cert = test_store->begin(); test_cert = (*current_cert)->getOpenSSLX509(); - ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); + UNSCOPED_INFO("validate first element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509ChildCert)); current_cert++; X509_free(test_cert); test_cert = (*current_cert)->getOpenSSLX509(); - ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509TestCert)); + UNSCOPED_INFO("validate second element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509TestCert)); X509_free(test_cert); current_cert++; - ensure("end of cert store", current_cert == test_store->end()); + UNSCOPED_INFO("end of cert store"); + REQUIRE(current_cert == test_store->end()); } // cert name wildcard matching - template<> template<> - void sechandler_basic_test_object::test<7>() + TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: hostnames match certificate names with wildcards and end periods", "[LLSecHandler]") { - ensure("simple name match", - _cert_hostname_wildcard_match("foo", "foo")); + UNSCOPED_INFO("simple name match"); + CHECK(_cert_hostname_wildcard_match("foo", "foo")); - ensure("simple name match, with end period", - _cert_hostname_wildcard_match("foo.", "foo.")); + UNSCOPED_INFO("simple name match, with end period"); + CHECK(_cert_hostname_wildcard_match("foo.", "foo.")); - ensure("simple name match, with begin period", - _cert_hostname_wildcard_match(".foo", ".foo")); + UNSCOPED_INFO("simple name match, with begin period"); + CHECK(_cert_hostname_wildcard_match(".foo", ".foo")); - ensure("simple name match, with mismatched period cn", - _cert_hostname_wildcard_match("foo.", "foo")); + UNSCOPED_INFO("simple name match, with mismatched period cn"); + CHECK(_cert_hostname_wildcard_match("foo.", "foo")); - ensure("simple name match, with mismatched period hostname", - _cert_hostname_wildcard_match("foo", "foo.")); + UNSCOPED_INFO("simple name match, with mismatched period hostname"); + CHECK(_cert_hostname_wildcard_match("foo", "foo.")); - ensure("simple name match, with subdomain", - _cert_hostname_wildcard_match("foo.bar", "foo.bar")); + UNSCOPED_INFO("simple name match, with subdomain"); + CHECK(_cert_hostname_wildcard_match("foo.bar", "foo.bar")); - ensure("stutter name match", - _cert_hostname_wildcard_match("foobbbbfoo", "foo*bbbfoo")); + UNSCOPED_INFO("stutter name match"); + CHECK(_cert_hostname_wildcard_match("foobbbbfoo", "foo*bbbfoo")); - ensure("simple name match, with beginning wildcard", - _cert_hostname_wildcard_match("foobar", "*bar")); + UNSCOPED_INFO("simple name match, with beginning wildcard"); + CHECK(_cert_hostname_wildcard_match("foobar", "*bar")); - ensure("simple name match, with ending wildcard", - _cert_hostname_wildcard_match("foobar", "foo*")); + UNSCOPED_INFO("simple name match, with ending wildcard"); + CHECK(_cert_hostname_wildcard_match("foobar", "foo*")); - ensure("simple name match, with beginning null wildcard", - _cert_hostname_wildcard_match("foobar", "*foobar")); + UNSCOPED_INFO("simple name match, with beginning null wildcard"); + CHECK(_cert_hostname_wildcard_match("foobar", "*foobar")); - ensure("simple name match, with ending null wildcard", - _cert_hostname_wildcard_match("foobar", "foobar*")); + UNSCOPED_INFO("simple name match, with ending null wildcard"); + CHECK(_cert_hostname_wildcard_match("foobar", "foobar*")); - ensure("simple name match, with embedded wildcard", - _cert_hostname_wildcard_match("foobar", "f*r")); + UNSCOPED_INFO("simple name match, with embedded wildcard"); + CHECK(_cert_hostname_wildcard_match("foobar", "f*r")); - ensure("simple name match, with embedded null wildcard", - _cert_hostname_wildcard_match("foobar", "foo*bar")); + UNSCOPED_INFO("simple name match, with embedded null wildcard"); + CHECK(_cert_hostname_wildcard_match("foobar", "foo*bar")); - ensure("simple name match, with dual embedded wildcard", - _cert_hostname_wildcard_match("foobar", "f*o*ar")); + UNSCOPED_INFO("simple name match, with dual embedded wildcard"); + CHECK(_cert_hostname_wildcard_match("foobar", "f*o*ar")); - ensure("simple name mismatch", - !_cert_hostname_wildcard_match("bar", "foo")); + UNSCOPED_INFO("simple name mismatch"); + CHECK_FALSE(_cert_hostname_wildcard_match("bar", "foo")); - ensure("simple name mismatch, with end period", - !_cert_hostname_wildcard_match("foobar.", "foo.")); + UNSCOPED_INFO("simple name mismatch, with end period"); + CHECK_FALSE(_cert_hostname_wildcard_match("foobar.", "foo.")); - ensure("simple name mismatch, with begin period", - !_cert_hostname_wildcard_match(".foobar", ".foo")); + UNSCOPED_INFO("simple name mismatch, with begin period"); + CHECK_FALSE(_cert_hostname_wildcard_match(".foobar", ".foo")); - ensure("simple name mismatch, with subdomain", - !_cert_hostname_wildcard_match("foobar.bar", "foo.bar")); + UNSCOPED_INFO("simple name mismatch, with subdomain"); + CHECK_FALSE(_cert_hostname_wildcard_match("foobar.bar", "foo.bar")); - ensure("simple name mismatch, with beginning wildcard", - !_cert_hostname_wildcard_match("foobara", "*bar")); + UNSCOPED_INFO("simple name mismatch, with beginning wildcard"); + CHECK_FALSE(_cert_hostname_wildcard_match("foobara", "*bar")); - ensure("simple name mismatch, with ending wildcard", - !_cert_hostname_wildcard_match("oobar", "foo*")); + UNSCOPED_INFO("simple name mismatch, with ending wildcard"); + CHECK_FALSE(_cert_hostname_wildcard_match("oobar", "foo*")); - ensure("simple name mismatch, with embedded wildcard", - !_cert_hostname_wildcard_match("oobar", "f*r")); + UNSCOPED_INFO("simple name mismatch, with embedded wildcard"); + CHECK_FALSE(_cert_hostname_wildcard_match("oobar", "f*r")); - ensure("simple name mismatch, with dual embedded wildcard", - !_cert_hostname_wildcard_match("foobar", "f*d*ar")); + UNSCOPED_INFO("simple name mismatch, with dual embedded wildcard"); + CHECK_FALSE(_cert_hostname_wildcard_match("foobar", "f*d*ar")); - ensure("simple wildcard", - _cert_hostname_wildcard_match("foobar", "*")); + UNSCOPED_INFO("simple wildcard"); + CHECK(_cert_hostname_wildcard_match("foobar", "*")); - ensure("long domain", - _cert_hostname_wildcard_match("foo.bar.com", "foo.bar.com")); + UNSCOPED_INFO("long domain"); + CHECK(_cert_hostname_wildcard_match("foo.bar.com", "foo.bar.com")); - ensure("long domain with multiple wildcards", - _cert_hostname_wildcard_match("foo.bar.com", "*.b*r.com")); + UNSCOPED_INFO("long domain with multiple wildcards"); + CHECK(_cert_hostname_wildcard_match("foo.bar.com", "*.b*r.com")); - ensure("end periods", - _cert_hostname_wildcard_match("foo.bar.com.", "*.b*r.com.")); + UNSCOPED_INFO("end periods"); + CHECK(_cert_hostname_wildcard_match("foo.bar.com.", "*.b*r.com.")); - ensure("match end period", - _cert_hostname_wildcard_match("foo.bar.com.", "*.b*r.com")); + UNSCOPED_INFO("match end period"); + CHECK(_cert_hostname_wildcard_match("foo.bar.com.", "*.b*r.com")); - ensure("match end period2", - _cert_hostname_wildcard_match("foo.bar.com", "*.b*r.com.")); + UNSCOPED_INFO("match end period2"); + CHECK(_cert_hostname_wildcard_match("foo.bar.com", "*.b*r.com.")); - ensure("wildcard mismatch", - !_cert_hostname_wildcard_match("bar.com", "*.bar.com")); + UNSCOPED_INFO("wildcard mismatch"); + CHECK_FALSE(_cert_hostname_wildcard_match("bar.com", "*.bar.com")); - ensure("wildcard match", - _cert_hostname_wildcard_match("foo.bar.com", "*.bar.com")); + UNSCOPED_INFO("wildcard match"); + CHECK(_cert_hostname_wildcard_match("foo.bar.com", "*.bar.com")); - ensure("wildcard match", - _cert_hostname_wildcard_match("foo.foo.bar.com", "*.bar.com")); + UNSCOPED_INFO("wildcard match"); + CHECK(_cert_hostname_wildcard_match("foo.foo.bar.com", "*.bar.com")); - ensure("wildcard match", - _cert_hostname_wildcard_match("foo.foo.bar.com", "*.*.com")); + UNSCOPED_INFO("wildcard match"); + CHECK(_cert_hostname_wildcard_match("foo.foo.bar.com", "*.*.com")); - ensure("wildcard mismatch", - !_cert_hostname_wildcard_match("foo.foo.bar.com", "*.foo.com")); + UNSCOPED_INFO("wildcard mismatch"); + CHECK_FALSE(_cert_hostname_wildcard_match("foo.foo.bar.com", "*.foo.com")); } // test cert chain - template<> template<> - void sechandler_basic_test_object::test<8>() + TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: a certificate chain follows issuers and drops unrelated certs", "[LLSecHandler]") { // validate create from empty chain LLPointer test_chain = new LLBasicCertificateChain(NULL); - ensure_equals("when loading with nothing, we should result in no certs in chain", test_chain->size(), 0); + UNSCOPED_INFO("when loading with nothing, we should result in no certs in chain"); + REQUIRE(test_chain->size() == 0); // Single cert in the chain. X509_STORE_CTX *test_store = X509_STORE_CTX_new(); @@ -1287,9 +1369,11 @@ namespace tut X509_STORE_CTX_set0_untrusted(test_store, sk_X509_new_null()); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - ensure_equals("two elements in store [1]", test_chain->size(), 1); + UNSCOPED_INFO("two elements in store [1]"); + REQUIRE(test_chain->size() == 1); X509* test_cert = (*test_chain)[0]->getOpenSSLX509(); - ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); + UNSCOPED_INFO("validate first element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); // cert + CA @@ -1300,12 +1384,15 @@ namespace tut sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509IntermediateCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - ensure_equals("two elements in store [2]", test_chain->size(), 2); + UNSCOPED_INFO("two elements in store [2]"); + REQUIRE(test_chain->size() == 2); test_cert = (*test_chain)[0]->getOpenSSLX509(); - ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); + UNSCOPED_INFO("validate first element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); test_cert = (*test_chain)[1]->getOpenSSLX509(); - ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509IntermediateCert)); + UNSCOPED_INFO("validate second element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509IntermediateCert)); X509_free(test_cert); // cert + nonrelated @@ -1316,9 +1403,11 @@ namespace tut sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509TestCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - ensure_equals("two elements in store [3]", test_chain->size(), 1); + UNSCOPED_INFO("two elements in store [3]"); + REQUIRE(test_chain->size() == 1); test_cert = (*test_chain)[0]->getOpenSSLX509(); - ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); + UNSCOPED_INFO("validate first element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); // cert + CA + nonrelated @@ -1329,12 +1418,15 @@ namespace tut sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509TestCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - ensure_equals("two elements in store [4]", test_chain->size(), 2); + UNSCOPED_INFO("two elements in store [4]"); + REQUIRE(test_chain->size() == 2); test_cert = (*test_chain)[0]->getOpenSSLX509(); - ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); + UNSCOPED_INFO("validate first element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); test_cert = (*test_chain)[1]->getOpenSSLX509(); - ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509IntermediateCert)); + UNSCOPED_INFO("validate second element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509IntermediateCert)); X509_free(test_cert); // cert + intermediate + CA @@ -1345,22 +1437,25 @@ namespace tut sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509RootCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - ensure_equals("three elements in store", test_chain->size(), 3); + UNSCOPED_INFO("three elements in store"); + REQUIRE(test_chain->size() == 3); test_cert = (*test_chain)[0]->getOpenSSLX509(); - ensure("validate first element in store is expected cert", !X509_cmp(test_cert, mX509ChildCert)); + UNSCOPED_INFO("validate first element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509ChildCert)); X509_free(test_cert); test_cert = (*test_chain)[1]->getOpenSSLX509(); - ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509IntermediateCert)); + UNSCOPED_INFO("validate second element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509IntermediateCert)); X509_free(test_cert); test_cert = (*test_chain)[2]->getOpenSSLX509(); - ensure("validate second element in store is expected cert", !X509_cmp(test_cert, mX509RootCert)); + UNSCOPED_INFO("validate second element in store is expected cert"); + CHECK_FALSE(X509_cmp(test_cert, mX509RootCert)); X509_free(test_cert); } // test cert validation - template<> template<> - void sechandler_basic_test_object::test<9>() + TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: validation needs a trusted CA and a valid date and SSL key usage", "[LLSecHandler]") { // start with a trusted store with our known root cert LLFile::remove("mycertstore.pem"); diff --git a/indra/newview/tests/llslurl_test.cpp b/indra/newview/tests/llslurl_test.cpp index 2e0f448842..83b04b89e2 100644 --- a/indra/newview/tests/llslurl_test.cpp +++ b/indra/newview/tests/llslurl_test.cpp @@ -27,7 +27,7 @@ */ #include "../llviewerprecompiledheaders.h" #include "../llviewernetwork.h" -#include "../test/lltut.h" +#include #include "../llslurl.h" #include "../../llxml/llcontrol.h" #include "llsdserialize.h" @@ -176,7 +176,7 @@ static const char *gSampleGridFile = // ------------------------------------------------------------------------------------------- // TUT // ------------------------------------------------------------------------------------------- -namespace tut +namespace { // Test wrapper declaration : wrapping nothing for the moment struct slurlTest @@ -192,17 +192,11 @@ namespace tut } }; - // Tut templating thingamagic: test group, object and test instance - typedef test_group slurlTestFactory; - typedef slurlTestFactory::object slurlTestObject; - tut::slurlTestFactory tut_slurl("LLSlurl"); - // --------------------------------------------------------------------------------------- // Test functions // --------------------------------------------------------------------------------------- // construction from slurl string - template<> template<> - void slurlTestObject::test<1>() + TEST_CASE_METHOD(slurlTest, "LLSlurl: construction from each form of SLURL string", "[LLSlurl]") { llofstream gridfile(TEST_FILENAME); gridfile << gSampleGridFile; @@ -213,119 +207,170 @@ namespace tut LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com"); LLSLURL slurl = LLSLURL(""); - ensure_equals("null slurl", (int)slurl.getType(), LLSLURL::LAST_LOCATION); + UNSCOPED_INFO("null slurl"); + CHECK((int)slurl.getType() == LLSLURL::LAST_LOCATION); slurl = LLSLURL("https://slurl.com/secondlife/myregion"); - ensure_equals("slurl.com slurl, region only - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("slurl.com slurl, region only", slurl.getSLURLString(), + UNSCOPED_INFO("slurl.com slurl, region only - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("slurl.com slurl, region only"); + CHECK(slurl.getSLURLString() == "https://maps.secondlife.com/secondlife/myregion/128/128/0"); slurl = LLSLURL("https://maps.secondlife.com/secondlife/myregion/1/2/3"); - ensure_equals("maps.secondlife.com slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("maps.secondlife.com slurl, region + coords", slurl.getSLURLString(), + UNSCOPED_INFO("maps.secondlife.com slurl, region + coords - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("maps.secondlife.com slurl, region + coords"); + CHECK(slurl.getSLURLString() == "https://maps.secondlife.com/secondlife/myregion/1/2/3"); slurl = LLSLURL("secondlife://"); - ensure_equals("secondlife: slurl, empty - type", slurl.getType(), LLSLURL::EMPTY); + UNSCOPED_INFO("secondlife: slurl, empty - type"); + CHECK(slurl.getType() == LLSLURL::EMPTY); slurl = LLSLURL("secondlife:///"); - ensure_equals("secondlife: slurl, root - type", slurl.getType(), LLSLURL::EMPTY); + UNSCOPED_INFO("secondlife: slurl, root - type"); + CHECK(slurl.getType() == LLSLURL::EMPTY); slurl = LLSLURL("secondlife://myregion"); - ensure_equals("secondlife: slurl, region only - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("secondlife: slurl, region only", slurl.getSLURLString(), + UNSCOPED_INFO("secondlife: slurl, region only - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("secondlife: slurl, region only"); + CHECK(slurl.getSLURLString() == "https://maps.secondlife.com/secondlife/myregion/128/128/0"); slurl = LLSLURL("secondlife://myregion/1/2/3"); - ensure_equals("secondlife: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("secondlife slurl, region + coords", slurl.getSLURLString(), + UNSCOPED_INFO("secondlife: slurl, region + coords - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("secondlife slurl, region + coords"); + CHECK(slurl.getSLURLString() == "https://maps.secondlife.com/secondlife/myregion/1/2/3"); slurl = LLSLURL("/myregion"); - ensure_equals("/region slurl, region- type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("/region slurl, region ", slurl.getSLURLString(), + UNSCOPED_INFO("/region slurl, region- type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("/region slurl, region "); + CHECK(slurl.getSLURLString() == "https://maps.secondlife.com/secondlife/myregion/128/128/0"); slurl = LLSLURL("/myregion/1/2/3"); - ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("/ slurl, region + coords", slurl.getSLURLString(), + UNSCOPED_INFO("/: slurl, region + coords - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("/ slurl, region + coords"); + CHECK(slurl.getSLURLString() == "https://maps.secondlife.com/secondlife/myregion/1/2/3"); slurl = LLSLURL("my region/1/2/3"); - ensure_equals(" slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals(" slurl, region + coords", slurl.getSLURLString(), + UNSCOPED_INFO(" slurl, region + coords - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO(" slurl, region + coords"); + CHECK(slurl.getSLURLString() == "https://maps.secondlife.com/secondlife/my%20region/1/2/3"); LLGridManager::getInstance()->setGridChoice("my.grid.com"); slurl = LLSLURL("https://my.grid.com/region/my%20region/1/2/3"); - ensure_equals("grid slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("grid slurl, region + coords", slurl.getSLURLString(), + UNSCOPED_INFO("grid slurl, region + coords - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("grid slurl, region + coords"); + CHECK(slurl.getSLURLString() == "https://my.grid.com/region/my%20region/1/2/3"); slurl = LLSLURL("https://my.grid.com/region/my region"); - ensure_equals("grid slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("grid slurl, region + coords", slurl.getSLURLString(), + UNSCOPED_INFO("grid slurl, region + coords - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("grid slurl, region + coords"); + CHECK(slurl.getSLURLString() == "https://my.grid.com/region/my%20region/128/128/0"); LLGridManager::getInstance()->setGridChoice("foo.bar.com"); slurl = LLSLURL("/myregion/1/2/3"); - ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("/ slurl, region + coords", slurl.getSLURLString(), + UNSCOPED_INFO("/: slurl, region + coords - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("/ slurl, region + coords"); + CHECK(slurl.getSLURLString() == "https://foo.bar.com/region/myregion/1/2/3"); slurl = LLSLURL("myregion/1/2/3"); - ensure_equals(": slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals(" slurl, region + coords", slurl.getSLURLString(), + UNSCOPED_INFO(": slurl, region + coords - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO(" slurl, region + coords"); + CHECK(slurl.getSLURLString() == "https://foo.bar.com/region/myregion/1/2/3"); slurl = LLSLURL(LLSLURL::SIM_LOCATION_HOME); - ensure_equals("home", slurl.getType(), LLSLURL::HOME_LOCATION); + UNSCOPED_INFO("home"); + CHECK(slurl.getType() == LLSLURL::HOME_LOCATION); slurl = LLSLURL(LLSLURL::SIM_LOCATION_LAST); - ensure_equals("last", slurl.getType(), LLSLURL::LAST_LOCATION); + UNSCOPED_INFO("last"); + CHECK(slurl.getType() == LLSLURL::LAST_LOCATION); slurl = LLSLURL("secondlife:///app/foo/bar?12345"); - ensure_equals("app", slurl.getType(), LLSLURL::APP); - ensure_equals("appcmd", slurl.getAppCmd(), "foo"); - ensure_equals("apppath", slurl.getAppPath().size(), 1); - ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar"); - ensure_equals("appquery", slurl.getAppQuery(), "12345"); - ensure_equals("grid1", slurl.getGrid(), "FooBar"); + UNSCOPED_INFO("app"); + CHECK(slurl.getType() == LLSLURL::APP); + UNSCOPED_INFO("appcmd"); + CHECK(slurl.getAppCmd() == "foo"); + UNSCOPED_INFO("apppath"); + REQUIRE(slurl.getAppPath().size() == 1); + UNSCOPED_INFO("apppath2"); + CHECK(slurl.getAppPath()[0].asString() == "bar"); + UNSCOPED_INFO("appquery"); + CHECK(slurl.getAppQuery() == "12345"); + UNSCOPED_INFO("grid1"); + CHECK(slurl.getGrid() == "FooBar"); slurl = LLSLURL("secondlife://Aditi/app/foo/bar?12345"); - ensure_equals("app", slurl.getType(), LLSLURL::APP); - ensure_equals("appcmd", slurl.getAppCmd(), "foo"); - ensure_equals("apppath", slurl.getAppPath().size(), 1); - ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar"); - ensure_equals("appquery", slurl.getAppQuery(), "12345"); - ensure_equals("grid2", slurl.getGrid(), "Aditi"); + UNSCOPED_INFO("app"); + CHECK(slurl.getType() == LLSLURL::APP); + UNSCOPED_INFO("appcmd"); + CHECK(slurl.getAppCmd() == "foo"); + UNSCOPED_INFO("apppath"); + REQUIRE(slurl.getAppPath().size() == 1); + UNSCOPED_INFO("apppath2"); + CHECK(slurl.getAppPath()[0].asString() == "bar"); + UNSCOPED_INFO("appquery"); + CHECK(slurl.getAppQuery() == "12345"); + UNSCOPED_INFO("grid2"); + CHECK(slurl.getGrid() == "Aditi"); LLGridManager::getInstance()->setGridChoice("foo.bar.com"); slurl = LLSLURL("secondlife:///secondlife/myregion/1/2/3"); - ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("location", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("region" , "myregion", slurl.getRegion()); - ensure_equals("grid3", slurl.getGrid(), "util.agni.lindenlab.com"); + UNSCOPED_INFO("/: slurl, region + coords - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("location"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("region"); + CHECK("myregion" == slurl.getRegion()); + UNSCOPED_INFO("grid3"); + CHECK(slurl.getGrid() == "util.agni.lindenlab.com"); slurl = LLSLURL("secondlife://Aditi/secondlife/myregion/1/2/3"); - ensure_equals("/: slurl, region + coords - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("location", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("region" , "myregion", slurl.getRegion()); - ensure_equals("grid4", slurl.getGrid(), "Aditi" ); + UNSCOPED_INFO("/: slurl, region + coords - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("location"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("region"); + CHECK("myregion" == slurl.getRegion()); + UNSCOPED_INFO("grid4"); + CHECK(slurl.getGrid() == "Aditi"); LLGridManager::getInstance()->setGridChoice("my.grid.com"); slurl = LLSLURL("https://my.grid.com/app/foo/bar?12345"); - ensure_equals("app", slurl.getType(), LLSLURL::APP); - ensure_equals("appcmd", slurl.getAppCmd(), "foo"); - ensure_equals("apppath", slurl.getAppPath().size(), 1); - ensure_equals("apppath2", slurl.getAppPath()[0].asString(), "bar"); - ensure_equals("appquery", slurl.getAppQuery(), "12345"); + UNSCOPED_INFO("app"); + CHECK(slurl.getType() == LLSLURL::APP); + UNSCOPED_INFO("appcmd"); + CHECK(slurl.getAppCmd() == "foo"); + UNSCOPED_INFO("apppath"); + REQUIRE(slurl.getAppPath().size() == 1); + UNSCOPED_INFO("apppath2"); + CHECK(slurl.getAppPath()[0].asString() == "bar"); + UNSCOPED_INFO("appquery"); + CHECK(slurl.getAppQuery() == "12345"); } // construction from grid/region/vector combos - template<> template<> - void slurlTestObject::test<2>() + TEST_CASE_METHOD(slurlTest, "LLSlurl: construction from grid/region/vector combos", "[LLSlurl]") { llofstream gridfile(TEST_FILENAME); gridfile << gSampleGridFile; @@ -334,31 +379,38 @@ namespace tut LLGridManager::getInstance()->initialize(TEST_FILENAME); LLSLURL slurl = LLSLURL("my.grid.com", "my region"); - ensure_equals("grid/region - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals("grid/region", slurl.getSLURLString(), + UNSCOPED_INFO("grid/region - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO("grid/region"); + CHECK(slurl.getSLURLString() == "https://my.grid.com/region/my%20region/128/128/0"); slurl = LLSLURL("my.grid.com", "my region", LLVector3(1,2,3)); - ensure_equals("grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals(" grid/region/vector", slurl.getSLURLString(), + UNSCOPED_INFO("grid/region/vector - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO(" grid/region/vector"); + CHECK(slurl.getSLURLString() == "https://my.grid.com/region/my%20region/1/2/3"); LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com"); slurl = LLSLURL("my region", LLVector3(1,2,3)); - ensure_equals("default grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals(" default grid/region/vector", slurl.getSLURLString(), + UNSCOPED_INFO("default grid/region/vector - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO(" default grid/region/vector"); + CHECK(slurl.getSLURLString() == "https://maps.secondlife.com/secondlife/my%20region/1/2/3"); LLGridManager::getInstance()->setGridChoice("MyGrid"); slurl = LLSLURL("my region", LLVector3(1,2,3)); - ensure_equals("default grid/region/vector - type", slurl.getType(), LLSLURL::LOCATION); - ensure_equals(" default grid/region/vector", slurl.getSLURLString(), + UNSCOPED_INFO("default grid/region/vector - type"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + UNSCOPED_INFO(" default grid/region/vector"); + CHECK(slurl.getSLURLString() == "https://my.grid.com/region/my%20region/1/2/3"); } // Accessors - template<> template<> - void slurlTestObject::test<3>() + TEST_CASE_METHOD(slurlTest, "LLSlurl: the accessors give the login and location strings and the parts", "[LLSlurl]") { llofstream gridfile(TEST_FILENAME); gridfile << gSampleGridFile; @@ -368,11 +420,16 @@ namespace tut LLGridManager::getInstance()->setGridChoice("my.grid.com"); LLSLURL slurl = LLSLURL("https://my.grid.com/region/my%20region/1/2/3"); - ensure_equals("login string", slurl.getLoginString(), "uri:my region&1&2&3"); - ensure_equals("location string", slurl.getLocationString(), "my region/1/2/3"); - ensure_equals("grid", slurl.getGrid(), "my.grid.com"); - ensure_equals("region", slurl.getRegion(), "my region"); - ensure_equals("position", slurl.getPosition(), LLVector3(1, 2, 3)); + UNSCOPED_INFO("login string"); + CHECK(slurl.getLoginString() == "uri:my region&1&2&3"); + UNSCOPED_INFO("location string"); + CHECK(slurl.getLocationString() == "my region/1/2/3"); + UNSCOPED_INFO("grid"); + CHECK(slurl.getGrid() == "my.grid.com"); + UNSCOPED_INFO("region"); + CHECK(slurl.getRegion() == "my region"); + UNSCOPED_INFO("position"); + CHECK(slurl.getPosition() == LLVector3(1, 2, 3)); } } diff --git a/indra/newview/tests/lltextureinfo_test.cpp b/indra/newview/tests/lltextureinfo_test.cpp index 2dcab18c14..747ff2125c 100644 --- a/indra/newview/tests/lltextureinfo_test.cpp +++ b/indra/newview/tests/lltextureinfo_test.cpp @@ -40,7 +40,7 @@ #include "../llvocache.h" // Tut header -#include "../test/lltut.h" +#include // ------------------------------------------------------------------------------------------- // Stubbing: Declarations required to link and run the class being tested @@ -89,7 +89,7 @@ LLVOCache::~LLVOCache() {} // TUT // ------------------------------------------------------------------------------------------- -namespace tut +namespace { // Test wrapper declarations struct textureinfo_test @@ -103,12 +103,6 @@ namespace tut } }; - // Tut templating thingamagic: test group, object and test instance - typedef test_group textureinfo_t; - typedef textureinfo_t::object textureinfo_object_t; - tut::textureinfo_t tut_textureinfo("LLTectureInfo"); - - // --------------------------------------------------------------------------------------- // Test functions // Notes: @@ -123,28 +117,26 @@ namespace tut // Test instantiation - template<> template<> - void textureinfo_object_t::test<1>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: an LLTextureInfo is made with logging on", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); - ensure("have we crashed?", true); + UNSCOPED_INFO("have we crashed?"); + CHECK(true); } // Check lltextureinfo does not contain UUIDs we haven't added - template<> template<> - void textureinfo_object_t::test<2>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: has() is false for a UUID never added", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1"); - ensure(!tex_info.has(nonExistant)); + REQUIRE_FALSE(tex_info.has(nonExistant)); } // Check we can add a request time for a texture - template<> template<> - void textureinfo_object_t::test<3>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: a request start time set is read back", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); @@ -152,34 +144,31 @@ namespace tut LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3"); tex_info.setRequestStartTime(id, 200); - ensure_equals(tex_info.getRequestStartTime(id), 200); + CHECK(tex_info.getRequestStartTime(id) == 200); } // Check time for non-existant texture - template<> template<> - void textureinfo_object_t::test<4>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: an unknown texture's request start time is 0", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1"); - ensure_equals(tex_info.getRequestStartTime(nonExistant), 0); + CHECK(tex_info.getRequestStartTime(nonExistant) == 0); } // Check download complete time for non existant texture - template<> template<> - void textureinfo_object_t::test<5>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: an unknown texture's request complete time is 0", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1"); - ensure_equals(tex_info.getRequestCompleteTime(nonExistant), 0); + CHECK(tex_info.getRequestCompleteTime(nonExistant) == 0); } // requested size is passed in correctly - template<> template<> - void textureinfo_object_t::test<6>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: a request size set is read back", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); @@ -187,12 +176,11 @@ namespace tut LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3"); tex_info.setRequestSize(id, 600); - ensure_equals(tex_info.getRequestSize(id), 600); + CHECK(tex_info.getRequestSize(id) == 600); } // transport type is recorded correctly (http) - template<> template<> - void textureinfo_object_t::test<7>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: an HTTP request type is recorded", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); @@ -200,12 +188,11 @@ namespace tut LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3"); tex_info.setRequestType(id, LLTextureInfoDetails::REQUEST_TYPE_HTTP); - ensure_equals(tex_info.getRequestType(id), LLTextureInfoDetails::REQUEST_TYPE_HTTP); + CHECK(tex_info.getRequestType(id) == LLTextureInfoDetails::REQUEST_TYPE_HTTP); } // transport type is recorded correctly (udp) - template<> template<> - void textureinfo_object_t::test<8>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: a UDP request type is recorded", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); @@ -213,12 +200,11 @@ namespace tut LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3"); tex_info.setRequestType(id, LLTextureInfoDetails::REQUEST_TYPE_UDP); - ensure_equals(tex_info.getRequestType(id), LLTextureInfoDetails::REQUEST_TYPE_UDP); + CHECK(tex_info.getRequestType(id) == LLTextureInfoDetails::REQUEST_TYPE_UDP); } // request offset is recorded correctly - template<> template<> - void textureinfo_object_t::test<9>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: a request offset set is read back", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); @@ -226,14 +212,13 @@ namespace tut LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3"); tex_info.setRequestOffset(id, 1234); - ensure_equals(tex_info.getRequestOffset(id), 1234); + CHECK(tex_info.getRequestOffset(id) == 1234); } // ask for averages gives us correct figure - template<> template<> - void textureinfo_object_t::test<10>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: getAverages gives the bit rate and bytes and transport", "[LLTectureInfo]") { - skip("Test skipped due to use of LLTrace stats failing in test"); + SKIP("Test skipped due to use of LLTrace stats failing in test"); LLTextureInfo tex_info; tex_info.setLogging(true); @@ -265,14 +250,16 @@ namespace tut S32 totalBytes = requestSizeOne + requestSizeTwo; LLSD results = tex_info.getAverages(); - ensure_equals("is average bits per second correct", results["bits_per_second"].asInteger(), averageBitRate); - ensure_equals("is total bytes is correct", results["bytes_downloaded"].asInteger(), totalBytes); - ensure_equals("is transport correct", results["transport"].asString(), std::string("HTTP")); + UNSCOPED_INFO("is average bits per second correct"); + CHECK(results["bits_per_second"].asInteger() == averageBitRate); + UNSCOPED_INFO("is total bytes is correct"); + CHECK(results["bytes_downloaded"].asInteger() == totalBytes); + UNSCOPED_INFO("is transport correct"); + CHECK(results["transport"].asString() == std::string("HTTP")); } // make sure averages cleared when reset is called - template<> template<> - void textureinfo_object_t::test<11>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: resetTextureStatistics clears the averages", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); @@ -289,14 +276,16 @@ namespace tut tex_info.getAverages(); tex_info.resetTextureStatistics(); LLSD results = tex_info.getAverages(); - ensure_equals("is average bits per second correct", results["bits_per_second"].asInteger(), 0); - ensure_equals("is total bytes is correct", results["bytes_downloaded"].asInteger(), 0); - ensure_equals("is transport correct", results["transport"].asString(), std::string("NONE")); + UNSCOPED_INFO("is average bits per second correct"); + CHECK(results["bits_per_second"].asInteger() == 0); + UNSCOPED_INFO("is total bytes is correct"); + CHECK(results["bytes_downloaded"].asInteger() == 0); + UNSCOPED_INFO("is transport correct"); + CHECK(results["transport"].asString() == std::string("NONE")); } // make sure map item removed when expired - template<> template<> - void textureinfo_object_t::test<12>() + TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: a request's map entry goes once it completes", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); @@ -309,11 +298,13 @@ namespace tut tex_info.setRequestSize(id1, requestSizeOne); tex_info.setRequestType(id1, LLTextureInfoDetails::REQUEST_TYPE_HTTP); - ensure_equals("map item created", tex_info.getTextureInfoMapSize(), 1); + UNSCOPED_INFO("map item created"); + CHECK(tex_info.getTextureInfoMapSize() == 1); tex_info.setRequestCompleteTimeAndLog(id1, requestEndTimeOne); - ensure_equals("map item removed when consumed", tex_info.getTextureInfoMapSize(), 0); + UNSCOPED_INFO("map item removed when consumed"); + CHECK(tex_info.getTextureInfoMapSize() == 0); } } diff --git a/indra/newview/tests/llversioninfo_test.cpp b/indra/newview/tests/llversioninfo_test.cpp index 2e217c7a19..c7d80869b4 100644 --- a/indra/newview/tests/llversioninfo_test.cpp +++ b/indra/newview/tests/llversioninfo_test.cpp @@ -25,7 +25,7 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include #include "../llversioninfo.h" @@ -38,7 +38,7 @@ // need to turn it into a quoted string. LL_TO_STRING() does that. #define ll_viewer_channel LL_TO_STRING(LL_VIEWER_CHANNEL) -namespace tut +namespace { struct versioninfo { @@ -77,38 +77,33 @@ namespace tut std::string mResetVersionAndChannel; }; - typedef test_group versioninfo_t; - typedef versioninfo_t::object versioninfo_object_t; - tut::versioninfo_t tut_versioninfo("LLVersionInfo"); - - template<> template<> - void versioninfo_object_t::test<1>() + TEST_CASE_METHOD(versioninfo, "LLVersionInfo: the version and channel are the build's until resetChannel", "[LLVersionInfo]") { std::cout << "What we parsed from CMake: " << LL_VIEWER_VERSION_BUILD << std::endl; std::cout << "What we get from llversioninfo: " << LLVersionInfo::instance().getBuild() << std::endl; - ensure_equals("Major version", - LLVersionInfo::instance().getMajor(), + UNSCOPED_INFO("Major version"); + CHECK(LLVersionInfo::instance().getMajor() == LL_VIEWER_VERSION_MAJOR); - ensure_equals("Minor version", - LLVersionInfo::instance().getMinor(), + UNSCOPED_INFO("Minor version"); + CHECK(LLVersionInfo::instance().getMinor() == LL_VIEWER_VERSION_MINOR); - ensure_equals("Patch version", - LLVersionInfo::instance().getPatch(), + UNSCOPED_INFO("Patch version"); + CHECK(LLVersionInfo::instance().getPatch() == LL_VIEWER_VERSION_PATCH); - ensure_equals("Build version", - LLVersionInfo::instance().getBuild(), + UNSCOPED_INFO("Build version"); + CHECK(LLVersionInfo::instance().getBuild() == LL_VIEWER_VERSION_BUILD); - ensure_equals("Channel version", - LLVersionInfo::instance().getChannel(), + UNSCOPED_INFO("Channel version"); + CHECK(LLVersionInfo::instance().getChannel() == ll_viewer_channel); - ensure_equals("Version String", - LLVersionInfo::instance().getVersion(), + UNSCOPED_INFO("Version String"); + CHECK(LLVersionInfo::instance().getVersion() == mVersion); - ensure_equals("Short Version String", - LLVersionInfo::instance().getShortVersion(), + UNSCOPED_INFO("Short Version String"); + CHECK(LLVersionInfo::instance().getShortVersion() == mShortVersion); - ensure_equals("Version and channel String", - LLVersionInfo::instance().getChannelAndVersion(), + UNSCOPED_INFO("Version and channel String"); + CHECK(LLVersionInfo::instance().getChannelAndVersion() == mVersionAndChannel); // The channel is the process's: put back however this ends. @@ -118,12 +113,12 @@ namespace tut ~ChannelBack() { LLVersionInfo::instance().resetChannel(was); } } channel_back; LLVersionInfo::instance().resetChannel(mResetChannel); - ensure_equals("Reset channel version", - LLVersionInfo::instance().getChannel(), + UNSCOPED_INFO("Reset channel version"); + CHECK(LLVersionInfo::instance().getChannel() == mResetChannel); - ensure_equals("Reset Version and channel String", - LLVersionInfo::instance().getChannelAndVersion(), + UNSCOPED_INFO("Reset Version and channel String"); + CHECK(LLVersionInfo::instance().getChannelAndVersion() == mResetVersionAndChannel); } } diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index 323affaded..8331445466 100644 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -27,10 +27,9 @@ #include "linden_common.h" -#include +#include #include -#include "lltut.h" #include "../llviewerassetstats.h" #include "lluuid.h" #include "llsdutil.h" @@ -237,10 +236,8 @@ get_region(const LLSD & sd, U64 region_handle1) return LLSD(); } -namespace tut +namespace { - namespace - { // The fixture's ThreadRecorder makes itself this thread's recorder, // with its own timer stack and current accumulators, and leaves all // of them null when it goes; the fixture makes it the master recorder @@ -270,7 +267,6 @@ namespace tut Current::setInstance(mTimers); } }; - } // anonymous namespace struct tst_viewerassetstats_index { @@ -288,16 +284,13 @@ namespace tut RecorderRestore mRestore; LLTrace::ThreadRecorder mThreadRecorder; }; - typedef test_group tst_viewerassetstats_index_t; - typedef tst_viewerassetstats_index_t::object tst_viewerassetstats_index_object_t; - tut::tst_viewerassetstats_index_t tut_tst_viewerassetstats_index("tst_viewerassetstats_test"); // Testing free functions without global stats allocated - template<> template<> - void tst_viewerassetstats_index_object_t::test<1>() + TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: the free functions run without global stats allocated", "[tst_viewerassetstats_test]") { // Check that helpers aren't bothered by missing global stats - ensure("Global gViewerAssetStats should be NULL", (NULL == gViewerAssetStats)); + UNSCOPED_INFO("Global gViewerAssetStats should be NULL"); + REQUIRE((NULL == gViewerAssetStats)); LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE, false, false); @@ -307,26 +300,30 @@ namespace tut } // Create a non-global instance and check the structure - template<> template<> - void tst_viewerassetstats_index_object_t::test<2>() + TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: a non-global instance's LLSD has every key", "[tst_viewerassetstats_test]") { - ensure("Global gViewerAssetStats should be NULL", (NULL == gViewerAssetStats)); + UNSCOPED_INFO("Global gViewerAssetStats should be NULL"); + REQUIRE((NULL == gViewerAssetStats)); LLViewerAssetStats * it = new LLViewerAssetStats(); - ensure("Global gViewerAssetStats should still be NULL", (NULL == gViewerAssetStats)); + UNSCOPED_INFO("Global gViewerAssetStats should still be NULL"); + REQUIRE((NULL == gViewerAssetStats)); LLSD sd_full = it->asLLSD(false); // Default (NULL) region ID doesn't produce LLSD results so should // get an empty map back from output - ensure("Stat-less LLSD initially", is_no_stats_map(sd_full)); + UNSCOPED_INFO("Stat-less LLSD initially"); + CHECK(is_no_stats_map(sd_full)); // Once the region is set, we will get a response even with no data collection it->setRegion(region1_handle); sd_full = it->asLLSD(false); - ensure("Correct single-key LLSD map root", is_double_key_map(sd_full, "duration", "regions")); - ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd_full["regions"], region1_handle)); + UNSCOPED_INFO("Correct single-key LLSD map root"); + CHECK(is_double_key_map(sd_full, "duration", "regions")); + UNSCOPED_INFO("Correct single-slot LLSD array regions"); + CHECK(is_single_slot_array(sd_full["regions"], region1_handle)); LLSD sd = sd_full["regions"][0]; @@ -336,7 +333,8 @@ namespace tut for (int i = 0; i < LL_ARRAY_SIZE(all_keys); ++i) { std::string line = llformat("Has '%s' key", all_keys[i]); - ensure(line, sd.has(all_keys[i])); + UNSCOPED_INFO(line); + REQUIRE(sd.has(all_keys[i])); } for (int i = 0; i < LL_ARRAY_SIZE(resp_keys); ++i) @@ -344,7 +342,8 @@ namespace tut for (int j = 0; j < LL_ARRAY_SIZE(sub_keys); ++j) { std::string line = llformat("Key '%s' has '%s' key", resp_keys[i], sub_keys[j]); - ensure(line, sd[resp_keys[i]].has(sub_keys[j])); + UNSCOPED_INFO(line); + REQUIRE(sd[resp_keys[i]].has(sub_keys[j])); } } @@ -353,33 +352,36 @@ namespace tut for (int j = 0; j < LL_ARRAY_SIZE(mmm_sub_keys); ++j) { std::string line = llformat("Key '%s' has '%s' key", mmm_resp_keys[i], mmm_sub_keys[j]); - ensure(line, sd[mmm_resp_keys[i]].has(mmm_sub_keys[j])); + UNSCOPED_INFO(line); + REQUIRE(sd[mmm_resp_keys[i]].has(mmm_sub_keys[j])); } } } // Create a non-global instance and check some content - template<> template<> - void tst_viewerassetstats_index_object_t::test<3>() + TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: a new non-global instance's counts start at zero", "[tst_viewerassetstats_test]") { LLViewerAssetStats * it = new LLViewerAssetStats(); it->setRegion(region1_handle); LLSD sd = it->asLLSD(false); - ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); - ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle)); + UNSCOPED_INFO("Correct single-key LLSD map root"); + CHECK(is_double_key_map(sd, "regions", "duration")); + UNSCOPED_INFO("Correct single-slot LLSD array regions"); + CHECK(is_single_slot_array(sd["regions"], region1_handle)); sd = sd[0]; delete it; // Check a few points on the tree for content - ensure("sd[get_texture_temp_http][dequeued] is 0", (0 == sd["get_texture_temp_http"]["dequeued"].asInteger())); - ensure("sd[get_sound_udp][resp_min] is 0", (0.0 == sd["get_sound_udp"]["resp_min"].asReal())); + UNSCOPED_INFO("sd[get_texture_temp_http][dequeued] is 0"); + CHECK(sd["get_texture_temp_http"]["dequeued"].asInteger() == 0); + UNSCOPED_INFO("sd[get_sound_udp][resp_min] is 0"); + CHECK(sd["get_sound_udp"]["resp_min"].asReal() == 0.0); } // Create a global instance and verify free functions do something useful - template<> template<> - void tst_viewerassetstats_index_object_t::test<4>() + TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: the free functions record into a global instance and reset clears it", "[tst_viewerassetstats_test]") { gViewerAssetStats = new LLViewerAssetStats(); LLViewerAssetStatsFF::set_region(region1_handle); @@ -391,16 +393,23 @@ namespace tut LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_BODYPART, false, false); LLSD sd = gViewerAssetStats->asLLSD(false); - ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); - ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle)); + UNSCOPED_INFO("Correct single-key LLSD map root"); + CHECK(is_double_key_map(sd, "regions", "duration")); + UNSCOPED_INFO("Correct single-slot LLSD array regions"); + CHECK(is_single_slot_array(sd["regions"], region1_handle)); sd = sd["regions"][0]; // Check a few points on the tree for content - ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); - ensure("sd[get_texture_temp_udp][enqueued] is 0", (0 == sd["get_texture_temp_udp"]["enqueued"].asInteger())); - ensure("sd[get_texture_non_temp_http][enqueued] is 0", (0 == sd["get_texture_non_temp_http"]["enqueued"].asInteger())); - ensure("sd[get_texture_temp_http][enqueued] is 0", (0 == sd["get_texture_temp_http"]["enqueued"].asInteger())); - ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + UNSCOPED_INFO("sd[get_texture_non_temp_udp][enqueued] is 1"); + CHECK(sd["get_texture_non_temp_udp"]["enqueued"].asInteger() == 1); + UNSCOPED_INFO("sd[get_texture_temp_udp][enqueued] is 0"); + CHECK(sd["get_texture_temp_udp"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd[get_texture_non_temp_http][enqueued] is 0"); + CHECK(sd["get_texture_non_temp_http"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd[get_texture_temp_http][enqueued] is 0"); + CHECK(sd["get_texture_temp_http"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd[get_gesture_udp][dequeued] is 0"); + CHECK(sd["get_gesture_udp"]["dequeued"].asInteger() == 0); // Reset and check zeros... // Reset leaves current region in place @@ -410,13 +419,14 @@ namespace tut delete gViewerAssetStats; gViewerAssetStats = NULL; - ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); - ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + UNSCOPED_INFO("sd[get_texture_non_temp_udp][enqueued] is reset"); + CHECK(sd["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd[get_gesture_udp][dequeued] is reset"); + CHECK(sd["get_gesture_udp"]["dequeued"].asInteger() == 0); } // Check multiple region collection - template<> template<> - void tst_viewerassetstats_index_object_t::test<5>() + TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: stats are collected per region across two regions", "[tst_viewerassetstats_test]") { gViewerAssetStats = new LLViewerAssetStats(); @@ -439,43 +449,58 @@ namespace tut // std::cout << sd << std::endl; - ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions")); - ensure("Correct double-slot LLSD array regions", is_double_slot_array(sd["regions"], region1_handle, region2_handle)); + UNSCOPED_INFO("Correct double-key LLSD map root"); + CHECK(is_double_key_map(sd, "duration", "regions")); + UNSCOPED_INFO("Correct double-slot LLSD array regions"); + CHECK(is_double_slot_array(sd["regions"], region1_handle, region2_handle)); LLSD sd1 = get_region(sd, region1_handle); LLSD sd2 = get_region(sd, region2_handle); - ensure("Region1 is present in results", sd1.isMap()); - ensure("Region2 is present in results", sd2.isMap()); + UNSCOPED_INFO("Region1 is present in results"); + REQUIRE(sd1.isMap()); + UNSCOPED_INFO("Region2 is present in results"); + REQUIRE(sd2.isMap()); // Check a few points on the tree for content - ensure_equals("sd1[get_texture_non_temp_udp][enqueued] is 1", sd1["get_texture_non_temp_udp"]["enqueued"].asInteger(), 1); - ensure_equals("sd1[get_texture_temp_udp][enqueued] is 0", sd1["get_texture_temp_udp"]["enqueued"].asInteger(), 0); - ensure_equals("sd1[get_texture_non_temp_http][enqueued] is 0", sd1["get_texture_non_temp_http"]["enqueued"].asInteger(), 0); - ensure_equals("sd1[get_texture_temp_http][enqueued] is 0", sd1["get_texture_temp_http"]["enqueued"].asInteger(), 0); - ensure_equals("sd1[get_gesture_udp][dequeued] is 0", sd1["get_gesture_udp"]["dequeued"].asInteger(), 0); + UNSCOPED_INFO("sd1[get_texture_non_temp_udp][enqueued] is 1"); + CHECK(sd1["get_texture_non_temp_udp"]["enqueued"].asInteger() == 1); + UNSCOPED_INFO("sd1[get_texture_temp_udp][enqueued] is 0"); + CHECK(sd1["get_texture_temp_udp"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd1[get_texture_non_temp_http][enqueued] is 0"); + CHECK(sd1["get_texture_non_temp_http"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd1[get_texture_temp_http][enqueued] is 0"); + CHECK(sd1["get_texture_temp_http"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd1[get_gesture_udp][dequeued] is 0"); + CHECK(sd1["get_gesture_udp"]["dequeued"].asInteger() == 0); // Check a few points on the tree for content - ensure("sd2[get_gesture_udp][enqueued] is 4", (4 == sd2["get_gesture_udp"]["enqueued"].asInteger())); - ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger())); - ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + UNSCOPED_INFO("sd2[get_gesture_udp][enqueued] is 4"); + CHECK(sd2["get_gesture_udp"]["enqueued"].asInteger() == 4); + UNSCOPED_INFO("sd2[get_gesture_udp][dequeued] is 0"); + CHECK(sd2["get_gesture_udp"]["dequeued"].asInteger() == 0); + UNSCOPED_INFO("sd2[get_texture_non_temp_udp][enqueued] is 0"); + CHECK(sd2["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); // Reset and check zeros... // Reset leaves current region in place gViewerAssetStats->reset(); sd = gViewerAssetStats->asLLSD(false); - ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); - ensure("Correct single-slot LLSD array regions (p2)", is_single_slot_array(sd["regions"], region2_handle)); + UNSCOPED_INFO("Correct single-key LLSD map root"); + CHECK(is_double_key_map(sd, "regions", "duration")); + UNSCOPED_INFO("Correct single-slot LLSD array regions (p2)"); + CHECK(is_single_slot_array(sd["regions"], region2_handle)); sd2 = sd["regions"][0]; delete gViewerAssetStats; gViewerAssetStats = NULL; - ensure("sd2[get_texture_non_temp_udp][enqueued] is reset", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); - ensure("sd2[get_gesture_udp][enqueued] is reset", (0 == sd2["get_gesture_udp"]["enqueued"].asInteger())); + UNSCOPED_INFO("sd2[get_texture_non_temp_udp][enqueued] is reset"); + CHECK(sd2["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd2[get_gesture_udp][enqueued] is reset"); + CHECK(sd2["get_gesture_udp"]["enqueued"].asInteger() == 0); } // Check multiple region collection jumping back-and-forth between regions - template<> template<> - void tst_viewerassetstats_index_object_t::test<6>() + TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: stats per region add up across moves back and forth between regions", "[tst_viewerassetstats_test]") { gViewerAssetStats = new LLViewerAssetStats(); @@ -511,44 +536,60 @@ namespace tut LLSD sd = gViewerAssetStats->asLLSD(false); - ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions")); - ensure("Correct double-slot LLSD array regions", is_double_slot_array(sd["regions"], region1_handle, region2_handle)); + UNSCOPED_INFO("Correct double-key LLSD map root"); + CHECK(is_double_key_map(sd, "duration", "regions")); + UNSCOPED_INFO("Correct double-slot LLSD array regions"); + CHECK(is_double_slot_array(sd["regions"], region1_handle, region2_handle)); LLSD sd1 = get_region(sd, region1_handle); LLSD sd2 = get_region(sd, region2_handle); - ensure("Region1 is present in results", sd1.isMap()); - ensure("Region2 is present in results", sd2.isMap()); + UNSCOPED_INFO("Region1 is present in results"); + REQUIRE(sd1.isMap()); + UNSCOPED_INFO("Region2 is present in results"); + REQUIRE(sd2.isMap()); // Check a few points on the tree for content - ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger())); - ensure("sd1[get_texture_temp_udp][enqueued] is 0", (0 == sd1["get_texture_temp_udp"]["enqueued"].asInteger())); - ensure("sd1[get_texture_non_temp_http][enqueued] is 0", (0 == sd1["get_texture_non_temp_http"]["enqueued"].asInteger())); - ensure("sd1[get_texture_temp_http][enqueued] is 1", (1 == sd1["get_texture_temp_http"]["enqueued"].asInteger())); - ensure("sd1[get_gesture_udp][dequeued] is 0", (0 == sd1["get_gesture_udp"]["dequeued"].asInteger())); + UNSCOPED_INFO("sd1[get_texture_non_temp_udp][enqueued] is 1"); + CHECK(sd1["get_texture_non_temp_udp"]["enqueued"].asInteger() == 1); + UNSCOPED_INFO("sd1[get_texture_temp_udp][enqueued] is 0"); + CHECK(sd1["get_texture_temp_udp"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd1[get_texture_non_temp_http][enqueued] is 0"); + CHECK(sd1["get_texture_non_temp_http"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd1[get_texture_temp_http][enqueued] is 1"); + CHECK(sd1["get_texture_temp_http"]["enqueued"].asInteger() == 1); + UNSCOPED_INFO("sd1[get_gesture_udp][dequeued] is 0"); + CHECK(sd1["get_gesture_udp"]["dequeued"].asInteger() == 0); // Check a few points on the tree for content - ensure("sd2[get_gesture_udp][enqueued] is 8", (8 == sd2["get_gesture_udp"]["enqueued"].asInteger())); - ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger())); - ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + UNSCOPED_INFO("sd2[get_gesture_udp][enqueued] is 8"); + CHECK(sd2["get_gesture_udp"]["enqueued"].asInteger() == 8); + UNSCOPED_INFO("sd2[get_gesture_udp][dequeued] is 0"); + CHECK(sd2["get_gesture_udp"]["dequeued"].asInteger() == 0); + UNSCOPED_INFO("sd2[get_texture_non_temp_udp][enqueued] is 0"); + CHECK(sd2["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); // Reset and check zeros... // Reset leaves current region in place gViewerAssetStats->reset(); sd = gViewerAssetStats->asLLSD(false); - ensure("Correct single-key LLSD map root", is_double_key_map(sd, "duration", "regions")); - ensure("Correct single-slot LLSD array regions (p2)", is_single_slot_array(sd["regions"], region2_handle)); + UNSCOPED_INFO("Correct single-key LLSD map root"); + CHECK(is_double_key_map(sd, "duration", "regions")); + UNSCOPED_INFO("Correct single-slot LLSD array regions (p2)"); + CHECK(is_single_slot_array(sd["regions"], region2_handle)); sd2 = get_region(sd, region2_handle); - ensure("Region2 is present in results", sd2.isMap()); + UNSCOPED_INFO("Region2 is present in results"); + REQUIRE(sd2.isMap()); delete gViewerAssetStats; gViewerAssetStats = NULL; - ensure_equals("sd2[get_texture_non_temp_udp][enqueued] is reset", sd2["get_texture_non_temp_udp"]["enqueued"].asInteger(), 0); - ensure_equals("sd2[get_gesture_udp][enqueued] is reset", sd2["get_gesture_udp"]["enqueued"].asInteger(), 0); + UNSCOPED_INFO("sd2[get_texture_non_temp_udp][enqueued] is reset"); + CHECK(sd2["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd2[get_gesture_udp][enqueued] is reset"); + CHECK(sd2["get_gesture_udp"]["enqueued"].asInteger() == 0); } // Non-texture assets ignore transport and persistence flags - template<> template<> - void tst_viewerassetstats_index_object_t::test<7>() + TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: non-texture assets ignore the transport and persistence flags", "[tst_viewerassetstats_test]") { gViewerAssetStats = new LLViewerAssetStats(); LLViewerAssetStatsFF::set_region(region1_handle); @@ -577,37 +618,53 @@ namespace tut LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_LSL_BYTECODE, true, true); LLSD sd = gViewerAssetStats->asLLSD(false); - ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); - ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle)); + UNSCOPED_INFO("Correct single-key LLSD map root"); + CHECK(is_double_key_map(sd, "regions", "duration")); + UNSCOPED_INFO("Correct single-slot LLSD array regions"); + CHECK(is_single_slot_array(sd["regions"], region1_handle)); sd = get_region(sd, region1_handle); - ensure("Region1 is present in results", sd.isMap()); + UNSCOPED_INFO("Region1 is present in results"); + REQUIRE(sd.isMap()); // Check a few points on the tree for content - ensure("sd[get_gesture_udp][enqueued] is 0", (0 == sd["get_gesture_udp"]["enqueued"].asInteger())); - ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); - - ensure("sd[get_wearable_http][enqueued] is 2", (2 == sd["get_wearable_http"]["enqueued"].asInteger())); - ensure("sd[get_wearable_http][dequeued] is 2", (2 == sd["get_wearable_http"]["dequeued"].asInteger())); - - ensure("sd[get_wearable_udp][enqueued] is 2", (2 == sd["get_wearable_udp"]["enqueued"].asInteger())); - ensure("sd[get_wearable_udp][dequeued] is 2", (2 == sd["get_wearable_udp"]["dequeued"].asInteger())); - - ensure("sd[get_other_http][enqueued] is 2", (2 == sd["get_other_http"]["enqueued"].asInteger())); - ensure("sd[get_other_http][dequeued] is 0", (0 == sd["get_other_http"]["dequeued"].asInteger())); - - ensure("sd[get_other_udp][enqueued] is 2", (2 == sd["get_other_udp"]["enqueued"].asInteger())); - ensure("sd[get_other_udp][dequeued] is 0", (0 == sd["get_other_udp"]["dequeued"].asInteger())); + UNSCOPED_INFO("sd[get_gesture_udp][enqueued] is 0"); + CHECK(sd["get_gesture_udp"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd[get_gesture_udp][dequeued] is 0"); + CHECK(sd["get_gesture_udp"]["dequeued"].asInteger() == 0); + + UNSCOPED_INFO("sd[get_wearable_http][enqueued] is 2"); + CHECK(sd["get_wearable_http"]["enqueued"].asInteger() == 2); + UNSCOPED_INFO("sd[get_wearable_http][dequeued] is 2"); + CHECK(sd["get_wearable_http"]["dequeued"].asInteger() == 2); + + UNSCOPED_INFO("sd[get_wearable_udp][enqueued] is 2"); + CHECK(sd["get_wearable_udp"]["enqueued"].asInteger() == 2); + UNSCOPED_INFO("sd[get_wearable_udp][dequeued] is 2"); + CHECK(sd["get_wearable_udp"]["dequeued"].asInteger() == 2); + + UNSCOPED_INFO("sd[get_other_http][enqueued] is 2"); + CHECK(sd["get_other_http"]["enqueued"].asInteger() == 2); + UNSCOPED_INFO("sd[get_other_http][dequeued] is 0"); + CHECK(sd["get_other_http"]["dequeued"].asInteger() == 0); + + UNSCOPED_INFO("sd[get_other_udp][enqueued] is 2"); + CHECK(sd["get_other_udp"]["enqueued"].asInteger() == 2); + UNSCOPED_INFO("sd[get_other_udp][dequeued] is 0"); + CHECK(sd["get_other_udp"]["dequeued"].asInteger() == 0); // Reset and check zeros... // Reset leaves current region in place gViewerAssetStats->reset(); sd = get_region(gViewerAssetStats->asLLSD(false), region1_handle); - ensure("Region1 is present in results", sd.isMap()); + UNSCOPED_INFO("Region1 is present in results"); + REQUIRE(sd.isMap()); delete gViewerAssetStats; gViewerAssetStats = NULL; - ensure_equals("sd[get_texture_non_temp_udp][enqueued] is reset", sd["get_texture_non_temp_udp"]["enqueued"].asInteger(), 0); - ensure_equals("sd[get_gesture_udp][dequeued] is reset", sd["get_gesture_udp"]["dequeued"].asInteger(), 0); + UNSCOPED_INFO("sd[get_texture_non_temp_udp][enqueued] is reset"); + CHECK(sd["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); + UNSCOPED_INFO("sd[get_gesture_udp][dequeued] is reset"); + CHECK(sd["get_gesture_udp"]["dequeued"].asInteger() == 0); } } diff --git a/indra/newview/tests/llviewercontrollistener_test.cpp b/indra/newview/tests/llviewercontrollistener_test.cpp index 8fb71b726d..04bf97b560 100644 --- a/indra/newview/tests/llviewercontrollistener_test.cpp +++ b/indra/newview/tests/llviewercontrollistener_test.cpp @@ -17,7 +17,9 @@ // std headers // external library headers // other Linden headers -#include "../test/lltut.h" +#include +#include +#include "altestmatchers.h" #include "../test/catch_and_store_what_in.h" // catch_what() #include "commoncontrol.h" #include "llcontrol.h" // LLControlGroup @@ -27,15 +29,13 @@ /***************************************************************************** * TUT *****************************************************************************/ -namespace tut -{ namespace { void ensure_contains(const std::string& msg, const std::string& substr) { - tut::ensure_contains("Exception does not contain " + substr, msg, substr); + UNSCOPED_INFO("Exception does not contain " + substr); + REQUIRE_THAT(msg, Catch::Matchers::ContainsSubstring(substr)); } -} // anonymous namespace struct llviewercontrollistener_data { @@ -48,120 +48,99 @@ namespace Global.declareBOOL("boolvar", true, "bool variable"); } }; - typedef test_group llviewercontrollistener_group; - typedef llviewercontrollistener_group::object object; - llviewercontrollistener_group llviewercontrollistenergrp("llviewercontrollistener"); - template<> template<> - void object::test<1>() + TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl with no listener is left untested", "[llviewercontrollistener]") { - set_test_name("CommonControl no listener"); // Not implemented: the linker drags in LLViewerControlListener when // we bring in LLViewerControl. } - template<> template<> - void object::test<2>() + TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::get of an unknown group names the group", "[llviewercontrollistener]") { - set_test_name("CommonControl bad group"); std::string threw{ catch_what( [](){ LL::CommonControl::get("Nonexistent", "Variable"); }) }; ensure_contains(threw, "group"); ensure_contains(threw, "Nonexistent"); } - template<> template<> - void object::test<3>() + TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::get of an unknown variable names the key", "[llviewercontrollistener]") { - set_test_name("CommonControl bad variable"); std::string threw{ catch_what( [](){ LL::CommonControl::get("FakeGlobal", "Nonexistent"); }) }; ensure_contains(threw, "key"); ensure_contains(threw, "Nonexistent"); } - template<> template<> - void object::test<4>() + TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::toggle of a string variable says it is non-boolean", "[llviewercontrollistener]") { - set_test_name("CommonControl toggle string"); std::string threw{ catch_what( [](){ LL::CommonControl::toggle("FakeGlobal", "strvar"); }) }; ensure_contains(threw, "non-boolean"); ensure_contains(threw, "strvar"); } - template<> template<> - void object::test<5>() + TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::get_vars of an unknown group names the group", "[llviewercontrollistener]") { - set_test_name("CommonControl list bad group"); std::string threw{ catch_what( [](){ LL::CommonControl::get_vars("Nonexistent"); }) }; ensure_contains(threw, "group"); ensure_contains(threw, "Nonexistent"); } - template<> template<> - void object::test<6>() + TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::get returns each variable's value", "[llviewercontrollistener]") { - set_test_name("CommonControl get"); auto strvar{ LL::CommonControl::get("FakeGlobal", "strvar") }; - ensure_equals(strvar, "woof"); + CHECK(strvar == "woof"); auto boolvar{ LL::CommonControl::get("FakeGlobal", "boolvar") }; - ensure(boolvar); + REQUIRE(boolvar); } - template<> template<> - void object::test<7>() + TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl set and set_default and toggle return the new value", "[llviewercontrollistener]") { - set_test_name("CommonControl set, set_default, toggle"); - std::string newstr{ LL::CommonControl::set("FakeGlobal", "strvar", "mouse").asString() }; - ensure_equals(newstr, "mouse"); - ensure_equals(LL::CommonControl::get("FakeGlobal", "strvar").asString(), "mouse"); - ensure_equals(LL::CommonControl::set_default("FakeGlobal", "strvar").asString(), "woof"); + CHECK(newstr == "mouse"); + CHECK(LL::CommonControl::get("FakeGlobal", "strvar").asString() == "mouse"); + CHECK(LL::CommonControl::set_default("FakeGlobal", "strvar").asString() == "woof"); bool newbool{ LL::CommonControl::set("FakeGlobal", "boolvar", false) }; - ensure(! newbool); - ensure(! LL::CommonControl::get("FakeGlobal", "boolvar").asBoolean()); - ensure(LL::CommonControl::set_default("FakeGlobal", "boolvar").asBoolean()); - ensure(! LL::CommonControl::toggle("FakeGlobal", "boolvar").asBoolean()); + CHECK_FALSE(newbool); + CHECK_FALSE(LL::CommonControl::get("FakeGlobal", "boolvar").asBoolean()); + CHECK(LL::CommonControl::set_default("FakeGlobal", "boolvar").asBoolean()); + CHECK_FALSE(LL::CommonControl::toggle("FakeGlobal", "boolvar").asBoolean()); } - template<> template<> - void object::test<8>() + TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::get_def describes a variable", "[llviewercontrollistener]") { - set_test_name("CommonControl get_def"); LLSD def{ LL::CommonControl::get_def("FakeGlobal", "strvar") }; - ensure_equals( - def, - llsd::map("name", "strvar", + CHECK_THAT(def, + ll_test::LLSDEquals(llsd::map("name", "strvar", "type", "String", "value", "woof", - "comment", "string variable")); + "comment", "string variable"))); } - template<> template<> - void object::test<9>() + TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::get_groups lists each group once while it lives", "[llviewercontrollistener]") { - set_test_name("CommonControl get_groups"); // Every group the process has: the fixture's, and whatever else has // been made -- HeadlessUI's, another test's gSavedSettings. So the // fixture's is there once, and one more group made adds its name. const std::vector groups{ LL::CommonControl::get_groups() }; - ensure_equals("FakeGlobal", std::count(groups.begin(), groups.end(), "FakeGlobal"), std::ptrdiff_t(1)); + UNSCOPED_INFO("FakeGlobal"); + CHECK(std::count(groups.begin(), groups.end(), "FakeGlobal") == std::ptrdiff_t(1)); { LLControlGroup another{ "FakeAnother" }; const std::vector more{ LL::CommonControl::get_groups() }; - ensure_equals("one more", more.size(), groups.size() + 1); - ensure_equals("FakeAnother", std::count(more.begin(), more.end(), "FakeAnother"), std::ptrdiff_t(1)); + UNSCOPED_INFO("one more"); + REQUIRE(more.size() == groups.size() + 1); + UNSCOPED_INFO("FakeAnother"); + CHECK(std::count(more.begin(), more.end(), "FakeAnother") == std::ptrdiff_t(1)); } - ensure_equals("one fewer once it goes", LL::CommonControl::get_groups().size(), groups.size()); + UNSCOPED_INFO("one fewer once it goes"); + REQUIRE(LL::CommonControl::get_groups().size() == groups.size()); } - template<> template<> - void object::test<10>() + TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::get_vars describes every variable of a group", "[llviewercontrollistener]") { - set_test_name("CommonControl get_vars"); LLSD vars{ LL::CommonControl::get_vars("FakeGlobal") }; // convert from array (unpredictable order) to map LLSD varsmap{ LLSD::emptyMap() }; @@ -170,9 +149,8 @@ namespace varsmap[var["name"].asString()] = var; } // comparing maps is order-insensitive - ensure_equals( - varsmap, - llsd::map( + CHECK_THAT(varsmap, + ll_test::LLSDEquals(llsd::map( "strvar", llsd::map("name", "strvar", "type", "String", @@ -182,6 +160,6 @@ namespace llsd::map("name", "boolvar", "type", "Boolean", "value", true, - "comment", "bool variable"))); + "comment", "bool variable")))); } -} // namespace tut +} // anonymous namespace diff --git a/indra/newview/tests/llviewerhelputil_test.cpp b/indra/newview/tests/llviewerhelputil_test.cpp index 9c9ae0e083..5ab4347a6e 100644 --- a/indra/newview/tests/llviewerhelputil_test.cpp +++ b/indra/newview/tests/llviewerhelputil_test.cpp @@ -27,7 +27,7 @@ // Precompiled header #include "../llviewerprecompiledheaders.h" -#include "../test/lltut.h" +#include #include "../llviewerhelputil.h" #include "../llweb.h" @@ -96,57 +96,56 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url, //---------------------------------------------------------------------------- -namespace tut +namespace { - struct viewerhelputil - { - }; - - typedef test_group viewerhelputil_t; - typedef viewerhelputil_t::object viewerhelputil_object_t; - tut::viewerhelputil_t tut_viewerhelputil("LLViewerHelpUtil"); - - template<> template<> - void viewerhelputil_object_t::test<1>() + TEST_CASE("LLViewerHelpUtil: buildHelpURL substitutes the topic and the viewer tags into the format", "[LLViewerHelpUtil]") { std::string topic("test_topic"); std::string subresult; gHelpURL = "fooformat"; subresult = LLViewerHelpUtil::buildHelpURL(topic); - ensure_equals("no substitution tags", subresult, "fooformat"); + UNSCOPED_INFO("no substitution tags"); + CHECK(subresult == "fooformat"); gHelpURL = ""; subresult = LLViewerHelpUtil::buildHelpURL(topic); - ensure_equals("blank substitution format", subresult, ""); + UNSCOPED_INFO("blank substitution format"); + CHECK(subresult == ""); gHelpURL = "[TOPIC]"; subresult = LLViewerHelpUtil::buildHelpURL(topic); - ensure_equals("topic name", subresult, "test_topic"); + UNSCOPED_INFO("topic name"); + CHECK(subresult == "test_topic"); gHelpURL = "[LANGUAGE]"; gLanguage = ""; subresult = LLViewerHelpUtil::buildHelpURL(topic); - ensure_equals("simple substitution with blank", subresult, ""); + UNSCOPED_INFO("simple substitution with blank"); + CHECK(subresult == ""); gHelpURL = "[LANGUAGE]"; gLanguage = "Esperanto"; subresult = LLViewerHelpUtil::buildHelpURL(topic); - ensure_equals("simple substitution", subresult, "Esperanto"); + UNSCOPED_INFO("simple substitution"); + CHECK(subresult == "Esperanto"); gHelpURL = "http://secondlife.com/[LANGUAGE]"; gLanguage = "Gaelic"; subresult = LLViewerHelpUtil::buildHelpURL(topic); - ensure_equals("simple substitution with url", subresult, "http://secondlife.com/Gaelic"); + UNSCOPED_INFO("simple substitution with url"); + CHECK(subresult == "http://secondlife.com/Gaelic"); gHelpURL = "[XXX]"; subresult = LLViewerHelpUtil::buildHelpURL(topic); - ensure_equals("unknown substitution", subresult, "[XXX]"); + UNSCOPED_INFO("unknown substitution"); + CHECK(subresult == "[XXX]"); gHelpURL = "[LANGUAGE]/[LANGUAGE]"; gLanguage = "Esperanto"; subresult = LLViewerHelpUtil::buildHelpURL(topic); - ensure_equals("multiple substitution", subresult, "Esperanto/Esperanto"); + UNSCOPED_INFO("multiple substitution"); + CHECK(subresult == "Esperanto/Esperanto"); gHelpURL = "http://[CHANNEL]/[VERSION]/[LANGUAGE]/[OS]/[GRID]/[XXX]"; gChannel = "Second Life Test"; @@ -155,6 +154,7 @@ namespace tut gOS = "AmigaOS 2.1"; gGrid = "mysim"; subresult = LLViewerHelpUtil::buildHelpURL(topic); - ensure_equals("complex substitution", subresult, "http://Second Life Test/2.0/gaelic/AmigaOS 2.1/mysim/[XXX]"); + UNSCOPED_INFO("complex substitution"); + CHECK(subresult == "http://Second Life Test/2.0/gaelic/AmigaOS 2.1/mysim/[XXX]"); } } diff --git a/indra/newview/tests/llviewernetwork_test.cpp b/indra/newview/tests/llviewernetwork_test.cpp index 63501b09dd..85ce97a07d 100644 --- a/indra/newview/tests/llviewernetwork_test.cpp +++ b/indra/newview/tests/llviewernetwork_test.cpp @@ -27,7 +27,7 @@ */ #include "../llviewerprecompiledheaders.h" #include "../llviewernetwork.h" -#include "../test/lltut.h" +#include #include "../../llxml/llcontrol.h" #include "llfile.h" @@ -168,7 +168,7 @@ static const char *gSampleGridFile = // ------------------------------------------------------------------------------------------- // TUT // ------------------------------------------------------------------------------------------- -namespace tut +namespace { // Test wrapper declaration : wrapping nothing for the moment struct viewerNetworkTest @@ -190,87 +190,83 @@ namespace tut } }; - // Tut templating thingamagic: test group, object and test instance - typedef test_group viewerNetworkTestFactory; - typedef viewerNetworkTestFactory::object viewerNetworkTestObject; - tut::viewerNetworkTestFactory tut_viewernetwork("LLViewerNetwork"); - // --------------------------------------------------------------------------------------- // Test functions // --------------------------------------------------------------------------------------- // initialization without a grid file - template<> template<> - void viewerNetworkTestObject::test<1>() + TEST_CASE_METHOD(viewerNetworkTest, "LLViewerNetwork: without a grid file Agni and Aditi are the known grids", "[LLViewerNetwork]") { LLGridManager *manager = LLGridManager::getInstance(); // grid file doesn't exist manager->initialize(TEST_FILENAME); // validate that some of the defaults are available. std::map known_grids = manager->getKnownGrids(); - ensure_equals("Known grids is a string-string map of size 2", known_grids.size(), 2); - ensure_equals("Agni has the right name and label", - known_grids[std::string("util.agni.lindenlab.com")], + UNSCOPED_INFO("Known grids is a string-string map of size 2"); + REQUIRE(known_grids.size() == 2); + UNSCOPED_INFO("Agni has the right name and label"); + CHECK(known_grids[std::string("util.agni.lindenlab.com")] == std::string("Second Life Main Grid (Agni)")); - ensure_equals("Aditi has the right name and label", - known_grids[std::string("util.aditi.lindenlab.com")], + UNSCOPED_INFO("Aditi has the right name and label"); + CHECK(known_grids[std::string("util.aditi.lindenlab.com")] == std::string("Second Life Beta Test Grid (Aditi)")); - ensure_equals("name for agni", - LLGridManager::getInstance()->getGrid("util.agni.lindenlab.com"), + UNSCOPED_INFO("name for agni"); + CHECK(LLGridManager::getInstance()->getGrid("util.agni.lindenlab.com") == std::string("util.agni.lindenlab.com")); - ensure_equals("id for agni", - std::string("Agni"), + UNSCOPED_INFO("id for agni"); + CHECK(std::string("Agni") == LLGridManager::getInstance()->getGridId("util.agni.lindenlab.com")); - ensure_equals("update url base for Agni", // relies on agni being the default - std::string("https://update.secondlife.com/update"), + UNSCOPED_INFO("update url base for Agni"); + CHECK(std::string("https://update.secondlife.com/update") == LLGridManager::getInstance()->getUpdateServiceURL()); - ensure_equals("label for agni", - LLGridManager::getInstance()->getGridLabel("util.agni.lindenlab.com"), + UNSCOPED_INFO("label for agni"); + CHECK(LLGridManager::getInstance()->getGridLabel("util.agni.lindenlab.com") == std::string("Second Life Main Grid (Agni)")); std::vector login_uris; LLGridManager::getInstance()->getLoginURIs(std::string("util.agni.lindenlab.com"), login_uris); - ensure_equals("Number of login uris for agni", 1, login_uris.size()); - ensure_equals("Agni login uri", - login_uris[0], + UNSCOPED_INFO("Number of login uris for agni"); + REQUIRE(1 == login_uris.size()); + UNSCOPED_INFO("Agni login uri"); + CHECK(login_uris[0] == std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi")); - ensure_equals("Agni helper uri", - LLGridManager::getInstance()->getHelperURI("util.agni.lindenlab.com"), + UNSCOPED_INFO("Agni helper uri"); + CHECK(LLGridManager::getInstance()->getHelperURI("util.agni.lindenlab.com") == std::string("https://secondlife.com/helpers/")); - ensure_equals("Agni login page", - LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com"), + UNSCOPED_INFO("Agni login page"); + CHECK(LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com") == std::string("https://viewer-splash-v2.secondlife.com/")); - ensure("Agni is a system grid", - LLGridManager::getInstance()->isSystemGrid("util.agni.lindenlab.com")); + UNSCOPED_INFO("Agni is a system grid"); + CHECK(LLGridManager::getInstance()->isSystemGrid("util.agni.lindenlab.com")); - ensure_equals("name for aditi", - LLGridManager::getInstance()->getGrid("util.aditi.lindenlab.com"), + UNSCOPED_INFO("name for aditi"); + CHECK(LLGridManager::getInstance()->getGrid("util.aditi.lindenlab.com") == std::string("util.aditi.lindenlab.com")); - ensure_equals("id for aditi", - LLGridManager::getInstance()->getGridId("util.aditi.lindenlab.com"), + UNSCOPED_INFO("id for aditi"); + CHECK(LLGridManager::getInstance()->getGridId("util.aditi.lindenlab.com") == std::string("Aditi")); - ensure_equals("label for aditi", - LLGridManager::getInstance()->getGridLabel("util.aditi.lindenlab.com"), + UNSCOPED_INFO("label for aditi"); + CHECK(LLGridManager::getInstance()->getGridLabel("util.aditi.lindenlab.com") == std::string("Second Life Beta Test Grid (Aditi)")); LLGridManager::getInstance()->getLoginURIs(std::string("util.aditi.lindenlab.com"), login_uris); - ensure_equals("Number of login uris for aditi", 1, login_uris.size()); - ensure_equals("Aditi login uri", - login_uris[0], + UNSCOPED_INFO("Number of login uris for aditi"); + REQUIRE(1 == login_uris.size()); + UNSCOPED_INFO("Aditi login uri"); + CHECK(login_uris[0] == std::string("https://login.aditi.lindenlab.com/cgi-bin/login.cgi")); - ensure_equals("Aditi helper uri", - LLGridManager::getInstance()->getHelperURI("util.aditi.lindenlab.com"), + UNSCOPED_INFO("Aditi helper uri"); + CHECK(LLGridManager::getInstance()->getHelperURI("util.aditi.lindenlab.com") == std::string("https://secondlife.aditi.lindenlab.com/helpers/")); - ensure_equals("Aditi login page", - LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com"), + UNSCOPED_INFO("Aditi login page"); + CHECK(LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com") == std::string("https://viewer-splash-v2.secondlife.com/")); - ensure("Aditi is a system grid", - LLGridManager::getInstance()->isSystemGrid("util.aditi.lindenlab.com")); + UNSCOPED_INFO("Aditi is a system grid"); + CHECK(LLGridManager::getInstance()->isSystemGrid("util.aditi.lindenlab.com")); } // initialization with a grid file - template<> template<> - void viewerNetworkTestObject::test<2>() + TEST_CASE_METHOD(viewerNetworkTest, "LLViewerNetwork: a grid file adds its grids without overwriting Agni or Aditi", "[LLViewerNetwork]") { llofstream gridfile(TEST_FILENAME); gridfile << gSampleGridFile; @@ -278,129 +274,133 @@ namespace tut LLGridManager::getInstance()->initialize(TEST_FILENAME); std::map known_grids = LLGridManager::getInstance()->getKnownGrids(); - ensure_equals("adding a grid via a grid file increases known grid size",4, + UNSCOPED_INFO("adding a grid via a grid file increases known grid size"); + REQUIRE(4 == known_grids.size()); // Verify that Agni and Aditi were not overwritten - ensure_equals("Agni has the right name and label", - known_grids[std::string("util.agni.lindenlab.com")], + UNSCOPED_INFO("Agni has the right name and label"); + CHECK(known_grids[std::string("util.agni.lindenlab.com")] == std::string("Second Life Main Grid (Agni)")); - ensure_equals("Aditi has the right name and label", - known_grids[std::string("util.aditi.lindenlab.com")], + UNSCOPED_INFO("Aditi has the right name and label"); + CHECK(known_grids[std::string("util.aditi.lindenlab.com")] == std::string("Second Life Beta Test Grid (Aditi)")); - ensure_equals("name for agni", - LLGridManager::getInstance()->getGrid("util.agni.lindenlab.com"), + UNSCOPED_INFO("name for agni"); + CHECK(LLGridManager::getInstance()->getGrid("util.agni.lindenlab.com") == std::string("util.agni.lindenlab.com")); - ensure_equals("id for agni", - LLGridManager::getInstance()->getGridId("util.agni.lindenlab.com"), + UNSCOPED_INFO("id for agni"); + CHECK(LLGridManager::getInstance()->getGridId("util.agni.lindenlab.com") == std::string("Agni")); - ensure_equals("update url base for Agni", // relies on agni being the default - std::string("https://update.secondlife.com/update"), + UNSCOPED_INFO("update url base for Agni"); + CHECK(std::string("https://update.secondlife.com/update") == LLGridManager::getInstance()->getUpdateServiceURL()); - ensure_equals("label for agni", - LLGridManager::getInstance()->getGridLabel("util.agni.lindenlab.com"), + UNSCOPED_INFO("label for agni"); + CHECK(LLGridManager::getInstance()->getGridLabel("util.agni.lindenlab.com") == std::string("Second Life Main Grid (Agni)")); std::vector login_uris; LLGridManager::getInstance()->getLoginURIs(std::string("util.agni.lindenlab.com"), login_uris); - ensure_equals("Number of login uris for agni", 1, login_uris.size()); - ensure_equals("Agni login uri", - login_uris[0], + UNSCOPED_INFO("Number of login uris for agni"); + REQUIRE(1 == login_uris.size()); + UNSCOPED_INFO("Agni login uri"); + CHECK(login_uris[0] == std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi")); - ensure_equals("Agni helper uri", - LLGridManager::getInstance()->getHelperURI("util.agni.lindenlab.com"), + UNSCOPED_INFO("Agni helper uri"); + CHECK(LLGridManager::getInstance()->getHelperURI("util.agni.lindenlab.com") == std::string("https://secondlife.com/helpers/")); - ensure_equals("Agni login page", - LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com"), + UNSCOPED_INFO("Agni login page"); + CHECK(LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com") == std::string("https://viewer-splash-v2.secondlife.com/")); - ensure("Agni is a system grid", - LLGridManager::getInstance()->isSystemGrid("util.agni.lindenlab.com")); + UNSCOPED_INFO("Agni is a system grid"); + CHECK(LLGridManager::getInstance()->isSystemGrid("util.agni.lindenlab.com")); - ensure_equals("name for aditi", - LLGridManager::getInstance()->getGrid("util.aditi.lindenlab.com"), + UNSCOPED_INFO("name for aditi"); + CHECK(LLGridManager::getInstance()->getGrid("util.aditi.lindenlab.com") == std::string("util.aditi.lindenlab.com")); - ensure_equals("id for aditi", - LLGridManager::getInstance()->getGridId("util.aditi.lindenlab.com"), + UNSCOPED_INFO("id for aditi"); + CHECK(LLGridManager::getInstance()->getGridId("util.aditi.lindenlab.com") == std::string("Aditi")); - ensure_equals("label for aditi", - LLGridManager::getInstance()->getGridLabel("util.aditi.lindenlab.com"), + UNSCOPED_INFO("label for aditi"); + CHECK(LLGridManager::getInstance()->getGridLabel("util.aditi.lindenlab.com") == std::string("Second Life Beta Test Grid (Aditi)")); LLGridManager::getInstance()->getLoginURIs(std::string("util.aditi.lindenlab.com"), login_uris); - ensure_equals("Number of login uris for aditi", 1, login_uris.size()); - ensure_equals("Aditi login uri", - login_uris[0], + UNSCOPED_INFO("Number of login uris for aditi"); + REQUIRE(1 == login_uris.size()); + UNSCOPED_INFO("Aditi login uri"); + CHECK(login_uris[0] == std::string("https://login.aditi.lindenlab.com/cgi-bin/login.cgi")); - ensure_equals("Aditi helper uri", - LLGridManager::getInstance()->getHelperURI("util.aditi.lindenlab.com"), + UNSCOPED_INFO("Aditi helper uri"); + CHECK(LLGridManager::getInstance()->getHelperURI("util.aditi.lindenlab.com") == std::string("https://secondlife.aditi.lindenlab.com/helpers/")); - ensure_equals("Aditi login page", - LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com"), + UNSCOPED_INFO("Aditi login page"); + CHECK(LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com") == std::string("https://viewer-splash-v2.secondlife.com/")); - ensure("Aditi is a system grid", - LLGridManager::getInstance()->isSystemGrid("util.aditi.lindenlab.com")); + UNSCOPED_INFO("Aditi is a system grid"); + CHECK(LLGridManager::getInstance()->isSystemGrid("util.aditi.lindenlab.com")); // Check the additional grid from the file - ensure_equals("alternative grid is in name<->label map", - known_grids["altgrid.long.name"], + UNSCOPED_INFO("alternative grid is in name<->label map"); + CHECK(known_grids["altgrid.long.name"] == std::string("Alternative Grid")); - ensure_equals("alternative grid name is set", - LLGridManager::getInstance()->getGrid("altgrid.long.name"), + UNSCOPED_INFO("alternative grid name is set"); + CHECK(LLGridManager::getInstance()->getGrid("altgrid.long.name") == std::string("altgrid.long.name")); - ensure_equals("alternative grid id", - LLGridManager::getInstance()->getGridId("altgrid.long.name"), + UNSCOPED_INFO("alternative grid id"); + CHECK(LLGridManager::getInstance()->getGridId("altgrid.long.name") == std::string("AltGrid")); - ensure_equals("alternative grid label", - LLGridManager::getInstance()->getGridLabel("altgrid.long.name"), + UNSCOPED_INFO("alternative grid label"); + CHECK(LLGridManager::getInstance()->getGridLabel("altgrid.long.name") == std::string("Alternative Grid")); std::vector alt_login_uris; LLGridManager::getInstance()->getLoginURIs(std::string("altgrid.long.name"), alt_login_uris); - ensure_equals("Number of login uris for altgrid", 2, alt_login_uris.size()); - ensure_equals("alternative grid first login uri", - alt_login_uris[0], + UNSCOPED_INFO("Number of login uris for altgrid"); + REQUIRE(2 == alt_login_uris.size()); + UNSCOPED_INFO("alternative grid first login uri"); + CHECK(alt_login_uris[0] == std::string("altgrid/myloginuri1")); - ensure_equals("alternative grid second login uri", - alt_login_uris[1], + UNSCOPED_INFO("alternative grid second login uri"); + CHECK(alt_login_uris[1] == std::string("altgrid/myloginuri2")); - ensure_equals("alternative grid helper uri", - LLGridManager::getInstance()->getHelperURI("altgrid.long.name"), + UNSCOPED_INFO("alternative grid helper uri"); + CHECK(LLGridManager::getInstance()->getHelperURI("altgrid.long.name") == std::string("https://helper1/helpers/")); - ensure_equals("alternative grid login page", - LLGridManager::getInstance()->getLoginPage("altgrid.long.name"), + UNSCOPED_INFO("alternative grid login page"); + CHECK(LLGridManager::getInstance()->getLoginPage("altgrid.long.name") == std::string("altgrid/loginpage")); - ensure("alternative grid is NOT a system grid", - ! LLGridManager::getInstance()->isSystemGrid("altgrid.long.name")); + UNSCOPED_INFO("alternative grid is NOT a system grid"); + CHECK_FALSE(LLGridManager::getInstance()->isSystemGrid("altgrid.long.name")); - ensure_equals("minimal grid is in name<->label map", - known_grids["minimal.long.name"], + UNSCOPED_INFO("minimal grid is in name<->label map"); + CHECK(known_grids["minimal.long.name"] == std::string("minimal.long.name")); - ensure_equals("minimal grid name is set", - LLGridManager::getInstance()->getGrid("minimal.long.name"), + UNSCOPED_INFO("minimal grid name is set"); + CHECK(LLGridManager::getInstance()->getGrid("minimal.long.name") == std::string("minimal.long.name")); - ensure_equals("minimal grid id", - LLGridManager::getInstance()->getGridId("minimal.long.name"), + UNSCOPED_INFO("minimal grid id"); + CHECK(LLGridManager::getInstance()->getGridId("minimal.long.name") == std::string("minimal.long.name")); - ensure_equals("minimal grid label", - LLGridManager::getInstance()->getGridLabel("minimal.long.name"), + UNSCOPED_INFO("minimal grid label"); + CHECK(LLGridManager::getInstance()->getGridLabel("minimal.long.name") == std::string("minimal.long.name")); LLGridManager::getInstance()->getLoginURIs(std::string("minimal.long.name"), alt_login_uris); - ensure_equals("Number of login uris for altgrid", 1, alt_login_uris.size()); - ensure_equals("minimal grid login uri", - alt_login_uris[0], + UNSCOPED_INFO("Number of login uris for altgrid"); + REQUIRE(1 == alt_login_uris.size()); + UNSCOPED_INFO("minimal grid login uri"); + CHECK(alt_login_uris[0] == std::string("https://minimal.long.name/cgi-bin/login.cgi")); - ensure_equals("minimal grid helper uri", - LLGridManager::getInstance()->getHelperURI("minimal.long.name"), + UNSCOPED_INFO("minimal grid helper uri"); + CHECK(LLGridManager::getInstance()->getHelperURI("minimal.long.name") == std::string("https://minimal.long.name/helpers/")); - ensure_equals("minimal grid login page", - LLGridManager::getInstance()->getLoginPage("minimal.long.name"), + UNSCOPED_INFO("minimal grid login page"); + CHECK(LLGridManager::getInstance()->getLoginPage("minimal.long.name") == std::string("https://minimal.long.name/app/login/")); } // validate grid selection - template<> template<> - void viewerNetworkTestObject::test<7>() + TEST_CASE_METHOD(viewerNetworkTest, "LLViewerNetwork: setGridChoice selects the grid the getters answer for", "[LLViewerNetwork]") { // adding a grid with simply a name will populate the values. llofstream gridfile(TEST_FILENAME); @@ -410,43 +410,45 @@ namespace tut LLGridManager::getInstance()->initialize(TEST_FILENAME); LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com"); - ensure_equals("getGridLabel", - LLGridManager::getInstance()->getGridLabel(), + UNSCOPED_INFO("getGridLabel"); + CHECK(LLGridManager::getInstance()->getGridLabel() == std::string("Second Life Main Grid (Agni)")); - ensure_equals("getGridId", - LLGridManager::getInstance()->getGridId(), + UNSCOPED_INFO("getGridId"); + CHECK(LLGridManager::getInstance()->getGridId() == std::string("Agni")); - ensure_equals("getGrid", - LLGridManager::getInstance()->getGrid(), + UNSCOPED_INFO("getGrid"); + CHECK(LLGridManager::getInstance()->getGrid() == std::string("util.agni.lindenlab.com")); - ensure_equals("getHelperURI", - LLGridManager::getInstance()->getHelperURI(), + UNSCOPED_INFO("getHelperURI"); + CHECK(LLGridManager::getInstance()->getHelperURI() == std::string("https://secondlife.com/helpers/")); - ensure_equals("getLoginPage", - LLGridManager::getInstance()->getLoginPage(), + UNSCOPED_INFO("getLoginPage"); + CHECK(LLGridManager::getInstance()->getLoginPage() == std::string("https://viewer-splash-v2.secondlife.com/")); - ensure_equals("update url base for Agni", // relies on agni being the default - std::string("https://update.secondlife.com/update"), + UNSCOPED_INFO("update url base for Agni"); + CHECK(std::string("https://update.secondlife.com/update") == LLGridManager::getInstance()->getUpdateServiceURL()); - ensure("Is Agni a production grid", LLGridManager::getInstance()->isInProductionGrid()); + UNSCOPED_INFO("Is Agni a production grid"); + CHECK(LLGridManager::getInstance()->isInProductionGrid()); std::vector uris; LLGridManager::getInstance()->getLoginURIs(uris); - ensure_equals("getLoginURIs size", 1, uris.size()); - ensure_equals("getLoginURIs", - uris[0], + UNSCOPED_INFO("getLoginURIs size"); + REQUIRE(1 == uris.size()); + UNSCOPED_INFO("getLoginURIs"); + CHECK(uris[0] == std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi")); LLGridManager::getInstance()->setGridChoice("altgrid.long.name"); - ensure_equals("getGridLabel", - LLGridManager::getInstance()->getGridLabel(), + UNSCOPED_INFO("getGridLabel"); + CHECK(LLGridManager::getInstance()->getGridLabel() == std::string("Alternative Grid")); - ensure_equals("getGridId", - LLGridManager::getInstance()->getGridId(), + UNSCOPED_INFO("getGridId"); + CHECK(LLGridManager::getInstance()->getGridId() == std::string("AltGrid")); - ensure("alternative grid is not a system grid", - !LLGridManager::getInstance()->isSystemGrid()); - ensure("alternative grid is not a production grid", - !LLGridManager::getInstance()->isInProductionGrid()); + UNSCOPED_INFO("alternative grid is not a system grid"); + CHECK_FALSE(LLGridManager::getInstance()->isSystemGrid()); + UNSCOPED_INFO("alternative grid is not a production grid"); + CHECK_FALSE(LLGridManager::getInstance()->isInProductionGrid()); } } diff --git a/indra/newview/tests/llvocache_test.cpp b/indra/newview/tests/llvocache_test.cpp index d4076625e0..dffaff231b 100644 --- a/indra/newview/tests/llvocache_test.cpp +++ b/indra/newview/tests/llvocache_test.cpp @@ -26,7 +26,7 @@ * $/LicenseInfo$ */ #include "../llviewerprecompiledheaders.h" -#include "../test/lltut.h" +#include #include "../llvocache.h" @@ -80,7 +80,7 @@ LLViewerRegion* LLWorld::getRegionFromHandle(const U64&) { return nullptr; } // ------------------------------------------------------------------------------------------- // TUT // ------------------------------------------------------------------------------------------- -namespace tut +namespace { // Each test gets a fresh cache singleton with the real LLDir's cache // directory pointed at a temporary directory of its own, so tests neither @@ -96,7 +96,8 @@ namespace tut { mRoot = std::filesystem::temp_directory_path() / ("llvocache_test_" + LLUUID::generateNewID().asString()); std::filesystem::create_directories(mRoot); - ensure("cache dir redirected", gDirUtilp->setCacheDir(mRoot.string())); + UNSCOPED_INFO("cache dir redirected"); + REQUIRE(gDirUtilp->setCacheDir(mRoot.string())); LLVOCache::initParamSingleton(/*read_only=*/false); LLVOCache::instance().initCache(LL_PATH_CACHE, CACHE_NUMBER_OF_REGIONS, CACHE_VERSION); @@ -146,13 +147,21 @@ namespace tut static void ensureSameEntry(const LLVOCacheEntry& expected, const LLVOCacheEntry& actual) { - ensure_equals("crc", actual.getCRC(), expected.getCRC()); - ensure_equals("hit count", actual.getHitCount(), expected.getHitCount()); + UNSCOPED_INFO("crc"); + REQUIRE(actual.getCRC() == expected.getCRC()); + UNSCOPED_INFO("hit count"); + REQUIRE(actual.getHitCount() == expected.getHitCount()); const LLDataPackerBinaryBuffer* a = expected.getDP(); const LLDataPackerBinaryBuffer* b = actual.getDP(); - ensure("body present", a && b); - ensure_equals("body size", b->getBufferSize(), a->getBufferSize()); - ensure("body bytes", memcmp(a->getBuffer(), b->getBuffer(), (size_t)a->getBufferSize()) == 0); + { + INFO("body present"); + REQUIRE(a); + REQUIRE(b); + } + UNSCOPED_INFO("body size"); + REQUIRE(b->getBufferSize() == a->getBufferSize()); + UNSCOPED_INFO("body bytes"); + REQUIRE(memcmp(a->getBuffer(), b->getBuffer(), (size_t)a->getBufferSize()) == 0); } // An override message in the shape LLGLTFOverrideCacheEntry::fromLLSD @@ -184,7 +193,8 @@ namespace tut static LLGLTFOverrideCacheEntry makeOverride(U32 local_id, U64 handle, int sides) { LLGLTFOverrideCacheEntry entry; - ensure("override parses", entry.fromLLSD(makeOverrideLLSD(local_id, handle, LLUUID::generateNewID(), sides))); + UNSCOPED_INFO("override parses"); + REQUIRE(entry.fromLLSD(makeOverrideLLSD(local_id, handle, LLUUID::generateNewID(), sides))); return entry; } @@ -257,115 +267,126 @@ namespace tut static void ensureSameOverride(const LLGLTFOverrideCacheEntry& expected, const LLGLTFOverrideCacheEntry& actual) { - ensure_equals("object id", actual.mObjectId, expected.mObjectId); - ensure_equals("local id", actual.mLocalId, expected.mLocalId); - ensure_equals("region handle", actual.mRegionHandle, expected.mRegionHandle); - ensure_equals("side count", actual.mSides.size(), expected.mSides.size()); + UNSCOPED_INFO("object id"); + REQUIRE(actual.mObjectId == expected.mObjectId); + UNSCOPED_INFO("local id"); + REQUIRE(actual.mLocalId == expected.mLocalId); + UNSCOPED_INFO("region handle"); + REQUIRE(actual.mRegionHandle == expected.mRegionHandle); + UNSCOPED_INFO("side count"); + REQUIRE(actual.mSides.size() == expected.mSides.size()); for (const auto& [side, llsd] : expected.mSides) { auto found = actual.mSides.find(side); - ensure("side present", found != actual.mSides.end()); - ensure("side llsd", llsd_equals(found->second, llsd)); + UNSCOPED_INFO("side present"); + REQUIRE(found != actual.mSides.end()); + UNSCOPED_INFO("side llsd"); + REQUIRE(llsd_equals(found->second, llsd)); } } }; - // The harness's main() owns APR for the run; a group factory is a static - // and must not tear it down a second time on the way out. - struct vocacheTestFactory : public test_group - { - vocacheTestFactory() : test_group("LLVOCache") {} - }; - - typedef vocacheTestFactory::object vocacheTestObject; - tut::vocacheTestFactory tut_vocache; - // --------------------------------------------------------------------------------------- // Test functions // --------------------------------------------------------------------------------------- - template<> template<> - void vocacheTestObject::test<1>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: an override entry round-trips LLSD and builds materials on demand", "[LLVOCache]") { - set_test_name("override entry round trip, materials built on demand"); - const U64 handle = to_region_handle(1000 * 256, 1000 * 256); const LLUUID object_id = LLUUID::generateNewID(); LLSD data = makeOverrideLLSD(42, handle, object_id, 3); LLGLTFOverrideCacheEntry entry; - ensure("fromLLSD", entry.fromLLSD(data)); - ensure_equals("object id", entry.mObjectId, object_id); - ensure_equals("local id", entry.mLocalId, 42u); - ensure_equals("region handle", entry.mRegionHandle, handle); - ensure_equals("sides", entry.mSides.size(), (size_t)3); - ensure("materials not built by loading", entry.mGLTFMaterial.empty()); + UNSCOPED_INFO("fromLLSD"); + REQUIRE(entry.fromLLSD(data)); + UNSCOPED_INFO("object id"); + CHECK(entry.mObjectId == object_id); + UNSCOPED_INFO("local id"); + CHECK(entry.mLocalId == 42u); + UNSCOPED_INFO("region handle"); + CHECK(entry.mRegionHandle == handle); + UNSCOPED_INFO("sides"); + REQUIRE(entry.mSides.size() == (size_t)3); + UNSCOPED_INFO("materials not built by loading"); + REQUIRE(entry.mGLTFMaterial.empty()); // toLLSD walks a hash map, so compare per side rather than as arrays. LLSD back = entry.toLLSD(); - ensure_equals("local id survives", back["local_id"].asInteger(), 42); - ensure_equals("object id survives", back["object_id"].asUUID(), object_id); - ensure_equals("region x survives", back["region_handle_x"].asInteger(), data["region_handle_x"].asInteger()); - ensure_equals("region y survives", back["region_handle_y"].asInteger(), data["region_handle_y"].asInteger()); - ensure_equals("side count survives", back["sides"].size(), (size_t)3); + UNSCOPED_INFO("local id survives"); + CHECK(back["local_id"].asInteger() == 42); + UNSCOPED_INFO("object id survives"); + CHECK(back["object_id"].asUUID() == object_id); + UNSCOPED_INFO("region x survives"); + CHECK(back["region_handle_x"].asInteger() == data["region_handle_x"].asInteger()); + UNSCOPED_INFO("region y survives"); + CHECK(back["region_handle_y"].asInteger() == data["region_handle_y"].asInteger()); + UNSCOPED_INFO("side count survives"); + REQUIRE(back["sides"].size() == (size_t)3); for (size_t i = 0; i < back["sides"].size(); ++i) { S32 side = back["sides"][i].asInteger(); - ensure("side llsd survives", llsd_equals(back["gltf_llsd"][i], data["gltf_llsd"][side])); + UNSCOPED_INFO("side llsd survives"); + REQUIRE(llsd_equals(back["gltf_llsd"][i], data["gltf_llsd"][side])); } entry.materialize(); - ensure_equals("one material per side", entry.mGLTFMaterial.size(), entry.mSides.size()); + UNSCOPED_INFO("one material per side"); + REQUIRE(entry.mGLTFMaterial.size() == entry.mSides.size()); for (const auto& [side, llsd] : entry.mSides) { - ensure("material for side", entry.mGLTFMaterial.find(side) != entry.mGLTFMaterial.end()); - ensure("material built", entry.mGLTFMaterial.at(side).notNull()); + UNSCOPED_INFO("material for side"); + REQUIRE(entry.mGLTFMaterial.find(side) != entry.mGLTFMaterial.end()); + UNSCOPED_INFO("material built"); + REQUIRE(entry.mGLTFMaterial.at(side).notNull()); } LLGLTFMaterial* first = entry.mGLTFMaterial.at(0).get(); entry.materialize(); - ensure("second materialize keeps the materials", entry.mGLTFMaterial.at(0).get() == first); + UNSCOPED_INFO("second materialize keeps the materials"); + CHECK(entry.mGLTFMaterial.at(0).get() == first); LLGLTFOverrideCacheEntry rejected; LLSD headless = data; headless.erase("region_handle_x"); - ensure("no region handle is rejected", !rejected.fromLLSD(headless)); + UNSCOPED_INFO("no region handle is rejected"); + REQUIRE_FALSE(rejected.fromLLSD(headless)); headless = data; headless.erase("local_id"); - ensure("no local id is rejected", !rejected.fromLLSD(headless)); + UNSCOPED_INFO("no local id is rejected"); + CHECK_FALSE(rejected.fromLLSD(headless)); } - template<> template<> - void vocacheTestObject::test<2>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: an object cache file round-trips every entry", "[LLVOCache]") { - set_test_name("object cache round trip"); - const U64 handle = to_region_handle(1000 * 256, 1000 * 256); const LLUUID id = LLUUID::generateNewID(); LLVOCacheEntry::vocache_entry_map_t written = makeEntries(500); LLVOCache::instance().writeToCache(handle, id, written, /*dirty=*/true, /*removal_enabled=*/false); - ensure("cache file written", std::filesystem::exists(objectFile(handle, ".slc"))); + UNSCOPED_INFO("cache file written"); + CHECK(std::filesystem::exists(objectFile(handle, ".slc"))); LLVOCacheEntry::vocache_entry_map_t read; - ensure("read succeeds", LLVOCache::instance().readFromCache(handle, id, read)); - ensure_equals("entry count", read.size(), written.size()); + UNSCOPED_INFO("read succeeds"); + REQUIRE(LLVOCache::instance().readFromCache(handle, id, read)); + UNSCOPED_INFO("entry count"); + REQUIRE(read.size() == written.size()); for (const auto& [local_id, entry] : written) { auto found = read.find(local_id); - ensure("entry present", found != read.end()); + UNSCOPED_INFO("entry present"); + REQUIRE(found != read.end()); ensureSameEntry(*entry, *found->second); } LLVOCacheEntry::vocache_entry_map_t other; - ensure("another region's id is refused", !LLVOCache::instance().readFromCache(handle, LLUUID::generateNewID(), other)); - ensure("nothing loaded for it", other.empty()); + UNSCOPED_INFO("another region's id is refused"); + REQUIRE_FALSE(LLVOCache::instance().readFromCache(handle, LLUUID::generateNewID(), other)); + UNSCOPED_INFO("nothing loaded for it"); + REQUIRE(other.empty()); } - template<> template<> - void vocacheTestObject::test<3>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: a save with removal enabled counts only what it wrote", "[LLVOCache]") { - set_test_name("a save with removal enabled counts only what it wrote"); - const U64 handle = to_region_handle(1001 * 256, 1000 * 256); const LLUUID id = LLUUID::generateNewID(); LLVOCacheEntry::vocache_entry_map_t written = makeEntries(200); @@ -375,24 +396,25 @@ namespace tut entry->setValid(local_id % 3 != 0); valid += entry->isValid() ? 1 : 0; } - ensure("some entries were invalidated", valid < written.size()); + UNSCOPED_INFO("some entries were invalidated"); + REQUIRE(valid < written.size()); LLVOCache::instance().writeToCache(handle, id, written, true, /*removal_enabled=*/true); LLVOCacheEntry::vocache_entry_map_t read; - ensure("read succeeds against the written count", LLVOCache::instance().readFromCache(handle, id, read)); - ensure_equals("only valid entries were written", read.size(), valid); + UNSCOPED_INFO("read succeeds against the written count"); + REQUIRE(LLVOCache::instance().readFromCache(handle, id, read)); + UNSCOPED_INFO("only valid entries were written"); + REQUIRE(read.size() == valid); for (const auto& [local_id, entry] : read) { - ensure("no invalid entry came back", written.at(local_id)->isValid()); + UNSCOPED_INFO("no invalid entry came back"); + REQUIRE(written.at(local_id)->isValid()); } } - template<> template<> - void vocacheTestObject::test<4>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: a truncated object cache is refused", "[LLVOCache]") { - set_test_name("a truncated object cache is refused"); - const U64 handle = to_region_handle(1002 * 256, 1000 * 256); const LLUUID id = LLUUID::generateNewID(); LLVOCacheEntry::vocache_entry_map_t written = makeEntries(100); @@ -403,15 +425,14 @@ namespace tut std::filesystem::resize_file(file, size - 100); LLVOCacheEntry::vocache_entry_map_t read; - ensure("truncated file fails the read", !LLVOCache::instance().readFromCache(handle, id, read)); - ensure("fewer entries than written", read.size() < written.size()); + UNSCOPED_INFO("truncated file fails the read"); + REQUIRE_FALSE(LLVOCache::instance().readFromCache(handle, id, read)); + UNSCOPED_INFO("fewer entries than written"); + REQUIRE(read.size() < written.size()); } - template<> template<> - void vocacheTestObject::test<5>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: the header survives a restart", "[LLVOCache]") { - set_test_name("the header survives a restart"); - const U64 handle = to_region_handle(1003 * 256, 1000 * 256); const LLUUID id = LLUUID::generateNewID(); LLVOCacheEntry::vocache_entry_map_t written = makeEntries(50); @@ -422,15 +443,14 @@ namespace tut LLVOCache::instance().initCache(LL_PATH_CACHE, CACHE_NUMBER_OF_REGIONS, CACHE_VERSION); LLVOCacheEntry::vocache_entry_map_t read; - ensure("region known after restart", LLVOCache::instance().readFromCache(handle, id, read)); - ensure_equals("entries after restart", read.size(), written.size()); + UNSCOPED_INFO("region known after restart"); + REQUIRE(LLVOCache::instance().readFromCache(handle, id, read)); + UNSCOPED_INFO("entries after restart"); + REQUIRE(read.size() == written.size()); } - template<> template<> - void vocacheTestObject::test<6>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: the override cache round-trips and drops overrides with no object", "[LLVOCache]") { - set_test_name("override cache round trip"); - const U64 handle = to_region_handle(1004 * 256, 1000 * 256); const LLUUID id = LLUUID::generateNewID(); LLVOCacheEntry::vocache_entry_map_t objects = makeEntries(20); @@ -445,29 +465,33 @@ namespace tut written[999] = makeOverride(999, handle, 2); LLVOCache::instance().writeGenericExtrasToCache(handle, id, written, true, false); - ensure("extras file written", std::filesystem::exists(objectFile(handle, "_extras.slec"))); + UNSCOPED_INFO("extras file written"); + CHECK(std::filesystem::exists(objectFile(handle, "_extras.slec"))); LLVOCacheEntry::vocache_gltf_overrides_map_t read; - ensure("read succeeds", LLVOCache::instance().readGenericExtrasFromCache(handle, id, read, objects)); - ensure_equals("all overrides with an object came back", read.size(), written.size() - 1); - ensure("orphan override dropped", read.find(999) == read.end()); + UNSCOPED_INFO("read succeeds"); + REQUIRE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, read, objects)); + UNSCOPED_INFO("all overrides with an object came back"); + REQUIRE(read.size() == written.size() - 1); + UNSCOPED_INFO("orphan override dropped"); + REQUIRE(read.find(999) == read.end()); for (const auto& [local_id, entry] : read) { ensureSameOverride(written.at(local_id), entry); - ensure("materials not built by loading", entry.mGLTFMaterial.empty()); + UNSCOPED_INFO("materials not built by loading"); + REQUIRE(entry.mGLTFMaterial.empty()); } LLVOCacheEntry::vocache_gltf_overrides_map_t none; LLVOCacheEntry::vocache_entry_map_t no_objects; - ensure("empty primary cache is not a failure", LLVOCache::instance().readGenericExtrasFromCache(handle, id, none, no_objects)); - ensure("and loads nothing", none.empty()); + UNSCOPED_INFO("empty primary cache is not a failure"); + REQUIRE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, none, no_objects)); + UNSCOPED_INFO("and loads nothing"); + REQUIRE(none.empty()); } - template<> template<> - void vocacheTestObject::test<7>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: a corrupt override record is skipped and a truncated file refused", "[LLVOCache]") { - set_test_name("a corrupt override record is skipped, a truncated file refused"); - const U64 handle = to_region_handle(1005 * 256, 1000 * 256); const LLUUID id = LLUUID::generateNewID(); LLVOCacheEntry::vocache_entry_map_t objects = makeEntries(10); @@ -488,20 +512,24 @@ namespace tut } // version line, cache id, count, then records of [length][llsd] const size_t line_end = bytes.find('\n'); - ensure("version line present", line_end != std::string::npos); - ensure_equals("version line", bytes.substr(0, line_end), LLGLTFOverrideCacheEntry::VERSION_LABEL + ":" + std::to_string(LLGLTFOverrideCacheEntry::VERSION)); + UNSCOPED_INFO("version line present"); + REQUIRE(line_end != std::string::npos); + UNSCOPED_INFO("version line"); + CHECK(bytes.substr(0, line_end) == LLGLTFOverrideCacheEntry::VERSION_LABEL + ":" + std::to_string(LLGLTFOverrideCacheEntry::VERSION)); size_t cursor = line_end + 1 + UUID_BYTES; U32 count = 0; memcpy(&count, bytes.data() + cursor, sizeof(U32)); cursor += sizeof(U32); - ensure_equals("record count", (size_t)count, written.size()); + UNSCOPED_INFO("record count"); + REQUIRE((size_t)count == written.size()); // Overwrite the second record's first byte with a type tag LLSD binary // does not have, so that one record and only that one fails to parse. U32 first_length = 0; memcpy(&first_length, bytes.data() + cursor, sizeof(U32)); const size_t second_record = cursor + sizeof(U32) + first_length + sizeof(U32); - ensure("second record inside file", second_record < bytes.size()); + UNSCOPED_INFO("second record inside file"); + REQUIRE(second_record < bytes.size()); std::string corrupted = bytes; corrupted[second_record] = (char)0xFF; { @@ -510,8 +538,10 @@ namespace tut } LLVOCacheEntry::vocache_gltf_overrides_map_t read; - ensure("corrupt record does not fail the file", LLVOCache::instance().readGenericExtrasFromCache(handle, id, read, objects)); - ensure_equals("one record skipped", read.size(), written.size() - 1); + UNSCOPED_INFO("corrupt record does not fail the file"); + REQUIRE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, read, objects)); + UNSCOPED_INFO("one record skipped"); + REQUIRE(read.size() == written.size() - 1); for (const auto& [local_id, entry] : read) { ensureSameOverride(written.at(local_id), entry); @@ -523,7 +553,8 @@ namespace tut out.write(bytes.data(), (std::streamsize)(bytes.size() - 3)); } LLVOCacheEntry::vocache_gltf_overrides_map_t partial; - ensure("truncated file is refused", !LLVOCache::instance().readGenericExtrasFromCache(handle, id, partial, objects)); + UNSCOPED_INFO("truncated file is refused"); + CHECK_FALSE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, partial, objects)); // An earlier format is refused by its version line alone. { @@ -531,15 +562,14 @@ namespace tut out << LLGLTFOverrideCacheEntry::VERSION_LABEL << ":1\n" << id << "\n0000000000\n"; } LLVOCacheEntry::vocache_gltf_overrides_map_t old; - ensure("old version is refused", !LLVOCache::instance().readGenericExtrasFromCache(handle, id, old, objects)); - ensure("old version loads nothing", old.empty()); + UNSCOPED_INFO("old version is refused"); + REQUIRE_FALSE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, old, objects)); + UNSCOPED_INFO("old version loads nothing"); + REQUIRE(old.empty()); } - template<> template<> - void vocacheTestObject::test<8>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: memoryAdjustFactor bounds follow RAM and stay under the heap cap", "[LLVOCache]") { - set_test_name("scene load memory factor: bounds from RAM, under the heap cap, always ordered"); - auto factor = [](F32 allocated, F32 physical, F32 cap, F32 low, F32 high) { return LLVOCacheEntry::memoryAdjustFactor(allocated, physical, cap, low, high); @@ -549,47 +579,61 @@ namespace tut // 8 GB with the default settings: the bounds are the RAM fractions, // 2048 and 4915, and the factor runs from 1 to 0 between them - ensure("at the low bound nothing is pulled in", close_to(factor(2048.f, 8192.f, no_cap, 750.f, 2048.f), 1.f)); - ensure("at the high bound everything is", close_to(factor(4915.2f, 8192.f, no_cap, 750.f, 2048.f), 0.f)); - ensure("halfway is half", close_to(factor(3481.6f, 8192.f, no_cap, 750.f, 2048.f), 0.5f)); - ensure("well below the low bound is still 1", close_to(factor(100.f, 8192.f, no_cap, 750.f, 2048.f), 1.f)); + UNSCOPED_INFO("at the low bound nothing is pulled in"); + CHECK(close_to(factor(2048.f, 8192.f, no_cap, 750.f, 2048.f), 1.f)); + UNSCOPED_INFO("at the high bound everything is"); + CHECK(close_to(factor(4915.2f, 8192.f, no_cap, 750.f, 2048.f), 0.f)); + UNSCOPED_INFO("halfway is half"); + CHECK(close_to(factor(3481.6f, 8192.f, no_cap, 750.f, 2048.f), 0.5f)); + UNSCOPED_INFO("well below the low bound is still 1"); + CHECK(close_to(factor(100.f, 8192.f, no_cap, 750.f, 2048.f), 1.f)); // no RAM figure: the settings alone - ensure("without a RAM figure the settings are the bounds", close_to(factor(1399.f, 0.f, no_cap, 750.f, 2048.f), 0.5f)); + UNSCOPED_INFO("without a RAM figure the settings are the bounds"); + CHECK(close_to(factor(1399.f, 0.f, no_cap, 750.f, 2048.f), 0.5f)); // 64 GB behind a 16 GB heap cap: the tightest point moves under the // cap and the loose point keeps its ratio to it const F32 cap = 16384.f; - ensure("the tightest point sits under the cap", close_to(factor(cap * 0.9f, 65536.f, cap, 750.f, 2048.f), 0.f)); - ensure("the loose point scaled with it", close_to(factor(6144.f, 65536.f, cap, 750.f, 2048.f), 1.f)); - ensure("between them is between", close_to(factor(10444.8f, 65536.f, cap, 750.f, 2048.f), 0.5f)); - ensure("past the cap is still a factor", factor(2.f * cap, 65536.f, cap, 750.f, 2048.f) == 0.f); + UNSCOPED_INFO("the tightest point sits under the cap"); + CHECK(close_to(factor(cap * 0.9f, 65536.f, cap, 750.f, 2048.f), 0.f)); + UNSCOPED_INFO("the loose point scaled with it"); + CHECK(close_to(factor(6144.f, 65536.f, cap, 750.f, 2048.f), 1.f)); + UNSCOPED_INFO("between them is between"); + CHECK(close_to(factor(10444.8f, 65536.f, cap, 750.f, 2048.f), 0.5f)); + UNSCOPED_INFO("past the cap is still a factor"); + CHECK(factor(2.f * cap, 65536.f, cap, 750.f, 2048.f) == 0.f); // settings the wrong way round for (F32 allocated : { 0.f, 2000.f, 2500.f, 3000.f, 4000.f }) { const F32 f = factor(allocated, 0.f, no_cap, 3000.f, 2048.f); - ensure("inverted settings still give a factor in [0, 1]", f >= 0.f && f <= 1.f); + { + INFO("inverted settings still give a factor in [0, 1]"); + REQUIRE(f >= 0.f); + REQUIRE(f <= 1.f); + } } - ensure("inverted settings: below the low setting nothing is pulled in", close_to(factor(2000.f, 0.f, no_cap, 3000.f, 2048.f), 1.f)); + UNSCOPED_INFO("inverted settings: below the low setting nothing is pulled in"); + CHECK(close_to(factor(2000.f, 0.f, no_cap, 3000.f, 2048.f), 1.f)); // a bound set by hand is the bound, tighter than RAM would make it too auto explicit_factor = [](F32 allocated, F32 physical, F32 cap, F32 low, F32 high) { return LLVOCacheEntry::memoryAdjustFactor(allocated, physical, cap, low, high, true, true); }; - ensure("explicit bounds on a big machine: at the low one nothing is pulled in", close_to(explicit_factor(1000.f, 65536.f, no_cap, 1000.f, 2000.f), 1.f)); - ensure("explicit bounds on a big machine: at the high one everything is", close_to(explicit_factor(2000.f, 65536.f, no_cap, 1000.f, 2000.f), 0.f)); - ensure("explicit bounds on a big machine: halfway is half", close_to(explicit_factor(1500.f, 65536.f, no_cap, 1000.f, 2000.f), 0.5f)); - ensure("an explicit high with a default low still comes out ordered", - LLVOCacheEntry::memoryAdjustFactor(16000.f, 65536.f, no_cap, 750.f, 2048.f, false, true) >= 0.f); + UNSCOPED_INFO("explicit bounds on a big machine: at the low one nothing is pulled in"); + CHECK(close_to(explicit_factor(1000.f, 65536.f, no_cap, 1000.f, 2000.f), 1.f)); + UNSCOPED_INFO("explicit bounds on a big machine: at the high one everything is"); + CHECK(close_to(explicit_factor(2000.f, 65536.f, no_cap, 1000.f, 2000.f), 0.f)); + UNSCOPED_INFO("explicit bounds on a big machine: halfway is half"); + CHECK(close_to(explicit_factor(1500.f, 65536.f, no_cap, 1000.f, 2000.f), 0.5f)); + UNSCOPED_INFO("an explicit high with a default low still comes out ordered"); + CHECK(LLVOCacheEntry::memoryAdjustFactor(16000.f, 65536.f, no_cap, 750.f, 2048.f, false, true) >= 0.f); } - template<> template<> - void vocacheTestObject::test<9>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: hostile extras records meet a depth cap and a budget and lose bad faces", "[LLVOCache]") { - set_test_name("hostile extras records: a depth cap, a budget for unreadable ones, and no face out of range"); - const U64 handle = to_region_handle(1006 * 256, 1000 * 256); const LLUUID id = LLUUID::generateNewID(); LLVOCacheEntry::vocache_entry_map_t objects = makeEntries(4); @@ -604,41 +648,49 @@ namespace tut writeExtrasFile(handle, id, { binaryRecord(shallow), binaryRecord(deep) }); LLVOCacheEntry::vocache_gltf_overrides_map_t overrides; - ensure("a file with one bad record is still a cache", LLVOCache::instance().readGenericExtrasFromCache(handle, id, overrides, objects)); - ensure_equals("the shallow record loaded, the deep one did not", overrides.size(), 1u); - ensure("it is the shallow one", overrides.find(1) != overrides.end()); + UNSCOPED_INFO("a file with one bad record is still a cache"); + REQUIRE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, overrides, objects)); + UNSCOPED_INFO("the shallow record loaded, the deep one did not"); + REQUIRE(overrides.size() == 1u); + UNSCOPED_INFO("it is the shallow one"); + REQUIRE(overrides.find(1) != overrides.end()); // up to the budget, unreadable records are skipped; past it the file is refused std::vector garbage(16, std::string("\xff\xfe\xfd\xfc", 4)); garbage.push_back(binaryRecord(makeOverrideLLSD(3, handle, LLUUID::generateNewID(), 1))); writeExtrasFile(handle, id, garbage); overrides.clear(); - ensure("sixteen unreadable records are within the budget", LLVOCache::instance().readGenericExtrasFromCache(handle, id, overrides, objects)); - ensure_equals("and the good record after them loaded", overrides.size(), 1u); + UNSCOPED_INFO("sixteen unreadable records are within the budget"); + CHECK(LLVOCache::instance().readGenericExtrasFromCache(handle, id, overrides, objects)); + UNSCOPED_INFO("and the good record after them loaded"); + REQUIRE(overrides.size() == 1u); garbage.insert(garbage.begin(), std::string("\xff\xfe\xfd\xfc", 4)); writeExtrasFile(handle, id, garbage); overrides.clear(); - ensure("seventeen is a bad file", !LLVOCache::instance().readGenericExtrasFromCache(handle, id, overrides, objects)); + UNSCOPED_INFO("seventeen is a bad file"); + CHECK_FALSE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, overrides, objects)); // a face index no object has is dropped by the record parser LLSD faces = makeOverrideLLSD(4, handle, LLUUID::generateNewID(), 2); faces["sides"][1] = 300; LLGLTFOverrideCacheEntry entry; - ensure("the record still parses", entry.fromLLSD(faces)); - ensure_equals("only the face in range is kept", entry.mSides.size(), 1u); - ensure("and it is face 0", entry.mSides.find(0) != entry.mSides.end()); + UNSCOPED_INFO("the record still parses"); + REQUIRE(entry.fromLLSD(faces)); + UNSCOPED_INFO("only the face in range is kept"); + REQUIRE(entry.mSides.size() == 1u); + UNSCOPED_INFO("and it is face 0"); + REQUIRE(entry.mSides.find(0) != entry.mSides.end()); faces["sides"][1] = -1; LLGLTFOverrideCacheEntry negative; - ensure("a negative face parses", negative.fromLLSD(faces)); - ensure_equals("and is dropped too", negative.mSides.size(), 1u); + UNSCOPED_INFO("a negative face parses"); + REQUIRE(negative.fromLLSD(faces)); + UNSCOPED_INFO("and is dropped too"); + REQUIRE(negative.mSides.size() == 1u); } - template<> template<> - void vocacheTestObject::test<10>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: header slots survive a removal followed by a crash", "[LLVOCache]") { - set_test_name("header slots survive a removal followed by a crash"); - const LLUUID id = LLUUID::generateNewID(); const U64 first = to_region_handle(1010 * 256, 1000 * 256); const U64 second = to_region_handle(1011 * 256, 1000 * 256); @@ -652,25 +704,27 @@ namespace tut // crash means nobody closes it up LLVOCache::instance().removeEntry(second); restartAsAfterCrash(); - ensure_equals("two regions come back", LLVOCache::instance().getCacheEntries(), 2u); + UNSCOPED_INFO("two regions come back"); + CHECK(LLVOCache::instance().getCacheEntries() == 2u); // a new region has to take the hole, not the slot of the one behind it LLVOCache::instance().writeToCache(fourth, id, makeEntries(3), true, false); restartAsAfterCrash(); - ensure_equals("three regions come back", LLVOCache::instance().getCacheEntries(), 3u); + UNSCOPED_INFO("three regions come back"); + CHECK(LLVOCache::instance().getCacheEntries() == 3u); LLVOCacheEntry::vocache_entry_map_t read; - ensure("the first region is still there", LLVOCache::instance().readFromCache(first, id, read)); + UNSCOPED_INFO("the first region is still there"); + REQUIRE(LLVOCache::instance().readFromCache(first, id, read)); read.clear(); - ensure("the third region was not overwritten", LLVOCache::instance().readFromCache(third, id, read)); + UNSCOPED_INFO("the third region was not overwritten"); + CHECK(LLVOCache::instance().readFromCache(third, id, read)); read.clear(); - ensure("the new region is there", LLVOCache::instance().readFromCache(fourth, id, read)); + UNSCOPED_INFO("the new region is there"); + CHECK(LLVOCache::instance().readFromCache(fourth, id, read)); } - template<> template<> - void vocacheTestObject::test<11>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: extras are only rewritten when the overrides changed", "[LLVOCache]") { - set_test_name("extras are only rewritten when the overrides changed"); - const U64 handle = to_region_handle(1020 * 256, 1000 * 256); const LLUUID id = LLUUID::generateNewID(); LLVOCacheEntry::vocache_entry_map_t objects = makeEntries(4); @@ -686,17 +740,16 @@ namespace tut LLVOCache::instance().writeGenericExtrasToCache(handle, id, nothing, false, false); LLVOCacheEntry::vocache_gltf_overrides_map_t read; - ensure("the file still reads", LLVOCache::instance().readGenericExtrasFromCache(handle, id, read, objects)); - ensure_equals("and still holds both overrides", read.size(), 2u); + UNSCOPED_INFO("the file still reads"); + REQUIRE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, read, objects)); + UNSCOPED_INFO("and still holds both overrides"); + REQUIRE(read.size() == 2u); ensureSameOverride(overrides[1], read[1]); ensureSameOverride(overrides[2], read[2]); } - template<> template<> - void vocacheTestObject::test<12>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: staysInMemory keeps entries seen lately or inside the rear sphere", "[LLVOCache]") { - set_test_name("an entry stays in memory while its group was seen, its frame window holds, or it is inside the rear sphere"); - // A stand-in for an entry that nothing has looked at in a while: its // group was last visible well outside the window, and it sits far // enough back that the sphere cannot reach it either. @@ -716,16 +769,16 @@ namespace tut return facts; }; - ensure("an entry nothing has seen, far behind the camera, is dropped", - !LLVOCacheEntry::staysInMemory(forgotten())); + UNSCOPED_INFO("an entry nothing has seen, far behind the camera, is dropped"); + CHECK_FALSE(LLVOCacheEntry::staysInMemory(forgotten())); // the group is the first answer, and it outranks distance entirely { LLVOCacheEntry::VisibilityFacts facts = forgotten(); facts.mGroupRecentlyVisible = true; facts.mDistanceSquared = 1e12f; - ensure("a recently visible group keeps an entry at any distance", - LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("a recently visible group keeps an entry at any distance"); + CHECK(LLVOCacheEntry::staysInMemory(facts)); } // the frame window, with no group to ask @@ -734,12 +787,12 @@ namespace tut facts.mHasGroup = false; facts.mGroupAnyVisibleFrame = 0; facts.mEntryVisibleFrame = NOW - ((S32)RANGE - 1); - ensure("inside the frame window a group-less entry is kept", - LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("inside the frame window a group-less entry is kept"); + CHECK(LLVOCacheEntry::staysInMemory(facts)); facts.mEntryVisibleFrame = NOW - ((S32)RANGE + 1); - ensure("past the frame window and past the sphere it is dropped", - !LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("past the frame window and past the sphere it is dropped"); + CHECK_FALSE(LLVOCacheEntry::staysInMemory(facts)); } // a group that saw something more recently than the entry did wins @@ -747,24 +800,25 @@ namespace tut LLVOCacheEntry::VisibilityFacts facts = forgotten(); facts.mEntryVisibleFrame = NOW - 1000; facts.mGroupAnyVisibleFrame = NOW - ((S32)RANGE - 1); - ensure("the more recent of group and entry is the one used", - LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("the more recent of group and entry is the one used"); + CHECK(LLVOCacheEntry::staysInMemory(facts)); } // the sphere behind the camera, and the two things that switch it off { LLVOCacheEntry::VisibilityFacts facts = forgotten(); facts.mDistanceSquared = 32.f * 32.f; // inside 32 + 1 - ensure("inside the rear sphere it is kept", LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("inside the rear sphere it is kept"); + CHECK(LLVOCacheEntry::staysInMemory(facts)); facts.mIsChild = true; - ensure("a child is not judged by the sphere; it goes with its parent", - !LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("a child is not judged by the sphere; it goes with its parent"); + CHECK_FALSE(LLVOCacheEntry::staysInMemory(facts)); facts.mIsChild = false; facts.mGroupOccluded = true; - ensure("a group known to be occluded does not get the sphere either", - !LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("a group known to be occluded does not get the sphere either"); + CHECK_FALSE(LLVOCacheEntry::staysInMemory(facts)); } // the sphere's edge is exclusive, and the entry's own radius widens it @@ -772,11 +826,12 @@ namespace tut LLVOCacheEntry::VisibilityFacts facts = forgotten(); const F32 edge = facts.mDistThreshold + facts.mRadius; facts.mDistanceSquared = edge * edge; - ensure("exactly on the sphere is outside it", !LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("exactly on the sphere is outside it"); + CHECK_FALSE(LLVOCacheEntry::staysInMemory(facts)); facts.mRadius = 80.f; - ensure("a large entry reaches into the sphere from further out", - LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("a large entry reaches into the sphere from further out"); + CHECK(LLVOCacheEntry::staysInMemory(facts)); } // A zero window evicts an object that was visible this very frame. The @@ -787,19 +842,17 @@ namespace tut facts.mMinFrameRange = 0; facts.mEntryVisibleFrame = NOW; facts.mGroupAnyVisibleFrame = NOW; - ensure("a zero frame window drops an entry seen this frame", - !LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("a zero frame window drops an entry seen this frame"); + CHECK_FALSE(LLVOCacheEntry::staysInMemory(facts)); facts.mMinFrameRange = 1; - ensure("a window of one keeps it", LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("a window of one keeps it"); + CHECK(LLVOCacheEntry::staysInMemory(facts)); } } - template<> template<> - void vocacheTestObject::test<13>() + TEST_CASE_METHOD(vocacheTest, "LLVOCache: the radius that evicts an entry is wider than the one that loads it", "[LLVOCache]") { - set_test_name("the radius that evicts an entry is wider than the one that loads it"); - const F32 MIN_RADIUS = 32.f; // SceneLoadMinRadius const F32 DRAW = 128.f; auto evict = [&](F32 rear_far) { return LLVOCacheEntry::evictRadius(rear_far, MIN_RADIUS, DRAW); }; @@ -811,22 +864,25 @@ namespace tut for (F32 rear_far : rear_radii) { const F32 radius = evict(rear_far); - ensure("the eviction radius clears the load radius", radius >= rear_far * 1.25f); - ensure("and never reaches inside SceneLoadMinRadius", radius >= llmin(MIN_RADIUS, DRAW)); - ensure("and does not shrink as the load radius grows", radius >= previous); + UNSCOPED_INFO("the eviction radius clears the load radius"); + REQUIRE(radius >= rear_far * 1.25f); + UNSCOPED_INFO("and never reaches inside SceneLoadMinRadius"); + REQUIRE(radius >= llmin(MIN_RADIUS, DRAW)); + UNSCOPED_INFO("and does not shrink as the load radius grows"); + REQUIRE(radius >= previous); previous = radius; } // a draw distance under the setting is the floor instead - ensure("a short draw distance floors the radius, not the setting", - LLVOCacheEntry::evictRadius(2.f, MIN_RADIUS, 16.f) == 16.f); + UNSCOPED_INFO("a short draw distance floors the radius, not the setting"); + CHECK(LLVOCacheEntry::evictRadius(2.f, MIN_RADIUS, 16.f) == 16.f); // The sphere is the whole sphere, not just the part behind the camera, // and nothing beyond the draw distance is drawn, so nothing beyond it is // worth keeping for the turn back. Above four fifths of draw distance the // band between the two radii narrows to what is left. - ensure("the draw distance caps the radius", - LLVOCacheEntry::evictRadius(120.f, MIN_RADIUS, DRAW) == DRAW); + UNSCOPED_INFO("the draw distance caps the radius"); + CHECK(LLVOCacheEntry::evictRadius(120.f, MIN_RADIUS, DRAW) == DRAW); // The invariant the two radii exist for: an entry sitting exactly at the // distance the back cull preloads it from is not evictable, however long @@ -839,8 +895,8 @@ namespace tut facts.mMinFrameRange = 64; facts.mDistanceSquared = rear_far * rear_far; facts.mDistThreshold = evict(rear_far); - ensure("an entry at the load radius is never evicted at the eviction radius", - LLVOCacheEntry::staysInMemory(facts)); + UNSCOPED_INFO("an entry at the load radius is never evicted at the eviction radius"); + REQUIRE(LLVOCacheEntry::staysInMemory(facts)); } } } diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp index 655ebb5052..49905cf720 100644 --- a/indra/newview/tests/llworldmap_test.cpp +++ b/indra/newview/tests/llworldmap_test.cpp @@ -37,7 +37,7 @@ // Class to test #include "../llworldmap.h" // Tut header -#include "../test/lltut.h" +#include // ------------------------------------------------------------------------------------------- // Stubbing: Declarations required to link and run the class being tested @@ -106,7 +106,7 @@ const std::string TOOLTIP_TEST = "Tooltip Foo"; const std::string SIM_NAME_TEST = "Sim Foo"; -namespace tut +namespace { // Test wrapper declarations struct iteminfo_test @@ -159,19 +159,6 @@ namespace tut } }; - // Tut templating thingamagic: test group, object and test instance - typedef test_group iteminfo_t; - typedef iteminfo_t::object iteminfo_object_t; - tut::iteminfo_t tut_iteminfo("LLItemInfo"); - - typedef test_group siminfo_t; - typedef siminfo_t::object siminfo_object_t; - tut::siminfo_t tut_siminfo("LLSimInfo"); - - typedef test_group worldmap_t; - typedef worldmap_t::object worldmap_object_t; - tut::worldmap_t tut_worldmap("LLWorldMap"); - // --------------------------------------------------------------------------------------- // Test functions // Notes: @@ -183,86 +170,99 @@ namespace tut // --------------------------------------------------------------------------------------- // Test the LLItemInfo interface // --------------------------------------------------------------------------------------- - template<> template<> - void iteminfo_object_t::test<1>() + TEST_CASE_METHOD(iteminfo_test, "LLItemInfo: each accessor returns what the item was made or set with", "[LLItemInfo]") { // Test 1 : setCount() / getCount() mItem->setCount(10); - ensure("LLItemInfo::setCount() test failed", mItem->getCount() == 10); + UNSCOPED_INFO("LLItemInfo::setCount() test failed"); + CHECK(mItem->getCount() == 10); // Test 2 : setTooltip() / getToolTip() std::string tooltip = TOOLTIP_TEST; mItem->setTooltip(tooltip); - ensure("LLItemInfo::setTooltip() test failed", mItem->getToolTip() == TOOLTIP_TEST); + UNSCOPED_INFO("LLItemInfo::setTooltip() test failed"); + CHECK(mItem->getToolTip() == TOOLTIP_TEST); // Test 3 : setElevation() / getGlobalPosition() mItem->setElevation(Z_WORLD_TEST); LLVector3d pos = mItem->getGlobalPosition(); LLVector3d ref(X_WORLD_TEST, Y_WORLD_TEST, Z_WORLD_TEST); - ensure("LLItemInfo::getGlobalPosition() test failed", pos == ref); + UNSCOPED_INFO("LLItemInfo::getGlobalPosition() test failed"); + CHECK(pos == ref); // Test 4 : getName() std::string name = mItem->getName(); - ensure("LLItemInfo::getName() test failed", name == ITEM_NAME_TEST); + UNSCOPED_INFO("LLItemInfo::getName() test failed"); + CHECK(name == ITEM_NAME_TEST); // Test 5 : isName() - ensure("LLItemInfo::isName() test failed", mItem->isName(name)); + UNSCOPED_INFO("LLItemInfo::isName() test failed"); + CHECK(mItem->isName(name)); // Test 6 : getUUID() LLUUID id; - ensure("LLItemInfo::getUUID() test failed", mItem->getUUID() == id); + UNSCOPED_INFO("LLItemInfo::getUUID() test failed"); + CHECK(mItem->getUUID() == id); // Test 7 : getRegionHandle() U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST); - ensure("LLItemInfo::getRegionHandle() test failed", mItem->getRegionHandle() == handle); + UNSCOPED_INFO("LLItemInfo::getRegionHandle() test failed"); + CHECK(mItem->getRegionHandle() == handle); } // --------------------------------------------------------------------------------------- // Test the LLSimInfo interface // --------------------------------------------------------------------------------------- // Test Setters and Accessors methods - template<> template<> - void siminfo_object_t::test<1>() + TEST_CASE_METHOD(siminfo_test, "LLSimInfo: each accessor returns what was set and image calls do not throw", "[LLSimInfo]") { // Test 1 : setName() / getName() std::string name = SIM_NAME_TEST; mSim->setName(name); - ensure("LLSimInfo::setName() test failed", mSim->getName() == SIM_NAME_TEST); + UNSCOPED_INFO("LLSimInfo::setName() test failed"); + CHECK(mSim->getName() == SIM_NAME_TEST); // Test 2 : isName() - ensure("LLSimInfo::isName() test failed", mSim->isName(name)); + UNSCOPED_INFO("LLSimInfo::isName() test failed"); + CHECK(mSim->isName(name)); // Test 3 : getGlobalPos() LLVector3 local; LLVector3d ref(X_WORLD_TEST, Y_WORLD_TEST, 0.0f); LLVector3d pos = mSim->getGlobalPos(local); - ensure("LLSimInfo::getGlobalPos() test failed", pos == ref); + UNSCOPED_INFO("LLSimInfo::getGlobalPos() test failed"); + CHECK(pos == ref); // Test 4 : getGlobalOrigin() pos = mSim->getGlobalOrigin(); - ensure("LLSimInfo::getGlobalOrigin() test failed", pos == ref); + UNSCOPED_INFO("LLSimInfo::getGlobalOrigin() test failed"); + CHECK(pos == ref); // Test 5 : clearImage() try { mSim->clearImage(); } catch (...) { - fail("LLSimInfo::clearImage() test failed"); + FAIL("LLSimInfo::clearImage() test failed"); } // Test 6 : dropImagePriority() try { mSim->dropImagePriority(); } catch (...) { - fail("LLSimInfo::dropImagePriority() test failed"); + FAIL("LLSimInfo::dropImagePriority() test failed"); } // Test 7 : updateAgentCount() try { mSim->updateAgentCount(0.0f); } catch (...) { - fail("LLSimInfo::updateAgentCount() test failed"); + FAIL("LLSimInfo::updateAgentCount() test failed"); } // Test 8 : getAgentCount() S32 agents = mSim->getAgentCount(); - ensure("LLSimInfo::getAgentCount() test failed", agents == 0); + UNSCOPED_INFO("LLSimInfo::getAgentCount() test failed"); + CHECK(agents == 0); // Test 9 : setLandForSaleImage() / getLandForSaleImage() LLUUID id; mSim->setLandForSaleImage(id); LLPointer image = mSim->getLandForSaleImage(); - ensure("LLSimInfo::getLandForSaleImage() test failed", image.isNull()); + UNSCOPED_INFO("LLSimInfo::getLandForSaleImage() test failed"); + REQUIRE(image.isNull()); // Test 10 : isPG() mSim->setAccess(SIM_ACCESS_PG); - ensure("LLSimInfo::isPG() test failed", mSim->isPG()); + UNSCOPED_INFO("LLSimInfo::isPG() test failed"); + CHECK(mSim->isPG()); // Test 11 : isDown() mSim->setAccess(SIM_ACCESS_DOWN); - ensure("LLSimInfo::isDown() test failed", mSim->isDown()); + UNSCOPED_INFO("LLSimInfo::isDown() test failed"); + CHECK(mSim->isDown()); // Test 12 : Access strings can't be accessed from unit test... //ensure("LLSimInfo::getAccessString() test failed", mSim->getAccessString() == "Offline"); // Test 13 : Region strings can't be accessed from unit test... @@ -270,30 +270,35 @@ namespace tut //ensure("LLSimInfo::setRegionFlags() test failed", mSim->getFlagsString() == "Sandbox"); } // Test management of LLInfoItem lists - template<> template<> - void siminfo_object_t::test<2>() + TEST_CASE_METHOD(siminfo_test, "LLSimInfo: clearItems empties every item list but agent locations", "[LLSimInfo]") { // Test 14 : clearItems() try { mSim->clearItems(); } catch (...) { - fail("LLSimInfo::clearItems() at init test failed"); + FAIL("LLSimInfo::clearItems() at init test failed"); } // Test 15 : Verify that all the lists are empty LLSimInfo::item_info_list_t list; list = mSim->getTeleHub(); - ensure("LLSimInfo::getTeleHub() empty at init test failed", list.empty()); + UNSCOPED_INFO("LLSimInfo::getTeleHub() empty at init test failed"); + REQUIRE(list.empty()); list = mSim->getInfoHub(); - ensure("LLSimInfo::getInfoHub() empty at init test failed", list.empty()); + UNSCOPED_INFO("LLSimInfo::getInfoHub() empty at init test failed"); + REQUIRE(list.empty()); list = mSim->getPGEvent(); - ensure("LLSimInfo::getPGEvent() empty at init test failed", list.empty()); + UNSCOPED_INFO("LLSimInfo::getPGEvent() empty at init test failed"); + REQUIRE(list.empty()); list = mSim->getMatureEvent(); - ensure("LLSimInfo::getMatureEvent() empty at init test failed", list.empty()); + UNSCOPED_INFO("LLSimInfo::getMatureEvent() empty at init test failed"); + REQUIRE(list.empty()); list = mSim->getLandForSale(); - ensure("LLSimInfo::getLandForSale() empty at init test failed", list.empty()); + UNSCOPED_INFO("LLSimInfo::getLandForSale() empty at init test failed"); + REQUIRE(list.empty()); list = mSim->getAgentLocation(); - ensure("LLSimInfo::getAgentLocation() empty at init test failed", list.empty()); + UNSCOPED_INFO("LLSimInfo::getAgentLocation() empty at init test failed"); + REQUIRE(list.empty()); // Create an item to be inserted LLUUID id; @@ -309,106 +314,118 @@ namespace tut // Test 16 : Verify that the lists contain 1 item each list = mSim->getTeleHub(); - ensure("LLSimInfo::insertTeleHub() test failed", list.size() == 1); + UNSCOPED_INFO("LLSimInfo::insertTeleHub() test failed"); + REQUIRE(list.size() == 1); list = mSim->getInfoHub(); - ensure("LLSimInfo::insertInfoHub() test failed", list.size() == 1); + UNSCOPED_INFO("LLSimInfo::insertInfoHub() test failed"); + REQUIRE(list.size() == 1); list = mSim->getPGEvent(); - ensure("LLSimInfo::insertPGEvent() test failed", list.size() == 1); + UNSCOPED_INFO("LLSimInfo::insertPGEvent() test failed"); + REQUIRE(list.size() == 1); list = mSim->getMatureEvent(); - ensure("LLSimInfo::insertMatureEvent() test failed", list.size() == 1); + UNSCOPED_INFO("LLSimInfo::insertMatureEvent() test failed"); + REQUIRE(list.size() == 1); list = mSim->getLandForSale(); - ensure("LLSimInfo::insertLandForSale() test failed", list.size() == 1); + UNSCOPED_INFO("LLSimInfo::insertLandForSale() test failed"); + REQUIRE(list.size() == 1); list = mSim->getAgentLocation(); - ensure("LLSimInfo::insertAgentLocation() test failed", list.size() == 1); + UNSCOPED_INFO("LLSimInfo::insertAgentLocation() test failed"); + REQUIRE(list.size() == 1); // Test 17 : clearItems() try { mSim->clearItems(); } catch (...) { - fail("LLSimInfo::clearItems() at end test failed"); + FAIL("LLSimInfo::clearItems() at end test failed"); } // Test 18 : Verify that all the lists are empty again... *except* agent which is persisted!! (on purpose) list = mSim->getTeleHub(); - ensure("LLSimInfo::getTeleHub() empty after clear test failed", list.empty()); + UNSCOPED_INFO("LLSimInfo::getTeleHub() empty after clear test failed"); + REQUIRE(list.empty()); list = mSim->getInfoHub(); - ensure("LLSimInfo::getInfoHub() empty after clear test failed", list.empty()); + UNSCOPED_INFO("LLSimInfo::getInfoHub() empty after clear test failed"); + REQUIRE(list.empty()); list = mSim->getPGEvent(); - ensure("LLSimInfo::getPGEvent() empty after clear test failed", list.empty()); + UNSCOPED_INFO("LLSimInfo::getPGEvent() empty after clear test failed"); + REQUIRE(list.empty()); list = mSim->getMatureEvent(); - ensure("LLSimInfo::getMatureEvent() empty after clear test failed", list.empty()); + UNSCOPED_INFO("LLSimInfo::getMatureEvent() empty after clear test failed"); + REQUIRE(list.empty()); list = mSim->getLandForSale(); - ensure("LLSimInfo::getLandForSale() empty after clear test failed", list.empty()); + UNSCOPED_INFO("LLSimInfo::getLandForSale() empty after clear test failed"); + REQUIRE(list.empty()); list = mSim->getAgentLocation(); - ensure("LLSimInfo::getAgentLocation() empty after clear test failed", list.size() == 1); + UNSCOPED_INFO("LLSimInfo::getAgentLocation() empty after clear test failed"); + REQUIRE(list.size() == 1); } // --------------------------------------------------------------------------------------- // Test the LLWorldMap interface // --------------------------------------------------------------------------------------- // Test Setters and Accessors methods - template<> template<> - void worldmap_object_t::test<1>() + TEST_CASE_METHOD(worldmap_test, "LLWorldMap: the image and region calls do not throw and no tile is loaded", "[LLWorldMap]") { // Test 1 : reset() try { mWorld->reset(); } catch (...) { - fail("LLWorldMap::reset() at init test failed"); + FAIL("LLWorldMap::reset() at init test failed"); } // Test 2 : clearImageRefs() try { mWorld->clearImageRefs(); } catch (...) { - fail("LLWorldMap::clearImageRefs() test failed"); + FAIL("LLWorldMap::clearImageRefs() test failed"); } // Test 3 : dropImagePriorities() try { mWorld->dropImagePriorities(); } catch (...) { - fail("LLWorldMap::dropImagePriorities() test failed"); + FAIL("LLWorldMap::dropImagePriorities() test failed"); } // Test 4 : reloadItems() try { mWorld->reloadItems(true); } catch (...) { - fail("LLWorldMap::reloadItems() test failed"); + FAIL("LLWorldMap::reloadItems() test failed"); } // Test 5 : updateRegions() try { mWorld->updateRegions(1000, 1000, 1004, 1004); } catch (...) { - fail("LLWorldMap::updateRegions() test failed"); + FAIL("LLWorldMap::updateRegions() test failed"); } // Test 6 : equalizeBoostLevels() try { mWorld->equalizeBoostLevels(); } catch (...) { - fail("LLWorldMap::equalizeBoostLevels() test failed"); + FAIL("LLWorldMap::equalizeBoostLevels() test failed"); } // Test 7 : getObjectsTile() try { LLPointer image = mWorld->getObjectsTile((U32)(X_WORLD_TEST/REGION_WIDTH_METERS), (U32)(Y_WORLD_TEST/REGION_WIDTH_METERS), 1); - ensure("LLWorldMap::getObjectsTile() failed", image.isNull()); + UNSCOPED_INFO("LLWorldMap::getObjectsTile() failed"); + REQUIRE(image.isNull()); } catch (...) { - fail("LLWorldMap::getObjectsTile() test failed with exception"); + FAIL("LLWorldMap::getObjectsTile() test failed with exception"); } } // Test management of LLSimInfo lists - template<> template<> - void worldmap_object_t::test<2>() + TEST_CASE_METHOD(worldmap_test, "LLWorldMap: inserted regions are found by position and name and handle until reset", "[LLWorldMap]") { // Test 8 : reset() try { mWorld->reset(); } catch (...) { - fail("LLWorldMap::reset() at init test failed"); + FAIL("LLWorldMap::reset() at init test failed"); } // Test 9 : Verify that all the region list is empty LLWorldMap::sim_info_map_t list; list = mWorld->getRegionMap(); - ensure("LLWorldMap::getRegionMap() empty at init test failed", list.empty()); + UNSCOPED_INFO("LLWorldMap::getRegionMap() empty at init test failed"); + REQUIRE(list.empty()); // Test 10 : Insert a region bool success; @@ -421,7 +438,11 @@ namespace tut SIM_ACCESS_PG, REGION_FLAGS_SANDBOX); list = mWorld->getRegionMap(); - ensure("LLWorldMap::insertRegion() failed", success && (list.size() == 1)); + { + INFO("LLWorldMap::insertRegion() failed"); + CHECK(success); + REQUIRE(list.size() == 1); + } // Test 11 : Insert an item in the same region -> number of regions doesn't increase std::string name_item = ITEM_NAME_TEST; @@ -432,7 +453,11 @@ namespace tut MAP_ITEM_LAND_FOR_SALE, 0, 0); list = mWorld->getRegionMap(); - ensure("LLWorldMap::insertItem() in existing region failed", success && (list.size() == 1)); + { + INFO("LLWorldMap::insertItem() in existing region failed"); + CHECK(success); + REQUIRE(list.size() == 1); + } // Test 12 : Insert an item in another region -> number of regions increases success = mWorld->insertItem( U32(X_WORLD_TEST + REGION_WIDTH_METERS*2), @@ -442,7 +467,11 @@ namespace tut MAP_ITEM_LAND_FOR_SALE, 0, 0); list = mWorld->getRegionMap(); - ensure("LLWorldMap::insertItem() in unexisting region failed", success && (list.size() == 2)); + { + INFO("LLWorldMap::insertItem() in unexisting region failed"); + CHECK(success); + REQUIRE(list.size() == 2); + } // Test 13 : simInfoFromPosGlobal() in region LLVector3d pos1( X_WORLD_TEST + REGION_WIDTH_METERS*2 + REGION_WIDTH_METERS/2, @@ -450,120 +479,158 @@ namespace tut 0.0f); LLSimInfo* sim; sim = mWorld->simInfoFromPosGlobal(pos1); - ensure("LLWorldMap::simInfoFromPosGlobal() test on existing region failed", sim != NULL); + UNSCOPED_INFO("LLWorldMap::simInfoFromPosGlobal() test on existing region failed"); + REQUIRE(sim != NULL); // Test 14 : simInfoFromPosGlobal() outside region LLVector3d pos2( X_WORLD_TEST + REGION_WIDTH_METERS*4 + REGION_WIDTH_METERS/2, Y_WORLD_TEST + REGION_WIDTH_METERS*4 + REGION_WIDTH_METERS/2, 0.0f); sim = mWorld->simInfoFromPosGlobal(pos2); - ensure("LLWorldMap::simInfoFromPosGlobal() test outside region failed", sim == NULL); + UNSCOPED_INFO("LLWorldMap::simInfoFromPosGlobal() test outside region failed"); + REQUIRE(sim == NULL); // Test 15 : simInfoFromName() sim = mWorld->simInfoFromName(name_sim); - ensure("LLWorldMap::simInfoFromName() test on existing region failed", sim != NULL); + UNSCOPED_INFO("LLWorldMap::simInfoFromName() test on existing region failed"); + REQUIRE(sim != NULL); // Test 16 : simInfoFromHandle() U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST); sim = mWorld->simInfoFromHandle(handle); - ensure("LLWorldMap::simInfoFromHandle() test on existing region failed", sim != NULL); + UNSCOPED_INFO("LLWorldMap::simInfoFromHandle() test on existing region failed"); + REQUIRE(sim != NULL); // Test 17 : simNameFromPosGlobal() LLVector3d pos3( X_WORLD_TEST + REGION_WIDTH_METERS/2, Y_WORLD_TEST + REGION_WIDTH_METERS/2, 0.0f); success = mWorld->simNameFromPosGlobal(pos3, name_sim); - ensure("LLWorldMap::simNameFromPosGlobal() test on existing region failed", success && (name_sim == SIM_NAME_TEST)); + { + INFO("LLWorldMap::simNameFromPosGlobal() test on existing region failed"); + CHECK(success); + CHECK(name_sim == SIM_NAME_TEST); + } // Test 18 : reset() try { mWorld->reset(); } catch (...) { - fail("LLWorldMap::reset() at end test failed"); + FAIL("LLWorldMap::reset() at end test failed"); } // Test 19 : Verify that all the region list is empty list = mWorld->getRegionMap(); - ensure("LLWorldMap::getRegionMap() empty at end test failed", list.empty()); + UNSCOPED_INFO("LLWorldMap::getRegionMap() empty at end test failed"); + REQUIRE(list.empty()); } // Test tracking - template<> template<> - void worldmap_object_t::test<3>() + TEST_CASE_METHOD(worldmap_test, "LLWorldMap: tracking a position sets its flags and keeps it until cancelled", "[LLWorldMap]") { // Point to track LLVector3d pos( X_WORLD_TEST + REGION_WIDTH_METERS/2, Y_WORLD_TEST + REGION_WIDTH_METERS/2, Z_WORLD_TEST); // Test 20 : no tracking mWorld->cancelTracking(); - ensure("LLWorldMap::cancelTracking() at begin test failed", mWorld->isTracking() == false); + UNSCOPED_INFO("LLWorldMap::cancelTracking() at begin test failed"); + CHECK_FALSE(mWorld->isTracking()); // Test 21 : set tracking mWorld->setTracking(pos); - ensure("LLWorldMap::setTracking() failed", mWorld->isTracking() && !mWorld->isTrackingValidLocation()); + { + INFO("LLWorldMap::setTracking() failed"); + REQUIRE(mWorld->isTracking()); + CHECK_FALSE(mWorld->isTrackingValidLocation()); + } // Test 22 : set click and commit flags mWorld->setTrackingDoubleClick(); - ensure("LLWorldMap::setTrackingDoubleClick() failed", mWorld->isTrackingDoubleClick()); + UNSCOPED_INFO("LLWorldMap::setTrackingDoubleClick() failed"); + CHECK(mWorld->isTrackingDoubleClick()); mWorld->setTrackingCommit(); - ensure("LLWorldMap::setTrackingCommit() failed", mWorld->isTrackingCommit()); + UNSCOPED_INFO("LLWorldMap::setTrackingCommit() failed"); + CHECK(mWorld->isTrackingCommit()); // Test 23 : in rectangle test bool inRect = mWorld->isTrackingInRectangle( X_WORLD_TEST, Y_WORLD_TEST, X_WORLD_TEST + REGION_WIDTH_METERS, Y_WORLD_TEST + REGION_WIDTH_METERS); - ensure("LLWorldMap::isTrackingInRectangle() in rectangle failed", inRect); + UNSCOPED_INFO("LLWorldMap::isTrackingInRectangle() in rectangle failed"); + CHECK(inRect); inRect = mWorld->isTrackingInRectangle( X_WORLD_TEST + REGION_WIDTH_METERS, Y_WORLD_TEST + REGION_WIDTH_METERS, X_WORLD_TEST + 2 * REGION_WIDTH_METERS, Y_WORLD_TEST + 2 * REGION_WIDTH_METERS); - ensure("LLWorldMap::isTrackingInRectangle() outside rectangle failed", !inRect); + UNSCOPED_INFO("LLWorldMap::isTrackingInRectangle() outside rectangle failed"); + CHECK_FALSE(inRect); // Test 24 : set tracking to valid and invalid mWorld->setTrackingValid(); - ensure("LLWorldMap::setTrackingValid() failed", mWorld->isTrackingValidLocation() && !mWorld->isTrackingInvalidLocation()); + { + INFO("LLWorldMap::setTrackingValid() failed"); + REQUIRE(mWorld->isTrackingValidLocation()); + CHECK_FALSE(mWorld->isTrackingInvalidLocation()); + } mWorld->setTrackingInvalid(); - ensure("LLWorldMap::setTrackingInvalid() failed", !mWorld->isTrackingValidLocation() && mWorld->isTrackingInvalidLocation()); + { + INFO("LLWorldMap::setTrackingInvalid() failed"); + REQUIRE_FALSE(mWorld->isTrackingValidLocation()); + CHECK(mWorld->isTrackingInvalidLocation()); + } // Test 25 : getTrackedPositionGlobal() LLVector3d res = mWorld->getTrackedPositionGlobal(); - ensure("LLWorldMap::getTrackedPositionGlobal() failed", res == pos); + UNSCOPED_INFO("LLWorldMap::getTrackedPositionGlobal() failed"); + CHECK(res == pos); // Test 26 : reset tracking mWorld->cancelTracking(); - ensure("LLWorldMap::cancelTracking() at end test failed", mWorld->isTracking() == false); + UNSCOPED_INFO("LLWorldMap::cancelTracking() at end test failed"); + CHECK_FALSE(mWorld->isTracking()); } // Test updateRegions() request grouping, size limits, and bounds - template<> template<> - void worldmap_object_t::test<4>() + TEST_CASE_METHOD(worldmap_test, "LLWorldMap: updateRegions asks in requests of at most 64 regions within bounds", "[LLWorldMap]") { // Test 27 : 1x1 block (4x4 = 16 regions) - single small request within bounds mWorld->reset(); gMapBlockRequests.clear(); mWorld->updateRegions(0, 0, 3, 3); - ensure("updateRegions 1x1 block: expected 1 request", gMapBlockRequests.size() == 1); + UNSCOPED_INFO("updateRegions 1x1 block: expected 1 request"); + REQUIRE(gMapBlockRequests.size() == 1); { const MapBlockRequest& req = gMapBlockRequests[0]; - ensure("updateRegions 1x1 block: min_x", req.min_x == 0); - ensure("updateRegions 1x1 block: min_y", req.min_y == 0); - ensure("updateRegions 1x1 block: max_x", req.max_x == 3); - ensure("updateRegions 1x1 block: max_y", req.max_y == 3); + UNSCOPED_INFO("updateRegions 1x1 block: min_x"); + CHECK(req.min_x == 0); + UNSCOPED_INFO("updateRegions 1x1 block: min_y"); + CHECK(req.min_y == 0); + UNSCOPED_INFO("updateRegions 1x1 block: max_x"); + CHECK(req.max_x == 3); + UNSCOPED_INFO("updateRegions 1x1 block: max_y"); + CHECK(req.max_y == 3); S32 regions = (req.max_x - req.min_x + 1) * (req.max_y - req.min_y + 1); - ensure("updateRegions 1x1 block: must not exceed 64 regions", regions <= 64); + UNSCOPED_INFO("updateRegions 1x1 block: must not exceed 64 regions"); + CHECK(regions <= 64); } // Test 28 : 2x2 blocks (8x8 = 64 regions) - single request at the 64-region limit mWorld->reset(); gMapBlockRequests.clear(); mWorld->updateRegions(0, 0, 7, 7); - ensure("updateRegions 2x2 blocks: expected 1 request", gMapBlockRequests.size() == 1); + UNSCOPED_INFO("updateRegions 2x2 blocks: expected 1 request"); + REQUIRE(gMapBlockRequests.size() == 1); { const MapBlockRequest& req = gMapBlockRequests[0]; - ensure("updateRegions 2x2 blocks: min_x", req.min_x == 0); - ensure("updateRegions 2x2 blocks: min_y", req.min_y == 0); - ensure("updateRegions 2x2 blocks: max_x", req.max_x == 7); - ensure("updateRegions 2x2 blocks: max_y", req.max_y == 7); + UNSCOPED_INFO("updateRegions 2x2 blocks: min_x"); + CHECK(req.min_x == 0); + UNSCOPED_INFO("updateRegions 2x2 blocks: min_y"); + CHECK(req.min_y == 0); + UNSCOPED_INFO("updateRegions 2x2 blocks: max_x"); + CHECK(req.max_x == 7); + UNSCOPED_INFO("updateRegions 2x2 blocks: max_y"); + CHECK(req.max_y == 7); S32 regions = (req.max_x - req.min_x + 1) * (req.max_y - req.min_y + 1); - ensure("updateRegions 2x2 blocks: must not exceed 64 regions", regions <= 64); + UNSCOPED_INFO("updateRegions 2x2 blocks: must not exceed 64 regions"); + CHECK(regions <= 64); } // Test 29 : 4x4 blocks (16x16 = 256 total regions) - must split into multiple requests @@ -571,24 +638,36 @@ namespace tut mWorld->reset(); gMapBlockRequests.clear(); mWorld->updateRegions(0, 0, 15, 15); - ensure("updateRegions 4x4 blocks: expected 4 requests", gMapBlockRequests.size() == 4); + UNSCOPED_INFO("updateRegions 4x4 blocks: expected 4 requests"); + REQUIRE(gMapBlockRequests.size() == 4); for (size_t i = 0; i < gMapBlockRequests.size(); ++i) { const MapBlockRequest& req = gMapBlockRequests[i]; S32 regions = (req.max_x - req.min_x + 1) * (req.max_y - req.min_y + 1); - ensure("updateRegions 4x4 blocks: each request must not exceed 64 regions", regions <= 64); + UNSCOPED_INFO("updateRegions 4x4 blocks: each request must not exceed 64 regions"); + REQUIRE(regions <= 64); // Requests must stay within the requested area (0..15) - ensure("updateRegions 4x4 blocks: max_x in bounds", req.max_x <= 15); - ensure("updateRegions 4x4 blocks: max_y in bounds", req.max_y <= 15); + UNSCOPED_INFO("updateRegions 4x4 blocks: max_x in bounds"); + REQUIRE(req.max_x <= 15); + UNSCOPED_INFO("updateRegions 4x4 blocks: max_y in bounds"); + REQUIRE(req.max_y <= 15); } // Each request covers one horizontal strip of 4 blocks (rows 0..3, 4..7, 8..11, 12..15) - ensure("updateRegions 4x4 blocks: request[0] min_y", gMapBlockRequests[0].min_y == 0); - ensure("updateRegions 4x4 blocks: request[0] max_y", gMapBlockRequests[0].max_y == 3); - ensure("updateRegions 4x4 blocks: request[1] min_y", gMapBlockRequests[1].min_y == 4); - ensure("updateRegions 4x4 blocks: request[1] max_y", gMapBlockRequests[1].max_y == 7); - ensure("updateRegions 4x4 blocks: request[2] min_y", gMapBlockRequests[2].min_y == 8); - ensure("updateRegions 4x4 blocks: request[2] max_y", gMapBlockRequests[2].max_y == 11); - ensure("updateRegions 4x4 blocks: request[3] min_y", gMapBlockRequests[3].min_y == 12); - ensure("updateRegions 4x4 blocks: request[3] max_y", gMapBlockRequests[3].max_y == 15); + UNSCOPED_INFO("updateRegions 4x4 blocks: request[0] min_y"); + CHECK(gMapBlockRequests[0].min_y == 0); + UNSCOPED_INFO("updateRegions 4x4 blocks: request[0] max_y"); + CHECK(gMapBlockRequests[0].max_y == 3); + UNSCOPED_INFO("updateRegions 4x4 blocks: request[1] min_y"); + CHECK(gMapBlockRequests[1].min_y == 4); + UNSCOPED_INFO("updateRegions 4x4 blocks: request[1] max_y"); + CHECK(gMapBlockRequests[1].max_y == 7); + UNSCOPED_INFO("updateRegions 4x4 blocks: request[2] min_y"); + CHECK(gMapBlockRequests[2].min_y == 8); + UNSCOPED_INFO("updateRegions 4x4 blocks: request[2] max_y"); + CHECK(gMapBlockRequests[2].max_y == 11); + UNSCOPED_INFO("updateRegions 4x4 blocks: request[3] min_y"); + CHECK(gMapBlockRequests[3].min_y == 12); + UNSCOPED_INFO("updateRegions 4x4 blocks: request[3] max_y"); + CHECK(gMapBlockRequests[3].max_y == 15); } } diff --git a/indra/newview/tests/llworldmipmap_test.cpp b/indra/newview/tests/llworldmipmap_test.cpp index 76b50c4c5b..f5690c30ba 100644 --- a/indra/newview/tests/llworldmipmap_test.cpp +++ b/indra/newview/tests/llworldmipmap_test.cpp @@ -32,7 +32,7 @@ // Class to test #include "../llworldmipmap.h" // Tut header -#include "../test/lltut.h" +#include // ------------------------------------------------------------------------------------------- // Stubbing: Declarations required to link and run the class being tested @@ -57,7 +57,7 @@ LLControlGroup gSavedSettings("llworldmipmap"); // ------------------------------------------------------------------------------------------- // TUT // ------------------------------------------------------------------------------------------- -namespace tut +namespace { // Test wrapper declaration struct worldmipmap_test @@ -81,11 +81,6 @@ namespace tut } }; - // Tut templating thingamagic: test group, object and test instance - typedef test_group worldmipmap_t; - typedef worldmipmap_t::object worldmipmap_object_t; - tut::worldmipmap_t tut_worldmipmap("LLWorldMipmap"); - // --------------------------------------------------------------------------------------- // Test functions // Notes: @@ -95,37 +90,44 @@ namespace tut // --------------------------------------------------------------------------------------- // Test static methods // Test 1 : scaleToLevel() - template<> template<> - void worldmipmap_object_t::test<1>() + TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: scaleToLevel is MAP_LEVELS at zero and 1 from a tile's size up", "[LLWorldMipmap]") { S32 level = mMap->scaleToLevel(0.0); - ensure("scaleToLevel() test 1 failed", level == LLWorldMipmap::MAP_LEVELS); + UNSCOPED_INFO("scaleToLevel() test 1 failed"); + CHECK(level == LLWorldMipmap::MAP_LEVELS); level = mMap->scaleToLevel((F32)LLWorldMipmap::MAP_TILE_SIZE); - ensure("scaleToLevel() test 2 failed", level == 1); + UNSCOPED_INFO("scaleToLevel() test 2 failed"); + CHECK(level == 1); level = mMap->scaleToLevel(10.f * LLWorldMipmap::MAP_TILE_SIZE); - ensure("scaleToLevel() test 3 failed", level == 1); + UNSCOPED_INFO("scaleToLevel() test 3 failed"); + CHECK(level == 1); } // Test 2 : globalToMipmap() - template<> template<> - void worldmipmap_object_t::test<2>() + TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: globalToMipmap gives a position's region grid cell", "[LLWorldMipmap]") { U32 grid_x, grid_y; mMap->globalToMipmap(1000.f*REGION_WIDTH_METERS, 1000.f*REGION_WIDTH_METERS, 1, &grid_x, &grid_y); - ensure("globalToMipmap() test 1 failed", (grid_x == 1000) && (grid_y == 1000)); + { + INFO("globalToMipmap() test 1 failed"); + CHECK(grid_x == 1000); + CHECK(grid_y == 1000); + } mMap->globalToMipmap(0.0, 0.0, LLWorldMipmap::MAP_LEVELS, &grid_x, &grid_y); - ensure("globalToMipmap() test 2 failed", (grid_x == 0) && (grid_y == 0)); + { + INFO("globalToMipmap() test 2 failed"); + CHECK(grid_x == 0); + CHECK(grid_y == 0); + } } // Test 3 : getObjectsTile() - template<> template<> - void worldmipmap_object_t::test<3>() + TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: getObjectsTile (not yet tested)", "[LLWorldMipmap]") { // Depends on some inline methods in LLViewerImage... Thinking about how to make this work // LLPointer img = mMap->getObjectsTile(0, 0, 1); // ensure("getObjectsTile() test failed", img.isNull()); } // Test 4 : equalizeBoostLevels() - template<> template<> - void worldmipmap_object_t::test<4>() + TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: equalizeBoostLevels does not throw", "[LLWorldMipmap]") { try { @@ -133,12 +135,11 @@ namespace tut } catch (...) { - fail("equalizeBoostLevels() test failed"); + FAIL("equalizeBoostLevels() test failed"); } } // Test 5 : dropBoostLevels() - template<> template<> - void worldmipmap_object_t::test<5>() + TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: dropBoostLevels does not throw", "[LLWorldMipmap]") { try { @@ -146,12 +147,11 @@ namespace tut } catch (...) { - fail("dropBoostLevels() test failed"); + FAIL("dropBoostLevels() test failed"); } } // Test 6 : reset() - template<> template<> - void worldmipmap_object_t::test<6>() + TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: reset does not throw", "[LLWorldMipmap]") { try { @@ -159,7 +159,7 @@ namespace tut } catch (...) { - fail("reset() test failed"); + FAIL("reset() test failed"); } } } diff --git a/indra/newview/tests/lutcube_test.cpp b/indra/newview/tests/lutcube_test.cpp index b4f183c19e..c468387c31 100644 --- a/indra/newview/tests/lutcube_test.cpp +++ b/indra/newview/tests/lutcube_test.cpp @@ -17,13 +17,13 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include #include "../lutcube.h" #include -namespace tut +namespace { struct lutcube_data { @@ -76,50 +76,56 @@ namespace tut static constexpr int MID = 32768; }; - typedef test_group lutcube_group; - typedef lutcube_group::object lutcube_object; - tut::lutcube_group lcg("LutCube"); - // The ordinary case, and the layout the uploader depends on: red varies // fastest, so entry 1 of a size-2 cube is (FULL, 0, 0). - template<> template<> - void lutcube_object::test<1>() + TEST_CASE_METHOD(lutcube_data, "LutCube: an identity cube parses with red varying fastest", "[LutCube]") { const LutCube cube = parse(identity(2)); - ensure_equals("size", cube.size, 2); - ensure_equals("entry count", (int)cube.colorCube.size(), 2 * 2 * 2 * 4); - - ensure_equals("black R", at(cube, 0, 0), 0); - ensure_equals("black G", at(cube, 0, 1), 0); - ensure_equals("black B", at(cube, 0, 2), 0); - - ensure_equals("red is next R", at(cube, 1, 0), FULL); - ensure_equals("red is next G", at(cube, 1, 1), 0); - ensure_equals("red is next B", at(cube, 1, 2), 0); - - ensure_equals("white is last R", at(cube, 7, 0), FULL); - ensure_equals("white is last G", at(cube, 7, 1), FULL); - ensure_equals("white is last B", at(cube, 7, 2), FULL); + UNSCOPED_INFO("size"); + REQUIRE(cube.size == 2); + UNSCOPED_INFO("entry count"); + REQUIRE((int)cube.colorCube.size() == 2 * 2 * 2 * 4); + + UNSCOPED_INFO("black R"); + CHECK(at(cube, 0, 0) == 0); + UNSCOPED_INFO("black G"); + CHECK(at(cube, 0, 1) == 0); + UNSCOPED_INFO("black B"); + CHECK(at(cube, 0, 2) == 0); + + UNSCOPED_INFO("red is next R"); + CHECK(at(cube, 1, 0) == FULL); + UNSCOPED_INFO("red is next G"); + CHECK(at(cube, 1, 1) == 0); + UNSCOPED_INFO("red is next B"); + CHECK(at(cube, 1, 2) == 0); + + UNSCOPED_INFO("white is last R"); + CHECK(at(cube, 7, 0) == FULL); + UNSCOPED_INFO("white is last G"); + CHECK(at(cube, 7, 1) == FULL); + UNSCOPED_INFO("white is last B"); + CHECK(at(cube, 7, 2) == FULL); } // Quantisation rounds rather than truncates. 0.5 * 65535 is 32767.5; // truncating biases every entry in the cube downwards by up to one step, // which on an identity LUT is a darkening for no reason at all. - template<> template<> - void lutcube_object::test<2>() + TEST_CASE_METHOD(lutcube_data, "LutCube: quantisation rounds rather than truncates", "[LutCube]") { const LutCube cube = parse(identity(3)); - ensure_equals("size", cube.size, 3); + UNSCOPED_INFO("size"); + REQUIRE(cube.size == 3); // Entry 1 is x = 1 of 2, i.e. exactly mid grey on red alone. - ensure_equals("mid rounds up", at(cube, 1, 0), MID); + UNSCOPED_INFO("mid rounds up"); + CHECK(at(cube, 1, 0) == MID); } // DOMAIN_MIN was parsed and then ignored: the original divided by the span // but never subtracted the offset. With a domain of [-1, 1], an input of 0 // is the middle of the domain and must land on mid grey -- the old code put // it at 0. - template<> template<> - void lutcube_object::test<3>() + TEST_CASE_METHOD(lutcube_data, "LutCube: DOMAIN_MIN offsets the input so the domain's centre is mid grey", "[LutCube]") { std::ostringstream text; text << "LUT_3D_SIZE 2\n"; @@ -131,18 +137,21 @@ namespace tut } const LutCube cube = parse(text.str()); - ensure_equals("size", cube.size, 2); - ensure_equals("domain centre is mid grey", at(cube, 0, 0), MID); - ensure_equals("domain centre is mid grey", at(cube, 0, 1), MID); - ensure_equals("domain centre is mid grey", at(cube, 0, 2), MID); + UNSCOPED_INFO("size"); + REQUIRE(cube.size == 2); + UNSCOPED_INFO("domain centre is mid grey"); + CHECK(at(cube, 0, 0) == MID); + UNSCOPED_INFO("domain centre is mid grey"); + CHECK(at(cube, 0, 1) == MID); + UNSCOPED_INFO("domain centre is mid grey"); + CHECK(at(cube, 0, 2) == MID); } // The one that shows up as an artefact rather than a failure. "clampTripel" // did not clamp, so 1.1 became 255 * 1.1 = 280, which wrapped to 24 on the // cast -- a blown highlight rendered as near-black speckle. Below the // domain wrapped the other way. - template<> template<> - void lutcube_object::test<4>() + TEST_CASE_METHOD(lutcube_data, "LutCube: values outside the domain clamp instead of wrapping", "[LutCube]") { std::ostringstream text; text << "LUT_3D_SIZE 2\n"; @@ -152,17 +161,19 @@ namespace tut } const LutCube cube = parse(text.str()); - ensure_equals("above domain clamps to white", at(cube, 0, 0), FULL); - ensure_equals("below domain clamps to black", at(cube, 0, 1), 0); - ensure_equals("in domain is untouched", at(cube, 0, 2), MID); + UNSCOPED_INFO("above domain clamps to white"); + CHECK(at(cube, 0, 0) == FULL); + UNSCOPED_INFO("below domain clamps to black"); + CHECK(at(cube, 0, 1) == 0); + UNSCOPED_INFO("in domain is untouched"); + CHECK(at(cube, 0, 2) == MID); } // Legal .cube files indent their data, and the original required a digit at // column zero. A rejected row does not merely lose itself: every later row // slides up into its slot, so the whole cube is wrong and the tail is left // at the full-scale fill. Indented, signed and bare-decimal rows all count. - template<> template<> - void lutcube_object::test<5>() + TEST_CASE_METHOD(lutcube_data, "LutCube: rows indented or signed or with a bare decimal point are accepted", "[LutCube]") { const LutCube plain = parse(identity(2)); @@ -178,65 +189,70 @@ namespace tut text << "1.0 1.0 1.0\n"; const LutCube indented = parse(text.str()); - ensure_equals("indented cube is accepted", indented.size, 2); - ensure("indented cube matches the plain one", indented.colorCube == plain.colorCube); + UNSCOPED_INFO("indented cube is accepted"); + REQUIRE(indented.size == 2); + UNSCOPED_INFO("indented cube matches the plain one"); + CHECK(indented.colorCube == plain.colorCube); } // The memory-safety one. With no LUT_3D_SIZE the cube is never allocated and // size stays zero, and the original wrote the first data row into it // regardless. Rejecting the file is the whole fix; the assertion here is // that we get an empty cube back and not a crash. - template<> template<> - void lutcube_object::test<6>() + TEST_CASE_METHOD(lutcube_data, "LutCube: data before LUT_3D_SIZE is rejected without writing anywhere", "[LutCube]") { const LutCube cube = parse("0.0 0.0 0.0\n1.0 1.0 1.0\n"); - ensure("data before LUT_3D_SIZE is rejected", cube.colorCube.empty()); - ensure_equals("and leaves no size", cube.size, 0); + UNSCOPED_INFO("data before LUT_3D_SIZE is rejected"); + REQUIRE(cube.colorCube.empty()); + UNSCOPED_INFO("and leaves no size"); + REQUIRE(cube.size == 0); } // A short file used to be kept. The allocation is prefilled with full // scale, so everything past the last row read came out white -- an "almost // working" LUT that blows out the top of the image. - template<> template<> - void lutcube_object::test<7>() + TEST_CASE_METHOD(lutcube_data, "LutCube: a file short of rows is rejected", "[LutCube]") { std::string text = identity(2); text.erase(text.find_last_of('\n', text.size() - 2) + 1); const LutCube cube = parse(text); - ensure("an incomplete cube is rejected", cube.colorCube.empty()); + UNSCOPED_INFO("an incomplete cube is rejected"); + REQUIRE(cube.colorCube.empty()); } // stof/stoi throw, and nothing used to catch them, so a corrupt file threw // out of setupGradingLUT rather than falling back. - template<> template<> - void lutcube_object::test<8>() + TEST_CASE_METHOD(lutcube_data, "LutCube: a non-numeric size or row is rejected rather than thrown", "[LutCube]") { const LutCube bad_size = parse("LUT_3D_SIZE banana\n"); - ensure("a non-numeric size is rejected", bad_size.colorCube.empty()); + UNSCOPED_INFO("a non-numeric size is rejected"); + REQUIRE(bad_size.colorCube.empty()); std::ostringstream text; text << "LUT_3D_SIZE 2\n"; text << "0.0 0.0 0.0\n"; text << "0.5 what 0.5\n"; const LutCube bad_row = parse(text.str()); - ensure("a malformed row is rejected", bad_row.colorCube.empty()); + UNSCOPED_INFO("a malformed row is rejected"); + REQUIRE(bad_row.colorCube.empty()); } // An absurd size should be refused before it is allocated, not after. - template<> template<> - void lutcube_object::test<9>() + TEST_CASE_METHOD(lutcube_data, "LutCube: a huge or degenerate or negative size is refused", "[LutCube]") { - ensure("a huge size is rejected", parse("LUT_3D_SIZE 100000\n").colorCube.empty()); - ensure("a degenerate size is rejected", parse("LUT_3D_SIZE 1\n").colorCube.empty()); - ensure("a negative size is rejected", parse("LUT_3D_SIZE -4\n").colorCube.empty()); + UNSCOPED_INFO("a huge size is rejected"); + REQUIRE(parse("LUT_3D_SIZE 100000\n").colorCube.empty()); + UNSCOPED_INFO("a degenerate size is rejected"); + REQUIRE(parse("LUT_3D_SIZE 1\n").colorCube.empty()); + UNSCOPED_INFO("a negative size is rejected"); + REQUIRE(parse("LUT_3D_SIZE -4\n").colorCube.empty()); } // Values separated by runs of spaces or by tabs, and a file with CRLF line // endings read somewhere that does not strip the CR. The original split on // the first " \n" it found and lost a value to any of these. - template<> template<> - void lutcube_object::test<10>() + TEST_CASE_METHOD(lutcube_data, "LutCube: runs of spaces and tabs and CRLF endings separate values", "[LutCube]") { const LutCube plain = parse(identity(2)); @@ -252,8 +268,10 @@ namespace tut text << "1.0 1.0 1.0\r\n"; const LutCube odd = parse(text.str()); - ensure_equals("odd whitespace is accepted", odd.size, 2); - ensure("odd whitespace matches the plain cube", odd.colorCube == plain.colorCube); + UNSCOPED_INFO("odd whitespace is accepted"); + REQUIRE(odd.size == 2); + UNSCOPED_INFO("odd whitespace matches the plain cube"); + CHECK(odd.colorCube == plain.colorCube); } // A value the text can carry but the arithmetic cannot survive. Whether a @@ -261,8 +279,7 @@ namespace tut // the parser must reject them itself rather than lean on the extraction // failing: a NaN sails through llclamp (both comparisons are false) and // the cast to unsigned short is undefined behaviour. - template<> template<> - void lutcube_object::test<11>() + TEST_CASE_METHOD(lutcube_data, "LutCube: nan and inf values and a non-finite domain are rejected", "[LutCube]") { static const char* const poison[] = { "nan", "inf", "-inf" }; for (const char* value : poison) @@ -274,8 +291,8 @@ namespace tut { text << "0.0 0.0 0.0\n"; } - ensure(std::string("a ") + value + " value is rejected", - parse(text.str()).colorCube.empty()); + UNSCOPED_INFO(std::string("a ") + value + " value is rejected"); + REQUIRE(parse(text.str()).colorCube.empty()); } // The domain lines go through the same reader, and a non-finite domain @@ -287,6 +304,7 @@ namespace tut { domain << "0.0 0.0 0.0\n"; } - ensure("a non-finite domain is rejected", parse(domain.str()).colorCube.empty()); + UNSCOPED_INFO("a non-finite domain is rejected"); + REQUIRE(parse(domain.str()).colorCube.empty()); } } diff --git a/indra/newview/tests/noise_test.cpp b/indra/newview/tests/noise_test.cpp index 9f5d1a4388..fe09b2144a 100644 --- a/indra/newview/tests/noise_test.cpp +++ b/indra/newview/tests/noise_test.cpp @@ -14,7 +14,8 @@ #include "linden_common.h" -#include "../test/lltut.h" +#include +#include "altestmatchers.h" #include "../noise.h" @@ -35,29 +36,24 @@ namespace tut } }; - typedef test_group noise_group; - typedef noise_group::object noise_object; - tut::noise_group ng("noise"); - // The generator is MSVC's rand(). Where that CRT is the one linked, it is the reference. - template<> template<> - void noise_object::test<1>() + TEST_CASE_METHOD(noise_data, "noise: ALNoiseRand draws what MSVC's rand() draws", "[noise]") { #ifdef _MSC_VER srand(42); ALNoiseRand rand(42); for (int i = 0; i < 65536; ++i) { - ensure_equals("draw agrees with the CRT", rand.next(), ::rand()); + UNSCOPED_INFO("draw agrees with the CRT"); + REQUIRE(rand.next() == ::rand()); } #else - skip("the CRT here is not the reference generator"); + SKIP("the CRT here is not the reference generator"); #endif } // The same draws, written down, for the platforms whose CRT is not the reference. - template<> template<> - void noise_object::test<2>() + TEST_CASE_METHOD(noise_data, "noise: ALNoiseRand draws MSVC's first sixteen values from seed 42", "[noise]") { static const S32 expected[16] = { 175, 400, 17869, 30056, 16083, 12879, 8016, 7644, @@ -66,13 +62,13 @@ namespace tut ALNoiseRand rand(42); for (int i = 0; i < 16; ++i) { - ensure_equals("draw", rand.next(), expected[i]); + UNSCOPED_INFO("draw"); + REQUIRE(rand.next() == expected[i]); } } // The permutation table: its head, its whole (as a weighted sum), and its wrap. - template<> template<> - void noise_object::test<3>() + TEST_CASE_METHOD(noise_data, "noise: the permutation table's head and weighted sum match and it wraps", "[noise]") { static const S32 head[32] = { 204, 117, 7, 120, 49, 222, 28, 96, 237, 17, 30, 184, 85, 140, 181, 18, @@ -80,22 +76,25 @@ namespace tut }; for (int i = 0; i < 32; ++i) { - ensure_equals("p head", p[i], head[i]); + UNSCOPED_INFO("p head"); + REQUIRE(p[i] == head[i]); } long long sum = 0; for (int i = 0; i < 256; ++i) { sum += (long long)p[i] * (i + 1); } - ensure_equals("p weighted sum", sum, 4318278LL); - ensure_equals("p wraps at 256", p[257], 117); - ensure_equals("p wraps at 512", p[513], 117); + UNSCOPED_INFO("p weighted sum"); + CHECK(sum == 4318278LL); + UNSCOPED_INFO("p wraps at 256"); + CHECK(p[257] == 117); + UNSCOPED_INFO("p wraps at 512"); + CHECK(p[513] == 117); } // The gradient tables. g1 holds multiples of 1/256 and compares exactly; g2 and g3 are // normalised, so they get the tolerance a float sqrt needs and no more. - template<> template<> - void noise_object::test<4>() + TEST_CASE_METHOD(noise_data, "noise: the gradient tables match MSVC's in their heads", "[noise]") { static const F32 g1_head[8] = { -0.31640625f, 0.3125f, -0.37890625f, -0.94140625f, @@ -103,7 +102,8 @@ namespace tut }; for (int i = 0; i < 8; ++i) { - ensure_equals("g1 head", g1[i], g1_head[i]); + UNSCOPED_INFO("g1 head"); + REQUIRE(g1[i] == g1_head[i]); } static const F32 g2_head[4][2] = { @@ -114,8 +114,10 @@ namespace tut }; for (int i = 0; i < 4; ++i) { - ensure_approximately_equals("g2 head x", g2[i][0], g2_head[i][0], 20); - ensure_approximately_equals("g2 head y", g2[i][1], g2_head[i][1], 20); + UNSCOPED_INFO("g2 head x"); + REQUIRE_THAT(g2[i][0], ll_test::WithinBits(g2_head[i][0], 20)); + UNSCOPED_INFO("g2 head y"); + REQUIRE_THAT(g2[i][1], ll_test::WithinBits(g2_head[i][1], 20)); } static const F32 g3_head[4][3] = { @@ -126,9 +128,12 @@ namespace tut }; for (int i = 0; i < 4; ++i) { - ensure_approximately_equals("g3 head x", g3[i][0], g3_head[i][0], 20); - ensure_approximately_equals("g3 head y", g3[i][1], g3_head[i][1], 20); - ensure_approximately_equals("g3 head z", g3[i][2], g3_head[i][2], 20); + UNSCOPED_INFO("g3 head x"); + REQUIRE_THAT(g3[i][0], ll_test::WithinBits(g3_head[i][0], 20)); + UNSCOPED_INFO("g3 head y"); + REQUIRE_THAT(g3[i][1], ll_test::WithinBits(g3_head[i][1], 20)); + UNSCOPED_INFO("g3 head z"); + REQUIRE_THAT(g3[i][2], ll_test::WithinBits(g3_head[i][2], 20)); } } } From 0347616212e40f54c7b21dae4421a921ce861992 Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 14 Oct 2026 02:14:01 -0400 Subject: [PATCH 3/4] newview's tests read as Catch2 The idiom pass over TM24's conversion, by twelve agents on copies, merged back onto it. Names, messages and assertion strength only: every case and every assertion is where the conversion put it. - Names: 782 of 832 changed. Most were set_test_name sentences or the first sentence of a comment, 501 had commas, which a Catch2 test spec reads as "or", and the Linden tests' were "#1" and the like. Where a shorter name dropped a why, a comment above the case keeps it. - Messages: 5,480 to 3,841, with 180 CAPTUREs. Most of those removed restated their check, or numbered it; most that remain say which step, pass or input a failure is at. A few that described another check than their own say what theirs checks. - 11 asserting helpers are named for it: require_pane, require_saved, require_contains, require_throws_with_cert and the like, and in llvocache, which names its helpers in camel case, requireSameEntry. - 21 CHECKs whose subject the next lines index or follow are REQUIREs, and 753 REQUIREs that guarded nothing are CHECKs. One of llworldmap's sat inside a try whose catch(...) reported its own failure as a throw. - The selection outline's and the HUD depth's convention loops say which convention with CAPTURE(reverse), and the helper that wrote it into every message is gone. - noise's namespace tut, kept only for the code the converter could not compile, is an anonymous namespace. tut_parity.py holds all 85 files under --recounted, every case's count unchanged, with the conversion's one site reviewed as never running here. Old test bugs the agents found, left as they were: - reads with no guard, where a failure would crash rather than fail: .back() and [n] of what nothing sized (statuses, reports, asks, candidates, did, the explorer's rows, the crumbs' path), a find<>(), findChild(), findDoc(), part(), word() or optional used unchecked, and shared_ptr texts dereferenced, in most of Script Studio's tests; lutcube reads a rejected cube; alcrashreporter indexes past a length; - checks that cannot fail: llviewerassetstats indexes the wrong LLSD level twice, so four checks compare undefined with 0; llsechandler_basic's grid checks read the credential it did not change, and its authenticator check reads the identifier again; alscriptregionusage, alscriptnavigation and llworldmap each have one that the setup already decides; lltextureinfo has a CHECK(true) and a case that always skips; llvocache's clamped factor is checked against its own clamp; - checks of something other or less than they say: llagentaccess's "pref adult, actual PG" passes on the preference alone; llviewerhelputil's substitutions are its own stub's; alfeedback's loopback user name is in the path; alscriptstudiovim's "off already" and ":wq over unsaved" steps run something else; the HUD outline case counts only one kind of hidden pixel; comments promising checks that are not there (alscopedata, alscriptstudiorecovery, alscriptstudioaccount, alrecoverykeeper, altexturetable, llhttpretrypolicy and others); - one that leans on evaluation order: alscriptcrumbsbar calls part() twice in one expression, and each call replaces the vector the other points into; - state a failure leaks: llviewerassetstats leaves gViewerAssetStats set, and alscriptsearchpane its sources' cache; - leftovers: unused variables and members inherited from TUT (lllogininstance, llviewerassetstats, alscriptstudiofiles), empty cases (llviewercontrollistener's first, llremoteparcelrequest's second, llworldmipmap's getObjectsTile), duplicated checks in llslurl, and a policy flag given twice in llsechandler_basic. Co-Authored-By: Claude Opus 5.5 --- .../tests/alagentlocationformat_test.cpp | 13 - indra/newview/tests/alchattimestamp_test.cpp | 14 +- .../newview/tests/alcolorwheelmodel_test.cpp | 63 +- indra/newview/tests/alcrashreporter_test.cpp | 65 +- indra/newview/tests/alcurvemodel_test.cpp | 216 ++---- .../tests/aldaycyclelandmarks_test.cpp | 56 +- indra/newview/tests/alfarplane_test.cpp | 55 +- indra/newview/tests/alfeedback_test.cpp | 91 --- indra/newview/tests/alfeedbackoutbox_test.cpp | 46 +- indra/newview/tests/algradehistory_test.cpp | 74 +- indra/newview/tests/alhuddepth_gl_test.cpp | 59 +- .../newview/tests/almotionpredictor_test.cpp | 29 +- .../newview/tests/alnotecardembedded_test.cpp | 11 +- indra/newview/tests/alrecoverykeeper_test.cpp | 51 +- .../tests/alsceneexplorerpredicate_test.cpp | 13 +- indra/newview/tests/alscopedata_test.cpp | 63 +- .../tests/alscriptanalysislane_test.cpp | 28 - .../newview/tests/alscriptanalyzers_test.cpp | 10 +- .../tests/alscriptcontentsindex_test.cpp | 80 +-- .../newview/tests/alscriptcrumbsbar_test.cpp | 97 ++- .../tests/alscriptexplorermodel_test.cpp | 98 ++- .../tests/alscriptexplorertree_test.cpp | 11 +- .../tests/alscriptexternaleditor_test.cpp | 138 ++-- .../tests/alscriptinspectorpane_test.cpp | 6 +- indra/newview/tests/alscriptitemdrop_test.cpp | 8 +- indra/newview/tests/alscriptjobqueue_test.cpp | 12 - indra/newview/tests/alscriptkeymap_test.cpp | 38 +- indra/newview/tests/alscriptlookup_test.cpp | 167 ++--- .../newview/tests/alscriptnavigation_test.cpp | 13 +- .../tests/alscriptobjectcheck_test.cpp | 26 +- .../tests/alscriptoutlinepane_test.cpp | 49 +- .../newview/tests/alscriptoutputpane_test.cpp | 78 +-- .../tests/alscriptproblemspane_test.cpp | 67 +- .../newview/tests/alscriptrecompile_test.cpp | 63 +- .../tests/alscriptreferencespane_test.cpp | 46 +- .../tests/alscriptregionusage_test.cpp | 27 +- indra/newview/tests/alscriptsaveflow_test.cpp | 44 +- .../newview/tests/alscriptsearchpane_test.cpp | 48 +- indra/newview/tests/alscriptsnippets_test.cpp | 42 +- .../tests/alscriptstudioaccount_test.cpp | 4 + .../tests/alscriptstudiocaret_test.cpp | 43 +- .../tests/alscriptstudiochecking_test.cpp | 78 +-- .../tests/alscriptstudiocommands_test.cpp | 15 +- .../tests/alscriptstudiocomparepairs_test.cpp | 23 +- .../tests/alscriptstudiocomparewith_test.cpp | 80 +-- .../newview/tests/alscriptstudiodoc_test.cpp | 68 +- .../alscriptstudioexpandedcompare_test.cpp | 23 +- .../tests/alscriptstudiofiles_test.cpp | 62 +- .../tests/alscriptstudiohistory_test.cpp | 77 +-- .../tests/alscriptstudiomasters_test.cpp | 29 +- .../tests/alscriptstudiomerging_test.cpp | 41 +- .../tests/alscriptstudioorphans_test.cpp | 130 ++-- .../tests/alscriptstudiorecovery_test.cpp | 103 +-- .../tests/alscriptstudiosaving_test.cpp | 165 ++--- .../tests/alscriptstudioselections_test.cpp | 4 - .../newview/tests/alscriptstudiovim_test.cpp | 256 +++---- .../tests/alscriptstudioweighing_test.cpp | 103 ++- .../tests/alscriptstudiowords_test.cpp | 144 ++-- indra/newview/tests/alscripttheme_test.cpp | 43 +- indra/newview/tests/alscripttypes_test.cpp | 2 - .../tests/alscriptweightspane_test.cpp | 123 ++-- .../tests/alselectionoutline_gl_test.cpp | 637 +++++++++--------- .../tests/alterrainsurfacemaps_test.cpp | 31 +- indra/newview/tests/altexturetable_test.cpp | 170 ++--- .../tests/alwhitebalancesolver_test.cpp | 13 +- indra/newview/tests/cppfeatures_test.cpp | 16 - indra/newview/tests/llagentaccess_test.cpp | 143 ++-- indra/newview/tests/lldateutil_test.cpp | 16 - .../newview/tests/llhttpretrypolicy_test.cpp | 67 +- indra/newview/tests/lllogininstance_test.cpp | 24 +- .../tests/llremoteparcelrequest_test.cpp | 1 + indra/newview/tests/llsecapi_test.cpp | 7 - .../newview/tests/llsechandler_basic_test.cpp | 206 ++---- indra/newview/tests/llslurl_test.cpp | 270 ++++---- indra/newview/tests/lltextureinfo_test.cpp | 24 +- indra/newview/tests/llversioninfo_test.cpp | 40 +- .../newview/tests/llviewerassetstats_test.cpp | 83 +-- .../tests/llviewercontrollistener_test.cpp | 22 +- indra/newview/tests/llviewernetwork_test.cpp | 67 +- indra/newview/tests/llvocache_test.cpp | 90 ++- indra/newview/tests/llworldmap_test.cpp | 160 ++--- indra/newview/tests/llworldmipmap_test.cpp | 29 +- indra/newview/tests/lutcube_test.cpp | 40 +- indra/newview/tests/noise_test.cpp | 18 +- 84 files changed, 2109 insertions(+), 3796 deletions(-) diff --git a/indra/newview/tests/alagentlocationformat_test.cpp b/indra/newview/tests/alagentlocationformat_test.cpp index 1121e50b63..3f35a050b8 100644 --- a/indra/newview/tests/alagentlocationformat_test.cpp +++ b/indra/newview/tests/alagentlocationformat_test.cpp @@ -88,30 +88,24 @@ namespace // behind, and the region takes its place. TEST_CASE_METHOD(alagentlocationformat_data, "ALAgentLocationFormat: an unnamed parcel drops out and the region takes its place", "[ALAgentLocationFormat]") { - UNSCOPED_INFO("NORMAL falls back to the region"); CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_NORMAL) == std::string("Hippotropolis")); - UNSCOPED_INFO("NORMAL_COORDS falls back to the region"); CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_NORMAL_COORDS) == std::string("Hippotropolis (128, 64, 22)")); - UNSCOPED_INFO("LANDMARK falls back to the region"); CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_LANDMARK) == std::string("Hippotropolis")); // The one place the two branches agree on the answer but reach it // differently: with no parcel to name, NO_MATURITY has nothing left to // distinguish it from NORMAL_COORDS. - UNSCOPED_INFO("NO_MATURITY falls back to the region"); CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_NO_MATURITY) == std::string("Hippotropolis (128, 64, 22)")); - UNSCOPED_INFO("NO_COORDS falls back to the region"); CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_NO_COORDS) == std::string("Hippotropolis - Adult")); - UNSCOPED_INFO("FULL falls back to the region"); CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_FULL) == std::string("Hippotropolis (128, 64, 22) - Adult")); } @@ -120,19 +114,15 @@ namespace // is what forgetting this looks like. TEST_CASE_METHOD(alagentlocationformat_data, "ALAgentLocationFormat: no rating leaves no separator for named or unnamed parcels", "[ALAgentLocationFormat]") { - UNSCOPED_INFO("a named parcel with no rating has no separator"); CHECK(named(LLAgentUI::LOCATION_FORMAT_NO_COORDS, "") == std::string("Ye Olde Parcel, Hippotropolis")); - UNSCOPED_INFO("nor does FULL"); CHECK(named(LLAgentUI::LOCATION_FORMAT_FULL, "") == std::string("Ye Olde Parcel, Hippotropolis (128, 64, 22)")); - UNSCOPED_INFO("nor does an unnamed parcel"); CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_NO_COORDS, "") == std::string("Hippotropolis")); - UNSCOPED_INFO("nor unnamed FULL"); CHECK(unnamed(LLAgentUI::LOCATION_FORMAT_FULL, "") == std::string("Hippotropolis (128, 64, 22)")); } @@ -143,7 +133,6 @@ namespace { ALAgentLocationFormat::format(out, LLAgentUI::LOCATION_FORMAT_FULL, "Parcel", "Region", "General", -4, 0, 4096); - UNSCOPED_INFO("negative and large coordinates survive"); CHECK(out == std::string("Parcel, Region (-4, 0, 4096) - General")); } @@ -152,7 +141,6 @@ namespace TEST_CASE_METHOD(alagentlocationformat_data, "ALAgentLocationFormat: the buffer is cleared rather than appended to", "[ALAgentLocationFormat]") { out = "left over from last time"; - UNSCOPED_INFO("the previous answer is gone"); CHECK(named(LLAgentUI::LOCATION_FORMAT_NORMAL) == std::string("Ye Olde Parcel, Hippotropolis")); @@ -200,7 +188,6 @@ namespace { ALAgentLocationFormat::format(out, LLAgentUI::LOCATION_FORMAT_LANDMARK, "Short", "Region", "", 0, 0, 0); - UNSCOPED_INFO("a short name is left alone"); CHECK(out == std::string("Short")); const std::string exact(ALAgentLocationFormat::LANDMARK_NAME_MAX_BYTES, 'x'); diff --git a/indra/newview/tests/alchattimestamp_test.cpp b/indra/newview/tests/alchattimestamp_test.cpp index 5863b56e65..44f1590d9d 100644 --- a/indra/newview/tests/alchattimestamp_test.cpp +++ b/indra/newview/tests/alchattimestamp_test.cpp @@ -41,9 +41,8 @@ TEST_CASE("alchattimestamp: each date and time form is cut with its spacing as t const std::string message = "Example Resident: text with a colon: and [14:05:09]"; const std::string line = prefix + message; const size_t length = ALChatTimestamp::prefixLength(line); - UNSCOPED_INFO("timestamp recognized: " + prefix); + CAPTURE(prefix); REQUIRE(length == prefix.size()); - UNSCOPED_INFO("message preserved"); REQUIRE(line.substr(length) == message); } } @@ -54,9 +53,9 @@ TEST_CASE("alchattimestamp: a timestamp without seconds is left as it is", "[alc { for (const std::string timestamp : { "14:05", "2:05 PM", "2026/09/25 14:05", "2026/09/25 2:05 pm", "" }) { - UNSCOPED_INFO("missing seconds stay missing"); + UNSCOPED_INFO("showing seconds invents none"); REQUIRE(ALChatTimestamp::format(timestamp, true) == timestamp); - UNSCOPED_INFO("minute display stays unchanged"); + UNSCOPED_INFO("hiding seconds changes nothing"); REQUIRE(ALChatTimestamp::format(timestamp, false) == timestamp); } } @@ -72,9 +71,9 @@ TEST_CASE("alchattimestamp: recorded seconds are shown or hidden without moving { const std::string minutes = date + "2:05" + suffix; const std::string timestamp = date + "2:05" + seconds + suffix; - UNSCOPED_INFO("recorded seconds retained"); + UNSCOPED_INFO("showing seconds keeps those recorded"); REQUIRE(ALChatTimestamp::format(timestamp, true) == timestamp); - UNSCOPED_INFO("seconds hidden"); + UNSCOPED_INFO("hiding seconds drops them"); REQUIRE(ALChatTimestamp::format(timestamp, false) == minutes); UNSCOPED_INFO("mixed logs share a merge minute"); REQUIRE(ALChatTimestamp::format(timestamp, false) == @@ -89,10 +88,9 @@ TEST_CASE("alchattimestamp: a malformed timestamp is neither cut nor rewritten", for (const std::string line : { "", "Example Resident: hello", "text [14:05:09]", "[14:05:9] hello", "[14:05:091] hello", "[14:05:09 hello" }) { - UNSCOPED_INFO("not a timestamp prefix: " + line); + CAPTURE(line); REQUIRE(ALChatTimestamp::prefixLength(line) == size_t(0)); } - UNSCOPED_INFO("unknown time is not rewritten"); CHECK(ALChatTimestamp::format("unknown:time:00", false) == "unknown:time:00"); UNSCOPED_INFO("overlong seconds are not rewritten"); CHECK(ALChatTimestamp::format("14:05:091", false) == "14:05:091"); diff --git a/indra/newview/tests/alcolorwheelmodel_test.cpp b/indra/newview/tests/alcolorwheelmodel_test.cpp index ce64454d74..19d1c016a9 100644 --- a/indra/newview/tests/alcolorwheelmodel_test.cpp +++ b/indra/newview/tests/alcolorwheelmodel_test.cpp @@ -56,9 +56,7 @@ namespace const LLVector3 v = ALColorWheelModel::chromaDirection(F_PI_BY_TWO); const LLVector3 grey(1.f, 1.f, 1.f); - UNSCOPED_INFO("u is unit"); CHECK_THAT(u.magVec(), ll_test::WithinBits(1.f, 5)); - UNSCOPED_INFO("v is unit"); CHECK_THAT(v.magVec(), ll_test::WithinBits(1.f, 5)); UNSCOPED_INFO("u and v are perpendicular"); CHECK_THAT(u * v, ll_test::WithinBits(0.f, 5)); @@ -92,10 +90,9 @@ namespace F32 hue, sat; for (F32 grey : { -0.4f, 0.f, 0.5f, 1.f }) { + CAPTURE(grey); ALColorWheelModel::toPolar(LLVector3(grey, grey, grey), hue, sat); - UNSCOPED_INFO("no saturation"); REQUIRE_THAT(sat, ll_test::WithinBits(0.f, 5)); - UNSCOPED_INFO("hue is finite"); REQUIRE(std::isfinite(hue)); } } @@ -114,17 +111,15 @@ namespace { for (F32 b : samples) { + CAPTURE(r, g, b); const LLVector3 in(r, g, b); F32 hue, sat; ALColorWheelModel::toPolar(in, hue, sat); const LLVector3 out = ALColorWheelModel::toRGB( ALColorWheelModel::masterOf(in), hue, sat); - UNSCOPED_INFO("r round trips"); REQUIRE_THAT(out.mV[VX], ll_test::WithinBits(in.mV[VX], 5)); - UNSCOPED_INFO("g round trips"); REQUIRE_THAT(out.mV[VY], ll_test::WithinBits(in.mV[VY], 5)); - UNSCOPED_INFO("b round trips"); REQUIRE_THAT(out.mV[VZ], ll_test::WithinBits(in.mV[VZ], 5)); } } @@ -137,13 +132,12 @@ namespace asLift(); for (S32 i = 0; i < 24; ++i) { + CAPTURE(i); const F32 hue = deg((F32)i * 15.f); const F32 sat = mWheel.getMaxSat() * 0.6f; mWheel.setPolar(hue, sat); - UNSCOPED_INFO("hue survives"); REQUIRE_THAT(angleDelta(mWheel.getHue(), hue), ll_test::WithinBits(0.f, 4)); - UNSCOPED_INFO("saturation survives"); REQUIRE_THAT(mWheel.getSat(), ll_test::WithinBits(sat, 4)); UNSCOPED_INFO("master untouched"); REQUIRE_THAT(mWheel.getMaster(), ll_test::WithinBits(0.f, 5)); @@ -160,11 +154,10 @@ namespace const F32 rim = mWheel.getMaxSat(); for (S32 i = 0; i < 72; ++i) { + CAPTURE(i); const F32 hue = deg((F32)i * 5.f); mWheel.setPolar(hue, rim); - UNSCOPED_INFO("rim is reachable at every hue"); REQUIRE_THAT(mWheel.getSat(), ll_test::WithinBits(rim, 3)); - UNSCOPED_INFO("and the hue is the one asked for"); REQUIRE_THAT(angleDelta(mWheel.getHue(), hue), ll_test::WithinBits(0.f, 3)); } } @@ -174,7 +167,6 @@ namespace TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: getMaxSat is the inradius and red on the rim sits on its limit", "[ALColorWheelModel]") { asLift(); - UNSCOPED_INFO("inradius"); CHECK_THAT(mWheel.getMaxSat(), ll_test::WithinBits(sqrtf(1.5f) * 0.5f, 4)); mWheel.setPolar(0.f, mWheel.getMaxSat()); @@ -212,17 +204,16 @@ namespace for (S32 i = 0; i < 36; ++i) { + CAPTURE(i); const F32 hue = deg((F32)i * 10.f); mWheel.setPolar(hue, rim * 4.f); const LLVector3& rgb = mWheel.getRGB(); for (S32 c = 0; c < 3; ++c) { - { - INFO("channel stayed in range"); - REQUIRE(rgb.mV[c] >= -0.5f - 1e-5f); - REQUIRE(rgb.mV[c] <= 0.5f + 1e-5f); - } + CAPTURE(c); + REQUIRE(rgb.mV[c] >= -0.5f - 1e-5f); + REQUIRE(rgb.mV[c] <= 0.5f + 1e-5f); } UNSCOPED_INFO("saturation did not run away"); REQUIRE(mWheel.getSat() <= widest + 1e-4f); @@ -248,9 +239,9 @@ namespace asLift(); for (S32 i = 0; i < 12; ++i) { + CAPTURE(i); const F32 hue = deg((F32)i * 30.f); mWheel.setPolar(hue, mWheel.getMaxSat() * 3.f); - UNSCOPED_INFO("hue held through the clamp"); REQUIRE_THAT(angleDelta(mWheel.getHue(), hue), ll_test::WithinBits(0.f, 3)); } } @@ -267,24 +258,19 @@ namespace const F32 sat = mWheel.getSat(); mWheel.setMaster(1.2f); - UNSCOPED_INFO("master moved"); CHECK_THAT(mWheel.getMaster(), ll_test::WithinBits(1.2f, 4)); - UNSCOPED_INFO("hue kept"); CHECK_THAT(angleDelta(mWheel.getHue(), hue), ll_test::WithinBits(0.f, 3)); - UNSCOPED_INFO("saturation kept"); CHECK_THAT(mWheel.getSat(), ll_test::WithinBits(sat, 3)); } - // A master pushed past its range clamps, and the triplet stays legal. TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: a master pushed past its range clamps and the triplet stays legal", "[ALColorWheelModel]") { asGain(); mWheel.setMaster(9.f); - UNSCOPED_INFO("master clamped"); CHECK(mWheel.getMaster() <= 1.5f + 1e-5f); for (S32 c = 0; c < 3; ++c) { - UNSCOPED_INFO("channel in range"); + CAPTURE(c); REQUIRE(mWheel.getRGB().mV[c] <= 1.5f + 1e-5f); } } @@ -317,14 +303,13 @@ namespace { for (S32 i = 0; i < 36; ++i) { + CAPTURE(i); const F32 hue = deg((F32)i * 10.f); const LLVector3 ring = ALColorWheelModel::ringColor(hue); F32 ring_hue, ring_sat; ALColorWheelModel::toPolar(ring, ring_hue, ring_sat); - UNSCOPED_INFO("ring hue matches the puck's"); REQUIRE_THAT(angleDelta(ring_hue, hue), ll_test::WithinBits(0.f, 3)); - UNSCOPED_INFO("ring is actually coloured"); REQUIRE(ring_sat > 0.f); } } @@ -338,11 +323,9 @@ namespace const LLVector3 ring = ALColorWheelModel::ringColor(deg((F32)i * 5.f)); for (S32 c = 0; c < 3; ++c) { - { - INFO("ring channel is strictly inside the gamut"); - REQUIRE(ring.mV[c] > 0.001f); - REQUIRE(ring.mV[c] < 0.999f); - } + CAPTURE(i, c); + REQUIRE(ring.mV[c] > 0.001f); + REQUIRE(ring.mV[c] < 0.999f); } } } @@ -354,7 +337,6 @@ namespace { asLift(); mWheel.setChannel(0, 0.2f); - UNSCOPED_INFO("channel written"); CHECK_THAT(mWheel.getRGB().mV[VX], ll_test::WithinBits(0.2f, 5)); UNSCOPED_INFO("g untouched"); CHECK_THAT(mWheel.getRGB().mV[VY], ll_test::WithinBits(0.f, 5)); @@ -374,7 +356,6 @@ namespace CHECK_THAT(mWheel.getRGB().mV[VX], ll_test::WithinBits(0.5f, 5)); } - // Reset returns the configured neutral for each flavour. TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: reset returns the configured neutral for each flavour", "[ALColorWheelModel]") { asLift(); @@ -407,15 +388,12 @@ namespace asGain(); for (S32 c = 0; c < 3; ++c) { - { - INFO("re-clamped on configure"); - REQUIRE(mWheel.getRGB().mV[c] >= 0.5f - 1e-5f); - REQUIRE(mWheel.getRGB().mV[c] <= 1.5f + 1e-5f); - } + CAPTURE(c); + REQUIRE(mWheel.getRGB().mV[c] >= 0.5f - 1e-5f); + REQUIRE(mWheel.getRGB().mV[c] <= 1.5f + 1e-5f); } } - // A reversed range is accepted rather than producing a negative width. TEST_CASE_METHOD(wheel_data, "ALColorWheelModel: a reversed range is accepted rather than producing a negative width", "[ALColorWheelModel]") { mWheel.configure(0.f, 0.5f, -0.5f, false); @@ -423,7 +401,6 @@ namespace CHECK_THAT(mWheel.getMin(), ll_test::WithinBits(-0.5f, 5)); UNSCOPED_INFO("max is the high one"); CHECK_THAT(mWheel.getMax(), ll_test::WithinBits(0.5f, 5)); - UNSCOPED_INFO("max saturation is positive"); CHECK(mWheel.getMaxSat() > 0.f); } @@ -435,12 +412,11 @@ namespace { for (S32 level = 0; level < 256; ++level) { + CAPTURE(level); const F32 grey = (F32)level / 255.f; F32 u = 1.f, v = 1.f; ALColorWheelModel::toChroma(LLVector3(grey, grey, grey), u, v); - UNSCOPED_INFO("grey has no u"); REQUIRE(u == 0.f); - UNSCOPED_INFO("grey has no v"); REQUIRE(v == 0.f); } @@ -448,11 +424,10 @@ namespace // side of the unit range. for (F32 grey : { -0.4f, 1.5f, 37.f }) { + CAPTURE(grey); F32 u = 1.f, v = 1.f; ALColorWheelModel::toChroma(LLVector3(grey, grey, grey), u, v); - UNSCOPED_INFO("grey has no u"); REQUIRE(u == 0.f); - UNSCOPED_INFO("grey has no v"); REQUIRE(v == 0.f); } } diff --git a/indra/newview/tests/alcrashreporter_test.cpp b/indra/newview/tests/alcrashreporter_test.cpp index 93fc705722..ba248bff05 100644 --- a/indra/newview/tests/alcrashreporter_test.cpp +++ b/indra/newview/tests/alcrashreporter_test.cpp @@ -57,8 +57,7 @@ namespace { const std::string& first = ALCrashReporter::runId(); UNSCOPED_INFO("a UUID"); - REQUIRE(first.size() == 36u); - UNSCOPED_INFO("stable"); + CHECK(first.size() == 36u); CHECK(ALCrashReporter::runId() == first); } @@ -87,12 +86,9 @@ namespace TEST_CASE("alcrashreporter: a file from before run ids reads as empty fields", "[alcrashreporter]") { ALCrashReporter::PreviousRun run = ALCrashReporter::previousRun(LLSD()); - UNSCOPED_INFO("no run id"); - REQUIRE(run.runId.empty()); - UNSCOPED_INFO("no log"); - REQUIRE(run.logFile.empty()); - UNSCOPED_INFO("no name"); - REQUIRE(run.agentName.empty()); + CHECK(run.runId.empty()); + CHECK(run.logFile.empty()); + CHECK(run.agentName.empty()); } TEST_CASE("alcrashreporter: consent is a sentinel file that allowing makes and withdrawing removes", "[alcrashreporter]") @@ -125,16 +121,12 @@ namespace const LLVector3 position(128.4f, -63.6f, 22.5f); char buffer[64]; size_t length = ALCrashReporter::locationTag(buffer, sizeof(buffer), "Hippotropolis", position); - UNSCOPED_INFO("whole"); CHECK(std::string(buffer, length) == "Hippotropolis/128/-64/23"); - UNSCOPED_INFO("terminated"); CHECK(buffer[length] == '\0'); char small[12]; length = ALCrashReporter::locationTag(small, sizeof(small), "Hippotropolis", position); - UNSCOPED_INFO("cut"); CHECK(std::string(small, length) == "Hippotropol"); - UNSCOPED_INFO("cut and terminated"); CHECK(small[length] == '\0'); length = ALCrashReporter::locationTag(small, sizeof(small), "Ahern", position); @@ -144,21 +136,17 @@ namespace TEST_CASE("alcrashreporter: an event id is its 32 hex digits however it is spelled", "[alcrashreporter]") { - UNSCOPED_INFO("dashed"); CHECK(ALCrashReporter::compactEventId("0123ABCD-89ab-cdef-0123-456789ABCDEF") == "0123abcd89abcdef0123456789abcdef"); - UNSCOPED_INFO("braced"); CHECK(ALCrashReporter::compactEventId("{0123abcd-89ab-cdef-0123-456789abcdef}") == "0123abcd89abcdef0123456789abcdef"); - UNSCOPED_INFO("already compact"); CHECK(ALCrashReporter::compactEventId("0123abcd89abcdef0123456789abcdef") == "0123abcd89abcdef0123456789abcdef"); UNSCOPED_INFO("too short"); - REQUIRE(ALCrashReporter::compactEventId("0123abcd").empty()); + CHECK(ALCrashReporter::compactEventId("0123abcd").empty()); UNSCOPED_INFO("not hex"); - REQUIRE(ALCrashReporter::compactEventId("0123abcd89abcdef0123456789abcdeg").empty()); - UNSCOPED_INFO("empty"); - REQUIRE(ALCrashReporter::compactEventId("").empty()); + CHECK(ALCrashReporter::compactEventId("0123abcd89abcdef0123456789abcdeg").empty()); + CHECK(ALCrashReporter::compactEventId("").empty()); } TEST_CASE("alcrashreporter: a freeze's report is recorded for the next run to take once", "[alcrashreporter]") @@ -168,35 +156,29 @@ namespace (std::filesystem::temp_directory_path() / ("alcrashreporter_test_last_report_" + LLUUID::generateNewID().asString())).string(); ALCrashReporter::takeRecordedReport(record); UNSCOPED_INFO("nothing to begin with"); - REQUIRE_FALSE(ALCrashReporter::takeRecordedReport(record)); + CHECK_FALSE(ALCrashReporter::takeRecordedReport(record)); ALCrashReporter::recordReport(record, { "freeze", "0123abcd89abcdef0123456789abcdef" }); const auto taken = ALCrashReporter::takeRecordedReport(record); - UNSCOPED_INFO("taken"); REQUIRE(taken.has_value()); - UNSCOPED_INFO("kind"); CHECK(taken->kind == "freeze"); - UNSCOPED_INFO("id"); CHECK(taken->eventId == "0123abcd89abcdef0123456789abcdef"); - UNSCOPED_INFO("once"); - REQUIRE_FALSE(ALCrashReporter::takeRecordedReport(record)); + UNSCOPED_INFO("taken only once"); + CHECK_FALSE(ALCrashReporter::takeRecordedReport(record)); ALCrashReporter::recordReport(record, { "lunch", "0123abcd89abcdef0123456789abcdef" }); UNSCOPED_INFO("an unknown kind is not a report"); - REQUIRE_FALSE(ALCrashReporter::takeRecordedReport(record)); + CHECK_FALSE(ALCrashReporter::takeRecordedReport(record)); ALCrashReporter::recordReport(record, { "crash", "nonsense" }); UNSCOPED_INFO("nor is a broken id"); - REQUIRE_FALSE(ALCrashReporter::takeRecordedReport(record)); + CHECK_FALSE(ALCrashReporter::takeRecordedReport(record)); } TEST_CASE("alcrashreporter: the nil UUID is no event however it is spelled", "[alcrashreporter]") { - UNSCOPED_INFO("dashed"); - REQUIRE(ALCrashReporter::compactEventId("00000000-0000-0000-0000-000000000000").empty()); - UNSCOPED_INFO("braced"); - REQUIRE(ALCrashReporter::compactEventId("{00000000-0000-0000-0000-000000000000}").empty()); - UNSCOPED_INFO("compact"); - REQUIRE(ALCrashReporter::compactEventId("00000000000000000000000000000000").empty()); + CHECK(ALCrashReporter::compactEventId("00000000-0000-0000-0000-000000000000").empty()); + CHECK(ALCrashReporter::compactEventId("{00000000-0000-0000-0000-000000000000}").empty()); + CHECK(ALCrashReporter::compactEventId("00000000000000000000000000000000").empty()); UNSCOPED_INFO("one digit set is an event"); CHECK(ALCrashReporter::compactEventId("00000000-0000-0000-0000-000000000001") == "00000000000000000000000000000001"); @@ -205,7 +187,7 @@ namespace (std::filesystem::temp_directory_path() / ("alcrashreporter_test_nil_report_" + LLUUID::generateNewID().asString())).string(); ALCrashReporter::recordReport(record, { "freeze", "00000000000000000000000000000000" }); UNSCOPED_INFO("a nil report is not taken"); - REQUIRE_FALSE(ALCrashReporter::takeRecordedReport(record)); + CHECK_FALSE(ALCrashReporter::takeRecordedReport(record)); } TEST_CASE("alcrashreporter: a crash found at start is the previous run's only if it carries its id", "[alcrashreporter]") @@ -216,22 +198,20 @@ namespace const auto crash = ALCrashReporter::previousRunCrash(event, previous, previous); UNSCOPED_INFO("the previous run's"); REQUIRE(crash.has_value()); - UNSCOPED_INFO("a crash"); CHECK(crash->kind == "crash"); - UNSCOPED_INFO("its id"); CHECK(crash->eventId == "0123abcd89abcdef0123456789abcdef"); UNSCOPED_INFO("the run id however it is spelled"); - REQUIRE(ALCrashReporter::previousRunCrash(event, "6F4B1B2E9D8C4D0FA5B72C3E4F5A6B7C", previous).has_value()); + CHECK(ALCrashReporter::previousRunCrash(event, "6F4B1B2E9D8C4D0FA5B72C3E4F5A6B7C", previous).has_value()); UNSCOPED_INFO("another run's"); - REQUIRE_FALSE(ALCrashReporter::previousRunCrash(event, "7f4b1b2e-9d8c-4d0f-a5b7-2c3e4f5a6b7c", + CHECK_FALSE(ALCrashReporter::previousRunCrash(event, "7f4b1b2e-9d8c-4d0f-a5b7-2c3e4f5a6b7c", previous)); UNSCOPED_INFO("one that carries no run id"); - REQUIRE_FALSE(ALCrashReporter::previousRunCrash(event, "", previous)); - UNSCOPED_INFO("any, when the previous run is not known"); - REQUIRE_FALSE(ALCrashReporter::previousRunCrash(event, previous, "")); + CHECK_FALSE(ALCrashReporter::previousRunCrash(event, "", previous)); + UNSCOPED_INFO("any when the previous run is not known"); + CHECK_FALSE(ALCrashReporter::previousRunCrash(event, previous, "")); UNSCOPED_INFO("one filed as nothing"); - REQUIRE_FALSE(ALCrashReporter::previousRunCrash("00000000-0000-0000-0000-000000000000", previous, previous)); + CHECK_FALSE(ALCrashReporter::previousRunCrash("00000000-0000-0000-0000-000000000000", previous, previous)); } TEST_CASE("alcrashreporter: a record replaces the last whole and leaves nothing beside it", "[alcrashreporter]") @@ -250,7 +230,6 @@ namespace UNSCOPED_INFO("the record alone"); CHECK(entries() == 1); const auto taken = ALCrashReporter::takeRecordedReport(record); - UNSCOPED_INFO("taken"); REQUIRE(taken.has_value()); UNSCOPED_INFO("the later kind"); CHECK(taken->kind == "crash"); diff --git a/indra/newview/tests/alcurvemodel_test.cpp b/indra/newview/tests/alcurvemodel_test.cpp index 2b0ea107f9..dbabd9c9ad 100644 --- a/indra/newview/tests/alcurvemodel_test.cpp +++ b/indra/newview/tests/alcurvemodel_test.cpp @@ -103,15 +103,13 @@ namespace // --- spline: ordering and point management ------------------------------- - // A fresh model is the identity ramp. TEST_CASE_METHOD(curve_data, "ALCurveModel: a fresh model is the identity ramp", "[ALCurveModel]") { - UNSCOPED_INFO("two points by default"); CHECK(mCurve.getPointCount() == 2); for (S32 i = 0; i <= 10; ++i) { const F32 x = i * 0.1f; - UNSCOPED_INFO("identity ramp"); + CAPTURE(x); REQUIRE_THAT(mCurve.evaluate(x), ll_test::WithinBits(x, 5)); } } @@ -127,13 +125,12 @@ namespace CHECK(idx_hi == 1); UNSCOPED_INFO("low point went before the high one"); CHECK(idx_lo == 1); - UNSCOPED_INFO("four points"); - CHECK(mCurve.getPointCount() == 4); + REQUIRE(mCurve.getPointCount() == 4); const auto& p = mCurve.getPoints(); for (size_t i = 1; i < p.size(); ++i) { - UNSCOPED_INFO("x is ascending"); + CAPTURE(i); REQUIRE(p[i].mX > p[i - 1].mX); } UNSCOPED_INFO("second point is the low one"); @@ -149,14 +146,12 @@ namespace mCurve.setPoints(pts({ { 0.f, 0.f }, { 0.5f, 0.3f }, { 0.5f, 0.7f }, { 1.f, 1.f } })); const auto& p = mCurve.getPoints(); - UNSCOPED_INFO("kept all four"); - REQUIRE((S32)p.size() == 4); + CHECK((S32)p.size() == 4); for (size_t i = 1; i < p.size(); ++i) { - UNSCOPED_INFO("gap is at least MIN_POINT_GAP"); + CAPTURE(i); REQUIRE(p[i].mX - p[i - 1].mX >= ALCurveModel::MIN_POINT_GAP - 1e-6f); } - UNSCOPED_INFO("evaluation is finite"); CHECK(std::isfinite(mCurve.evaluate(0.5f))); } @@ -203,7 +198,6 @@ namespace CHECK_FALSE(mCurve.removePoint(7)); UNSCOPED_INFO("interior removed"); CHECK(mCurve.removePoint(1)); - UNSCOPED_INFO("two left"); CHECK(mCurve.getPointCount() == 2); UNSCOPED_INFO("cannot go below two"); CHECK_FALSE(mCurve.removePoint(0)); @@ -211,14 +205,13 @@ namespace // --- spline: shape ------------------------------------------------------- - // The curve passes through every control point. TEST_CASE_METHOD(curve_data, "ALCurveModel: the curve passes through every control point", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.05f }, { 0.25f, 0.5f }, { 0.7f, 0.6f }, { 1.f, 0.95f } })); for (const auto& p : mCurve.getPoints()) { - UNSCOPED_INFO("interpolates its points"); + CAPTURE(p.mX); REQUIRE_THAT(mCurve.evaluate(p.mX), ll_test::WithinBits(p.mY, 4)); } } @@ -234,12 +227,11 @@ namespace mCurve.sample(s, 257); for (size_t i = 1; i < s.size(); ++i) { - UNSCOPED_INFO("never decreases"); + CAPTURE(i); REQUIRE(s[i] >= s[i - 1] - 1e-5f); } } - // A flat run stays exactly flat -- no ringing between equal-valued points. TEST_CASE_METHOD(curve_data, "ALCurveModel: a flat run stays exactly flat with no ringing between equal points", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.f }, { 0.3f, 0.5f }, { 0.7f, 0.5f }, { 1.f, 1.f } })); @@ -247,7 +239,7 @@ namespace for (S32 i = 0; i <= 8; ++i) { const F32 x = 0.3f + i * 0.05f; - UNSCOPED_INFO("flat between equal points"); + CAPTURE(x); REQUIRE_THAT(mCurve.evaluate(x), ll_test::WithinBits(0.5f, 4)); } } @@ -275,40 +267,31 @@ namespace mCurve.sample(s, 129); for (F32 y : s) { - { - INFO("in range"); - REQUIRE(y >= 0.f); - REQUIRE(y <= 1.f); - } - UNSCOPED_INFO("finite"); + REQUIRE(y >= 0.f); + REQUIRE(y <= 1.f); REQUIRE(std::isfinite(y)); } } // --- sampling ------------------------------------------------------------ - // sample() spans 0..1 inclusive and honours its count. TEST_CASE_METHOD(curve_data, "ALCurveModel: sample() spans 0..1 inclusive and honours its count", "[ALCurveModel]") { mCurve.setPoints(pts({ { 0.f, 0.1f }, { 0.5f, 0.4f }, { 1.f, 0.9f } })); std::vector s; mCurve.sample(s, 65); - UNSCOPED_INFO("count honoured"); REQUIRE((S32)s.size() == 65); - UNSCOPED_INFO("starts at evaluate(0)"); CHECK_THAT(s.front(), ll_test::WithinBits(mCurve.evaluate(0.f), 6)); - UNSCOPED_INFO("ends at evaluate(1)"); CHECK_THAT(s.back(), ll_test::WithinBits(mCurve.evaluate(1.f), 6)); UNSCOPED_INFO("the last sample is the value at exactly 1"); CHECK_THAT(s.back(), ll_test::WithinBits(0.9f, 6)); mCurve.sample(s, 1); UNSCOPED_INFO("a single sample is not a curve"); - REQUIRE(s.empty()); + CHECK(s.empty()); mCurve.sample(s, 0); - UNSCOPED_INFO("zero samples"); - REQUIRE(s.empty()); + CHECK(s.empty()); } // Unlocking the endpoints lets the first and last points move horizontally; @@ -346,7 +329,7 @@ namespace for (S32 i = 1; i <= ALCurveModel::MAX_POINTS - 2; ++i) { const F32 x = (F32)i / (F32)(ALCurveModel::MAX_POINTS - 1); - UNSCOPED_INFO("added while under the cap"); + CAPTURE(i); REQUIRE(mCurve.addPoint(x, x) >= 0); } UNSCOPED_INFO("at the cap"); @@ -367,7 +350,7 @@ namespace } mCurve.setPoints(many); UNSCOPED_INFO("twenty stored points survive"); - CHECK(mCurve.getPointCount() == 20); + REQUIRE(mCurve.getPointCount() == 20); UNSCOPED_INFO("interior point kept"); CHECK_THAT(mCurve.getPoints()[15].mX, ll_test::WithinBits(15.f / 19.f, 5)); UNSCOPED_INFO("but no further adds"); @@ -406,11 +389,9 @@ namespace F32 lo, md, hi; shaderSplitWeights(l, mid, lo, md, hi); const auto w = ALCurveModel::splitToneWeights(l, mid); - UNSCOPED_INFO("shadow matches the old shader"); + CAPTURE(mid, l); REQUIRE_THAT(w.mShadow, ll_test::WithinBits(lo, 5)); - UNSCOPED_INFO("midtone matches the old shader"); REQUIRE_THAT(w.mMidtone, ll_test::WithinBits(md, 5)); - UNSCOPED_INFO("highlight matches the old shader"); REQUIRE_THAT(w.mHighlight, ll_test::WithinBits(hi, 5)); } } @@ -430,23 +411,14 @@ namespace for (S32 i = 0; i <= 64; ++i) { const auto w = ALCurveModel::splitToneWeights((F32)i / 64.f, mid); - UNSCOPED_INFO("weights sum to one"); + CAPTURE(mid, i); REQUIRE_THAT(w.mShadow + w.mMidtone + w.mHighlight, ll_test::WithinBits(1.f, 5)); - { - INFO("shadow in range"); - REQUIRE(w.mShadow >= 0.f); - REQUIRE(w.mShadow <= 1.f); - } - { - INFO("midtone in range"); - REQUIRE(w.mMidtone >= 0.f); - REQUIRE(w.mMidtone <= 1.f); - } - { - INFO("highlight in range"); - REQUIRE(w.mHighlight >= 0.f); - REQUIRE(w.mHighlight <= 1.f); - } + REQUIRE(w.mShadow >= 0.f); + REQUIRE(w.mShadow <= 1.f); + REQUIRE(w.mMidtone >= 0.f); + REQUIRE(w.mMidtone <= 1.f); + REQUIRE(w.mHighlight >= 0.f); + REQUIRE(w.mHighlight <= 1.f); } } @@ -472,9 +444,8 @@ namespace for (S32 i = 0; i <= 64; ++i) { const auto w = ALCurveModel::splitToneWeights((F32)i / 64.f, mid); - UNSCOPED_INFO("highlight never falls"); + CAPTURE(i); REQUIRE(w.mHighlight >= prev_hi - 1e-5f); - UNSCOPED_INFO("shadow never rises"); REQUIRE(w.mShadow <= prev_lo + 1e-5f); prev_hi = w.mHighlight; prev_lo = w.mShadow; @@ -490,12 +461,9 @@ namespace { const F32 balance = (F32)i / 10.f; const F32 mid = ALCurveModel::splitToneMid(balance); - { - INFO("split point stays in range"); - REQUIRE(mid >= 0.1f - 1e-5f); - REQUIRE(mid <= 0.9f + 1e-5f); - } - UNSCOPED_INFO("balance round-trips"); + CAPTURE(balance); + REQUIRE(mid >= 0.1f - 1e-5f); + REQUIRE(mid <= 0.9f + 1e-5f); REQUIRE_THAT(ALCurveModel::splitToneBalance(mid), ll_test::WithinBits(balance, 5)); } @@ -525,11 +493,9 @@ namespace F32 lo, md, hi; shaderSplitWeightsRamped(l, mid, wsh.first, wsh.second, lo, md, hi); const auto w = ALCurveModel::splitToneWeights(l, mid, wsh.first, wsh.second); - UNSCOPED_INFO("shadow matches the shader"); + CAPTURE(mid, wsh.first, wsh.second, l); REQUIRE_THAT(w.mShadow, ll_test::WithinBits(lo, 5)); - UNSCOPED_INFO("midtone matches the shader"); REQUIRE_THAT(w.mMidtone, ll_test::WithinBits(md, 5)); - UNSCOPED_INFO("highlight matches the shader"); REQUIRE_THAT(w.mHighlight, ll_test::WithinBits(hi, 5)); } } @@ -545,31 +511,21 @@ namespace { for (const auto& wsh : widths) { + CAPTURE(mid, wsh.first, wsh.second); F32 prev_hi = -1.f, prev_lo = 2.f; for (S32 i = 0; i <= 64; ++i) { const F32 l = (F32)i / 64.f; const auto w = ALCurveModel::splitToneWeights(l, mid, wsh.first, wsh.second); - UNSCOPED_INFO("weights sum to one"); + CAPTURE(l); REQUIRE_THAT(w.mShadow + w.mMidtone + w.mHighlight, ll_test::WithinBits(1.f, 5)); - { - INFO("shadow in range"); - REQUIRE(w.mShadow >= 0.f); - REQUIRE(w.mShadow <= 1.f); - } - { - INFO("midtone in range"); - REQUIRE(w.mMidtone >= 0.f); - REQUIRE(w.mMidtone <= 1.f); - } - { - INFO("highlight in range"); - REQUIRE(w.mHighlight >= 0.f); - REQUIRE(w.mHighlight <= 1.f); - } - UNSCOPED_INFO("highlight never falls"); + REQUIRE(w.mShadow >= 0.f); + REQUIRE(w.mShadow <= 1.f); + REQUIRE(w.mMidtone >= 0.f); + REQUIRE(w.mMidtone <= 1.f); + REQUIRE(w.mHighlight >= 0.f); + REQUIRE(w.mHighlight <= 1.f); REQUIRE(w.mHighlight >= prev_hi - 1e-5f); - UNSCOPED_INFO("shadow never rises"); REQUIRE(w.mShadow <= prev_lo + 1e-5f); prev_hi = w.mHighlight; prev_lo = w.mShadow; @@ -602,9 +558,7 @@ namespace TEST_CASE_METHOD(curve_data, "ALCurveModel: a zero width is a finite step at the split and still a partition", "[ALCurveModel]") { const auto ramp = ALCurveModel::splitToneRamp(0.5f, 0.f); - UNSCOPED_INFO("scale finite"); CHECK(std::isfinite(ramp.mScale)); - UNSCOPED_INFO("bias finite"); CHECK(std::isfinite(ramp.mBias)); const auto below = ALCurveModel::splitToneWeights(0.49f, 0.5f, 0.f, 0.f); @@ -616,7 +570,7 @@ namespace for (S32 i = 0; i <= 64; ++i) { const auto w = ALCurveModel::splitToneWeights((F32)i / 64.f, 0.5f, 0.f, 0.f); - UNSCOPED_INFO("still sums to one"); + CAPTURE(i); REQUIRE_THAT(w.mShadow + w.mMidtone + w.mHighlight, ll_test::WithinBits(1.f, 5)); } } @@ -635,14 +589,13 @@ namespace for (S32 i = 0; i <= 20; ++i) { const F32 l = (F32)i / 20.f; - UNSCOPED_INFO("folded form agrees"); + CAPTURE(edge0, width, l); REQUIRE_THAT(l * ramp.mScale + ramp.mBias, ll_test::WithinBits((l - edge0) / width, 4)); } } } } - // The two-argument overload is the four-argument call at the default. TEST_CASE_METHOD(curve_data, "ALCurveModel: the two-argument overload is the four-argument call at the default", "[ALCurveModel]") { for (F32 mid : { 0.1f, 0.5f, 0.9f }) @@ -652,11 +605,9 @@ namespace const F32 l = (F32)i / 32.f; const auto a = ALCurveModel::splitToneWeights(l, mid); const auto b = ALCurveModel::splitToneWeights(l, mid, 0.35f, 0.35f); - UNSCOPED_INFO("shadow bit for bit"); + CAPTURE(mid, l); REQUIRE(a.mShadow == b.mShadow); - UNSCOPED_INFO("midtone bit for bit"); REQUIRE(a.mMidtone == b.mMidtone); - UNSCOPED_INFO("highlight bit for bit"); REQUIRE(a.mHighlight == b.mHighlight); } } @@ -664,18 +615,16 @@ namespace // --- ALToneCurveSet ------------------------------------------------------ - // A fresh set is identity in every channel, and bakes to the identity ramp. TEST_CASE_METHOD(curve_data, "ALCurveModel: a fresh set is identity in every channel and bakes to the identity ramp", "[ALCurveModel]") { ALToneCurveSet set; - UNSCOPED_INFO("identity by default"); CHECK(set.isIdentity()); for (S32 c = 0; c < ALToneCurveSet::CH_COUNT; ++c) { for (S32 i = 0; i <= 20; ++i) { const F32 x = (F32)i / 20.f; - UNSCOPED_INFO("evaluates to x"); + CAPTURE(c, x); REQUIRE_THAT(set.evaluate((ALToneCurveSet::EChannel)c, x), ll_test::WithinBits(x, 6)); } } @@ -686,16 +635,16 @@ namespace REQUIRE((S32)texels.size() == 512 * 4); for (S32 i = 0; i < 512; ++i) { + CAPTURE(i); const S32 expected = (S32)std::floor(65535.0 * i / 511.0 + 0.5); for (S32 c = 0; c < 3; ++c) { // Within one code: the spline runs in F32, and a few of the // ratios sit close enough to a rounding boundary for the last // bit to decide which side. - UNSCOPED_INFO("identity ramp texel"); + CAPTURE(c); REQUIRE(std::abs((S32)texels[i * 4 + c] - expected) <= 1); } - UNSCOPED_INFO("alpha opaque"); REQUIRE((S32)texels[i * 4 + 3] == (S32)ALToneCurveSet::ALPHA_OPAQUE); } } @@ -706,38 +655,29 @@ namespace { const auto in = pts({ { 0.f, 0.05f }, { 0.25f, 0.2f }, { 0.75f, 0.8f }, { 1.f, 0.95f } }); const LLSD sd = ALToneCurveSet::pointsToLLSD(in); - UNSCOPED_INFO("array"); REQUIRE(sd.isArray()); - UNSCOPED_INFO("one entry per point"); REQUIRE((S32)sd.size() == 4); for (S32 i = 0; i < 4; ++i) { - UNSCOPED_INFO("entry is an array"); + CAPTURE(i); REQUIRE(sd[i].isArray()); - UNSCOPED_INFO("entry is a pair"); REQUIRE((S32)sd[i].size() == 2); - UNSCOPED_INFO("x is a real"); REQUIRE(sd[i][0].isReal()); - UNSCOPED_INFO("y is a real"); REQUIRE(sd[i][1].isReal()); } std::vector out; - UNSCOPED_INFO("parsed"); - REQUIRE(ALToneCurveSet::pointsFromLLSD(sd, out)); - UNSCOPED_INFO("all points back"); + CHECK(ALToneCurveSet::pointsFromLLSD(sd, out)); REQUIRE((S32)out.size() == 4); for (S32 i = 0; i < 4; ++i) { - UNSCOPED_INFO("x survives"); + CAPTURE(i); REQUIRE_THAT(out[i].mX, ll_test::WithinBits(in[i].mX, 6)); - UNSCOPED_INFO("y survives"); REQUIRE_THAT(out[i].mY, ll_test::WithinBits(in[i].mY, 6)); } ALToneCurveSet set; - UNSCOPED_INFO("set from LLSD"); - REQUIRE(set.setCurveFromLLSD(ALToneCurveSet::CH_GREEN, sd)); + CHECK(set.setCurveFromLLSD(ALToneCurveSet::CH_GREEN, sd)); UNSCOPED_INFO("no longer identity"); CHECK_FALSE(set.isIdentity()); const LLSD back = set.getCurveAsLLSD(ALToneCurveSet::CH_GREEN); @@ -754,9 +694,9 @@ namespace std::vector out; UNSCOPED_INFO("undefined refused"); - REQUIRE_FALSE(ALToneCurveSet::pointsFromLLSD(LLSD(), out)); + CHECK_FALSE(ALToneCurveSet::pointsFromLLSD(LLSD(), out)); UNSCOPED_INFO("identity on refusal"); - REQUIRE((S32)out.size() == 2); + CHECK((S32)out.size() == 2); UNSCOPED_INFO("string refused"); CHECK_FALSE(ALToneCurveSet::pointsFromLLSD(LLSD("[[0,0],[1,1]]"), out)); UNSCOPED_INFO("map refused"); @@ -782,7 +722,7 @@ namespace UNSCOPED_INFO("survivors accepted"); CHECK(ALToneCurveSet::pointsFromLLSD(mixed, out)); UNSCOPED_INFO("exactly the three well-formed pairs"); - REQUIRE((S32)out.size() == 3); + CHECK((S32)out.size() == 3); // One well-formed pair is not a curve. LLSD one = LLSD::emptyArray(); @@ -790,27 +730,20 @@ namespace UNSCOPED_INFO("a lone pair refused"); CHECK_FALSE(ALToneCurveSet::pointsFromLLSD(one, out)); UNSCOPED_INFO("identity again"); - REQUIRE((S32)out.size() == 2); + CHECK((S32)out.size() == 2); // Out of range is clamped by the model, not rejected. LLSD wild = LLSD::emptyArray(); wild.append(pair(LLSD::Real(-1.0), LLSD::Real(-1.0))); wild.append(pair(LLSD::Real(2.0), LLSD::Real(2.0))); ALToneCurveSet set; - UNSCOPED_INFO("parsed"); - REQUIRE(set.setCurveFromLLSD(ALToneCurveSet::CH_RED, wild)); + CHECK(set.setCurveFromLLSD(ALToneCurveSet::CH_RED, wild)); for (const auto& p : set.curve(ALToneCurveSet::CH_RED).getPoints()) { - { - INFO("x clamped"); - REQUIRE(p.mX >= 0.f); - REQUIRE(p.mX <= 1.f); - } - { - INFO("y clamped"); - REQUIRE(p.mY >= 0.f); - REQUIRE(p.mY <= 1.f); - } + REQUIRE(p.mX >= 0.f); + REQUIRE(p.mX <= 1.f); + REQUIRE(p.mY >= 0.f); + REQUIRE(p.mY <= 1.f); } // More points than the editor adds are kept as long as a file could @@ -821,14 +754,10 @@ namespace const F64 x = i / 39.0; many.append(pair(LLSD::Real(x), LLSD::Real(x * x))); } - UNSCOPED_INFO("parsed"); CHECK(set.setCurveFromLLSD(ALToneCurveSet::CH_BLUE, many)); const auto& kept = set.curve(ALToneCurveSet::CH_BLUE).getPoints(); - UNSCOPED_INFO("all forty kept"); REQUIRE((S32)kept.size() == 40); - UNSCOPED_INFO("first at 0"); CHECK_THAT(kept.front().mX, ll_test::WithinBits(0.f, 6)); - UNSCOPED_INFO("last at 1"); CHECK_THAT(kept.back().mX, ll_test::WithinBits(1.f, 6)); UNSCOPED_INFO("shape honoured"); CHECK_THAT(set.curve(ALToneCurveSet::CH_BLUE).evaluate(0.5f), ll_test::WithinBits(0.25f, 4)); @@ -845,7 +774,6 @@ namespace CHECK(set.curve(ALToneCurveSet::CH_BLUE).getPointCount() == 2); } - // Composite order: the channel curve first, then master on its output. TEST_CASE_METHOD(curve_data, "ALCurveModel: a channel's curve applies first and master on its output", "[ALCurveModel]") { ALToneCurveSet set; @@ -869,7 +797,7 @@ namespace master_only.curve(ALToneCurveSet::CH_MASTER).setPoints(pts({ { 0.f, 0.1f }, { 1.f, 0.9f } })); for (S32 c = ALToneCurveSet::CH_RED; c <= ALToneCurveSet::CH_BLUE; ++c) { - UNSCOPED_INFO("every channel follows master"); + CAPTURE(c); REQUIRE_THAT(master_only.evaluate((ALToneCurveSet::EChannel)c, 0.f), ll_test::WithinBits(0.1f, 5)); } } @@ -889,7 +817,6 @@ namespace CHECK_FALSE(ALToneCurveSet::isIdentityCurve(far_curve)); ALToneCurveSet set; - UNSCOPED_INFO("all identity"); CHECK(set.isIdentity()); set.curve(ALToneCurveSet::CH_BLUE).setPoints(pts({ { 0.f, 0.f }, { 0.5f, 0.6f }, { 1.f, 1.f } })); UNSCOPED_INFO("one channel is enough"); @@ -908,7 +835,6 @@ namespace const S32 n = ALToneCurveSet::LUT_SIZE; std::vector texels; set.bake(texels, n); - UNSCOPED_INFO("size"); REQUIRE((S32)texels.size() == n * 4); for (S32 c = 0; c < 3; ++c) @@ -916,26 +842,27 @@ namespace const ALToneCurveSet::EChannel channel = (ALToneCurveSet::EChannel)(ALToneCurveSet::CH_RED + c); const F32 lo = set.evaluate(channel, 0.f) * 65535.f; const F32 hi = set.evaluate(channel, 1.f) * 65535.f; + CAPTURE(c); UNSCOPED_INFO("first texel is the curve at 0"); REQUIRE(fabsf((F32)texels[c] - lo) <= 1.f); UNSCOPED_INFO("last texel is the curve at 1"); REQUIRE(fabsf((F32)texels[(n - 1) * 4 + c] - hi) <= 1.f); for (S32 i = 1; i < n; ++i) { - UNSCOPED_INFO("monotone row"); + CAPTURE(i); REQUIRE(texels[i * 4 + c] >= texels[(i - 1) * 4 + c]); } } for (S32 i = 0; i < n; ++i) { - UNSCOPED_INFO("alpha opaque"); + CAPTURE(i); REQUIRE((S32)texels[i * 4 + 3] == (S32)ALToneCurveSet::ALPHA_OPAQUE); } std::vector tiny; set.bake(tiny, 1); UNSCOPED_INFO("a size below 2 is raised to 2"); - REQUIRE((S32)tiny.size() == 2 * 4); + CHECK((S32)tiny.size() == 2 * 4); } // What the shader will read back agrees with the analytic curve to well @@ -974,6 +901,7 @@ namespace { worst = std::max(worst, fabsf(shaderLutFetch(texels, n, c, x) - set.evaluate(channel, x))); } + CAPTURE(c); UNSCOPED_INFO("endpoint 0 exact to the U16"); REQUIRE(fabsf(shaderLutFetch(texels, n, c, 0.f) - set.evaluate(channel, 0.f)) <= 1.f / 65535.f + 1e-6f); UNSCOPED_INFO("endpoint 1 exact to the U16"); @@ -993,24 +921,17 @@ namespace ALToneCurveSet::lutScaleBias(n, scale, bias); const F32 u0 = 0.f * scale + bias; const F32 u1 = 1.f * scale + bias; - UNSCOPED_INFO("x = 0 is texel 0's centre"); + CAPTURE(n); REQUIRE_THAT(u0 * (F32)n - 0.5f, ll_test::WithinBits(0.f, 6)); - UNSCOPED_INFO("x = 1 is the last texel's centre"); REQUIRE_THAT(u1 * (F32)n - 0.5f, ll_test::WithinBits((F32)(n - 1), 6)); } } - // The channel combo's values map onto the set, with anything unexpected - // landing on Master rather than on a channel. TEST_CASE_METHOD(curve_data, "ALCurveModel: combo values map onto channels and anything else onto master", "[ALCurveModel]") { - UNSCOPED_INFO("-1 is master"); CHECK((S32)ALToneCurveSet::channelFromCombo(-1) == (S32)ALToneCurveSet::CH_MASTER); - UNSCOPED_INFO("0 is red"); CHECK((S32)ALToneCurveSet::channelFromCombo(0) == (S32)ALToneCurveSet::CH_RED); - UNSCOPED_INFO("1 is green"); CHECK((S32)ALToneCurveSet::channelFromCombo(1) == (S32)ALToneCurveSet::CH_GREEN); - UNSCOPED_INFO("2 is blue"); CHECK((S32)ALToneCurveSet::channelFromCombo(2) == (S32)ALToneCurveSet::CH_BLUE); UNSCOPED_INFO("anything else is master"); CHECK((S32)ALToneCurveSet::channelFromCombo(7) == (S32)ALToneCurveSet::CH_MASTER); @@ -1030,8 +951,7 @@ namespace { UNSCOPED_INFO("added at the right edge"); CHECK(mCurve.addPoint(1.f, 0.03f) >= 0); - UNSCOPED_INFO("three points"); - CHECK(mCurve.getPointCount() == 3); + REQUIRE(mCurve.getPointCount() == 3); UNSCOPED_INFO("interior, one gap inside"); CHECK_THAT(mCurve.getPoints()[1].mX, ll_test::WithinBits(1.f - ALCurveModel::MIN_POINT_GAP, 5)); UNSCOPED_INFO("the end is still the end"); @@ -1059,11 +979,10 @@ namespace { mCurve.setPoints(pts({ { 0.f, 0.f }, { 1.f, 0.2f }, { 1.f, 0.4f }, { 1.f, 0.6f }, { 1.f, 1.f } })); const auto& p = mCurve.getPoints(); - UNSCOPED_INFO("all kept"); REQUIRE((S32)p.size() == 5); for (size_t i = 1; i < p.size(); ++i) { - UNSCOPED_INFO("separated"); + CAPTURE(i); REQUIRE(p[i].mX - p[i - 1].mX >= ALCurveModel::MIN_POINT_GAP - 1e-6f); } UNSCOPED_INFO("the end is still at 1"); @@ -1075,28 +994,25 @@ namespace mCurve.sample(s, 1025); for (size_t i = 1; i < s.size(); ++i) { - UNSCOPED_INFO("finite"); + CAPTURE(i); REQUIRE(std::isfinite(s[i])); - UNSCOPED_INFO("monotone"); REQUIRE(s[i] >= s[i - 1] - 1e-5f); } } - // The setting names are one list: distinct, and channel-shaped. TEST_CASE_METHOD(curve_data, "ALCurveModel: the setting names are distinct and named for the curve", "[ALCurveModel]") { for (S32 c = 0; c < ALToneCurveSet::CH_COUNT; ++c) { const std::string name = ALToneCurveSet::settingName((ALToneCurveSet::EChannel)c); - UNSCOPED_INFO("named for the curve"); + CAPTURE(c); REQUIRE(name.rfind("RenderColorGradeCurve", 0) == 0); for (S32 d = 0; d < c; ++d) { - UNSCOPED_INFO("distinct"); + CAPTURE(d); REQUIRE(name != ALToneCurveSet::settingName((ALToneCurveSet::EChannel)d)); } } - UNSCOPED_INFO("master"); CHECK(std::string(ALToneCurveSet::settingName(ALToneCurveSet::CH_MASTER)) == std::string("RenderColorGradeCurveMaster")); } diff --git a/indra/newview/tests/aldaycyclelandmarks_test.cpp b/indra/newview/tests/aldaycyclelandmarks_test.cpp index b317c98cab..8dc2b48b34 100644 --- a/indra/newview/tests/aldaycyclelandmarks_test.cpp +++ b/indra/newview/tests/aldaycyclelandmarks_test.cpp @@ -55,22 +55,14 @@ namespace { const auto marks = ALDayCycleLandmarks::find(sine()); - UNSCOPED_INFO("has sunrise"); CHECK(marks.has_sunrise); - UNSCOPED_INFO("has noon"); CHECK(marks.has_noon); - UNSCOPED_INFO("has sunset"); CHECK(marks.has_sunset); - UNSCOPED_INFO("has midnight"); CHECK(marks.has_midnight); - UNSCOPED_INFO("sunrise at 0"); CHECK(apart(marks.sunrise, 0.f) < 0.02f); - UNSCOPED_INFO("noon at 0.25"); CHECK(apart(marks.noon, 0.25f) < 0.02f); - UNSCOPED_INFO("sunset at 0.5"); CHECK(apart(marks.sunset, 0.5f) < 0.02f); - UNSCOPED_INFO("midnight at 0.75"); CHECK(apart(marks.midnight, 0.75f) < 0.02f); } @@ -81,13 +73,9 @@ namespace const F32 phase = 0.3f; const auto marks = ALDayCycleLandmarks::find(sine(phase)); - UNSCOPED_INFO("sunrise moved"); CHECK(apart(marks.sunrise, phase) < 0.02f); - UNSCOPED_INFO("noon moved"); CHECK(apart(marks.noon, phase + 0.25f) < 0.02f); - UNSCOPED_INFO("sunset moved"); CHECK(apart(marks.sunset, std::fmod(phase + 0.5f, 1.f)) < 0.02f); - UNSCOPED_INFO("midnight moved"); CHECK(apart(marks.midnight, std::fmod(phase + 0.75f, 1.f)) < 0.02f); } @@ -99,7 +87,6 @@ namespace const auto marks = ALDayCycleLandmarks::find(sine(0.1f), 16); const F32 grid = 1.f / 16.f; - UNSCOPED_INFO("has sunrise"); CHECK(marks.has_sunrise); UNSCOPED_INFO("beats the grid"); CHECK(apart(marks.sunrise, 0.1f) < grid * 0.5f); @@ -112,13 +99,9 @@ namespace const auto marks = ALDayCycleLandmarks::find( [](F32 p) { return 0.5f + 0.25f * std::sin(TWO_PI * p); }); - UNSCOPED_INFO("has noon"); CHECK(marks.has_noon); - UNSCOPED_INFO("no sunrise"); CHECK_FALSE(marks.has_sunrise); - UNSCOPED_INFO("no sunset"); CHECK_FALSE(marks.has_sunset); - UNSCOPED_INFO("no midnight"); CHECK_FALSE(marks.has_midnight); UNSCOPED_INFO("noon at the peak"); CHECK(apart(marks.noon, 0.25f) < 0.02f); @@ -130,13 +113,9 @@ namespace const auto marks = ALDayCycleLandmarks::find( [](F32 p) { return -0.5f + 0.25f * std::sin(TWO_PI * p); }); - UNSCOPED_INFO("has midnight"); CHECK(marks.has_midnight); - UNSCOPED_INFO("no noon"); CHECK_FALSE(marks.has_noon); - UNSCOPED_INFO("no sunrise"); CHECK_FALSE(marks.has_sunrise); - UNSCOPED_INFO("no sunset"); CHECK_FALSE(marks.has_sunset); } @@ -146,7 +125,6 @@ namespace { const auto marks = ALDayCycleLandmarks::find([](F32) { return 0.5f; }); - UNSCOPED_INFO("nothing to find"); CHECK_FALSE(marks.any()); } @@ -158,36 +136,22 @@ namespace { const F32 phase = (F32)i / 20.f; const auto marks = ALDayCycleLandmarks::find(sine(phase)); - - { - INFO("sunrise in range"); - REQUIRE(marks.sunrise >= 0.f); - REQUIRE(marks.sunrise < 1.f); - } - { - INFO("noon in range"); - REQUIRE(marks.noon >= 0.f); - REQUIRE(marks.noon < 1.f); - } - { - INFO("sunset in range"); - REQUIRE(marks.sunset >= 0.f); - REQUIRE(marks.sunset < 1.f); - } - { - INFO("midnight in range"); - REQUIRE(marks.midnight >= 0.f); - REQUIRE(marks.midnight < 1.f); - } + CAPTURE(phase); + + REQUIRE(marks.sunrise >= 0.f); + REQUIRE(marks.sunrise < 1.f); + REQUIRE(marks.noon >= 0.f); + REQUIRE(marks.noon < 1.f); + REQUIRE(marks.sunset >= 0.f); + REQUIRE(marks.sunset < 1.f); + REQUIRE(marks.midnight >= 0.f); + REQUIRE(marks.midnight < 1.f); } } - // Nothing to sample with, nothing to say. TEST_CASE_METHOD(daycycle_landmarks, "ALDayCycleLandmarks: no sampler or too few samples finds nothing", "[ALDayCycleLandmarks]") { - UNSCOPED_INFO("no sampler"); CHECK_FALSE(ALDayCycleLandmarks::find(nullptr).any()); - UNSCOPED_INFO("too few samples"); CHECK_FALSE(ALDayCycleLandmarks::find(sine(), 1).any()); } } diff --git a/indra/newview/tests/alfarplane_test.cpp b/indra/newview/tests/alfarplane_test.cpp index e04e41e5dd..404027be15 100644 --- a/indra/newview/tests/alfarplane_test.cpp +++ b/indra/newview/tests/alfarplane_test.cpp @@ -86,23 +86,15 @@ namespace CHECK(projectionFar(true, true) == FINITE_PROJECTION_FAR); UNSCOPED_INFO("forward cube snapshot"); CHECK(projectionFar(false, true) == FINITE_PROJECTION_FAR); - UNSCOPED_INFO("finite plane is 1024 m"); CHECK(FINITE_PROJECTION_FAR == 1024.f); - UNSCOPED_INFO("1024 is finite"); CHECK_FALSE(isInfinite(1024.f)); - { - INFO("infinite constant"); - CHECK(isInfinite(INFINITE_FAR)); - CHECK(INFINITE_FAR > 0.f); - } + CHECK(isInfinite(INFINITE_FAR)); + CHECK(INFINITE_FAR > 0.f); - UNSCOPED_INFO("auto"); CHECK(isInfinite(projectionFar(true, false, FORCE_AUTOMATIC, 2048.f))); - UNSCOPED_INFO("finite"); CHECK(projectionFar(true, false, FORCE_FINITE, 2048.f) == 4096.f); UNSCOPED_INFO("finite never under the finite plane"); CHECK(projectionFar(true, false, FORCE_FINITE, 256.f) == FINITE_PROJECTION_FAR); - UNSCOPED_INFO("infinite"); CHECK(isInfinite(projectionFar(true, false, FORCE_INFINITE, 2048.f))); UNSCOPED_INFO("unknown mode"); CHECK(isInfinite(projectionFar(true, false, 7, 2048.f))); @@ -120,7 +112,6 @@ namespace TEST_CASE("alfarplane: how far terrain and water reach and from how high water shows", "[alfarplane]") { using namespace ALFarPlane; - UNSCOPED_INFO("terrain reach under the infinite projection"); CHECK(terrainReach(INFINITE_FAR) == 8192.f); UNSCOPED_INFO("terrain unbounded on forward-Z"); CHECK(terrainReach(projectionFar(false, false)) == 0.f); @@ -130,7 +121,6 @@ namespace CHECK(edgeWaterStretch(true) == 256000.f); UNSCOPED_INFO("edge water, finite keeps 2048"); CHECK(edgeWaterStretch(false) == 2048.f); - UNSCOPED_INFO("edge water covers the terrain reach"); CHECK(edgeWaterStretch(true) >= TERRAIN_REACH); UNSCOPED_INFO("finite: below 1024 m"); @@ -164,7 +154,6 @@ namespace // The sky keeps the cleared depth, 0 under reverse-Z. Anything drawn stores near / distance, which must stay // a normal float out to the reconstruction floor so no geometry rounds onto the sky. - UNSCOPED_INFO("reconstruction floor past the reach"); CHECK(MAX_RECONSTRUCT_DISTANCE > TERRAIN_REACH); UNSCOPED_INFO("geometry at the floor stores a normal depth"); CHECK(MIN_NEAR_PLANE / MAX_RECONSTRUCT_DISTANCE >= std::numeric_limits::min()); @@ -176,9 +165,7 @@ namespace REQUIRE_FALSE(util.empty()); UNSCOPED_INFO("deferredUtil floor"); CHECK(literal_after(util, "#define RECONSTRUCT_W_FLOOR ") == floor); - UNSCOPED_INFO("aoUtil floor"); CHECK(literal_after(shader_source("class1/deferred/aoUtil.glsl"), "pos.w = max(pos.w, ") == floor); - UNSCOPED_INFO("cofF floor"); CHECK(literal_after(shader_source("class1/deferred/cofF.glsl"), "p.z/max(p.w, ") == floor); } @@ -198,9 +185,9 @@ namespace "class2/deferred/sunLightV.glsl", "class1/deferred/blurLightV.glsl" }) { const std::string v = shader_source(path); - UNSCOPED_INFO(std::string(path) + " drawn on the far plane, reversed"); + UNSCOPED_INFO(path << " drawn on the far plane, reversed"); REQUIRE(v.find("gl_Position = vec4(position.xy, 0.0, 1.0);") != std::string::npos); - UNSCOPED_INFO(std::string(path) + " drawn on the far plane, forward"); + UNSCOPED_INFO(path << " drawn on the far plane, forward"); REQUIRE(v.find("gl_Position = vec4(position.xy, 1.0, 1.0);") != std::string::npos); } const std::string soften = shader_source("class3/deferred/softenLightF.glsl"); @@ -226,7 +213,6 @@ namespace // The farthest geometry: a top corner of the edge water's extent, from as high above it as the water shows. const F64 edge = (F64)ALFarPlane::edgeWaterStretch(true) + MAX_FAR_CLIP; const F64 farthest = sqrt(2.0 * edge * edge + (F64)ALFarPlane::EDGE_WATER_STRETCH * ALFarPlane::EDGE_WATER_STRETCH); - UNSCOPED_INFO("farthest water inside the floor"); CHECK(farthest < MAX_RECONSTRUCT_DISTANCE); UNSCOPED_INFO("farthest water stores a normal depth"); CHECK((F32)(MIN_NEAR_PLANE / farthest) >= std::numeric_limits::min()); @@ -240,17 +226,13 @@ namespace const LLVector2 lo(-1000.f, -2000.f); const LLVector2 hi(3000.f, 500.f); const WaterFar finite = waterFar(FINITE_PROJECTION_FAR, true, lo, hi); - UNSCOPED_INFO("finite wave clamp"); CHECK(finite.mWaveClamp == 2560.f); - UNSCOPED_INFO("finite no edge fade"); CHECK(finite.mEdgeFade == 0.f); const WaterFar infinite = waterFar(INFINITE_FAR, true, lo, hi); UNSCOPED_INFO("wave clamp at the farthest rim corner"); CHECK(fabsf(infinite.mWaveClamp - sqrtf(3000.f * 3000.f + 2000.f * 2000.f)) < 0.01f); - UNSCOPED_INFO("edge fade over the stretch"); CHECK(infinite.mEdgeFade == EDGE_WATER_STRETCH); const WaterFar rimless = waterFar(INFINITE_FAR, false, LLVector2(), LLVector2()); - UNSCOPED_INFO("no rim, no fade"); CHECK(rimless.mEdgeFade == 0.f); UNSCOPED_INFO("no rim, waves past the regions"); CHECK(rimless.mWaveClamp >= EDGE_WATER_STRETCH); @@ -267,9 +249,9 @@ namespace // The per-fragment rebuild scrolls by the offsets waterV takes from the CPU, which sets no wave direction or time. for (const char* scroll : { "+ bigWaveScroll;", "+ littleWaveScroll.xy;", "+ littleWaveScroll.zw;" }) { - UNSCOPED_INFO(std::string("waterV scrolls by ") + scroll); + UNSCOPED_INFO("waterV scrolls by " << scroll); REQUIRE(water_v.find(scroll) != std::string::npos); - UNSCOPED_INFO(std::string("rebuilt waves scroll by ") + scroll); + UNSCOPED_INFO("rebuilt waves scroll by " << scroll); REQUIRE(water_f.find(scroll) != std::string::npos); } } @@ -279,43 +261,32 @@ namespace TEST_CASE("alfarplane: overlay columns pair up out to 100 km at one angular size", "[alfarplane]") { const std::vector& columns = ALFarPlane::overlayColumns(); - { - INFO("pairs"); - REQUIRE(columns.size() >= 2); - REQUIRE(columns.size() % 2 == 0); - } - UNSCOPED_INFO("reaches 100 km"); + REQUIRE(columns.size() >= 2); + REQUIRE(columns.size() % 2 == 0); REQUIRE(columns[columns.size() - 2].mDistance == 100000.f); for (size_t i = 0; i < columns.size(); i += 2) { const ALFarPlane::OverlayColumn& n = columns[i]; const ALFarPlane::OverlayColumn& f = columns[i + 1]; - const std::string at = std::to_string((S32)n.mDistance) + " m"; - { - INFO("nearer first at " + at); - REQUIRE(n.mNearer); - REQUIRE_FALSE(f.mNearer); - } - UNSCOPED_INFO("farther behind at " + at); + CAPTURE(n.mDistance); + REQUIRE(n.mNearer); + REQUIRE_FALSE(f.mNearer); REQUIRE(f.mDistance > n.mDistance); - UNSCOPED_INFO("same bearing at " + at); REQUIRE(f.mBearing == n.mBearing); // On screen the farther column's near edge sits inside the nearer column. const F32 f_left = (f.mOffset - f.mHalfWidth) / f.mDistance; const F32 n_right = (n.mOffset + n.mHalfWidth) / n.mDistance; const F32 n_left = (n.mOffset - n.mHalfWidth) / n.mDistance; { - INFO("overlap at " + at); + INFO("the farther column overlaps the nearer on screen"); REQUIRE(f_left > n_left); REQUIRE(f_left < n_right); } - UNSCOPED_INFO("same angle at " + at); + UNSCOPED_INFO("every column the same angular size"); REQUIRE(fabsf(n.mHeight / n.mDistance - columns[0].mHeight / columns[0].mDistance) < 1e-6f); if (i > 0) { - UNSCOPED_INFO("own bearing at " + at); REQUIRE(n.mBearing != columns[i - 2].mBearing); - UNSCOPED_INFO("receding at " + at); REQUIRE(n.mDistance > columns[i - 2].mDistance); } } diff --git a/indra/newview/tests/alfeedback_test.cpp b/indra/newview/tests/alfeedback_test.cpp index 44136a5de0..938904eb43 100644 --- a/indra/newview/tests/alfeedback_test.cpp +++ b/indra/newview/tests/alfeedback_test.cpp @@ -64,7 +64,6 @@ namespace TEST_CASE("alfeedback: a sentry.io DSN sends to its project's envelope endpoint", "[alfeedback]") { const auto endpoint = ALFeedback::endpointFromDsn("https://0123abcd@o42.ingest.sentry.io/4501"); - UNSCOPED_INFO("parsed"); REQUIRE(endpoint.has_value()); CHECK(endpoint->url == "https://o42.ingest.sentry.io/api/4501/envelope/"); CHECK(endpoint->publicKey == "0123abcd"); @@ -73,7 +72,6 @@ namespace TEST_CASE("alfeedback: a self-hosted DSN keeps its port and path and drops an old secret", "[alfeedback]") { const auto endpoint = ALFeedback::endpointFromDsn("https://key:secret@sentry.example.com:9000/prefix/7/"); - UNSCOPED_INFO("parsed"); REQUIRE(endpoint.has_value()); CHECK(endpoint->url == "https://sentry.example.com:9000/prefix/api/7/envelope/"); CHECK(endpoint->publicKey == "key"); @@ -93,7 +91,6 @@ namespace REQUIRE_FALSE(ALFeedback::endpointFromDsn("https://key@host")); UNSCOPED_INFO("empty host"); REQUIRE_FALSE(ALFeedback::endpointFromDsn("https://key@/1")); - UNSCOPED_INFO("empty"); REQUIRE_FALSE(ALFeedback::endpointFromDsn("")); } @@ -105,15 +102,11 @@ namespace TEST_CASE("alfeedback: settings named for keys or passwords or secrets or emails stay private", "[alfeedback]") { - UNSCOPED_INFO("translation key"); CHECK(ALFeedback::privateSetting("DeepLTranslateAPIKey")); UNSCOPED_INFO("any case"); CHECK(ALFeedback::privateSetting("someapikey")); - UNSCOPED_INFO("password"); CHECK(ALFeedback::privateSetting("RememberPassword")); - UNSCOPED_INFO("token"); CHECK(ALFeedback::privateSetting("ServiceToken")); - UNSCOPED_INFO("secret"); CHECK(ALFeedback::privateSetting("ClientSecret")); UNSCOPED_INFO("an address"); CHECK(ALFeedback::privateSetting("AlchemyFeedbackEmail")); @@ -143,7 +136,6 @@ namespace CHECK_FALSE(ALFeedback::plausibleEmail("rye@.com")); UNSCOPED_INFO("space"); CHECK_FALSE(ALFeedback::plausibleEmail("r ye@example.com")); - UNSCOPED_INFO("empty"); CHECK_FALSE(ALFeedback::plausibleEmail("")); } @@ -173,11 +165,8 @@ namespace TEST_CASE("alfeedback: an event id is 32 lower-case hex digits and new each time", "[alfeedback]") { const std::string id = ALFeedback::newEventId(); - UNSCOPED_INFO("length"); REQUIRE(id.size() == 32u); - UNSCOPED_INFO("hex"); REQUIRE(id.find_first_not_of("0123456789abcdef") == std::string::npos); - UNSCOPED_INFO("new"); CHECK(id != ALFeedback::newEventId()); } @@ -202,40 +191,24 @@ namespace context.tags = { { "run_id", "run" }, { "empty", "" } }; const LLSD event = ALFeedback::feedbackEvent("feedc0de", "2026-10-09T12:00:00Z", message, context); - UNSCOPED_INFO("id"); CHECK(event["event_id"].asString() == "feedc0de"); - UNSCOPED_INFO("timestamp"); CHECK(event["timestamp"].asString() == "2026-10-09T12:00:00Z"); - UNSCOPED_INFO("level"); CHECK(event["level"].asString() == "info"); - UNSCOPED_INFO("release"); CHECK(event["release"].asString() == "alchemy@26.4.0+64033"); - UNSCOPED_INFO("environment"); CHECK(event["environment"].asString() == "Alchemy Test"); - UNSCOPED_INFO("dist"); CHECK(event["dist"].asString() == "64033"); - UNSCOPED_INFO("user id"); CHECK(event["user"]["id"].asString() == context.userId); - UNSCOPED_INFO("user name"); CHECK(event["user"]["username"].asString() == "rye.resident"); - UNSCOPED_INFO("kind"); CHECK(event["tags"]["feedback_kind"].asString() == "idea"); - UNSCOPED_INFO("tag"); CHECK(event["tags"]["run_id"].asString() == "run"); UNSCOPED_INFO("an empty tag is left out"); REQUIRE_FALSE(event["tags"].has("empty")); const LLSD& feedback = event["contexts"]["feedback"]; - UNSCOPED_INFO("message"); CHECK(feedback["message"].asString() == "More knobs"); - UNSCOPED_INFO("email"); CHECK(feedback["contact_email"].asString() == "rye@example.com"); - UNSCOPED_INFO("name"); CHECK(feedback["name"].asString() == "Rye"); - UNSCOPED_INFO("associated"); CHECK(feedback["associated_event_id"].asString() == message.associatedEventId); - UNSCOPED_INFO("os"); CHECK(event["contexts"]["os"]["name"].asString() == context.osName); - UNSCOPED_INFO("gpu"); CHECK(event["contexts"]["gpu"]["vendor_name"].asString() == "NVIDIA"); } @@ -244,20 +217,13 @@ namespace ALFeedback::Message message; message.text = "It broke"; const LLSD event = ALFeedback::feedbackEvent("feedc0de", "2026-10-09T12:00:00Z", message, ALFeedback::Context()); - UNSCOPED_INFO("no user"); REQUIRE_FALSE(event.has("user")); - UNSCOPED_INFO("no release"); REQUIRE_FALSE(event.has("release")); - UNSCOPED_INFO("no os"); REQUIRE_FALSE(event["contexts"].has("os")); - UNSCOPED_INFO("no gpu"); REQUIRE_FALSE(event["contexts"].has("gpu")); const LLSD& feedback = event["contexts"]["feedback"]; - UNSCOPED_INFO("no email"); REQUIRE_FALSE(feedback.has("contact_email")); - UNSCOPED_INFO("no name"); REQUIRE_FALSE(feedback.has("name")); - UNSCOPED_INFO("no association"); REQUIRE_FALSE(feedback.has("associated_event_id")); UNSCOPED_INFO("problem by default"); CHECK(event["tags"]["feedback_kind"].asString() == "problem"); @@ -292,36 +258,26 @@ namespace size_t pos = 0; const LLSD header = json(take(bytes, pos)); - UNSCOPED_INFO("header id"); CHECK(header["event_id"].asString() == "feedc0de"); - UNSCOPED_INFO("header dsn"); CHECK(header["dsn"].asString() == "https://k@h/1"); // A kept envelope goes again as it is, days later maybe: a time it // was sent would be read as the client's clock being wrong. - UNSCOPED_INFO("no time sent"); REQUIRE_FALSE(header.has("sent_at")); - UNSCOPED_INFO("header sdk"); CHECK(header["sdk"]["name"].asString() == "alchemy.feedback"); const LLSD feedback_item = json(take(bytes, pos)); - UNSCOPED_INFO("feedback type"); CHECK(feedback_item["type"].asString() == "feedback"); const LLSD payload = json(take(bytes, pos, feedback_item["length"].asInteger())); UNSCOPED_INFO("the message round-trips"); CHECK(payload["contexts"]["feedback"]["message"].asString() == message.text); const LLSD screenshot_item = json(take(bytes, pos)); - UNSCOPED_INFO("attachment type"); CHECK(screenshot_item["type"].asString() == "attachment"); - UNSCOPED_INFO("filename"); CHECK(screenshot_item["filename"].asString() == "screenshot.png"); - UNSCOPED_INFO("content type"); CHECK(screenshot_item["content_type"].asString() == "image/png"); - UNSCOPED_INFO("binary bytes"); CHECK(std::string(take(bytes, pos, screenshot_item["length"].asInteger())) == binary); const LLSD log_item = json(take(bytes, pos)); - UNSCOPED_INFO("log bytes"); CHECK(std::string(take(bytes, pos, log_item["length"].asInteger())) == "line\n"); UNSCOPED_INFO("nothing after"); REQUIRE(pos == bytes.size()); @@ -335,7 +291,6 @@ namespace data += "2026-10-09T12:00:00Z INFO: a log line that repeats\n"; } std::string zipped; - UNSCOPED_INFO("compressed"); REQUIRE(ALFeedback::gzip(data, zipped)); { INFO("gzip magic"); @@ -348,7 +303,6 @@ namespace std::string inflated(data.size(), '\0'); z_stream stream = {}; - UNSCOPED_INFO("inflate init"); CHECK(inflateInit2(&stream, MAX_WBITS + 16) == Z_OK); stream.next_in = reinterpret_cast(zipped.data()); stream.avail_in = static_cast(zipped.size()); @@ -364,42 +318,27 @@ namespace TEST_CASE("alfeedback: the server's answer reads as an outcome", "[alfeedback]") { using ALFeedback::Outcome; - UNSCOPED_INFO("200"); CHECK(ALFeedback::classify(200) == Outcome::Sent); - UNSCOPED_INFO("429"); CHECK(ALFeedback::classify(429) == Outcome::RateLimited); - UNSCOPED_INFO("413"); CHECK(ALFeedback::classify(413) == Outcome::TooLarge); - UNSCOPED_INFO("400"); CHECK(ALFeedback::classify(400) == Outcome::Rejected); - UNSCOPED_INFO("403"); CHECK(ALFeedback::classify(403) == Outcome::Rejected); - UNSCOPED_INFO("408"); CHECK(ALFeedback::classify(408) == Outcome::Unreachable); - UNSCOPED_INFO("503"); CHECK(ALFeedback::classify(503) == Outcome::Unreachable); UNSCOPED_INFO("no answer"); CHECK(ALFeedback::classify(0) == Outcome::Unreachable); - UNSCOPED_INFO("retry when limited"); CHECK(ALFeedback::retryable(Outcome::RateLimited)); - UNSCOPED_INFO("retry when unreachable"); CHECK(ALFeedback::retryable(Outcome::Unreachable)); - UNSCOPED_INFO("no retry when refused"); CHECK_FALSE(ALFeedback::retryable(Outcome::Rejected)); - UNSCOPED_INFO("no retry when too large"); CHECK_FALSE(ALFeedback::retryable(Outcome::TooLarge)); - UNSCOPED_INFO("no retry when sent"); CHECK_FALSE(ALFeedback::retryable(Outcome::Sent)); } TEST_CASE("alfeedback: a kept report's wait doubles from 15 minutes to 6 hours or more if asked", "[alfeedback]") { const S64 now = 1000000; - UNSCOPED_INFO("first"); CHECK(ALFeedback::nextAttempt(now, 1, 0.f) == now + 15 * 60); - UNSCOPED_INFO("second"); CHECK(ALFeedback::nextAttempt(now, 2, 0.f) == now + 30 * 60); - UNSCOPED_INFO("third"); CHECK(ALFeedback::nextAttempt(now, 3, 0.f) == now + 60 * 60); UNSCOPED_INFO("capped"); CHECK(ALFeedback::nextAttempt(now, 20, 0.f) == now + 6 * 60 * 60); @@ -429,15 +368,10 @@ namespace queued.attempts = 3; queued.nextAt = 4102448400; const auto back = ALFeedback::queuedFromJson(ALFeedback::queuedToJson(queued)); - UNSCOPED_INFO("parsed"); REQUIRE(back.has_value()); - UNSCOPED_INFO("id"); CHECK(back->eventId == queued.eventId); - UNSCOPED_INFO("created"); CHECK(back->created == queued.created); - UNSCOPED_INFO("attempts"); CHECK(back->attempts == queued.attempts); - UNSCOPED_INFO("next"); CHECK(back->nextAt == queued.nextAt); UNSCOPED_INFO("not a record"); REQUIRE_FALSE(ALFeedback::queuedFromJson("{\"nothing\":1}")); @@ -451,7 +385,6 @@ namespace UNSCOPED_INFO("loopback"); REQUIRE(local.has_value()); CHECK(local->url == "http://127.0.0.1:8765/api/1/envelope/"); - UNSCOPED_INFO("localhost"); REQUIRE(ALFeedback::endpointFromDsn("http://k@localhost/1").has_value()); UNSCOPED_INFO("IPv6 loopback"); REQUIRE(ALFeedback::endpointFromDsn("http://k@[::1]:9000/1").has_value()); @@ -492,7 +425,6 @@ namespace TEST_CASE("alfeedback: only an id can name a file", "[alfeedback]") { - UNSCOPED_INFO("an id"); CHECK(ALFeedback::validEventId(ALFeedback::newEventId())); UNSCOPED_INFO("upper case"); CHECK_FALSE(ALFeedback::validEventId("0123456789ABCDEF0123456789abcdef")); @@ -531,11 +463,8 @@ namespace TEST_CASE("alfeedback: a wait the server asks for is a sane number of seconds", "[alfeedback]") { - UNSCOPED_INFO("none"); CHECK(ALFeedback::serverWait(0.f) == 0); - UNSCOPED_INFO("negative"); CHECK(ALFeedback::serverWait(-5.f) == 0); - UNSCOPED_INFO("not a number"); CHECK(ALFeedback::serverWait(std::numeric_limits::quiet_NaN()) == 0); UNSCOPED_INFO("rounded up"); CHECK(ALFeedback::serverWait(90.2f) == 91); @@ -557,13 +486,9 @@ namespace queued.kind = ALFeedback::Kind::Idea; queued.message = "More knobs \xF0\x9F\x99\x82"; const auto back = ALFeedback::queuedFromJson(ALFeedback::queuedToJson(queued)); - UNSCOPED_INFO("parsed"); REQUIRE(back.has_value()); - UNSCOPED_INFO("not before"); CHECK(back->notBefore == queued.notBefore); - UNSCOPED_INFO("kind"); CHECK(back->kind == ALFeedback::Kind::Idea); - UNSCOPED_INFO("message"); CHECK(back->message == queued.message); UNSCOPED_INFO("a path for an id"); REQUIRE_FALSE(ALFeedback::queuedFromJson("{\"event_id\":\"../../x\",\"created\":1,\"attempts\":0}")); @@ -571,11 +496,8 @@ namespace "{\"event_id\":\"0123abcd89abcdef0123456789abcdef\",\"created\":1e300,\"next_at\":-5,\"attempts\":-3}"); UNSCOPED_INFO("times that are not times"); REQUIRE(wild.has_value()); - UNSCOPED_INFO("created"); CHECK(wild->created == 0); - UNSCOPED_INFO("next"); CHECK(wild->nextAt == 0); - UNSCOPED_INFO("attempts"); CHECK(wild->attempts == 0); } @@ -590,30 +512,19 @@ namespace draft.linkedAt = "2026-10-09T12:00:00Z"; draft.linkedRunId = "run"; const auto back = ALFeedback::draftFromJson(ALFeedback::draftToJson(draft)); - UNSCOPED_INFO("parsed"); REQUIRE(back.has_value()); - UNSCOPED_INFO("kind"); CHECK(back->kind == ALFeedback::Kind::Other); - UNSCOPED_INFO("message"); CHECK(back->message == draft.message); - UNSCOPED_INFO("id"); CHECK(back->eventId == draft.eventId); - UNSCOPED_INFO("associated"); CHECK(back->associatedEventId == draft.associatedEventId); - UNSCOPED_INFO("linked"); CHECK(back->linked == "freeze"); - UNSCOPED_INFO("when"); CHECK(back->linkedAt == draft.linkedAt); - UNSCOPED_INFO("run"); CHECK(back->linkedRunId == "run"); const auto odd = ALFeedback::draftFromJson( "{\"message\":\"hi there\",\"event_id\":\"../x\",\"linked\":\"party\",\"kind\":\"nonsense\"}"); - UNSCOPED_INFO("parsed"); REQUIRE(odd.has_value()); - UNSCOPED_INFO("no id"); REQUIRE(odd->eventId.empty()); - UNSCOPED_INFO("no link"); REQUIRE(odd->linked.empty()); UNSCOPED_INFO("a problem"); CHECK(odd->kind == ALFeedback::Kind::Problem); @@ -623,9 +534,7 @@ namespace TEST_CASE("alfeedback: kinds and outcomes have names", "[alfeedback]") { - UNSCOPED_INFO("idea"); CHECK(ALFeedback::kindFromName(ALFeedback::kindName(ALFeedback::Kind::Idea)) == ALFeedback::Kind::Idea); - UNSCOPED_INFO("other"); CHECK(ALFeedback::kindFromName("other") == ALFeedback::Kind::Other); UNSCOPED_INFO("anything else"); CHECK(ALFeedback::kindFromName("bug") == ALFeedback::Kind::Problem); diff --git a/indra/newview/tests/alfeedbackoutbox_test.cpp b/indra/newview/tests/alfeedbackoutbox_test.cpp index 91c4b88851..a17faa7e9e 100644 --- a/indra/newview/tests/alfeedbackoutbox_test.cpp +++ b/indra/newview/tests/alfeedbackoutbox_test.cpp @@ -98,23 +98,15 @@ namespace ALFeedbackOutbox box(mDir); std::vector given_up; const S64 now = now_seconds(); - UNSCOPED_INFO("kept"); REQUIRE(box.keep(report(id(1)), "body", now, given_up)); - UNSCOPED_INFO("has"); REQUIRE(box.has(id(1))); - UNSCOPED_INFO("body"); CHECK(LLFile::getContents(path(id(1), ".envelope")) == "body"); const auto records = box.records(now, given_up); - UNSCOPED_INFO("one"); REQUIRE(records.size() == 1u); - UNSCOPED_INFO("made now"); CHECK(records[0].created == now); - UNSCOPED_INFO("due"); CHECK(records[0].nextAt == now + ALFeedback::QUEUE_RETRY_SECONDS); - UNSCOPED_INFO("what the user wrote"); CHECK(records[0].message == "It broke"); - UNSCOPED_INFO("nothing given up"); REQUIRE(given_up.empty()); } @@ -122,11 +114,8 @@ namespace { ALFeedbackOutbox box(mDir); std::vector given_up; - UNSCOPED_INFO("not kept"); CHECK_FALSE(box.keep(report("../escape"), "body", now_seconds(), given_up)); - UNSCOPED_INFO("not claimed"); CHECK_FALSE(box.claim("../escape")); - UNSCOPED_INFO("nothing written"); REQUIRE(gDirUtilp->getFilesInDir(mDir).empty()); } @@ -136,16 +125,12 @@ namespace ALFeedbackOutbox other(mDir); std::vector given_up; box.keep(report(id(1)), "body", now_seconds(), given_up); - UNSCOPED_INFO("claimed"); CHECK(box.claim(id(1))); - UNSCOPED_INFO("not twice"); CHECK_FALSE(other.claim(id(1))); - UNSCOPED_INFO("its body"); CHECK(box.claimedBody(id(1)) == "body"); - UNSCOPED_INFO("still kept"); + UNSCOPED_INFO("a claimed report is still kept"); REQUIRE(box.has(id(1))); box.release(id(1)); - UNSCOPED_INFO("free again"); CHECK(other.claim(id(1))); } @@ -157,7 +142,6 @@ namespace box.keep(report(id(1)), "body", now, given_up); // A report kept for hours: the body's time is old, the claim's is not. age(path(id(1), ".envelope"), 3 * 60 * 60); - UNSCOPED_INFO("claimed"); CHECK(box.claim(id(1))); ALFeedbackOutbox(mDir).records(now, given_up); @@ -176,7 +160,7 @@ namespace box.claim(id(1)); age(path(id(1), ".sending"), ALFeedbackOutbox::CLAIM_STALE_SECONDS + 60); box.records(now, given_up); - UNSCOPED_INFO("freed"); + UNSCOPED_INFO("the stale claim is freed"); CHECK(LLFile::isfile(path(id(1), ".envelope"))); } @@ -189,27 +173,21 @@ namespace box.keep(report(id(2)), "body", now, given_up); box.keep(report(id(3)), "body", now, given_up); - UNSCOPED_INFO("sent is gone"); CHECK_FALSE(box.settle(id(1), false, ALFeedback::Outcome::Sent, 0.f, now).kept); - UNSCOPED_INFO("forgotten"); REQUIRE_FALSE(box.has(id(1))); - UNSCOPED_INFO("refused is gone"); CHECK_FALSE(box.settle(id(2), false, ALFeedback::Outcome::Rejected, 0.f, now).kept); box.claim(id(3)); const auto settled = box.settle(id(3), true, ALFeedback::Outcome::RateLimited, 7200.f, now); - UNSCOPED_INFO("unreached is kept"); + UNSCOPED_INFO("a rate-limited report is kept"); CHECK(settled.kept); - UNSCOPED_INFO("released"); + UNSCOPED_INFO("the claim is released"); CHECK(LLFile::isfile(path(id(3), ".envelope"))); const auto records = box.records(now, given_up); - UNSCOPED_INFO("one left"); REQUIRE(records.size() == 1u); - UNSCOPED_INFO("tried"); CHECK(records[0].attempts == 1); - UNSCOPED_INFO("waits as asked"); + UNSCOPED_INFO("waits as long as the server asked"); CHECK(records[0].nextAt == now + 7200); - UNSCOPED_INFO("not before"); CHECK(records[0].notBefore == now + 7200); } @@ -224,11 +202,8 @@ namespace { settled = box.settle(id(1), false, ALFeedback::Outcome::Unreachable, 0.f, now); } - UNSCOPED_INFO("given up"); REQUIRE(settled.givenUp.has_value()); - UNSCOPED_INFO("its words"); CHECK(settled.givenUp->message == "Lost words"); - UNSCOPED_INFO("forgotten"); REQUIRE_FALSE(box.has(id(1))); } @@ -240,9 +215,7 @@ namespace box.keep(report(id(1)), "body", now, given_up); box.claim(id(1)); box.forget(id(1)); - UNSCOPED_INFO("not kept"); CHECK_FALSE(box.settle(id(1), true, ALFeedback::Outcome::Unreachable, 0.f, now).kept); - UNSCOPED_INFO("nothing left"); REQUIRE(gDirUtilp->getFilesInDir(mDir).empty()); } @@ -255,14 +228,12 @@ namespace { box.keep(report(id(i)), "body", now + i, given_up); } - UNSCOPED_INFO("room so far"); + UNSCOPED_INFO("nothing given up while there is room"); REQUIRE(given_up.empty()); box.keep(report(id(99)), "body", now + 99, given_up); - UNSCOPED_INFO("one made room"); REQUIRE(given_up.size() == 1u); - UNSCOPED_INFO("the oldest"); + UNSCOPED_INFO("the oldest is given back"); CHECK(given_up[0].eventId == id(0)); - UNSCOPED_INFO("as many as fit"); REQUIRE(box.records(now + 100, given_up).size() == ALFeedback::QUEUE_MAX_ENTRIES); } @@ -299,11 +270,8 @@ namespace TEST_CASE_METHOD(alfeedbackoutbox_data, "alfeedbackoutbox: replaceFile replaces a file whole and leaves no parts", "[alfeedbackoutbox]") { const std::string file = gDirUtilp->add(mDir, "file.json"); - UNSCOPED_INFO("written"); CHECK(ALFeedbackOutbox::replaceFile(file, "first")); - UNSCOPED_INFO("replaced"); CHECK(ALFeedbackOutbox::replaceFile(file, "second")); - UNSCOPED_INFO("the new"); CHECK(LLFile::getContents(file) == "second"); UNSCOPED_INFO("no parts left"); REQUIRE(gDirUtilp->getFilesInDir(mDir).size() == 1u); diff --git a/indra/newview/tests/algradehistory_test.cpp b/indra/newview/tests/algradehistory_test.cpp index 0c3350bbb9..a903e326fb 100644 --- a/indra/newview/tests/algradehistory_test.cpp +++ b/indra/newview/tests/algradehistory_test.cpp @@ -43,29 +43,19 @@ namespace // it started from. TEST_CASE_METHOD(history_data, "ALGradeHistory: one change is one step whose undo hands back where it started", "[ALGradeHistory]") { - UNSCOPED_INFO("nothing to undo yet"); CHECK_FALSE(mHistory.canUndo()); - UNSCOPED_INFO("nothing to redo yet"); CHECK_FALSE(mHistory.canRedo()); mHistory.record("RenderColorGradeSaturation", LLSD(1.0), LLSD(1.5), 1.f); - UNSCOPED_INFO("something to undo"); CHECK(mHistory.canUndo()); - UNSCOPED_INFO("one step"); CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - UNSCOPED_INFO("undo returned a transaction"); REQUIRE(t != nullptr); - UNSCOPED_INFO("covering one control"); REQUIRE(t->size() == (size_t)1); - UNSCOPED_INFO("the right control"); CHECK(t->front().mName == std::string("RenderColorGradeSaturation")); - UNSCOPED_INFO("restoring the original"); CHECK(t->front().mBefore.asReal() == 1.0); - UNSCOPED_INFO("nothing left to undo"); CHECK_FALSE(mHistory.canUndo()); - UNSCOPED_INFO("but something to redo"); CHECK(mHistory.canRedo()); } @@ -77,11 +67,9 @@ namespace { drag("RenderColorGradeLift", 100, 0.01f); - UNSCOPED_INFO("a whole drag is one step"); CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - UNSCOPED_INFO("got the step"); REQUIRE(t != nullptr); UNSCOPED_INFO("from where the drag began"); CHECK(t->front().mBefore.asReal() == 0.0); @@ -96,7 +84,6 @@ namespace mHistory.record("RenderColorGradeGain", LLSD(1.0), LLSD(1.1), 1.f); mHistory.record("RenderColorGradeGain", LLSD(1.1), LLSD(1.2), 1.f + ALGradeHistory::COALESCE_SECONDS * 2.f); - UNSCOPED_INFO("two separate edits"); CHECK(mHistory.depth() == (size_t)2); } @@ -107,7 +94,6 @@ namespace { mHistory.record("RenderColorGradeContrast", LLSD(1.0), LLSD(1.2), 1.f); mHistory.record("RenderColorGradeSaturation", LLSD(1.0), LLSD(1.2), 1.01f); - UNSCOPED_INFO("two steps"); CHECK(mHistory.depth() == (size_t)2); } @@ -121,12 +107,9 @@ namespace mHistory.record("C", LLSD(3.0), LLSD(0.0), 1.f); mHistory.endGroup(); - UNSCOPED_INFO("one step"); CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - UNSCOPED_INFO("got it"); REQUIRE(t != nullptr); - UNSCOPED_INFO("covering all three"); REQUIRE(t->size() == (size_t)3); } @@ -141,13 +124,9 @@ namespace mHistory.endGroup(); const auto* t = mHistory.undo(); - UNSCOPED_INFO("got it"); REQUIRE(t != nullptr); - UNSCOPED_INFO("still one control"); REQUIRE(t->size() == (size_t)1); - UNSCOPED_INFO("from the original value"); CHECK(t->front().mBefore.asReal() == 1.0); - UNSCOPED_INFO("to the final one"); CHECK(t->front().mAfter.asReal() == 3.0); } @@ -158,11 +137,9 @@ namespace mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); mHistory.record("B", LLSD(0.0), LLSD(1.0), 2.f); mHistory.undo(); - UNSCOPED_INFO("can redo before the new edit"); CHECK(mHistory.canRedo()); mHistory.record("C", LLSD(0.0), LLSD(1.0), 3.f); - UNSCOPED_INFO("redo tail is gone"); CHECK_FALSE(mHistory.canRedo()); UNSCOPED_INFO("and the stack was truncated"); CHECK(mHistory.depth() == (size_t)2); @@ -175,13 +152,9 @@ namespace mHistory.undo(); const auto* t = mHistory.redo(); - UNSCOPED_INFO("redo returned the step"); REQUIRE(t != nullptr); - UNSCOPED_INFO("with the destination"); CHECK(t->front().mAfter.asReal() == 1.0); - UNSCOPED_INFO("nothing further to redo"); CHECK_FALSE(mHistory.canRedo()); - UNSCOPED_INFO("and it is undoable again"); CHECK(mHistory.canUndo()); } @@ -198,7 +171,6 @@ namespace UNSCOPED_INFO("the undone step was replaced, not extended"); CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - UNSCOPED_INFO("got the new step"); REQUIRE(t != nullptr); UNSCOPED_INFO("carrying the new values"); CHECK(t->front().mBefore.asReal() == 1.0); @@ -212,12 +184,10 @@ namespace { mHistory.record("A", LLSD((F64)i), LLSD((F64)(i + 1)), (F32)i * 10.f); } - UNSCOPED_INFO("capped"); CHECK(mHistory.depth() == ALGradeHistory::MAX_DEPTH); // The newest is still the newest after the drop. const auto* t = mHistory.undo(); - UNSCOPED_INFO("got the newest"); REQUIRE(t != nullptr); UNSCOPED_INFO("which is the last one recorded"); CHECK(t->front().mAfter.asReal() == (F64)(ALGradeHistory::MAX_DEPTH + 20)); @@ -229,9 +199,7 @@ namespace { mHistory.beginGroup(); mHistory.endGroup(); - UNSCOPED_INFO("no step"); CHECK_FALSE(mHistory.canUndo()); - UNSCOPED_INFO("nothing recorded"); CHECK(mHistory.depth() == (size_t)0); } @@ -247,12 +215,9 @@ namespace mHistory.record("C", LLSD(0.0), LLSD(1.0), 1.f); mHistory.endGroup(); - UNSCOPED_INFO("one step"); CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - UNSCOPED_INFO("got it"); REQUIRE(t != nullptr); - UNSCOPED_INFO("covering all three"); REQUIRE(t->size() == (size_t)3); } @@ -260,9 +225,7 @@ namespace // than misbehaving -- the key handler calls these without checking first. TEST_CASE_METHOD(history_data, "ALGradeHistory: undo and redo past either end answer null", "[ALGradeHistory]") { - UNSCOPED_INFO("undo on empty is null"); REQUIRE(mHistory.undo() == nullptr); - UNSCOPED_INFO("redo on empty is null"); REQUIRE(mHistory.redo() == nullptr); mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); @@ -281,7 +244,6 @@ namespace CHECK_FALSE(mHistory.canUndo()); CHECK_FALSE(mHistory.canRedo()); } - UNSCOPED_INFO("really empty"); CHECK(mHistory.depth() == (size_t)0); } @@ -298,16 +260,13 @@ namespace mHistory.record("B", LLSD((F64)i), LLSD((F64)(i + 1)), 1.f); mHistory.endGroup(); } - UNSCOPED_INFO("capped"); CHECK(mHistory.depth() == ALGradeHistory::MAX_DEPTH); UNSCOPED_INFO("everything on the stack is applied"); CHECK(mHistory.cursor() == mHistory.depth()); // The newest is still the newest after the drop, and still whole. const auto* t = mHistory.undo(); - UNSCOPED_INFO("got the newest"); REQUIRE(t != nullptr); - UNSCOPED_INFO("still covering both controls"); REQUIRE(t->size() == (size_t)2); UNSCOPED_INFO("which is the last group recorded"); CHECK(t->front().mAfter.asReal() == (F64)(ALGradeHistory::MAX_DEPTH + 20)); @@ -334,8 +293,7 @@ namespace mHistory.endGroup(); mHistory.record("C", LLSD(0.0), LLSD(1.0), 5.f); - UNSCOPED_INFO("two steps"); - CHECK(mHistory.depth() == (size_t)2); + REQUIRE(mHistory.depth() == (size_t)2); UNSCOPED_INFO("the group's step carries its name"); CHECK(mHistory.labelOf(0) == std::string("Reset Bloom")); UNSCOPED_INFO("a lone write's step has none"); @@ -360,9 +318,7 @@ namespace mHistory.endGroup(); mHistory.endGroup(); - UNSCOPED_INFO("one step"); - CHECK(mHistory.depth() == (size_t)1); - UNSCOPED_INFO("named by the outermost group"); + REQUIRE(mHistory.depth() == (size_t)1); CHECK(mHistory.labelOf(0) == std::string("Look: Soft Film")); } @@ -377,8 +333,7 @@ namespace mHistory.record("A", LLSD((F64)i), LLSD((F64)(i + 1)), 1.f); mHistory.endGroup(); } - UNSCOPED_INFO("capped"); - CHECK(mHistory.depth() == ALGradeHistory::MAX_DEPTH); + REQUIRE(mHistory.depth() == ALGradeHistory::MAX_DEPTH); UNSCOPED_INFO("the oldest kept is the sixth made"); CHECK(mHistory.labelOf(0) == std::string("step 5")); UNSCOPED_INFO("the newest is the last made"); @@ -398,7 +353,7 @@ namespace mHistory.record("four", LLSD(0.0), LLSD(1.0), 1.f); mHistory.endGroup(); UNSCOPED_INFO("the undone two were cut"); - CHECK(mHistory.depth() == (size_t)2); + REQUIRE(mHistory.depth() == (size_t)2); UNSCOPED_INFO("the first kept its name"); CHECK(mHistory.labelOf(0) == std::string("one")); UNSCOPED_INFO("and the new one has its own"); @@ -413,9 +368,7 @@ namespace mHistory.record("A", LLSD(1.0), LLSD(2.0), 1.f); mHistory.record("A", LLSD(2.0), LLSD(1.0), 1.f); mHistory.endGroup(); - UNSCOPED_INFO("no step"); CHECK_FALSE(mHistory.canUndo()); - UNSCOPED_INFO("nothing kept"); CHECK(mHistory.depth() == (size_t)0); mHistory.beginGroup(); @@ -423,14 +376,11 @@ namespace mHistory.record("B", LLSD(0.0), LLSD(5.0), 1.f); mHistory.record("A", LLSD(2.0), LLSD(1.0), 1.f); mHistory.endGroup(); - UNSCOPED_INFO("one step"); CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - UNSCOPED_INFO("got it"); REQUIRE(t != nullptr); UNSCOPED_INFO("holding only what changed"); REQUIRE(t->size() == (size_t)1); - UNSCOPED_INFO("which is B"); CHECK(t->front().mName == std::string("B")); } @@ -440,20 +390,16 @@ namespace { mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); mHistory.record("A", LLSD(1.0), LLSD(0.0), 1.1f); - UNSCOPED_INFO("back where it started, no step"); CHECK(mHistory.depth() == (size_t)0); - UNSCOPED_INFO("nothing to undo"); CHECK_FALSE(mHistory.canUndo()); mHistory.record("A", LLSD(0.0), LLSD(2.0), 1.2f); UNSCOPED_INFO("carrying on is a step"); CHECK(mHistory.depth() == (size_t)1); const auto* t = mHistory.undo(); - UNSCOPED_INFO("got it"); REQUIRE(t != nullptr); UNSCOPED_INFO("from the value the drag began at"); CHECK(t->front().mBefore.asReal() == 0.0); - UNSCOPED_INFO("to where it went"); CHECK(t->front().mAfter.asReal() == 2.0); // A drag that returns to its start does not take an earlier step with @@ -463,8 +409,7 @@ namespace mHistory.record("A", LLSD(0.0), LLSD(1.0), 5.f); mHistory.record("A", LLSD(1.0), LLSD(0.0), 5.1f); UNSCOPED_INFO("the earlier step stays"); - CHECK(mHistory.depth() == (size_t)1); - UNSCOPED_INFO("and it is B's"); + REQUIRE(mHistory.depth() == (size_t)1); CHECK(mHistory.at(0).front().mName == std::string("B")); } @@ -475,11 +420,9 @@ namespace mHistory.record("A", LLSD(0.0), LLSD(1.0), 1.f); mHistory.record("B", LLSD(0.0), LLSD(1.0), 2.f); mHistory.undo(); - UNSCOPED_INFO("something to redo"); CHECK(mHistory.canRedo()); mHistory.record("C", LLSD(5.0), LLSD(5.0), 3.f); - UNSCOPED_INFO("still something to redo"); CHECK(mHistory.canRedo()); UNSCOPED_INFO("and nothing added"); CHECK(mHistory.depth() == (size_t)2); @@ -535,15 +478,10 @@ namespace const ALGradeHistory::Transaction shown = mHistory.at(1); const auto* undone = mHistory.undo(); - UNSCOPED_INFO("got it"); REQUIRE(undone != nullptr); - UNSCOPED_INFO("the same size"); REQUIRE(undone->size() == shown.size()); - UNSCOPED_INFO("the same control"); CHECK(undone->front().mName == shown.front().mName); - UNSCOPED_INFO("the same start"); CHECK(undone->front().mBefore.asReal() == shown.front().mBefore.asReal()); - UNSCOPED_INFO("the same end"); CHECK(undone->front().mAfter.asReal() == shown.front().mAfter.asReal()); UNSCOPED_INFO("and the cursor says it is no longer in force"); CHECK(mHistory.cursor() == (size_t)1); @@ -568,7 +506,7 @@ namespace CHECK(mHistory.labelOf(1) == std::string("two")); UNSCOPED_INFO("the last redo"); CHECK(mHistory.labelOf(2) == std::string("three")); - UNSCOPED_INFO("its changes"); + UNSCOPED_INFO("a redo step's changes"); CHECK(mHistory.at(2).front().mName == std::string("three")); mHistory.clear(); diff --git a/indra/newview/tests/alhuddepth_gl_test.cpp b/indra/newview/tests/alhuddepth_gl_test.cpp index 705a3b56e4..63f453baa7 100644 --- a/indra/newview/tests/alhuddepth_gl_test.cpp +++ b/indra/newview/tests/alhuddepth_gl_test.cpp @@ -146,11 +146,6 @@ namespace return reverse; } - static std::string named(bool reverse, const std::string& what) - { - return what + (reverse ? " (reverse-Z)" : " (forward)"); - } - void setConvention(bool reverse) { LLRender::sReverseZ = reverse; @@ -175,12 +170,11 @@ namespace std::map defines; for (const char* object : { "deferred/textureUtilV.glsl", "objects/nonindexedTextureV.glsl" }) { + CAPTURE(object); S32 level = 1; - UNSCOPED_INFO(std::string("compiled ") + object); REQUIRE(mShaders.loadShaderFile(object, level, GL_VERTEX_SHADER, &defines) != 0); } S32 level = 1; - UNSCOPED_INFO("compiled deferred/globalF.glsl"); REQUIRE(mShaders.loadShaderFile("deferred/globalF.glsl", level, GL_FRAGMENT_SHADER, &defines) != 0); mBlitProgram.mName = "Copy Depth Blit"; @@ -190,7 +184,6 @@ namespace mBlitProgram.clearPermutations(); mBlitProgram.addPermutation("COPY_DEPTH", "1"); mBlitProgram.mShaderLevel = 1; - UNSCOPED_INFO("blit copy builds"); REQUIRE(mBlitProgram.createShader()); mCopyDepthProgram.mName = "Copy Depth Shader"; @@ -201,7 +194,6 @@ namespace mCopyDepthProgram.addPermutation("COPY_DEPTH", "1"); mCopyDepthProgram.addPermutation("DEPTH_ONLY", "1"); mCopyDepthProgram.mShaderLevel = 1; - UNSCOPED_INFO("depth copy builds"); REQUIRE(mCopyDepthProgram.createShader()); const GLuint vs = ll_test::compileTestShader(GL_VERTEX_SHADER, kQuadVertex); @@ -224,15 +216,12 @@ namespace glGenVertexArrays(1, &mVAO); glGenBuffers(1, &mVBO); - UNSCOPED_INFO("window"); REQUIRE(mWindow.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, LLRenderTarget::DEPTH_FMT_24)); - UNSCOPED_INFO("scene"); REQUIRE(mScene.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, reverse ? LLRenderTarget::DEPTH_FMT_32F : LLRenderTarget::DEPTH_FMT_24)); mTriangle = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX); - UNSCOPED_INFO("triangle"); REQUIRE(mTriangle->allocateBuffer(3, 0)); LLStrider vert; mTriangle->getVertexStrider(vert); @@ -416,6 +405,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); blit(); const std::vector scene = depths(mScene); @@ -425,14 +415,14 @@ namespace { worst = llmax(worst, std::fabs(scene[i] - window[i])); } - UNSCOPED_INFO(named(reverse, "the window holds the scene's depth")); + UNSCOPED_INFO("the window holds the scene's depth"); REQUIRE(worst < 1e-6f); - UNSCOPED_INFO(named(reverse, "and its colour")); + UNSCOPED_INFO("and its colour"); REQUIRE(colourAt(40, 24) == unorm(MID_COLOUR)); const F32 cleared = reverse ? 0.f : 1.f; - UNSCOPED_INFO(named(reverse, "sky is the cleared depth")); + UNSCOPED_INFO("sky is the cleared depth"); REQUIRE(window[(size_t)40 * W + 40] == cleared); - UNSCOPED_INFO(named(reverse, "the near surface is nearer than the mid one")); + UNSCOPED_INFO("the near surface is nearer than the mid one"); REQUIRE((reverse ? window[(size_t)24 * W + 24] > window[(size_t)24 * W + 40] : window[(size_t)24 * W + 24] < window[(size_t)24 * W + 40])); } } @@ -443,20 +433,21 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); blit(); drawHUD(); - UNSCOPED_INFO(named(reverse, "uncleared, the near world hides the HUD")); + UNSCOPED_INFO("uncleared, the near world hides the HUD"); REQUIRE(colourAt(24, 24) == unorm(NEAR_COLOUR)); - UNSCOPED_INFO(named(reverse, "where there is sky, the HUD shows anyway")); + UNSCOPED_INFO("where there is sky, the HUD shows anyway"); REQUIRE(colourAt(24, 40) == unorm(HUD_COLOUR)); blit(); clearUnderHUD(); drawHUD(); - UNSCOPED_INFO(named(reverse, "cleared, the HUD shows over the near world")); + UNSCOPED_INFO("cleared, the HUD shows over the near world"); REQUIRE(colourAt(24, 24) == unorm(HUD_COLOUR)); - UNSCOPED_INFO(named(reverse, "and over the sky")); + UNSCOPED_INFO("and over the sky"); REQUIRE(colourAt(24, 40) == unorm(HUD_COLOUR)); } } @@ -467,6 +458,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); blit(); clearUnderHUD(); @@ -476,20 +468,20 @@ namespace overlay(44, 20, 3.f); overlay(24, 40, 3.f); overlay(40, 40, 3.f); - UNSCOPED_INFO(named(reverse, "behind the world, off the HUD: hidden")); + UNSCOPED_INFO("behind the world, off the HUD: hidden"); REQUIRE(colourAt(40, 24) == unorm(MID_COLOUR)); - UNSCOPED_INFO(named(reverse, "in front of the world, off the HUD: shown")); + UNSCOPED_INFO("in front of the world, off the HUD: shown"); REQUIRE(colourAt(44, 20) == unorm(OVERLAY_COLOUR)); - UNSCOPED_INFO(named(reverse, "on the HUD: hidden behind it")); + UNSCOPED_INFO("on the HUD: hidden behind it"); REQUIRE(colourAt(24, 40) == unorm(HUD_COLOUR)); - UNSCOPED_INFO(named(reverse, "over sky, off the HUD: shown")); + UNSCOPED_INFO("over sky, off the HUD: shown"); REQUIRE(colourAt(40, 40) == unorm(OVERLAY_COLOUR)); blit(); clearUnderHUD(); drawHUD(); overlay(40, 24, 8.f); - UNSCOPED_INFO(named(reverse, "unrestored, what the world hides shows through")); + UNSCOPED_INFO("unrestored, what the world hides shows through"); REQUIRE(colourAt(40, 24) == unorm(OVERLAY_COLOUR)); } } @@ -500,11 +492,11 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); - UNSCOPED_INFO(named(reverse, "one rect")); REQUIRE(mRects.size() == size_t(1)); { - INFO(named(reverse, "the rect is inside the window and not all of it")); + INFO("the rect is inside the window and not all of it"); REQUIRE(mRects[0].mLeft > 0); REQUIRE(mRects[0].mRight < W); REQUIRE(mRects[0].mBottom > 0); @@ -533,9 +525,9 @@ namespace } } } - UNSCOPED_INFO(named(reverse, "the clear leaves the outside alone")); + UNSCOPED_INFO("the clear leaves the outside alone"); REQUIRE(changed_outside == size_t(0)); - UNSCOPED_INFO(named(reverse, "and empties the inside")); + UNSCOPED_INFO("and empties the inside"); REQUIRE(uncleared_inside == size_t(0)); restoreUnderHUD(); @@ -545,7 +537,7 @@ namespace { differing += restored[i] != before[i] ? 1 : 0; } - UNSCOPED_INFO(named(reverse, "the restore gives back the blit's depth")); + UNSCOPED_INFO("the restore gives back the blit's depth"); REQUIRE(differing == size_t(0)); } } @@ -603,19 +595,20 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); LLGLSLShader unloaded; blit(); const std::vector before = depths(mWindow); clearUnderHUD(&unloaded); - UNSCOPED_INFO(named(reverse, "nothing cleared")); + UNSCOPED_INFO("nothing cleared"); REQUIRE(depths(mWindow) == before); drawHUD(); restoreUnderHUD(&unloaded); overlay(40, 24, 8.f); - UNSCOPED_INFO(named(reverse, "behind the world under the HUD's rect: hidden")); + UNSCOPED_INFO("behind the world under the HUD's rect: hidden"); REQUIRE(colourAt(40, 24) == unorm(MID_COLOUR)); - UNSCOPED_INFO(named(reverse, "the near world still hides the HUD")); + UNSCOPED_INFO("the near world still hides the HUD"); REQUIRE(colourAt(24, 24) == unorm(NEAR_COLOUR)); } } diff --git a/indra/newview/tests/almotionpredictor_test.cpp b/indra/newview/tests/almotionpredictor_test.cpp index f73058b416..18ec12c518 100644 --- a/indra/newview/tests/almotionpredictor_test.cpp +++ b/indra/newview/tests/almotionpredictor_test.cpp @@ -89,14 +89,12 @@ namespace TEST_CASE_METHOD(predictor_data, "ALMotionPredictor: cadence converges on a steady rate", "[ALMotionPredictor]") { feedCadence(0.1f); - UNSCOPED_INFO("10 Hz"); CHECK_THAT(mPredictor.getUpdateInterval(), ll_test::WithinBits(0.1f, 16)); ALMotionPredictor slow; // Drive the second one directly so both start clean. F64 t = 100.0; for (S32 i = 0; i < 12; ++i) { slow.noteUpdate(t); t += 1.0; } - UNSCOPED_INFO("1 Hz"); CHECK_THAT(slow.getUpdateInterval(), ll_test::WithinBits(1.0f, 16)); } @@ -144,11 +142,9 @@ namespace for (S32 i = 0; i < 12; ++i) { p.noteUpdate(t); t += c.mInterval; } const ALMotionPredictor::Window w = p.phaseOutWindow(mTuning); - UNSCOPED_INFO("tapers"); + CAPTURE(c.mInterval); REQUIRE(w.isTapering()); - UNSCOPED_INFO("start"); REQUIRE_THAT(w.mStart, ll_test::WithinBits(c.mStart, 16)); - UNSCOPED_INFO("end"); REQUIRE_THAT(w.mEnd, ll_test::WithinBits(c.mEnd, 16)); UNSCOPED_INFO("taper span is preserved"); REQUIRE(w.mEnd - w.mStart >= 2.f - 1e-4f); @@ -166,9 +162,7 @@ namespace mTuning.mCadenceFactor = 8.f; const ALMotionPredictor::Window w = p.phaseOutWindow(mTuning); - UNSCOPED_INFO("tapers"); CHECK(w.isTapering()); - UNSCOPED_INFO("clamped to the cap"); CHECK_THAT(w.mStart, ll_test::WithinBits(mTuning.mCadenceCap, 16)); UNSCOPED_INFO("and the taper still follows it"); CHECK_THAT(w.mEnd, ll_test::WithinBits(mTuning.mCadenceCap + 2.f, 16)); @@ -178,11 +172,8 @@ namespace { // No cadence observed at all, yet the window still exists -- that is the default. const ALMotionPredictor::Window w = mPredictor.phaseOutWindow(mTuning); - UNSCOPED_INFO("tapers"); CHECK(w.isTapering()); - UNSCOPED_INFO("start"); CHECK_THAT(w.mStart, ll_test::WithinBits(1.f, 4)); - UNSCOPED_INFO("end"); CHECK_THAT(w.mEnd, ll_test::WithinBits(3.f, 4)); } @@ -213,7 +204,7 @@ namespace for (F32 t = 0.f; t < 4.f; t += dt) { const F32 v = ALMotionPredictor::phaseOutFactor(t, w); - UNSCOPED_INFO("monotone non-increasing"); + CAPTURE(t); REQUIRE(v <= prev + 1e-6f); worst = llmax(worst, prev - v); prev = v; @@ -228,7 +219,7 @@ namespace { UNSCOPED_INFO("an ordinary frame passes through"); CHECK_THAT(ALMotionPredictor::clampFrameStep(1.f / 60.f, mTuning), - ll_test::WithinBits(1.f / 60.f, 5)); + ll_test::WithinBits(1.f / 60.f, 5)); UNSCOPED_INFO("a 30 s pause is bounded"); CHECK(ALMotionPredictor::clampFrameStep(30.f, mTuning) == mTuning.mMaxFrameStep); UNSCOPED_INFO("time never runs backwards"); @@ -248,7 +239,7 @@ namespace for (F32 f : fps) { - UNSCOPED_INFO("same fall at any frame rate"); + CAPTURE(f); REQUIRE_THAT(drop(f, 1.f), ll_test::WithinBits(reference, 8)); } } @@ -285,7 +276,7 @@ namespace new_vel += accel * dt; } - UNSCOPED_INFO("same trajectory as the form it replaces"); + CAPTURE(f); REQUIRE_THAT(new_pos, ll_test::WithinBits(old_pos, 20)); } } @@ -326,14 +317,10 @@ namespace // Half a timestep of gravity, ~0.109 m/s. Direction is deliberately whatever the viewer // has always used; see SIGN_AVERAGE_TO_FINAL. - UNSCOPED_INFO("offset magnitude"); CHECK_THAT(fabsf(converted.mV[VZ]), - ll_test::WithinBits(fabsf(0.5f * GRAVITY * ALMotionPredictor::SIM_TIMESTEP), 16)); - { - INFO("horizontal axes untouched"); - CHECK(converted.mV[VX] == 0.f); - CHECK(converted.mV[VY] == 0.f); - } + ll_test::WithinBits(fabsf(0.5f * GRAVITY * ALMotionPredictor::SIM_TIMESTEP), 16)); + CHECK(converted.mV[VX] == 0.f); + CHECK(converted.mV[VY] == 0.f); // With no acceleration there is nothing to convert, which is the overwhelmingly common // case -- an avatar walking, a scripted mover at constant velocity. diff --git a/indra/newview/tests/alnotecardembedded_test.cpp b/indra/newview/tests/alnotecardembedded_test.cpp index 334002c83d..907946fce4 100644 --- a/indra/newview/tests/alnotecardembedded_test.cpp +++ b/indra/newview/tests/alnotecardembedded_test.cpp @@ -198,7 +198,7 @@ namespace { INFO("C, then A; B left behind"); REQUIRE(items.size() == 2); - REQUIRE(items[0] == c); + CHECK(items[0] == c); CHECK(items[1] == a); } UNSCOPED_INFO("the editor's own text as it was"); @@ -211,9 +211,7 @@ namespace make("text\n"); const LLRect rect = view->textRect(); const ALTextPos where = view->posAtLocal(rect.mLeft + 1, rect.mTop - 2, true); - UNSCOPED_INFO("taken"); CHECK(drop(a, true) == ACCEPT_YES_COPY_MULTI); - UNSCOPED_INFO("taken"); CHECK(drop(b, true) == ACCEPT_YES_COPY_MULTI); const std::string line = view->document().line(where.line); UNSCOPED_INFO("A, then B after it"); @@ -227,7 +225,6 @@ namespace drop(c, true); UNSCOPED_INFO("a new frame's drop lands where the pointer is"); CHECK(view->document().line(where.line).substr(where.column, 4) == at(2)); - UNSCOPED_INFO("three carried"); REQUIRE(tab->items().size() == size_t(3)); UNSCOPED_INFO("one undo takes the last away"); CHECK(view->undoJournal().canUndo()); @@ -284,7 +281,7 @@ namespace REQUIRE(world.copies.empty()); { INFO("one saved: asked"); - REQUIRE(card.copy(saved, LLUUID::null)); + CHECK(card.copy(saved, LLUUID::null)); REQUIRE(world.copies.size() == 1); CHECK(world.copies.back() == saved->getUUID()); } @@ -335,7 +332,7 @@ namespace REQUIRE(back[1].isNull()); { INFO("the rest as they were"); - REQUIRE(back[0]->getUUID() == a->getUUID()); + CHECK(back[0]->getUUID() == a->getUUID()); CHECK(back[2]->getName() == "B"); } } @@ -402,7 +399,7 @@ namespace ALNotecardEmbedded& card = make("above\nhere " + at(0) + " it is\nbelow\n", { item("A") }); (void)card; const S32 text_h = view->layout().rowHeight(); - UNSCOPED_INFO("a row an inventory icon is taller than: " + std::to_string(text_h)); + UNSCOPED_INFO("a row an inventory icon is taller than: " << text_h); CHECK(text_h < 16 + 4); view->placeAtomViews(); UNSCOPED_INFO("the item's line: the icon, a pixel either side, and a pixel off the rows"); diff --git a/indra/newview/tests/alrecoverykeeper_test.cpp b/indra/newview/tests/alrecoverykeeper_test.cpp index 7c4946d9da..1d2c07ff97 100644 --- a/indra/newview/tests/alrecoverykeeper_test.cpp +++ b/indra/newview/tests/alrecoverykeeper_test.cpp @@ -100,16 +100,15 @@ namespace { ALRecoveryKeeper keeper(holder()); keeper.setItem(object, item); - UNSCOPED_INFO("the window's own key"); CHECK(ALRecoveryStore::isWindowKey(keeper.key())); keeper.pump(1, 10.0); UNSCOPED_INFO("nothing unsaved, nothing written"); - REQUIRE_FALSE(mine()); + CHECK_FALSE(mine()); unsaved = true; text = "typed"; keeper.pump(2, 10.0); UNSCOPED_INFO("not at once"); - REQUIRE_FALSE(mine()); + CHECK_FALSE(mine()); keeper.pump(3, 10.5); keeper.pump(3, 10.0 + ALRecoveryKeeper::DELAY); { @@ -129,8 +128,7 @@ namespace unsaved = false; keeper.pump(4, 20.0); UNSCOPED_INFO("saved: forgotten"); - REQUIRE_FALSE(mine()); - UNSCOPED_INFO("nothing failed"); + CHECK_FALSE(mine()); CHECK(failed == 0); } @@ -142,18 +140,15 @@ namespace text = "thrown away"; keeper.pump(1, 0.0); keeper.pump(1, ALRecoveryKeeper::DELAY); - UNSCOPED_INFO("written"); REQUIRE(mine().has_value()); - UNSCOPED_INFO("set aside"); CHECK(keeper.setAside()); UNSCOPED_INFO("its own gone"); - REQUIRE_FALSE(mine()); + CHECK_FALSE(mine()); bool discarded = false; for (const ALRecoveryEntry& entry : store->list()) { discarded |= entry.state == ALRecoveryEntry::State::Discarded && entry.key == keeper.key(); } - UNSCOPED_INFO("among the discarded"); CHECK(discarded); // What a session that ended left of the same item. @@ -165,15 +160,11 @@ namespace left.item = item; left.name = "Card"; left.text = "left behind"; - UNSCOPED_INFO("left"); CHECK(before.write(left)); } std::optional offered = keeper.left(); - { - INFO("offered"); - REQUIRE(offered); - CHECK(offered->text == "left behind"); - } + REQUIRE(offered); + CHECK(offered->text == "left behind"); text = "left behind"; keeper.took(*offered, 7); { @@ -182,7 +173,7 @@ namespace CHECK(mine()->text == "left behind"); } UNSCOPED_INFO("and the one taken up gone"); - REQUIRE_FALSE(keeper.left()); + CHECK_FALSE(keeper.left()); // Turned down: among the discarded, and offered no more. { @@ -194,14 +185,11 @@ namespace before.write(left); } offered = keeper.left(); - { - INFO("offered again"); - REQUIRE(offered); - CHECK(offered->text == "not wanted"); - } + REQUIRE(offered); + CHECK(offered->text == "not wanted"); keeper.turnDown(*offered); UNSCOPED_INFO("turned down: offered no more"); - REQUIRE_FALSE(keeper.left()); + CHECK_FALSE(keeper.left()); } TEST_CASE_METHOD(alrecoverykeeper_data, "ALRecoveryKeeper: a new item or none moves the key and a failed write is said once", "[ALRecoveryKeeper]") @@ -211,7 +199,6 @@ namespace unsaved = true; keeper.pump(1, 0.0); keeper.pump(1, ALRecoveryKeeper::DELAY); - UNSCOPED_INFO("written"); REQUIRE(mine().has_value()); const LLUUID was = item; item = LLUUID::generateNewID(); @@ -227,10 +214,10 @@ namespace keeper.pump(2, 5.0); keeper.pump(2, 5.0 + ALRecoveryKeeper::DELAY); UNSCOPED_INFO("the new one kept"); - REQUIRE(mine().has_value()); + CHECK(mine().has_value()); keeper.setItem(object, LLUUID::null); UNSCOPED_INFO("no item, no key"); - REQUIRE(keeper.key().empty()); + CHECK(keeper.key().empty()); // Where the store cannot write: said once. const std::string blocked = folder + "/blocked"; @@ -246,13 +233,13 @@ namespace failing.pump(1, ALRecoveryKeeper::DELAY); nowhere.flush(); failing.pump(1, 10.0); - UNSCOPED_INFO("said"); + UNSCOPED_INFO("the failed write said"); CHECK(failed == 1); failing.pump(2, 11.0); failing.pump(2, 11.0 + ALRecoveryKeeper::DELAY); nowhere.flush(); failing.pump(2, 20.0); - UNSCOPED_INFO("once"); + UNSCOPED_INFO("and not said again"); CHECK(failed == 1); ALRecovery::useStore(store.get()); } @@ -274,19 +261,15 @@ namespace llofstream other(temp + "/unrelated.txt"); other << "left alone"; } - UNSCOPED_INFO("two taken"); CHECK(ALRecovery::importLegacyBackups(temp) == 2); - { - INFO("the backups gone"); - CHECK_FALSE(LLFile::isfile(temp + "/Door Script-1A2B3C4D.lslbackup")); - CHECK_FALSE(LLFile::isfile(temp + "/Settings-0000ABCD.ncbackup")); - } + CHECK_FALSE(LLFile::isfile(temp + "/Door Script-1A2B3C4D.lslbackup")); + CHECK_FALSE(LLFile::isfile(temp + "/Settings-0000ABCD.ncbackup")); UNSCOPED_INFO("anything else left alone"); CHECK(LLFile::isfile(temp + "/unrelated.txt")); bool script = false, card = false; for (ALRecoveryEntry& entry : store->left()) { - UNSCOPED_INFO("whole"); + CAPTURE(entry.name); REQUIRE(store->load(entry)); script |= entry.name == "Door Script" && !entry.notecard && entry.text == "default { state_entry() {} }\n" && entry.state == ALRecoveryEntry::State::Unsaved; diff --git a/indra/newview/tests/alsceneexplorerpredicate_test.cpp b/indra/newview/tests/alsceneexplorerpredicate_test.cpp index 5b28c3b880..b7d0fabc86 100644 --- a/indra/newview/tests/alsceneexplorerpredicate_test.cpp +++ b/indra/newview/tests/alsceneexplorerpredicate_test.cpp @@ -68,7 +68,6 @@ namespace } }; - // Default constraints match anything (and a null record never does). TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: default constraints match anything but a null record", "[ALSceneExplorerPredicate]") { UNSCOPED_INFO("defaults match"); @@ -92,7 +91,6 @@ namespace CHECK_FALSE(matches(mFacts, mC)); } - // Description / UUID / owner searches hit only their own field. TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: description / UUID / owner searches hit only their own field", "[ALSceneExplorerPredicate]") { mC.mSearchType = SEARCH_DESCRIPTION; @@ -120,14 +118,13 @@ namespace CHECK_FALSE(matches(mFacts, mC)); } - // ALL searches every field; a miss everywhere fails. TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: SEARCH_ALL finds text in any field and fails a miss in all", "[ALSceneExplorerPredicate]") { mC.mSearchType = SEARCH_ALL; for (const char* needle : { "oak", "weathered", "rye" }) { mC.mFilterSubString = needle; - UNSCOPED_INFO(std::string("all-search finds ") + needle); + CAPTURE(needle); REQUIRE(matches(mFacts, mC)); } mC.mFilterSubString = mUUID.substr(4, 8); @@ -138,7 +135,6 @@ namespace CHECK_FALSE(matches(mFacts, mC)); } - // Owner modes for an owned object. TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: mine / others / group owner modes for an owned object", "[ALSceneExplorerPredicate]") { mC.mOwnerMode = OWNER_MINE; @@ -167,7 +163,6 @@ namespace CHECK_FALSE(matches(mFacts, mC)); } - // OWNER_SPECIFIC: direct owner or the deeding group. TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: OWNER_SPECIFIC matches the direct owner or the deeding group", "[ALSceneExplorerPredicate]") { mC.mOwnerMode = OWNER_SPECIFIC; @@ -229,7 +224,6 @@ namespace CHECK(matches(mFacts, mC)); } - // Flag mask requires ALL set bits. TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: a flag mask requires every bit it sets", "[ALSceneExplorerPredicate]") { mC.mFlagMask = ALObjectProperties::FLAG_SCRIPTED; @@ -298,7 +292,6 @@ namespace CHECK(matches(mFacts, mC)); } - // Predicates compose: every constraint must hold at once. TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: constraints compose and every one must hold at once", "[ALSceneExplorerPredicate]") { mC.mSearchType = SEARCH_NAME; @@ -320,7 +313,6 @@ namespace // backspacing cases), including the empty-needle transitions. TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: classifySubstringChange tells typing from backspacing", "[ALSceneExplorerPredicate]") { - UNSCOPED_INFO("same needle"); CHECK(classifySubstringChange("oak", "oak") == CHANGE_NONE); UNSCOPED_INFO("typing from empty"); CHECK(classifySubstringChange("", "oak") == CHANGE_MORE_RESTRICTIVE); @@ -340,7 +332,6 @@ namespace const U32 a = ALObjectProperties::FLAG_SCRIPTED; const U32 b = ALObjectProperties::FLAG_LIGHT; const U32 c = ALObjectProperties::FLAG_PHANTOM; - UNSCOPED_INFO("same mask"); CHECK(classifyRequireAllMaskChange(a | b, a | b) == CHANGE_NONE); UNSCOPED_INFO("first requirement"); CHECK(classifyRequireAllMaskChange(0, a) == CHANGE_MORE_RESTRICTIVE); @@ -359,7 +350,6 @@ namespace { const U32 prim = 1u << ALObjectProperties::GEOM_PRIM; const U32 mesh = 1u << ALObjectProperties::GEOM_MESH; - UNSCOPED_INFO("same set"); CHECK(classifyAllowedMaskChange(prim, prim) == CHANGE_NONE); UNSCOPED_INFO("any to one kind"); CHECK(classifyAllowedMaskChange(0, prim) == CHANGE_MORE_RESTRICTIVE); @@ -376,7 +366,6 @@ namespace // Change classification: minimum thresholds (0 = off). TEST_CASE_METHOD(predicate_data, "ALSceneExplorerPredicate: classifyMinThresholdChange restricts on a raise with 0 as off", "[ALSceneExplorerPredicate]") { - UNSCOPED_INFO("same threshold"); CHECK(classifyMinThresholdChange(50.f, 50.f) == CHANGE_NONE); UNSCOPED_INFO("enabling"); CHECK(classifyMinThresholdChange(0.f, 50.f) == CHANGE_MORE_RESTRICTIVE); diff --git a/indra/newview/tests/alscopedata_test.cpp b/indra/newview/tests/alscopedata_test.cpp index f7e3df8dbc..523b9af84c 100644 --- a/indra/newview/tests/alscopedata_test.cpp +++ b/indra/newview/tests/alscopedata_test.cpp @@ -104,13 +104,9 @@ namespace // A fresh object measures nothing and reports nothing. TEST_CASE_METHOD(scope_data, "ALScopeData: a fresh object measures nothing and reports nothing", "[ALScopeData]") { - UNSCOPED_INFO("starts empty"); CHECK(mScope.isEmpty()); - UNSCOPED_INFO("no samples"); CHECK(mScope.getSampleCount() == 0); - UNSCOPED_INFO("no peak"); CHECK_THAT(mScope.getPeak(ALScopeData::CH_LUMA), ll_test::WithinBits(0.f, 6)); - UNSCOPED_INFO("no bins"); CHECK_THAT(binSum(mScope, ALScopeData::CH_RED), ll_test::WithinBits(0.f, 6)); } @@ -120,13 +116,9 @@ namespace const std::vector px = flat(64, 128, 192, 100); mScope.accumulate(px.data(), 100, 1); - UNSCOPED_INFO("sample count"); CHECK(mScope.getSampleCount() == 100); - UNSCOPED_INFO("all red in bin 64"); CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 64), ll_test::WithinBits(1.f, 5)); - UNSCOPED_INFO("all green in bin 128"); CHECK_THAT(mScope.getBin(ALScopeData::CH_GREEN, 128), ll_test::WithinBits(1.f, 5)); - UNSCOPED_INFO("all blue in bin 192"); CHECK_THAT(mScope.getBin(ALScopeData::CH_BLUE, 192), ll_test::WithinBits(1.f, 5)); UNSCOPED_INFO("nothing anywhere else"); CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 65), ll_test::WithinBits(0.f, 6)); @@ -140,7 +132,7 @@ namespace for (S32 c = 0; c < ALScopeData::CH_COUNT; ++c) { - UNSCOPED_INFO("bins sum to 1"); + CAPTURE(c); REQUIRE_THAT(binSum(mScope, (ALScopeData::EChannel)c), ll_test::WithinBits(1.f, 4)); } UNSCOPED_INFO("a flat ramp peaks at 1/256"); @@ -161,7 +153,7 @@ namespace for (S32 i = 0; i < ALScopeData::BIN_COUNT; ++i) { - UNSCOPED_INFO("size independent"); + CAPTURE(i); REQUIRE_THAT(small_sample.getBin(ALScopeData::CH_RED, i), ll_test::WithinBits(large_sample.getBin(ALScopeData::CH_RED, i), 5)); } @@ -182,9 +174,7 @@ namespace grey.accumulate(n.data(), 16, 1); // 0.7152 * 255 = 182.4; 0.0722 * 255 = 18.4 - UNSCOPED_INFO("green luma"); CHECK_THAT(green.getBin(ALScopeData::CH_LUMA, 182), ll_test::WithinBits(1.f, 5)); - UNSCOPED_INFO("blue luma"); CHECK_THAT(blue.getBin(ALScopeData::CH_LUMA, 18), ll_test::WithinBits(1.f, 5)); UNSCOPED_INFO("grey is its own luma"); CHECK_THAT(grey.getBin(ALScopeData::CH_LUMA, 137), ll_test::WithinBits(1.f, 5)); @@ -203,7 +193,6 @@ namespace UNSCOPED_INFO("white luma is 255"); CHECK_THAT(white.getBin(ALScopeData::CH_LUMA, ALScopeData::BIN_COUNT - 1), ll_test::WithinBits(1.f, 5)); - UNSCOPED_INFO("black luma is 0"); CHECK_THAT(black.getBin(ALScopeData::CH_LUMA, 0), ll_test::WithinBits(1.f, 5)); } @@ -217,9 +206,7 @@ namespace for (S32 i = 0; i < 60; ++i) { px.insert(px.end(), { 128, 128, 128, 255 }); } mScope.accumulate(px.data(), 100, 1); - UNSCOPED_INFO("10% blown"); CHECK_THAT(mScope.getClippedHigh(ALScopeData::CH_RED), ll_test::WithinBits(0.10f, 4)); - UNSCOPED_INFO("30% crushed"); CHECK_THAT(mScope.getClippedLow(ALScopeData::CH_RED), ll_test::WithinBits(0.30f, 4)); UNSCOPED_INFO("luma agrees on the blown share"); CHECK_THAT(mScope.getClippedHigh(ALScopeData::CH_LUMA), ll_test::WithinBits(0.10f, 4)); @@ -234,9 +221,7 @@ namespace px[0] = px[1] = px[2] = 255; mScope.accumulate(px.data(), 10000, 1); - UNSCOPED_INFO("one blown pixel is visible"); CHECK(mScope.getClippedHigh(ALScopeData::CH_RED) > 0.f); - UNSCOPED_INFO("and it is 1 in 10000"); CHECK_THAT(mScope.getClippedHigh(ALScopeData::CH_RED), ll_test::WithinBits(0.0001f, 6)); } @@ -261,7 +246,6 @@ namespace { const std::vector px = flat(60, 60, 60, 8); mScope.accumulate(px.data(), 8, 1); - UNSCOPED_INFO("measured"); CHECK_FALSE(mScope.isEmpty()); mScope.accumulate(px.data(), 0, 1); @@ -288,7 +272,6 @@ namespace fresh.accumulate(px.data(), 20, 1); mScope.blendToward(fresh, 0.25f); - UNSCOPED_INFO("taken whole"); CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 90), ll_test::WithinBits(1.f, 5)); UNSCOPED_INFO("count carried"); CHECK(mScope.getSampleCount() == 20); @@ -340,7 +323,7 @@ namespace const F32 peak = mScope.getPeak(ch); for (S32 i = 0; i < ALScopeData::BIN_COUNT; ++i) { - UNSCOPED_INFO("no bin exceeds the peak"); + CAPTURE(c, i); REQUIRE(mScope.getBin(ch, i) <= peak + 1e-6f); } } @@ -355,7 +338,6 @@ namespace const ALScopeData nothing; mScope.blendToward(nothing, 0.5f); - UNSCOPED_INFO("unchanged"); CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, 150), ll_test::WithinBits(1.f, 5)); } @@ -365,13 +347,9 @@ namespace const std::vector px = flat(1, 2, 3, 4); mScope.accumulate(px.data(), 4, 1); - UNSCOPED_INFO("negative bin"); CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, -1), ll_test::WithinBits(0.f, 6)); - UNSCOPED_INFO("past the end"); CHECK_THAT(mScope.getBin(ALScopeData::CH_RED, ALScopeData::BIN_COUNT), ll_test::WithinBits(0.f, 6)); - UNSCOPED_INFO("bad channel"); CHECK_THAT(mScope.getBin((ALScopeData::EChannel)99, 0), ll_test::WithinBits(0.f, 6)); - UNSCOPED_INFO("bad channel peak"); CHECK_THAT(mScope.getPeak((ALScopeData::EChannel)-3), ll_test::WithinBits(0.f, 6)); } // --- vectorscope --------------------------------------------------------- @@ -432,13 +410,9 @@ namespace TEST_CASE_METHOD(scope_data, "ALScopeData: chroma cells are shares that sum to one and blend like bins", "[ALScopeData]") { mScope.accumulate(ramp().data(), ALScopeData::BIN_COUNT, 1); - UNSCOPED_INFO("cells sum to one"); CHECK_THAT(chromaSum(mScope), ll_test::WithinBits(1.f, 4)); - { - INFO("peak is a real share"); - CHECK(mScope.getChromaPeak() > 0.f); - CHECK(mScope.getChromaPeak() <= 1.f); - } + CHECK(mScope.getChromaPeak() > 0.f); + CHECK(mScope.getChromaPeak() <= 1.f); // A ramp is entirely neutral, so all of it is in one place. UNSCOPED_INFO("a grey ramp is a point"); @@ -458,22 +432,15 @@ namespace TEST_CASE_METHOD(scope_data, "ALScopeData: out-of-range cells answer zero and clear empties the grid", "[ALScopeData]") { mScope.accumulate(flat(200, 30, 30, 4).data(), 4, 1); - UNSCOPED_INFO("something was measured"); CHECK(mScope.getChromaPeak() > 0.f); - UNSCOPED_INFO("negative u"); CHECK_THAT(mScope.getChromaCell(-1, 0), ll_test::WithinBits(0.f, 6)); - UNSCOPED_INFO("negative v"); CHECK_THAT(mScope.getChromaCell(0, -1), ll_test::WithinBits(0.f, 6)); - UNSCOPED_INFO("past the end in u"); CHECK_THAT(mScope.getChromaCell(ALScopeData::CHROMA_SIZE, 0), ll_test::WithinBits(0.f, 6)); - UNSCOPED_INFO("past the end in v"); CHECK_THAT(mScope.getChromaCell(0, ALScopeData::CHROMA_SIZE), ll_test::WithinBits(0.f, 6)); mScope.clear(); - UNSCOPED_INFO("cleared peak"); CHECK_THAT(mScope.getChromaPeak(), ll_test::WithinBits(0.f, 6)); - UNSCOPED_INFO("cleared cells"); CHECK_THAT(chromaSum(mScope), ll_test::WithinBits(0.f, 6)); } @@ -493,7 +460,7 @@ namespace ll_test::WithinBits(0.f, 5)); for (S32 i = 1; i < ALScopeData::CHROMA_SIZE; ++i) { - UNSCOPED_INFO("centres increase"); + CAPTURE(i); REQUIRE(ALScopeData::chromaCellCentre(i) > ALScopeData::chromaCellCentre(i - 1)); } } @@ -634,17 +601,11 @@ namespace const S32 column = ALScopeData::WAVE_COLUMNS / 2; const S32 top = ALScopeData::WAVE_LEVELS - 1; - UNSCOPED_INFO("red is at the top"); CHECK_THAT(mScope.getWaveCell(ALScopeData::CH_RED, column, top), ll_test::WithinBits(1.f, 5)); - UNSCOPED_INFO("blue is at the bottom"); CHECK_THAT(mScope.getWaveCell(ALScopeData::CH_BLUE, column, 0), ll_test::WithinBits(1.f, 5)); - UNSCOPED_INFO("red is not also at the bottom"); CHECK(mScope.getWaveCell(ALScopeData::CH_RED, column, 0) == 0.f); - { - INFO("green is at neither end"); - CHECK(mScope.getWaveCell(ALScopeData::CH_GREEN, column, 0) == 0.f); - CHECK(mScope.getWaveCell(ALScopeData::CH_GREEN, column, top) == 0.f); - } + CHECK(mScope.getWaveCell(ALScopeData::CH_GREEN, column, 0) == 0.f); + CHECK(mScope.getWaveCell(ALScopeData::CH_GREEN, column, top) == 0.f); } // A plot walks the whole grid without checking, so out-of-range reads and a @@ -653,26 +614,18 @@ namespace TEST_CASE_METHOD(scope_data, "ALScopeData: waveform reads answer zero when unmeasured or cleared or out of range", "[ALScopeData]") { ALScopeData fresh; - UNSCOPED_INFO("unmeasured reads zero"); CHECK(fresh.getWaveCell(ALScopeData::CH_LUMA, 0, 0) == 0.f); - UNSCOPED_INFO("unmeasured has no peak"); CHECK(fresh.getWavePeak(ALScopeData::CH_LUMA) == 0.f); mScope.accumulate(flat(200, 200, 200, 16).data(), 16, 1); - UNSCOPED_INFO("negative column"); CHECK(mScope.getWaveCell(ALScopeData::CH_LUMA, -1, 0) == 0.f); - UNSCOPED_INFO("column past the end"); CHECK(mScope.getWaveCell(ALScopeData::CH_LUMA, ALScopeData::WAVE_COLUMNS, 0) == 0.f); - UNSCOPED_INFO("level past the end"); CHECK(mScope.getWaveCell(ALScopeData::CH_LUMA, 0, ALScopeData::WAVE_LEVELS) == 0.f); - UNSCOPED_INFO("bad channel"); CHECK(mScope.getWaveCell(ALScopeData::CH_COUNT, 0, 0) == 0.f); // And clearing has to let go of the grid again. mScope.clear(); - UNSCOPED_INFO("cleared reads zero"); CHECK(mScope.getWaveCell(ALScopeData::CH_LUMA, 0, 0) == 0.f); - UNSCOPED_INFO("cleared has no peak"); CHECK(mScope.getWavePeak(ALScopeData::CH_LUMA) == 0.f); } } diff --git a/indra/newview/tests/alscriptanalysislane_test.cpp b/indra/newview/tests/alscriptanalysislane_test.cpp index 80f256296d..033f4a8a6a 100644 --- a/indra/newview/tests/alscriptanalysislane_test.cpp +++ b/indra/newview/tests/alscriptanalysislane_test.cpp @@ -189,20 +189,15 @@ namespace auto gate = std::make_shared(); ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, false); }, main()); ALScriptAnalysisLane lsl("TestLSL", [gate] { return std::make_unique(gate, false); }, main()); - UNSCOPED_INFO("taken"); CHECK(post(luau, job("slow", ALScriptAnalysis::Kind::Check, true))); - UNSCOPED_INFO("held"); CHECK(gate->waitEntered()); - UNSCOPED_INFO("taken too"); CHECK(post(lsl, job("other", ALScriptAnalysis::Kind::Hover, true))); UNSCOPED_INFO("the other lane's question answered while the check is held"); CHECK(answers.waitFor(1)); - UNSCOPED_INFO("it alone"); CHECK(answers.all() == std::string("other/2")); gate->release(); UNSCOPED_INFO("then the check"); CHECK(answers.waitFor(2)); - UNSCOPED_INFO("in that order"); CHECK(answers.all() == std::string("other/2 slow/0")); luau.close(); lsl.close(); @@ -214,13 +209,9 @@ namespace { auto gate = std::make_shared(); ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, true); }, main()); - UNSCOPED_INFO("taken"); CHECK(post(luau, job("slow", ALScriptAnalysis::Kind::Check, false))); - UNSCOPED_INFO("held"); CHECK(gate->waitEntered()); - UNSCOPED_INFO("asked"); CHECK(post(luau, job("front", ALScriptAnalysis::Kind::Complete, true))); - UNSCOPED_INFO("both answered"); CHECK(answers.waitFor(2)); UNSCOPED_INFO("the question first, then the check, run again"); CHECK(answers.all() == std::string("front/1 slow/0")); @@ -231,14 +222,10 @@ namespace { auto gate = std::make_shared(); ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, true); }, main()); - UNSCOPED_INFO("taken"); CHECK(post(luau, job("slow", ALScriptAnalysis::Kind::Check, true))); - UNSCOPED_INFO("held"); CHECK(gate->waitEntered()); - UNSCOPED_INFO("asked"); CHECK(post(luau, job("front", ALScriptAnalysis::Kind::Complete, true))); gate->release(); - UNSCOPED_INFO("both answered"); CHECK(answers.waitFor(2)); UNSCOPED_INFO("the check first, not stopped"); CHECK(answers.all() == std::string("slow/0 front/1")); @@ -250,17 +237,13 @@ namespace auto gate = std::make_shared(); gate->always = true; ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, true); }, main()); - UNSCOPED_INFO("taken"); CHECK(post(luau, job("slow", ALScriptAnalysis::Kind::Check, false))); - UNSCOPED_INFO("held"); CHECK(gate->waitEntered()); - UNSCOPED_INFO("asked"); CHECK(post(luau, job("front", ALScriptAnalysis::Kind::Complete, true))); UNSCOPED_INFO("the question answered"); CHECK(answers.waitFor(1)); UNSCOPED_INFO("the check run again, and held"); CHECK(gate->waitEntered(2)); - UNSCOPED_INFO("asked again"); CHECK(post(luau, job("again", ALScriptAnalysis::Kind::Hover, true))); // A moment, in which a question that stopped it would be answered. std::this_thread::sleep_for(std::chrono::milliseconds(200)); @@ -269,9 +252,7 @@ namespace UNSCOPED_INFO("not started over"); CHECK(gate->enteredNow() == 2); gate->release(); - UNSCOPED_INFO("all answered"); CHECK(answers.waitFor(3)); - UNSCOPED_INFO("the check, then the question"); CHECK(answers.all() == std::string("front/1 slow/0 again/2")); luau.close(); } @@ -280,19 +261,14 @@ namespace { auto gate = std::make_shared(); ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, true); }, main()); - UNSCOPED_INFO("taken"); CHECK(post(luau, job("slow", ALScriptAnalysis::Kind::Check, false))); - UNSCOPED_INFO("held"); CHECK(gate->waitEntered()); luau.forget("slow"); - UNSCOPED_INFO("asked"); CHECK(post(luau, job("front", ALScriptAnalysis::Kind::Hover, true))); UNSCOPED_INFO("the question answered"); CHECK(answers.waitFor(1)); gate->release(); - UNSCOPED_INFO("asked again"); CHECK(post(luau, job("last", ALScriptAnalysis::Kind::Hover, true))); - UNSCOPED_INFO("answered"); CHECK(answers.waitFor(2)); UNSCOPED_INFO("nothing for the tab let go of"); CHECK(answers.all() == std::string("front/2 last/2")); @@ -319,13 +295,9 @@ namespace auto gate = std::make_shared(); ALScriptAnalysisLane luau("TestLuau", [gate] { return std::make_unique(gate, true); }, main()); - UNSCOPED_INFO("taken"); CHECK(post(luau, job("slow", Kind::References, false))); - UNSCOPED_INFO("held"); CHECK(gate->waitEntered()); - UNSCOPED_INFO("asked"); CHECK(post(luau, job("front", Kind::Complete, true))); - UNSCOPED_INFO("both answered"); CHECK(answers.waitFor(2)); UNSCOPED_INFO("the question first, then the lookup's, run again"); CHECK(answers.all() == std::string("front/1 slow/5")); diff --git a/indra/newview/tests/alscriptanalyzers_test.cpp b/indra/newview/tests/alscriptanalyzers_test.cpp index 3539e36b15..5e380e0503 100644 --- a/indra/newview/tests/alscriptanalyzers_test.cpp +++ b/indra/newview/tests/alscriptanalyzers_test.cpp @@ -52,15 +52,13 @@ namespace const ALScriptAnalysis::Request broken = request(ALScriptAnalysis::Kind::Check, "default { state_entry() { llSay(0, \"x\" } }\n"); ALScriptAnalysis::Result checked; lsl.answer(broken, *broken.text, setup, checked); - UNSCOPED_INFO("builtins loaded: " + checked.definitionsError); + UNSCOPED_INFO("builtins loaded: " << checked.definitionsError); REQUIRE(checked.definitionsError.empty()); - UNSCOPED_INFO("the broken text did not parse"); CHECK_FALSE(checked.parsed); ALScriptAnalysis::Request weighing = request(ALScriptAnalysis::Kind::Weigh, "default { state_entry() { llSay(0, \"x\"); } }\n"); weighing.targets = { ALScriptWeight::Target::Mono }; ALScriptAnalysis::Result weighed; lsl.answer(weighing, *weighing.text, setup, weighed); - UNSCOPED_INFO("weighed"); REQUIRE(weighed.weights.size() == size_t(1)); UNSCOPED_INFO("not the check's parse"); CHECK(weighed.parsed); @@ -81,7 +79,7 @@ namespace CHECK(lsl_shape.outline[2].depth == 1); } UNSCOPED_INFO("nothing else answered"); - REQUIRE(lsl_shape.problems.empty()); + CHECK(lsl_shape.problems.empty()); ALLuauAnalyzer luau; ALScriptAnalysis::Request slua = request(ALScriptAnalysis::Kind::Shape, "local function half(n: number)\n return n / 2\nend\n"); @@ -92,9 +90,9 @@ namespace INFO("SLua: the function, untyped"); REQUIRE(luau_shape.outline.size() == 1); CHECK(luau_shape.outline[0].name == "half"); - REQUIRE(luau_shape.outline[0].detail.empty()); + CHECK(luau_shape.outline[0].detail.empty()); } UNSCOPED_INFO("no definitions asked for"); - REQUIRE(luau_shape.definitionsError.empty()); + CHECK(luau_shape.definitionsError.empty()); } } diff --git a/indra/newview/tests/alscriptcontentsindex_test.cpp b/indra/newview/tests/alscriptcontentsindex_test.cpp index 9f19e22d85..31c5289d54 100644 --- a/indra/newview/tests/alscriptcontentsindex_test.cpp +++ b/indra/newview/tests/alscriptcontentsindex_test.cpp @@ -150,26 +150,18 @@ namespace const LLUUID chair = object(10); S32 heard = 0; index.onHeard([&heard, chair](const Index::Contents& contents) { heard += contents.prim == chair; }); - UNSCOPED_INFO("asked"); CHECK(index.ask(chair)); UNSCOPED_INFO("not again while it is not answered"); CHECK_FALSE(index.ask(chair)); - UNSCOPED_INFO("asking"); CHECK(index.asking(chair)); - REQUIRE(asked.size() == size_t(1)); - { - INFO("not known yet"); - CHECK_FALSE(index.fetched(chair)); - REQUIRE(index.prim(chair) == nullptr); - } - UNSCOPED_INFO("answered"); - CHECK(answer(chair, { "sit.lsl", "readme" }, true, "Chair")); - UNSCOPED_INFO("heard once"); + CHECK(asked.size() == size_t(1)); + CHECK_FALSE(index.fetched(chair)); + CHECK(index.prim(chair) == nullptr); + // Unanswered, the prim would not be known, and it is read below. + REQUIRE(answer(chair, { "sit.lsl", "readme" }, true, "Chair")); CHECK(heard == 1); CHECK(names(chair) == std::string("sit.lsl readme")); - UNSCOPED_INFO("its name"); CHECK(index.prim(chair)->name == std::string("Chair")); - UNSCOPED_INFO("no longer asking"); CHECK_FALSE(index.asking(chair)); // Known: asked again only where the object's copy is not current, @@ -183,12 +175,12 @@ namespace UNSCOPED_INFO("current, not asked"); CHECK_FALSE(index.ask(chair)); { - INFO("a refetch is"); + INFO("a refetch is asked"); CHECK(index.ask(chair, true)); CHECK(answer(chair, { "sit.lsl" })); } { - INFO("and of the region"); + INFO("so is one of the region"); CHECK(index.ask(chair, false, true)); CHECK(asked.back().second); } @@ -204,10 +196,9 @@ namespace UNSCOPED_INFO("each script asked whether it runs"); REQUIRE(askedRunning.size() == size_t(2)); index.running(askedRunning[0], true); - UNSCOPED_INFO("known"); CHECK(index.running(askedRunning[0]) == std::optional(true)); - UNSCOPED_INFO("not known"); - REQUIRE_FALSE(index.running(askedRunning[1])); + UNSCOPED_INFO("one not answered is not known"); + CHECK_FALSE(index.running(askedRunning[1])); index.ask(chair, true); answer(chair, {}, false); @@ -216,16 +207,16 @@ namespace UNSCOPED_INFO("still fetched"); CHECK(index.fetched(chair)); UNSCOPED_INFO("only the one not known asked again"); - REQUIRE(askedRunning.size() == size_t(3)); + CHECK(askedRunning.size() == size_t(3)); index.forgetRunning({ chair }); - UNSCOPED_INFO("let go of"); - REQUIRE_FALSE(index.running(askedRunning[0])); + UNSCOPED_INFO("whether it runs let go of"); + CHECK_FALSE(index.running(askedRunning[0])); index.forget(chair); { - INFO("all of it"); - REQUIRE(index.prim(chair) == nullptr); - REQUIRE(names(chair).empty()); + INFO("all of the prim let go of"); + CHECK(index.prim(chair) == nullptr); + CHECK(names(chair).empty()); } } @@ -243,23 +234,22 @@ namespace std::optional listed; index.ensureListed(id(23), [&listed](const Index::Listed& out) { listed = out; }); UNSCOPED_INFO("the root and the one never asked"); - REQUIRE(asked.size() - before == size_t(2)); - UNSCOPED_INFO("not yet"); - REQUIRE_FALSE(listed); + CHECK(asked.size() - before == size_t(2)); + UNSCOPED_INFO("not told yet"); + CHECK_FALSE(listed); answer(id(20), { "main.lsl" }); answer(id(22), { "light.lsl" }); UNSCOPED_INFO("not while one is out"); - REQUIRE_FALSE(listed); + CHECK_FALSE(listed); answer(id(23), {}, false); - UNSCOPED_INFO("told"); REQUIRE(listed.has_value()); { INFO("by its root"); - REQUIRE(listed->root == house); + CHECK(listed->root == house); CHECK(listed->present); } UNSCOPED_INFO("every prim"); - REQUIRE(listed->prims.size() == size_t(4)); + CHECK(listed->prims.size() == size_t(4)); UNSCOPED_INFO("the one that did not answer said"); CHECK(listed->unlisted == std::vector{ id(23) }); @@ -275,17 +265,17 @@ namespace { INFO("at once"); REQUIRE(listed.has_value()); - REQUIRE(listed->unlisted.empty()); + CHECK(listed->unlisted.empty()); } // Not in sight: no prims, not present, told at once. listed.reset(); index.ensureListed(id(99), [&listed](const Index::Listed& out) { listed = out; }); { - INFO("away"); + INFO("not in sight"); REQUIRE(listed.has_value()); - REQUIRE_FALSE(listed->present); - REQUIRE(listed->prims.empty()); + CHECK_FALSE(listed->present); + CHECK(listed->prims.empty()); } } @@ -319,6 +309,8 @@ namespace CHECK(told == 2); } + // The studio's draw looks once a second, and asks a prim at most every + // few seconds. TEST_CASE_METHOD(alscriptcontentsindex_data, "alscriptcontentsindex: refresh asks a prim again once its serial moved or its copy went", "[alscriptcontentsindex]") { const LLUUID chair = object(40); @@ -328,17 +320,17 @@ namespace answer(chair, { "sit.lsl" }); index.refresh(10.0); UNSCOPED_INFO("unchanged: not asked"); - REQUIRE(pending.empty()); + CHECK(pending.empty()); // A script added from the build tools. serials[chair] = 4; index.refresh(10.5); UNSCOPED_INFO("not looked at again within the second"); - REQUIRE(pending.empty()); + CHECK(pending.empty()); index.refresh(11.0); { INFO("its serial moved: asked"); - REQUIRE(pending.size() == 1); + CHECK(pending.size() == 1); CHECK(asked.back().first == chair); } answer(chair, { "sit.lsl", "new.lsl" }); @@ -346,28 +338,28 @@ namespace CHECK(names(chair) == std::string("sit.lsl new.lsl")); index.refresh(12.0); UNSCOPED_INFO("heard at its serial: not asked"); - REQUIRE(pending.empty()); + CHECK(pending.empty()); // Its object's copy let go of, and no answer coming. current.erase(chair); index.refresh(13.0); UNSCOPED_INFO("not asked again so soon"); - REQUIRE(pending.empty()); + CHECK(pending.empty()); index.refresh(16.0); UNSCOPED_INFO("asked"); - REQUIRE(pending.size() == 1); + CHECK(pending.size() == 1); index.refresh(17.0); UNSCOPED_INFO("not while it is asked"); - REQUIRE(pending.size() == 1); + CHECK(pending.size() == 1); answer(chair, {}, false); UNSCOPED_INFO("no answer keeps what was known"); CHECK(names(chair) == std::string("sit.lsl new.lsl")); index.refresh(18.0); UNSCOPED_INFO("not asked again at once"); - REQUIRE(pending.empty()); + CHECK(pending.empty()); index.refresh(21.0); UNSCOPED_INFO("asked again a while after"); - REQUIRE(pending.size() == 1); + CHECK(pending.size() == 1); answer(chair, { "sit.lsl" }); // Asked for directly, a prim that changed is asked though known. diff --git a/indra/newview/tests/alscriptcrumbsbar_test.cpp b/indra/newview/tests/alscriptcrumbsbar_test.cpp index 3ec537a038..9c71cd0680 100644 --- a/indra/newview/tests/alscriptcrumbsbar_test.cpp +++ b/indra/newview/tests/alscriptcrumbsbar_test.cpp @@ -251,7 +251,6 @@ namespace doc.editor->setCaret(ALTextPos(3, 5)); place(crumbs, doc); const std::string top = "Script a [default, f, g, h, other]"; - UNSCOPED_INFO("the path"); CHECK(path() == top + ", default [default, f, g, h, other], state_entry [state_entry, touch_start]"); UNSCOPED_INFO("kept"); REQUIRE(doc.caret->crumbPath.size() == size_t(2)); @@ -265,8 +264,7 @@ namespace doc.editor->setCaret(ALTextPos(4, 0)); place(crumbs, doc); - UNSCOPED_INFO("the trailer is"); - REQUIRE(trailer().find("Ln 5, Col 1") != std::string::npos); + CHECK(trailer().find("Ln 5, Col 1") != std::string::npos); doc.editor->setCaret(ALTextPos(11, 0)); place(crumbs, doc); UNSCOPED_INFO("in f"); @@ -278,7 +276,7 @@ namespace doc.editor->setCaret(ALTextPos(4, 5)); place(crumbs, doc); UNSCOPED_INFO("at a symbol's very end: still in it"); - REQUIRE(path().find("state_entry [") != std::string::npos); + CHECK(path().find("state_entry [") != std::string::npos); doc.editor->setCaret(ALTextPos(13, 5)); place(crumbs, doc); UNSCOPED_INFO("where two meet: the later"); @@ -300,8 +298,8 @@ namespace crumbs->forget(); { INFO("forgotten"); - REQUIRE(jump()->path().empty()); - REQUIRE(jump()->trailer().empty()); + CHECK(jump()->path().empty()); + CHECK(jump()->trailer().empty()); } place(crumbs, doc); UNSCOPED_INFO("and shown again whatever"); @@ -364,12 +362,12 @@ namespace doc.editor->setSelection(ALTextRange(ALTextPos(2, 0), ALTextPos(4, 2))); crumbs->showTrailer(doc); UNSCOPED_INFO("a line begun counts"); - REQUIRE(part("3 lines") != nullptr); + CHECK(part("3 lines") != nullptr); doc.editor->setText("a\tb\xC3\xA9\n"); doc.editor->setSelection(ALTextRange(ALTextPos(0, 0), ALTextPos(0, 5))); crumbs->showTrailer(doc); UNSCOPED_INFO("characters, a tab one and an accented one one"); - REQUIRE(part("4 characters selected") != nullptr); + CHECK(part("4 characters selected") != nullptr); doc.editor->setCaret(ALTextPos(0, 2)); crumbs->showTrailer(doc); UNSCOPED_INFO("the column as seen, past the tab"); @@ -379,8 +377,8 @@ namespace crumbs->showTrailer(doc); { INFO("not loaded: not said read only, nor how it is indented"); - REQUIRE(part("Read") == nullptr); - REQUIRE(part("Tab") == nullptr); + CHECK(part("Read") == nullptr); + CHECK(part("Tab") == nullptr); } } @@ -400,17 +398,17 @@ namespace { INFO("weighed"); REQUIRE(weighed); - REQUIRE(weighed->text == "LSL (Mono) 40.0 of 64 KB used"); - REQUIRE_FALSE(weighed->color); + CHECK(weighed->text == "LSL (Mono) 40.0 of 64 KB used"); + CHECK_FALSE(weighed->color); } UNSCOPED_INFO("before the optimizer"); - REQUIRE(weighed->toolTip.find("Measured before the preprocessor") != std::string::npos); + CHECK(weighed->toolTip.find("Measured before the preprocessor") != std::string::npos); doc.weighing->exact = true; doc.weighing->sent = true; doc.weighing->weight->total = 60000; crumbs->showTrailer(doc); UNSCOPED_INFO("as sent"); - REQUIRE(part("LSL (Mono)")->toolTip.find("as it is saved") != std::string::npos); + CHECK(part("LSL (Mono)")->toolTip.find("as it is saved") != std::string::npos); UNSCOPED_INFO("near: the warning's"); CHECK(part("LSL (Mono)")->color == warn); doc.weighing->weight->total = 70000; @@ -420,22 +418,22 @@ namespace doc.weighing->weight->estimate = true; crumbs->showTrailer(doc); UNSCOPED_INFO("an estimate"); - REQUIRE(part("LSL (Mono) ~") != nullptr); + CHECK(part("LSL (Mono) ~") != nullptr); doc.weighing->weight.reset(); const size_t LIMIT = ALScriptEnvelope::MAX_ASSET_BYTES; doc.weighing->assetBytes = LIMIT / 2; crumbs->showTrailer(doc); UNSCOPED_INFO("half: nothing"); - REQUIRE(parts().size() == 2); + CHECK(parts().size() == 2); doc.weighing->assetBytes = LIMIT / 2 + 1; crumbs->showTrailer(doc); UNSCOPED_INFO("past half"); REQUIRE(part(std::to_string((LIMIT / 2 + 1 + 1023) / 1024) + " KB") != nullptr); { INFO("said"); - REQUIRE(parts().back().toolTip.find("Save size") != std::string::npos); - REQUIRE_FALSE(parts().back().color); + CHECK(parts().back().toolTip.find("Save size") != std::string::npos); + CHECK_FALSE(parts().back().color); } doc.weighing->assetBytes = LIMIT * 9 / 10 + 1; crumbs->showTrailer(doc); @@ -446,12 +444,12 @@ namespace UNSCOPED_INFO("over: the error's"); CHECK(parts().back().color == error); UNSCOPED_INFO("and by how much"); - REQUIRE(parts().back().toolTip.find("1 over the") != std::string::npos); + CHECK(parts().back().toolTip.find("1 over the") != std::string::npos); doc.notecard = true; doc.weighing->assetBytes = static_cast(LLNotecard::MAX_SIZE) / 2 + 1; crumbs->showTrailer(doc); UNSCOPED_INFO("a notecard's by its own limit"); - REQUIRE(parts().back().toolTip.find("Notecard text") != std::string::npos); + CHECK(parts().back().toolTip.find("Notecard text") != std::string::npos); doc.notecard = false; doc.weighing->assetBytes = 0; @@ -474,7 +472,7 @@ namespace CHECK(parts().back().toolTip == "expanded tip"); } UNSCOPED_INFO("its own caret"); - REQUIRE(part("Ln 1, Col 4") != nullptr); + CHECK(part("Ln 1, Col 4") != nullptr); } TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: the optimizer's sizes replace the weight while the expansion is in front", "[alscriptcrumbsbar]") @@ -498,7 +496,7 @@ namespace UNSCOPED_INFO("before and after"); CHECK(part("LSL (Mono)")->text == std::string("LSL (Mono) ~20.0 \xE2\x86\x92 ~10.0 of 64 KB used")); UNSCOPED_INFO("once"); - REQUIRE(parts().size() == size_t(4)); + CHECK(parts().size() == size_t(4)); doc.uploaded.codeAfter = 60000; crumbs->showTrailer(doc); UNSCOPED_INFO("near: the warning's"); @@ -512,18 +510,18 @@ namespace { INFO("measured, not estimated"); REQUIRE(part("LSL (LSO)")); - REQUIRE(part("LSL (LSO)")->text.find('~') == std::string::npos); + CHECK(part("LSL (LSO)")->text.find('~') == std::string::npos); } doc.editor->insertText("x"); crumbs->showTrailer(doc); UNSCOPED_INFO("typed since: its weight"); - REQUIRE(part("LSL (Mono) 40.0") != nullptr); + CHECK(part("LSL (Mono) 40.0") != nullptr); doc.view = Doc::View::Source; doc.uploaded.version = doc.editor->document().version(); told().target = ALScriptWeight::Target::Mono; crumbs->showTrailer(doc); UNSCOPED_INFO("the source in front: its weight"); - REQUIRE(part("LSL (Mono) 40.0") != nullptr); + CHECK(part("LSL (Mono) 40.0") != nullptr); } TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: a chosen step goes to the top or a symbol's name or nowhere if gone", "[alscriptcrumbsbar]") @@ -535,7 +533,6 @@ namespace crumbs->choose("9\ngone"); doc.outline.erase(doc.outline.begin()); crumbs->choose("1\ntouch_start"); - UNSCOPED_INFO("each"); CHECK(joined(told().chosen) == std::string("a 0:0-0:0, a 2:4-2:15, a nowhere, a 5:4-5:15")); } @@ -550,11 +547,11 @@ namespace CHECK(part("Tab Size")->value == "indent"); } UNSCOPED_INFO("the default's tip"); - REQUIRE(part("Tab Size")->toolTip.find("Default indentation from Preferences") != std::string::npos); + CHECK(part("Tab Size")->toolTip.find("Default indentation from Preferences") != std::string::npos); { INFO("checked as it is"); - REQUIRE(crumbs->indentChecked("tabs")); - REQUIRE(crumbs->indentChecked("width_4")); + CHECK(crumbs->indentChecked("tabs")); + CHECK(crumbs->indentChecked("width_4")); CHECK_FALSE(crumbs->indentChecked("spaces")); } UNSCOPED_INFO("nothing chosen to forget"); @@ -565,18 +562,18 @@ namespace { INFO("read from the script"); REQUIRE(part("Spaces: 2")); - REQUIRE(part("Spaces")->toolTip.find("detected from this script's lines") != std::string::npos); + CHECK(part("Spaces")->toolTip.find("detected from this script's lines") != std::string::npos); } crumbs->indentAct("width_4"); { INFO("a width chosen"); REQUIRE(part("Spaces: 4")); - REQUIRE(part("Spaces")->toolTip.find("set for this script") != std::string::npos); + CHECK(part("Spaces")->toolTip.find("set for this script") != std::string::npos); } { INFO("and checked"); - REQUIRE(crumbs->indentChecked("width_4")); + CHECK(crumbs->indentChecked("width_4")); CHECK_FALSE(crumbs->indentChecked("width_2")); } UNSCOPED_INFO("the text untouched"); @@ -584,20 +581,20 @@ namespace crumbs->indentAct("tabs"); { INFO("tabs chosen"); - REQUIRE(part("Tab Size: 4") != nullptr); + CHECK(part("Tab Size: 4") != nullptr); CHECK(crumbs->indentChecked("tabs")); } UNSCOPED_INFO("to be forgotten"); CHECK(crumbs->indentEnabled("read")); crumbs->indentAct("read"); UNSCOPED_INFO("the script's own again"); - REQUIRE(part("Spaces: 2") != nullptr); + CHECK(part("Spaces: 2") != nullptr); crumbs->indentAct("convert_tabs"); UNSCOPED_INFO("converted, a tab of the width"); CHECK(doc.editor->text() == std::string("a\n\tb\n")); UNSCOPED_INFO("and tabs from here on"); - REQUIRE(part("Tab Size: 2") != nullptr); + CHECK(part("Tab Size: 2") != nullptr); doc.modifiable = false; UNSCOPED_INFO("not a script that may only be read"); CHECK_FALSE(crumbs->indentEnabled("convert_spaces")); @@ -617,7 +614,7 @@ namespace doc.check->askedAt = now; crumbs->showTrailer(doc); UNSCOPED_INFO("just asked: nothing"); - REQUIRE(part("Checking") == nullptr); + CHECK(part("Checking") == nullptr); doc.check->askedAt = now - 1.0; crumbs->showTrailer(doc); const Part* checking = part("Checking"); @@ -629,7 +626,7 @@ namespace doc.check->analysisVersion = doc.check->requestedVersion; crumbs->showTrailer(doc); UNSCOPED_INFO("answered: gone"); - REQUIRE(part("Checking") == nullptr); + CHECK(part("Checking") == nullptr); } TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: only what changed is said again so a caret move says just its place", "[alscriptcrumbsbar]") @@ -666,7 +663,7 @@ namespace { INFO("indented otherwise"); CHECK(said > 2); - REQUIRE(part("Tab Size: 2") != nullptr); + CHECK(part("Tab Size: 2") != nullptr); } said = 0; crumbs->setTips({ "line", "problems", "source", "expanded" }); @@ -682,8 +679,8 @@ namespace { INFO("another tab: its own"); CHECK(said > 2); - REQUIRE(part("3 errors") != nullptr); - REQUIRE(part("Tab Size: 4") != nullptr); + CHECK(part("3 errors") != nullptr); + CHECK(part("Tab Size: 4") != nullptr); } } @@ -693,20 +690,20 @@ namespace Doc& doc = tab("a"); crumbs->showTrailer(doc); UNSCOPED_INFO("none: not said"); - REQUIRE(trailer().find("left from LSL") == std::string::npos); + CHECK(trailer().find("left from LSL") == std::string::npos); doc.shownMigration = 3; crumbs->showTrailer(doc); const Part* left = part("3 left from LSL"); { INFO("counted"); REQUIRE(left != nullptr); - REQUIRE(left->value == "migration"); - REQUIRE_FALSE(left->toolTip.empty()); + CHECK(left->value == "migration"); + CHECK_FALSE(left->toolTip.empty()); } doc.shownMigration = 1; crumbs->showTrailer(doc); UNSCOPED_INFO("counted again"); - REQUIRE(part("1 left from LSL") != nullptr); + CHECK(part("1 left from LSL") != nullptr); } TEST_CASE_METHOD(alscriptcrumbsbar_data, "alscriptcrumbsbar: the view's tip says why a save preprocesses and warns where it will not", "[alscriptcrumbsbar]") @@ -718,19 +715,19 @@ namespace told().wanted = ALPreprocessor::Wanted::Directives; crumbs->showTrailer(doc); UNSCOPED_INFO("not warned where a save preprocesses it"); - REQUIRE(part("Not preprocessed on save") == nullptr); + CHECK(part("Not preprocessed on save") == nullptr); const Part* view = part("Preprocessed"); { INFO("why, on the view's tip: " + (view ? view->toolTip : std::string())); REQUIRE(view); - REQUIRE(view->toolTip.find("it has directives") != std::string::npos); + CHECK(view->toolTip.find("it has directives") != std::string::npos); } told().wanted = ALPreprocessor::Wanted::Enveloped; crumbs->showTrailer(doc); { INFO("saved with it before"); REQUIRE(part("Preprocessed")); - REQUIRE(part("Preprocessed")->toolTip.find("saved with the preprocessor before") != std::string::npos); + CHECK(part("Preprocessed")->toolTip.find("saved with the preprocessor before") != std::string::npos); } told().wanted = ALPreprocessor::Wanted::No; crumbs->showTrailer(doc); @@ -738,13 +735,13 @@ namespace { INFO("said where a save sends it as written"); REQUIRE(warned); - REQUIRE(warned->color == doc.editor->markColor(ALCodeEditor::Mark::Warning)); - REQUIRE(warned->toolTip.find("as written") != std::string::npos); + CHECK(warned->color == doc.editor->markColor(ALCodeEditor::Mark::Warning)); + CHECK(warned->toolTip.find("as written") != std::string::npos); } doc.expandedEditor = nullptr; doc.view = Doc::View::Source; crumbs->showTrailer(doc); UNSCOPED_INFO("nothing said with no preprocessed view"); - REQUIRE(part("Not preprocessed on save") == nullptr); + CHECK(part("Not preprocessed on save") == nullptr); } } diff --git a/indra/newview/tests/alscriptexplorermodel_test.cpp b/indra/newview/tests/alscriptexplorermodel_test.cpp index ed26f15609..207b7cced7 100644 --- a/indra/newview/tests/alscriptexplorermodel_test.cpp +++ b/indra/newview/tests/alscriptexplorermodel_test.cpp @@ -230,13 +230,10 @@ namespace { INFO("an object by a prim of it, listed by its root"); CHECK(model.objects().back().root == table); - REQUIRE(model.objects().back().prims.size() == 3); - } - { - INFO("listed prims"); - CHECK(model.listed(id(22))); - CHECK_FALSE(model.listed(id(90))); + CHECK(model.objects().back().prims.size() == 3); } + CHECK(model.listed(id(22))); + CHECK_FALSE(model.listed(id(90))); { INFO("what coming or going concerns: a listed prim, a pin away"); CHECK(model.concerns(id(22))); @@ -260,7 +257,6 @@ namespace UNSCOPED_INFO("what a prim holds not known yet, a folder of it may still be opened"); CHECK_FALSE(model.rows(std::string()).front().known); holds(chair, { "sit.lsl", "readme" }); - UNSCOPED_INFO("known"); CHECK(model.rows(std::string()).front().known); CHECK(rows() == std::string("O:Chair I:sit.lsl I:readme")); list(); @@ -284,13 +280,13 @@ namespace holds(id(12), {}); holds(id(13), {}); UNSCOPED_INFO("the root, empty, stays first; the two others holding nothing go under one row, folded; one not answered stays"); - CHECK(rows() == + REQUIRE(rows() == std::string("O:House P:House P:House.1 I:door.lsl P:House.4 E:2+ P:House.2 P:House.3")); const std::vector all = model.rows(std::string()); const Model::Row& group = all[all.size() - 3]; { INFO("the row of them is of no prim to act on or drop into"); - REQUIRE_FALSE(Model::Choice::of(group.value)); + CHECK_FALSE(Model::Choice::of(group.value)); CHECK(Model::primOf(group.value).isNull()); } UNSCOPED_INFO("opened, it asks only to be filled again"); @@ -331,7 +327,6 @@ namespace UNSCOPED_INFO("an object by its name, with every prim, the empty ones by name"); CHECK(rows("house") == std::string("O:House P:House I:main.lsl P:House.1 I:door.lsl I:notes P:House.2 P:House.3")); - UNSCOPED_INFO("nothing"); CHECK(rows("zzz") == std::string()); } @@ -350,26 +345,23 @@ namespace { INFO("a folded prim is listed, folded, what it holds not known"); REQUIRE(one); - REQUIRE(one->folded); + CHECK(one->folded); CHECK_FALSE(one->known); } UNSCOPED_INFO("the linkset's own row is known: its prims are"); CHECK(all.front().known); - { - INFO("which"); - CHECK(asked[0] == id(100)); - CHECK(asked[1] == id(105)); - } + CHECK(asked[0] == id(100)); + CHECK(asked[1] == id(105)); UNSCOPED_INFO("asked, not again until answered"); - REQUIRE(ask(false, false).empty()); + CHECK(ask(false, false).empty()); UNSCOPED_INFO("a filter looks through the rest"); - REQUIRE(ask(false, true).size() == count - 2); + CHECK(ask(false, true).size() == count - 2); UNSCOPED_INFO("a refetch asks them all again"); - REQUIRE(ask(true, true).size() == count); + CHECK(ask(true, true).size() == count); holds(id(100), { "core.lsl" }); UNSCOPED_INFO("answered and current: not asked"); - REQUIRE(ask(false, false).empty()); + CHECK(ask(false, false).empty()); stale.insert(id(100)); std::vector again = ask(false, false); { @@ -403,7 +395,7 @@ namespace { INFO("not listed yet, nothing opens"); CHECK(heard.listed); - REQUIRE(heard.opening.empty()); + CHECK(heard.opening.empty()); } UNSCOPED_INFO("the script asked whether it runs"); CHECK(askedRunning == std::vector{ ALScriptRef(chair, id(500)) }); @@ -422,18 +414,18 @@ namespace CHECK(askedRunning[1].item == id(501)); } heard = feed(contents); - UNSCOPED_INFO("once"); - REQUIRE(heard.opening.empty()); + UNSCOPED_INFO("opened once only"); + CHECK(heard.opening.empty()); UNSCOPED_INFO("a prim not listed is no answer"); CHECK_FALSE(model.contents(ALScriptContents{ id(77) }).listed); { INFO("what runs, known"); CHECK(model.knownRunning(ALScriptRef(chair, id(500))) == std::optional(true)); - REQUIRE_FALSE(model.knownRunning(ALScriptRef(chair, id(501)))); + CHECK_FALSE(model.knownRunning(ALScriptRef(chair, id(501)))); } model.forgetRunning(); UNSCOPED_INFO("let go of for the listed prims, to be asked again"); - REQUIRE_FALSE(model.knownRunning(ALScriptRef(chair, id(500)))); + CHECK_FALSE(model.knownRunning(ALScriptRef(chair, id(500)))); } TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: chosen rows reach their prims and scripts and count each script once", "[alscriptexplorermodel]") @@ -453,7 +445,7 @@ namespace CHECK(whole.prim == house); } UNSCOPED_INFO("every prim of it"); - REQUIRE(model.containerPrims({ whole }).size() == size_t(3)); + CHECK(model.containerPrims({ whole }).size() == size_t(3)); UNSCOPED_INFO("each script once"); CHECK(model.scriptsReached({ whole }) == 3); @@ -535,11 +527,8 @@ namespace holds(id(10), { "a.lsl" }); holds(id(11), { "b.lsl" }); holds(chair, {}); - { - INFO("folded"); - CHECK(model.fold(house, false) == Model::Refold::Refill); - CHECK(model.folded(house)); - } + CHECK(model.fold(house, false) == Model::Refold::Refill); + CHECK(model.folded(house)); CHECK(rows() == std::string("O:House+ P:House I:a.lsl P:House.1 I:b.lsl O:Chair")); { INFO("a prim revealed unfolds what holds it, and was asked what it holds"); @@ -557,14 +546,14 @@ namespace model.pin({ *Model::Choice::of(all[0].value), *Model::Choice::of(rowNamed(all, "b.lsl")->value), *Model::Choice::of(rowNamed(all, "Chair")->value) }); { INFO("both pinned, each once"); - REQUIRE(model.pins().size() == 2); + CHECK(model.pins().size() == 2); CHECK(model.isPinned(house)); CHECK(model.isPinned(chair)); } model.pin({ *Model::Choice::of(rowNamed(all, "Chair")->value) }); { INFO("let go"); - REQUIRE(model.pins().size() == 1); + CHECK(model.pins().size() == 1); CHECK_FALSE(model.isPinned(chair)); } } @@ -575,11 +564,11 @@ namespace selected = { house }; list(); UNSCOPED_INFO("both asked first"); - REQUIRE(ask(false, false).size() == size_t(2)); + CHECK(ask(false, false).size() == size_t(2)); holds(id(10), { "a.lsl" }); holds(id(11), {}); UNSCOPED_INFO("known and current: nothing asked"); - REQUIRE(ask(false, false).empty()); + CHECK(ask(false, false).empty()); model.askRegion(id(11)); UNSCOPED_INFO("the one dropped into, though its object says current"); CHECK(ask(false, false) == std::vector({ id(11) })); @@ -596,7 +585,7 @@ namespace model.doneAskingRegion(); { INFO("let go of: as any other"); - REQUIRE(ask(false, false).empty()); + CHECK(ask(false, false).empty()); CHECK_FALSE(model.asksRegion(id(11))); } } @@ -637,14 +626,11 @@ namespace CHECK(model.fold(id(205), true, false) == Model::Refold::None); model.renamed(id(203), "Middle"); UNSCOPED_INFO("renamed in place"); - REQUIRE(rowNamed(model.rows(std::string()), "Middle") != nullptr); + CHECK(rowNamed(model.rows(std::string()), "Middle") != nullptr); UNSCOPED_INFO("named by its root"); CHECK(model.nameOf(big) == std::string("Big")); - { - INFO("present"); - CHECK(model.present(big)); - CHECK_FALSE(model.present(id(203))); - } + CHECK(model.present(big)); + CHECK_FALSE(model.present(id(203))); } TEST_CASE_METHOD(alscriptexplorermodel_data, "alscriptexplorermodel: link numbers and the permissions of items and prims", "[alscriptexplorermodel]") @@ -671,7 +657,7 @@ namespace { INFO("the second prim is link 2"); REQUIRE(hinge); - REQUIRE(hinge->kind == Model::Row::Kind::Prim); + CHECK(hinge->kind == Model::Row::Kind::Prim); CHECK(hinge->link == 2); } const Model::Row* latch = rowNamed(all, "House.2"); @@ -688,7 +674,7 @@ namespace { INFO("no modify, no copy"); REQUIRE(item); - REQUIRE(item->noModify); + CHECK(item->noModify); CHECK(item->noCopy); } { @@ -721,7 +707,7 @@ namespace INFO("pinned with its place"); REQUIRE(pin); REQUIRE(pin->position); - REQUIRE(pin->position->mdV[VZ] == 30.0); + CHECK(pin->position->mdV[VZ] == 30.0); CHECK(pin->region == "Ahern"); } @@ -730,7 +716,7 @@ namespace list(); { INFO("a step is no new place"); - REQUIRE_FALSE(model.takePinsChanged()); + CHECK_FALSE(model.takePinsChanged()); CHECK(model.pinOf(house)->position->mdV[VX] == 256010.0); } world[house].position = LLVector3d(256000.0 + 100.0, 256000.0 + 20.0, 30.0); @@ -738,7 +724,7 @@ namespace list(); { INFO("far, and elsewhere: kept, and said"); - REQUIRE(model.takePinsChanged()); + CHECK(model.takePinsChanged()); CHECK(model.pinOf(house)->region == "Morris"); } @@ -750,7 +736,7 @@ namespace { INFO("read back"); REQUIRE(again.pinOf(house)); - REQUIRE(again.pinOf(house)->position); + CHECK(again.pinOf(house)->position); CHECK(again.pinOf(house)->region == "Morris"); } world.clear(); @@ -815,19 +801,19 @@ namespace { INFO("two scripts, in their order"); REQUIRE(pair); - REQUIRE(pair->first.ref() == here.ref()); + CHECK(pair->first.ref() == here.ref()); CHECK(pair->second.ref() == there.ref()); } UNSCOPED_INFO("not a script and a notecard"); - REQUIRE_FALSE(Model::comparing({ here, notes })); + CHECK_FALSE(Model::comparing({ here, notes })); UNSCOPED_INFO("not one"); - REQUIRE_FALSE(Model::comparing({ here })); + CHECK_FALSE(Model::comparing({ here })); UNSCOPED_INFO("not three"); - REQUIRE_FALSE(Model::comparing({ here, there, blink })); + CHECK_FALSE(Model::comparing({ here, there, blink })); UNSCOPED_INFO("not a prim"); - REQUIRE_FALSE(Model::comparing({ here, prim })); + CHECK_FALSE(Model::comparing({ here, prim })); UNSCOPED_INFO("not the same twice"); - REQUIRE_FALSE(Model::comparing({ here, here })); + CHECK_FALSE(Model::comparing({ here, here })); const std::vector others = model.comparableWith(here); std::string said; @@ -839,9 +825,9 @@ namespace CHECK(said == "Door" + std::string(Model::PLACE_SEPARATOR) + "Door.1/open.lsl Lamp/open.lsl Lamp/blink.lsl"); UNSCOPED_INFO("a notecard's are notecards"); - REQUIRE(model.comparableWith(notes).size() == 1U); + CHECK(model.comparableWith(notes).size() == 1U); UNSCOPED_INFO("a prim compares with nothing"); - REQUIRE(model.comparableWith(prim).empty()); + CHECK(model.comparableWith(prim).empty()); UNSCOPED_INFO("a root's place is its object"); CHECK(model.placeOf(here) == std::string("Door")); UNSCOPED_INFO("a child's has its prim"); diff --git a/indra/newview/tests/alscriptexplorertree_test.cpp b/indra/newview/tests/alscriptexplorertree_test.cpp index 3abfe22fc4..48a91b4445 100644 --- a/indra/newview/tests/alscriptexplorertree_test.cpp +++ b/indra/newview/tests/alscriptexplorertree_test.cpp @@ -230,11 +230,8 @@ namespace holds(id(12), {}); holds(chair, { "sit.lsl" }); show(); - { - INFO("chosen"); - CHECK(t.choose(itemRow("a.lsl"), false)); - REQUIRE(t.chosen().size() == 1); - } + CHECK(t.choose(itemRow("a.lsl"), false)); + REQUIRE(t.chosen().size() == 1); state = "stopped"; show(); { @@ -319,7 +316,6 @@ namespace show(); UNSCOPED_INFO("folded as the rows say"); CHECK_FALSE(t.isOpen(primRow(house, id(11)))); - UNSCOPED_INFO("chosen"); CHECK(t.choose(itemRow("b.lsl"), false)); UNSCOPED_INFO("what holds it opened"); CHECK(t.isOpen(primRow(house, id(11)))); @@ -335,7 +331,6 @@ namespace REQUIRE(t.chosen().size() == 1); } t.chooseNone(); - UNSCOPED_INFO("none"); REQUIRE(t.chosen().empty()); } @@ -386,7 +381,6 @@ namespace t.setHooks(std::move(hooks)); // The folder view drags only from a row that says it may move; the // press and the move themselves want a window this has none of. - UNSCOPED_INFO("chosen"); CHECK(t.choose(itemRow("a.lsl"), false)); LLFolderViewItem* item = t.folderView()->getCurSelectedItem(); { @@ -399,7 +393,6 @@ namespace CHECK(t.folderView()->startDrag()); CHECK(drags == 1); } - UNSCOPED_INFO("chosen"); CHECK(t.choose(objectRow(house), false)); UNSCOPED_INFO("an object may not"); CHECK_FALSE(t.folderView()->getCurSelectedItem()->isMovable()); diff --git a/indra/newview/tests/alscriptexternaleditor_test.cpp b/indra/newview/tests/alscriptexternaleditor_test.cpp index ef5da3a5df..5803af8385 100644 --- a/indra/newview/tests/alscriptexternaleditor_test.cpp +++ b/indra/newview/tests/alscriptexternaleditor_test.cpp @@ -175,24 +175,13 @@ namespace Doc& a = tab("a", "default {}"); unit.edit(a); const std::string file = unit.fileName(a); - UNSCOPED_INFO("the copy"); CHECK(contents(file) == std::string("default {}")); - { - INFO("watched"); - REQUIRE(a.watch); - CHECK(a.watch->path() == file); - } - { - INFO("the log beside it"); - REQUIRE(a.external->log); - CHECK(a.external->log->path() == file + ".log"); - } - { - INFO("the bridge told"); - CHECK(studio.subscribed == Names{ "a" }); - CHECK(a.external->subscribed); - } - UNSCOPED_INFO("the editor started on it"); + REQUIRE(a.watch); + CHECK(a.watch->path() == file); + REQUIRE(a.external->log); + CHECK(a.external->log->path() == file + ".log"); + CHECK(studio.subscribed == Names{ "a" }); + CHECK(a.external->subscribed); CHECK(studio.started == Names{ file }); UNSCOPED_INFO("what it holds, known"); CHECK(a.external->written == std::string("default {}")); @@ -213,8 +202,8 @@ namespace } { INFO("with no log, and nothing for the bridge"); - REQUIRE_FALSE(d.external->log); - REQUIRE(studio.subscribed.size() == 2); + CHECK_FALSE(d.external->log); + CHECK(studio.subscribed.size() == 2); } Doc& n = tab("n", "x"); @@ -222,8 +211,8 @@ namespace unit.edit(n); { INFO("a notecard not"); - REQUIRE(studio.started.size() == 3); - REQUIRE_FALSE(n.watch); + CHECK(studio.started.size() == 3); + CHECK_FALSE(n.watch); } } @@ -234,11 +223,8 @@ namespace unit.edit(a); write(unit.fileName(a), "two"); unit.changed("a", unit.fileName(a)); - { - INFO("taken"); - CHECK(studio.taken == Names{ "two" }); - CHECK(a.editor->text() == "two"); - } + CHECK(studio.taken == Names{ "two" }); + CHECK(a.editor->text() == "two"); { INFO("saved from here, as the editor's"); CHECK(studio.saved == Names{ "a" }); @@ -246,18 +232,17 @@ namespace } UNSCOPED_INFO("what the copy holds, known"); CHECK(a.external->written == std::string("two")); - UNSCOPED_INFO("nothing asked"); CHECK_FALSE(asked()); a.editor->resetDirty(); unit.changed("a", unit.fileName(a)); { INFO("the same again, with the tab saved: nothing to take or save"); - REQUIRE(studio.taken.size() == 1); - REQUIRE(studio.saved.size() == 1); + CHECK(studio.taken.size() == 1); + CHECK(studio.saved.size() == 1); } unit.changed("nobody", unit.fileName(a)); UNSCOPED_INFO("a tab gone: nothing"); - REQUIRE(studio.taken.size() == 1); + CHECK(studio.taken.size() == 1); } TEST_CASE_METHOD(alscriptexternaleditor_data, "alscriptexternaleditor: a save outside over changes here is held until the author takes it", "[alscriptexternaleditor]") @@ -269,27 +254,18 @@ namespace a.editor->insertText(" here"); write(unit.fileName(a), "two"); unit.changed("a", unit.fileName(a)); - { - INFO("not taken"); - REQUIRE(studio.taken.empty()); - CHECK(a.editor->text() == "one here"); - } - { - INFO("held"); - REQUIRE(a.external->waiting); - CHECK(*a.external->waiting == "two"); - } - { - INFO("and asked about"); - CHECK(asked()); - CHECK(services.reports.back().failure); - CHECK(services.reports.back().doc == "a"); - } + CHECK(studio.taken.empty()); + CHECK(a.editor->text() == "one here"); + REQUIRE(a.external->waiting); + CHECK(*a.external->waiting == "two"); + REQUIRE(asked()); + CHECK(services.reports.back().failure); + CHECK(services.reports.back().doc == "a"); unit.take(a, *a.external->waiting); { INFO("taken once said"); CHECK(studio.taken == Names{ "two" }); - REQUIRE_FALSE(a.external->waiting); + CHECK_FALSE(a.external->waiting); CHECK(studio.saved == Names{ "a" }); } } @@ -305,11 +281,8 @@ namespace CHECK(studio.taken == Names{ "a\nb" }); write(unit.fileName(a), "a\r\nb\r\nc"); unit.changed("a", unit.fileName(a)); - { - INFO("the second taken too"); - CHECK(studio.taken == Names{ "a\nb", "a\nb\nc" }); - CHECK_FALSE(asked()); - } + CHECK(studio.taken == Names{ "a\nb", "a\nb\nc" }); + CHECK_FALSE(asked()); } TEST_CASE_METHOD(alscriptexternaleditor_data, "alscriptexternaleditor: an emptied copy is taken only if still empty a moment later", "[alscriptexternaleditor]") @@ -320,7 +293,7 @@ namespace write(unit.fileName(a), ""); unit.changed("a", unit.fileName(a)); UNSCOPED_INFO("not taken at once"); - REQUIRE(studio.taken.empty()); + CHECK(studio.taken.empty()); unit.changed("a", unit.fileName(a), true); UNSCOPED_INFO("still empty a moment later: taken"); CHECK(studio.taken == Names{ "" }); @@ -330,7 +303,7 @@ namespace { INFO("the second step heard first: the look after takes nothing more"); CHECK(studio.taken == Names{ "", "two" }); - REQUIRE(studio.saved.size() == 2); + CHECK(studio.saved.size() == 2); } } @@ -342,9 +315,8 @@ namespace a.editor->setCaret(a.editor->document().end()); a.editor->insertText(" two"); unit.sync(a); - UNSCOPED_INFO("written again"); CHECK(contents(unit.fileName(a)) == std::string("one two")); - UNSCOPED_INFO("and known"); + UNSCOPED_INFO("what it holds, known"); CHECK(a.external->written == std::string("one two")); ALScriptCompileResult result; result.messages = { "(1, 2) : ERROR : Syntax error\x07" }; @@ -353,8 +325,8 @@ namespace { INFO("the log: when, then the words, what cannot be printed dropped"); CHECK(log.find("// [when]") == 0); - REQUIRE(log.find("Syntax error\n") != std::string::npos); - REQUIRE(log.find('\x07') == std::string::npos); + CHECK(log.find("Syntax error\n") != std::string::npos); + CHECK(log.find('\x07') == std::string::npos); } Doc& d = tab("d", "x"); d.file = "/somewhere/d.lsl"; @@ -362,8 +334,8 @@ namespace unit.sync(d); { INFO("a tab not held outside: nothing"); - REQUIRE_FALSE(d.external->log); - REQUIRE_FALSE(d.watch); + CHECK_FALSE(d.external->log); + CHECK_FALSE(d.watch); } } @@ -377,28 +349,19 @@ namespace unit.log(a, result); const std::string file = unit.fileName(a); const std::string log = a.external->log->path(); - { - INFO("both there"); - CHECK(exists(file)); - CHECK(exists(log)); - } + CHECK(exists(file)); + CHECK(exists(log)); a.save.fromExternal(1); unit.stop(a); - { - INFO("the bridge told"); - CHECK(studio.unsubscribed == Names{ "a" }); - CHECK_FALSE(a.external->subscribed); - } + CHECK(studio.unsubscribed == Names{ "a" }); + CHECK_FALSE(a.external->subscribed); { INFO("the watch gone, and the studio's copy with it"); - REQUIRE_FALSE(a.watch); + CHECK_FALSE(a.watch); CHECK_FALSE(exists(file)); } - { - INFO("the log gone"); - CHECK_FALSE(exists(log)); - REQUIRE_FALSE(a.external->log); - } + CHECK_FALSE(exists(log)); + CHECK_FALSE(a.external->log); UNSCOPED_INFO("a save under way is no longer the editor's"); CHECK_FALSE(a.save.external()); } @@ -412,22 +375,13 @@ namespace a.editor->insertText(" here"); write(unit.fileName(a), "two"); unit.changed("a", unit.fileName(a)); - { - INFO("held"); - REQUIRE(a.external->waiting); - CHECK(*a.external->waiting == "two"); - } + REQUIRE(a.external->waiting); + CHECK(*a.external->waiting == "two"); unit.keep(a); - { - INFO("let go, the tab's text standing"); - REQUIRE_FALSE(a.external->waiting); - REQUIRE(studio.taken.empty()); - CHECK(a.editor->text() == "one here"); - } - { - INFO("said"); - REQUIRE_FALSE(services.statuses.empty()); - CHECK(services.statuses.back().find("ExternalKept") == 0); - } + CHECK_FALSE(a.external->waiting); + CHECK(studio.taken.empty()); + CHECK(a.editor->text() == "one here"); + REQUIRE_FALSE(services.statuses.empty()); + CHECK(services.statuses.back().find("ExternalKept") == 0); } } diff --git a/indra/newview/tests/alscriptinspectorpane_test.cpp b/indra/newview/tests/alscriptinspectorpane_test.cpp index a968d8fea5..09adf68b36 100644 --- a/indra/newview/tests/alscriptinspectorpane_test.cpp +++ b/indra/newview/tests/alscriptinspectorpane_test.cpp @@ -136,7 +136,6 @@ namespace result.hover.documentation = "How many."; result.hover.link = "https://example.com/count"; inspector->inspected(doc, result, ALTextPos(0, 8)); - UNSCOPED_INFO("said"); CHECK(shown() == std::string("integer count\nDeclared on line 1.\nExpected here: float\n\ninteger\n count\n\nHow many.\n" "https://example.com/count")); @@ -156,7 +155,7 @@ namespace } { INFO("to the line"); - REQUIRE(to->value["line"].asInteger() == 0); + CHECK(to->value["line"].asInteger() == 0); CHECK(to->value["column"].asInteger() == 8); } UNSCOPED_INFO("in the script"); @@ -288,9 +287,8 @@ namespace doc.editor->setDecorations({ squiggle(0, 8, 13, "Unused."), squiggle(0, 0, 13, "Twice."), squiggle(0, 8, 13, ""), squiggle(0, 8, 13, "Lit.", ALCodeEditor::Decoration::Style::Background), squiggle(1, 0, 5, "Elsewhere.") }); - UNSCOPED_INFO("each"); + UNSCOPED_INFO("each squiggle under the caret that says something"); CHECK(inspector->problemsAt(doc, ALTextPos(0, 9)) == std::string("Problem: Unused.\nProblem: Twice.")); - UNSCOPED_INFO("none"); CHECK(inspector->problemsAt(doc, ALTextPos(2, 0)) == std::string()); inspector->inspected(doc, hover("integer count"), ALTextPos(0, 8)); UNSCOPED_INFO("under the name"); diff --git a/indra/newview/tests/alscriptitemdrop_test.cpp b/indra/newview/tests/alscriptitemdrop_test.cpp index 8b063e1b21..bee2fd75d2 100644 --- a/indra/newview/tests/alscriptitemdrop_test.cpp +++ b/indra/newview/tests/alscriptitemdrop_test.cpp @@ -114,8 +114,8 @@ namespace UNSCOPED_INFO("offered"); CHECK(drop(wood, false, MASK_NONE, &tip) == ACCEPT_YES_SINGLE); UNSCOPED_INFO("the tip says what goes in"); - REQUIRE(tip.find("\"Wood \\\"oak\\\"\"") != std::string::npos); - UNSCOPED_INFO("nothing yet"); + CHECK(tip.find("\"Wood \\\"oak\\\"\"") != std::string::npos); + UNSCOPED_INFO("a drag over changes nothing"); CHECK(doc->editor->text() == "x;"); drop(wood, true); UNSCOPED_INFO("in where it lands"); @@ -127,7 +127,7 @@ namespace { INFO("its key not to be seen: refused"); CHECK(drop(wood, false, MASK_SHIFT, &tip) == ACCEPT_NO); - REQUIRE_FALSE(tip.empty()); + CHECK_FALSE(tip.empty()); } shown.generate(); drop(wood, true, MASK_SHIFT); @@ -144,7 +144,7 @@ namespace { INFO("refused, and said why"); CHECK(drop(wood, true, MASK_NONE, &tip) == ACCEPT_NO); - REQUIRE_FALSE(tip.empty()); + CHECK_FALSE(tip.empty()); CHECK(doc->editor->text() == "x;"); } doc->modifiable = true; diff --git a/indra/newview/tests/alscriptjobqueue_test.cpp b/indra/newview/tests/alscriptjobqueue_test.cpp index fc0dc478cc..7126db4174 100644 --- a/indra/newview/tests/alscriptjobqueue_test.cpp +++ b/indra/newview/tests/alscriptjobqueue_test.cpp @@ -59,7 +59,6 @@ namespace CHECK(queue.waiting() == size_t(5)); UNSCOPED_INFO("by rank, then by when"); CHECK(drained() == std::string("front-hover front-check-2 front-weigh back-check-1 other-check")); - UNSCOPED_INFO("nothing passed over"); CHECK(queue.passedOver() == size_t(0)); } @@ -87,7 +86,6 @@ namespace TEST_CASE_METHOD(alscriptjobqueue_data, "alscriptjobqueue: the running job is superseded only by its own key or a newer text", "[alscriptjobqueue]") { queue.add("a/check", "a", 3, 1, "check-3"); - UNSCOPED_INFO("taken"); REQUIRE(queue.take().has_value()); UNSCOPED_INFO("nothing asked since"); CHECK_FALSE(queue.superseded()); @@ -101,7 +99,6 @@ namespace CHECK_FALSE(queue.superseded()); UNSCOPED_INFO("its own key asked again stops it"); CHECK(queue.add("a/check", "a", 3, 1, "check-3-again")); - UNSCOPED_INFO("unwanted"); CHECK(queue.superseded()); UNSCOPED_INFO("said once"); CHECK_FALSE(queue.add("a/check", "a", 4, 1, "check-4")); @@ -109,7 +106,6 @@ namespace UNSCOPED_INFO("done with"); CHECK_FALSE(queue.superseded()); queue.add("x/hover", "x", 1, 0, "x-hover"); - UNSCOPED_INFO("taken"); REQUIRE(queue.take().has_value()); UNSCOPED_INFO("a newer text of its script stops it"); CHECK(queue.add("x/check", "x", 2, 1, "x-check")); @@ -119,13 +115,11 @@ namespace TEST_CASE_METHOD(alscriptjobqueue_data, "alscriptjobqueue: a yielding job stops for a rank 0 question and runs after it", "[alscriptjobqueue]") { queue.add("back/check", "back", 1, 4, "back-check", true); - UNSCOPED_INFO("taken"); REQUIRE(queue.take().has_value()); UNSCOPED_INFO("a check of the front tab leaves it be"); CHECK_FALSE(queue.add("front/check", "front", 1, 1, "front-check")); UNSCOPED_INFO("a question of the front tab stops it"); CHECK(queue.add("front/hover", "front", 1, 0, "front-hover")); - UNSCOPED_INFO("as it yields"); CHECK(queue.yielded()); UNSCOPED_INFO("its answer wanted still"); CHECK_FALSE(queue.superseded()); @@ -138,7 +132,6 @@ namespace // Asked again while it ran: the newer stands for it. queue.add("back/check", "back", 1, 4, "back-check-1", true); - UNSCOPED_INFO("taken"); REQUIRE(queue.take().has_value()); UNSCOPED_INFO("stopped"); CHECK(queue.add("front/hover", "front", 2, 0, "front-hover-2")); @@ -150,7 +143,6 @@ namespace // One that does not yield runs on. queue.add("back/weigh", "back", 3, 3, "back-weigh"); - UNSCOPED_INFO("taken"); REQUIRE(queue.take().has_value()); { INFO("left be"); @@ -164,7 +156,6 @@ namespace TEST_CASE_METHOD(alscriptjobqueue_data, "alscriptjobqueue: a yielded job keeps its turn and one forgotten while running is dropped", "[alscriptjobqueue]") { queue.add("back/check", "back", 1, 4, "back-check", true); - UNSCOPED_INFO("taken"); REQUIRE(queue.take().has_value()); queue.add("other/check", "other", 1, 4, "other-check", true); { @@ -201,14 +192,11 @@ namespace // Let go of while it runs: unwanted, said once, and not put back // though it was stopped as it yielded. queue.add("gone/check", "gone", 1, 4, "gone-check", true); - UNSCOPED_INFO("taken"); REQUIRE(queue.take().has_value()); queue.add("gone/hover", "gone", 1, 0, "gone-hover"); - UNSCOPED_INFO("yielded"); CHECK(queue.yielded()); UNSCOPED_INFO("let go of: to be stopped"); CHECK(queue.forget("gone")); - UNSCOPED_INFO("unwanted"); CHECK(queue.superseded()); UNSCOPED_INFO("said once"); CHECK_FALSE(queue.forget("gone")); diff --git a/indra/newview/tests/alscriptkeymap_test.cpp b/indra/newview/tests/alscriptkeymap_test.cpp index d2fc4d475c..9979bdd2f1 100644 --- a/indra/newview/tests/alscriptkeymap_test.cpp +++ b/indra/newview/tests/alscriptkeymap_test.cpp @@ -191,12 +191,12 @@ namespace { for (const ALKeyChord& chord : ALScriptKeymap::menuKeys(id)) { - UNSCOPED_INFO("one command's key: " + id + " " + chord.describe()); + UNSCOPED_INFO("one command's key: " << id << " " << chord.describe()); REQUIRE(seen.insert({ chord.key, chord.mask, chord.leadKey, chord.leadMask }).second); for (const auto& [key, mask] : { std::pair{ chord.key, chord.mask }, std::pair{ chord.leadKey, chord.leadMask } }) { const bool types = key >= 0x20 && key < 0x80; - UNSCOPED_INFO("no Control-Alt: " + id); + UNSCOPED_INFO("no Control-Alt: " << id); REQUIRE((!types || (mask & (MASK_CONTROL | MASK_ALT)) != (MASK_CONTROL | MASK_ALT))); } } @@ -214,16 +214,16 @@ namespace std::set ids; for (const ALScriptKeymap::MenuItem& item : items) { - UNSCOPED_INFO("the only item so named: " + item.id); + UNSCOPED_INFO("the only item so named: " << item.id); REQUIRE(ids.insert(item.id).second); - UNSCOPED_INFO("can take keys: " + item.id); + UNSCOPED_INFO("can take keys: " << item.id); REQUIRE((alEditorCommandFromName(item.id).has_value() || ALScriptKeymap::isMenuCommand(item.id))); - UNSCOPED_INFO("named by its menus: " + item.id); + UNSCOPED_INFO("named by its menus: " << item.id); REQUIRE(item.path.find(" > ") != std::string::npos); } for (const std::string& id : ALScriptKeymap::menuIds()) { - UNSCOPED_INFO("the table's commands are the menus': " + id); + UNSCOPED_INFO("the table's commands are the menus': " << id); REQUIRE(ids.count(id) == 1); } const auto map = std::find_if(items.begin(), items.end(), [](const ALScriptKeymap::MenuItem& item) { return item.id == "map_left"; }); @@ -332,7 +332,8 @@ namespace UNSCOPED_INFO("back on the Mac's Control-minus"); CHECK(has("back", ALKeyChord{ '-', MASK_MAC_CONTROL })); #else - { UNSCOPED_INFO("back on Alt-Left"); REQUIRE((has("back", ALKeyChord{ KEY_LEFT, MASK_ALT }) && has("forward", ALKeyChord{ KEY_RIGHT, MASK_ALT }))); } + UNSCOPED_INFO("back on Alt-Left and forward on Alt-Right"); + CHECK((has("back", ALKeyChord{ KEY_LEFT, MASK_ALT }) && has("forward", ALKeyChord{ KEY_RIGHT, MASK_ALT }))); #endif } @@ -343,7 +344,6 @@ namespace CHECK(ALScriptKeyPresets::all().front().id == ALScriptKeyPresets::STANDARD); REQUIRE(ALScriptKeyPresets::all().front().bindings.empty()); } - UNSCOPED_INFO("four"); REQUIRE(ALScriptKeyPresets::all().size() == 4); for (const ALScriptKeyPresets::Preset& preset : ALScriptKeyPresets::all()) { @@ -351,16 +351,16 @@ namespace for (const ALScriptKeyPresets::Binding& binding : preset.bindings) { const std::string what = preset.id + ": " + binding.id; - UNSCOPED_INFO("once: " + what); + UNSCOPED_INFO("once: " << what); REQUIRE(named.insert(binding.id).second); - UNSCOPED_INFO("keys: " + what); + UNSCOPED_INFO("keys: " << what); REQUIRE_FALSE(binding.keys.empty()); const bool editor = alEditorCommandFromName(binding.id).has_value(); - UNSCOPED_INFO("a command: " + what); + UNSCOPED_INFO("a command: " << what); REQUIRE((editor || ALScriptKeymap::isMenuCommand(binding.id))); for (const ALKeyChord& chord : binding.keys) { - UNSCOPED_INFO("one key at a time for an editor's: " + what); + UNSCOPED_INFO("one key at a time for an editor's: " << what); REQUIRE((!editor || !chord.twoKeys())); } } @@ -382,13 +382,13 @@ namespace { for (const ALKeyChord& chord : binding.keys) { - UNSCOPED_INFO("the editor's key: " + what + " " + chord.describe()); + UNSCOPED_INFO("the editor's key: " << what << " " << chord.describe()); REQUIRE(map.lookup(chord.key, chord.mask) == *command); } } else { - UNSCOPED_INFO("the menu's keys: " + what + " " + ALScriptKeymap::describe(ALScriptKeymap::menuKeys(binding.id))); + UNSCOPED_INFO("the menu's keys: " << what << " " << ALScriptKeymap::describe(ALScriptKeymap::menuKeys(binding.id))); REQUIRE(ALScriptKeymap::menuKeys(binding.id) == binding.keys); } } @@ -401,7 +401,7 @@ namespace const std::string what = preset.id + ": " + id + " " + chord.describe(); const KEY first_key = chord.twoKeys() ? chord.leadKey : chord.key; const MASK first_mask = chord.twoKeys() ? chord.leadMask : chord.mask; - UNSCOPED_INFO("not an editor's key: " + what); + UNSCOPED_INFO("not an editor's key: " << what); REQUIRE(map.lookup(first_key, first_mask) == ALEditorCommand::None); for (const std::string& other : ALScriptKeymap::menuIds()) { @@ -413,7 +413,7 @@ namespace { const bool clash = theirs == chord || (!chord.twoKeys() && theirs.ledBy(chord.key, chord.mask)) || (chord.twoKeys() && !theirs.twoKeys() && theirs.key == chord.leadKey && theirs.mask == chord.leadMask); - UNSCOPED_INFO("not " + other + "'s too: " + what); + UNSCOPED_INFO("not " << other << "'s too: " << what); REQUIRE_FALSE(clash); } } @@ -469,11 +469,11 @@ namespace }; for (const auto& [id, chord] : keys) { - UNSCOPED_INFO(std::string("a menu command: ") + id); + UNSCOPED_INFO("a menu command: " << id); REQUIRE(ALScriptKeymap::isMenuCommand(id)); - UNSCOPED_INFO(std::string("its key: ") + id + " " + chord.describe()); + UNSCOPED_INFO("its key: " << id << " " << chord.describe()); REQUIRE(ALScriptKeymap::menuKey(id) == chord); - UNSCOPED_INFO(std::string("no editor's: ") + id); + UNSCOPED_INFO("no editor's: " << id); REQUIRE(ALScriptKeymap::current().lookup(chord.key, chord.mask) == C::None); } UNSCOPED_INFO("the step beside it"); diff --git a/indra/newview/tests/alscriptlookup_test.cpp b/indra/newview/tests/alscriptlookup_test.cpp index 7d41ecbff0..c54cd34908 100644 --- a/indra/newview/tests/alscriptlookup_test.cpp +++ b/indra/newview/tests/alscriptlookup_test.cpp @@ -400,7 +400,7 @@ namespace ALScriptLookup::addPlace(lookup, place("", 1, 2, 7)); ALScriptLookup::addPlace(lookup, place("x", 1, 2)); UNSCOPED_INFO("once a file and a start"); - REQUIRE(lookup.places.size() == size_t(2)); + CHECK(lookup.places.size() == size_t(2)); std::vector places = { place("object:z", 0, 0, 5, "Beta"), place("", 3, 0, 5, "Zeta"), place("object:y", 2, 0, 5, "Alpha"), place("object:x", 0, 0, 5, "Beta"), @@ -452,34 +452,25 @@ namespace CHECK_FALSE(doc.preview); { INFO("nothing else asked"); - REQUIRE(studio.asked.empty()); - REQUIRE(studio.loads.empty()); + CHECK(studio.asked.empty()); + CHECK(studio.loads.empty()); } - UNSCOPED_INFO("shown"); CHECK(studio.shows == 1); - UNSCOPED_INFO("in its tab"); CHECK(studio.shownIn == std::string("a")); - UNSCOPED_INFO("from"); CHECK(studio.shown.from == std::string("a")); - UNSCOPED_INFO("named"); CHECK(studio.shown.fromName == std::string("A")); - UNSCOPED_INFO("the name"); CHECK(studio.shown.name == std::string("count")); { INFO("in order"); REQUIRE(studio.shown.places.size() == 2); CHECK(studio.shown.places[0].span.line == 0); } - UNSCOPED_INFO("not declared"); CHECK_FALSE(studio.shown.hasDefinition); - { - INFO("said"); - REQUIRE_FALSE(services.statuses.empty()); - CHECK(has(services.statuses.back(), "ReferencesFound [COUNT]=2")); - } + REQUIRE_FALSE(services.statuses.empty()); + CHECK(has(services.statuses.back(), "ReferencesFound [COUNT]=2")); { INFO("done with"); - REQUIRE(doc.lookup->command == ALEditorCommand::None); + CHECK(doc.lookup->command == ALEditorCommand::None); CHECK(doc.lookup->pending == 0); } } @@ -492,10 +483,9 @@ namespace Doc& doc = lookUp(ALEditorCommand::FindReferences); UNSCOPED_INFO("candidates asked for"); CHECK(studio.asked == Names{ "a" }); - UNSCOPED_INFO("one to read"); REQUIRE(studio.loads.size() == size_t(1)); UNSCOPED_INFO("the open one passed over"); - REQUIRE(studio.expands.empty()); + CHECK(studio.expands.empty()); UNSCOPED_INFO("waiting said"); CHECK(has(services.statuses.back(), "LookingAcross [COUNT]=1 [NAME]=count")); UNSCOPED_INFO("nothing shown yet"); @@ -503,7 +493,6 @@ namespace const LLUUID asset("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee"); studio.loads[0].loaded(asset, B_TEXT); - UNSCOPED_INFO("expanded"); REQUIRE(studio.expands.size() == size_t(1)); const ALScriptPreprocessor::Request& request = studio.expands[0].request; { @@ -517,7 +506,6 @@ namespace studio.expands[0].expanded( expansion("B", ALScriptPreprocessor::pathOf(b), B_TEXT, "A", ALScriptPreprocessor::pathOf(a), "integer count;\n")); - UNSCOPED_INFO("asked"); REQUIRE(studio.asks.size() == size_t(1)); const ALScriptAnalysis::Request& asked = studio.asks[0].request; { @@ -532,22 +520,16 @@ namespace CHECK(asked.version == doc.lookup->generation); studio.asks[0].answered(answer({ span(0, 8, 5), span(1, 8, 5) })); - UNSCOPED_INFO("shown"); CHECK(studio.shows == 1); UNSCOPED_INFO("its own through the other's expansion left out"); REQUIRE(studio.shown.places.size() == size_t(3)); const Doc::Place& other = studio.shown.places[2]; - UNSCOPED_INFO("in B"); CHECK(other.file == ALScriptPreprocessor::pathOf(b)); - UNSCOPED_INFO("named"); CHECK(other.fileName == std::string("B")); - UNSCOPED_INFO("as written"); CHECK(other.text == std::string("foo() { count = 2; }")); UNSCOPED_INFO("the name in it"); CHECK(other.at == 8); - UNSCOPED_INFO("declared"); CHECK(studio.shown.hasDefinition); - UNSCOPED_INFO("across scripts"); CHECK(has(services.statuses.back(), "ReferencesFoundAcross [COUNT]=3 [FILES]=2")); } @@ -585,7 +567,6 @@ namespace studio.loads[0].loaded(LLUUID::null, ""); UNSCOPED_INFO("an empty one passed over"); CHECK(studio.shows == 1); - UNSCOPED_INFO("one place"); REQUIRE(studio.shown.places.size() == size_t(1)); const Doc::Place& found = studio.shown.places[0]; { @@ -627,7 +608,7 @@ namespace studio.loads[0].loaded(LLUUID::null, B_TEXT); { INFO("the first's answer dropped"); - REQUIRE(studio.expands.empty()); + CHECK(studio.expands.empty()); CHECK(studio.shows == 1); } @@ -635,13 +616,12 @@ namespace studio.loads.back().loaded(LLUUID::null, B_TEXT); studio.expands.back().expanded(expansion("B", ALScriptPreprocessor::pathOf(b), B_TEXT)); UNSCOPED_INFO("no declaration in it: nothing asked"); - REQUIRE(studio.asks.empty()); + CHECK(studio.asks.empty()); UNSCOPED_INFO("shown without it"); CHECK(studio.shows == 2); const U32 generation = doc.lookup->generation; lookUp(ALEditorCommand::FindReferences); - UNSCOPED_INFO("a new generation"); CHECK(doc.lookup->generation != generation); studio.loads.back().loaded(LLUUID::null, B_TEXT); // A lookup of another tab's, still waiting on its read, as this @@ -655,12 +635,12 @@ namespace expansion("B", ALScriptPreprocessor::pathOf(b), B_TEXT, "A", ALScriptPreprocessor::pathOf(a), "integer count;\n")); { INFO("nothing asked once gone"); - REQUIRE(studio.asks.empty()); + CHECK(studio.asks.empty()); CHECK(studio.shows == 2); } studio.loads.back().loaded(LLUUID::null, B_TEXT); UNSCOPED_INFO("nothing read once gone"); - REQUIRE(studio.expands.size() == expands); + CHECK(studio.expands.size() == expands); } TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: Rename says what is not renamable and hints at what return will do", "[alscriptlookup]") @@ -670,7 +650,7 @@ namespace { INFO("not renamable"); CHECK(has(services.statuses.back(), "NotRenamable")); - REQUIRE(studio.askedName.empty()); + CHECK(studio.askedName.empty()); } Doc& doc = lookUp(ALEditorCommand::Rename, false); @@ -681,14 +661,9 @@ namespace doc.outline.push_back(entry); UNSCOPED_INFO("nothing typed"); CHECK(has(studio.hint(""), "RenameHint [COUNT]=2 [FILES]=1 [NAME]=count")); - { - INFO("no name"); - CHECK(has(studio.hint("9lives"), "RenameBadName")); - CHECK(has(studio.hint("9lives"), "[NAME]=9lives")); - } - UNSCOPED_INFO("reserved"); + CHECK(has(studio.hint("9lives"), "RenameBadName")); + CHECK(has(studio.hint("9lives"), "[NAME]=9lives")); CHECK(has(studio.hint("state"), "RenameReserved [NAME]=state")); - UNSCOPED_INFO("the same"); CHECK(has(studio.hint(" count "), "RenameSame")); UNSCOPED_INFO("a clash said, allowed"); CHECK(has(studio.hint("total"), "RenameClash")); @@ -699,7 +674,7 @@ namespace } services.docs.clear(); UNSCOPED_INFO("its tab gone: nothing said"); - REQUIRE(studio.hint("sum").empty()); + CHECK(studio.hint("sum").empty()); } TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: a rename across scripts edits open tabs and opens others with it pending", "[alscriptlookup]") @@ -723,22 +698,17 @@ namespace moved.editor->insertText("// "); UNSCOPED_INFO("asked"); REQUIRE((bool)studio.chosen); - UNSCOPED_INFO("across scripts"); CHECK(has(studio.hint("sum"), "RenameToAcross [COUNT]=9 [FILES]=6")); studio.chosen("9lives"); - { - INFO("no name"); - CHECK(has(services.statuses.back(), "RenameBadName")); - CHECK(doc.editor->text() == A_TEXT); - } + CHECK(has(services.statuses.back(), "RenameBadName")); + CHECK(doc.editor->text() == A_TEXT); studio.chosen("state"); - UNSCOPED_INFO("reserved"); CHECK(has(services.statuses.back(), "RenameReserved")); studio.chosen("count"); { INFO("the same: nothing"); - REQUIRE(services.reports.empty()); + CHECK(services.reports.empty()); CHECK(doc.editor->text() == A_TEXT); } @@ -754,7 +724,7 @@ namespace CHECK(open.editor->undoJournal().undoLabel() == std::string("rename")); { INFO("moved on since: left"); - REQUIRE(has(moved.editor->text(), "count")); + CHECK(has(moved.editor->text(), "count")); CHECK_FALSE(has(moved.editor->text(), "total")); } { @@ -777,7 +747,6 @@ namespace UNSCOPED_INFO("said once"); REQUIRE(services.reports.size() == size_t(1)); const al_studio_test::FakeServices::Said& said = services.reports[0]; - UNSCOPED_INFO("the counts"); CHECK(has(said.text, "RenamedIn [NAME]=total [PLACES]=Places [COUNT]=6 [SCRIPTS]=Scripts [COUNT]=4")); UNSCOPED_INFO("opened, a clause joined on"); CHECK(has(said.text, "[SECOND]=RenamedOpened [NAME]=total [PLACES]=Places [COUNT]=6 [SCRIPTS]=Scripts [COUNT]=2")); @@ -797,22 +766,17 @@ namespace Doc& doc = lookUp(ALEditorCommand::Rename, false); doc.editor->insertText(" "); studio.chosen("total"); - { - INFO("stale"); - CHECK(has(services.statuses.back(), "RenameStale [NAME]=total")); - REQUIRE(services.reports.empty()); - } + CHECK(has(services.statuses.back(), "RenameStale [NAME]=total")); + CHECK(services.reports.empty()); lookUp(ALEditorCommand::Rename, false); studio.chosen("total"); - UNSCOPED_INFO("said"); REQUIRE(services.reports.size() == size_t(1)); { INFO("here"); CHECK(has(services.reports[0].text, "RenamedHere")); CHECK_FALSE(has(services.reports[0].text, ";")); } - UNSCOPED_INFO("not a failure"); CHECK_FALSE(services.reports[0].failure); Doc& open = tab("b", b, "foo() { count = 2; }\n", "B"); @@ -838,7 +802,7 @@ namespace unit->applyPendingEdits(doc); { INFO("not loaded: kept"); - REQUIRE(doc.pendingEdits.size() == 2); + CHECK(doc.pendingEdits.size() == 2); CHECK(doc.editor->text() == "integer count;\nx = count;\n"); } @@ -847,7 +811,7 @@ namespace unit->applyPendingEdits(doc); { INFO("made"); - REQUIRE(doc.pendingEdits.empty()); + CHECK(doc.pendingEdits.empty()); CHECK(doc.editor->text() == "integer total;\nx = count;\n"); } UNSCOPED_INFO("one step"); @@ -868,11 +832,11 @@ namespace unit->applyPendingEdits(doc); { INFO("a replace"); - REQUIRE(doc.editor->text() == "integer sum;\nx = count;\n"); + CHECK(doc.editor->text() == "integer sum;\nx = count;\n"); CHECK(doc.editor->undoJournal().undoLabel() == "replace"); } UNSCOPED_INFO("nothing missed"); - REQUIRE(services.reports.size() == 1); + CHECK(services.reports.size() == 1); doc.modifiable = false; doc.pendingEdits = { { span(0, 8, 3), "sum", "total", true } }; @@ -930,7 +894,7 @@ namespace REQUIRE(studio.loads.size() == size_t(4)); studio.loads[2].loaded(LLUUID::null, ""); UNSCOPED_INFO("the new one's go on"); - REQUIRE(studio.loads.size() == size_t(5)); + CHECK(studio.loads.size() == size_t(5)); } TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: folderCandidates are the folder's other scripts in the same language", "[alscriptlookup]") @@ -979,7 +943,7 @@ namespace { INFO("no name: nothing shown"); CHECK(has(services.statuses.back(), "RenameBadName")); - REQUIRE_FALSE(studio.apply); + CHECK_FALSE(studio.apply); } studio.previewed("sum"); { @@ -1040,11 +1004,9 @@ namespace studio.unlisted = 2; studio.holdCandidates = true; lookUp(ALEditorCommand::FindReferences); - UNSCOPED_INFO("asked"); CHECK(studio.asked == Names{ "a" }); UNSCOPED_INFO("nothing read while the prims are asked"); - REQUIRE(studio.loads.empty()); - UNSCOPED_INFO("nothing shown"); + CHECK(studio.loads.empty()); CHECK(studio.shows == 0); studio.heldCandidates(); UNSCOPED_INFO("both read"); @@ -1053,7 +1015,6 @@ namespace UNSCOPED_INFO("one still out"); CHECK(studio.shows == 0); studio.loads[1].loaded(LLUUID::null, std::string("default { }\n")); - UNSCOPED_INFO("shown"); CHECK(studio.shows == 1); const std::string said = services.statuses.back(); { @@ -1087,38 +1048,38 @@ namespace const ALScriptPlaces::Lines held(std::make_shared("one\r\ntwo\n\nfour")); { INFO("four lines"); - REQUIRE(held.has(0)); - REQUIRE(held.has(3)); - REQUIRE_FALSE(held.has(4)); - REQUIRE_FALSE(held.has(-1)); + CHECK(held.has(0)); + CHECK(held.has(3)); + CHECK_FALSE(held.has(4)); + CHECK_FALSE(held.has(-1)); } { INFO("each as it is"); CHECK(held.line(0) == "one"); CHECK(held.line(1) == "two"); - REQUIRE(held.line(2).empty()); + CHECK(held.line(2).empty()); CHECK(held.line(3) == "four"); } UNSCOPED_INFO("none past the end"); - REQUIRE(held.line(9).empty()); + CHECK(held.line(9).empty()); const std::string text = "a\nb\n"; const ALScriptPlaces::Lines here(text); { INFO("read where it is, the last line empty"); CHECK(here.line(1) == "b"); - REQUIRE(here.has(2)); - REQUIRE(here.line(2).empty()); - REQUIRE_FALSE(here.has(3)); + CHECK(here.has(2)); + CHECK(here.line(2).empty()); + CHECK_FALSE(here.has(3)); } const ALTextDocument open("x\ny"); const ALScriptPlaces::Lines tab(&open); { INFO("a tab's"); CHECK(tab.line(1) == "y"); - REQUIRE_FALSE(tab.has(2)); + CHECK_FALSE(tab.has(2)); } UNSCOPED_INFO("nothing: no lines"); - REQUIRE_FALSE(ALScriptPlaces::Lines().has(0)); + CHECK_FALSE(ALScriptPlaces::Lines().has(0)); } TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: a rename preview compares an open unchanged file with its renamed text", "[alscriptlookup]") @@ -1131,7 +1092,6 @@ namespace { place("", 0, 8), place("", 1, 26), place(pb, 0, 8, 5, "B"), place(pb, 1, 16, 5, "B"), place(pd, 2, 4, 5, "D") }, doc.editor->document().version()); studio.previewed("sum"); - UNSCOPED_INFO("offered"); REQUIRE((bool)studio.changes); studio.changes("", { 1, 2, 3 }); @@ -1156,15 +1116,15 @@ namespace studio.changes(pd, { 4 }); { INFO("not open: said, not shown"); - REQUIRE(studio.compared.size() == before); + CHECK(studio.compared.size() == before); CHECK(has(services.statuses.back(), "RenameChangesNotHere [NAME]=sum [SCRIPT]=D")); - REQUIRE(services.statusFailures.back()); + CHECK(services.statusFailures.back()); } open.editor->insertText("// "); studio.changes(pb, { 2, 3 }); { INFO("changed since: said"); - REQUIRE(studio.compared.size() == before); + CHECK(studio.compared.size() == before); CHECK(has(services.statuses.back(), "RenameChangesNotHere")); } } @@ -1200,11 +1160,8 @@ namespace CHECK(module.name == "lib.luau"); CHECK(module.sourceText() == LIB_TEXT); } - { - INFO("the other script"); - CHECK(studio.expands[1].request.path == OTHER); - CHECK(studio.expands[1].request.sourceText() == B_LUA); - } + CHECK(studio.expands[1].request.path == OTHER); + CHECK(studio.expands[1].request.sourceText() == B_LUA); // The module read alone is the home itself; the other script has it // ahead of its own lines. @@ -1228,7 +1185,7 @@ namespace UNSCOPED_INFO("asked for the new name"); REQUIRE((bool)studio.chosen); UNSCOPED_INFO("each place once: the script's, the module's, the other's"); - REQUIRE(doc.lookup->places.size() == size_t(3)); + CHECK(doc.lookup->places.size() == size_t(3)); UNSCOPED_INFO("the other's, by its path"); CHECK(std::any_of(doc.lookup->places.begin(), doc.lookup->places.end(), [&](const Doc::Place& place) { return place.file == OTHER && place.fileName == "b.luau" && place.span.line == 1 && place.span.column == 10; @@ -1243,7 +1200,7 @@ namespace CHECK(other.editor->text() == std::string("local lib = require(\"./lib\")\nprint(lib.double(4))\n")); { INFO("each its own step"); - REQUIRE(lib.editor->undoJournal().undoLabel() == "rename"); + CHECK(lib.editor->undoJournal().undoLabel() == "rename"); CHECK(other.editor->undoJournal().undoLabel() == "rename"); } UNSCOPED_INFO("another language's file left alone"); @@ -1339,7 +1296,6 @@ namespace UNSCOPED_INFO("apart asked for"); CHECK(studio.expands[0].request.apart); studio.expands[0].expanded(apartExpansion("b.luau", OTHER, B_LUA, "./lib", "lib.luau", LIB, LIB_TEXT)); - UNSCOPED_INFO("asked"); REQUIRE(studio.asks.size() == size_t(1)); const ALScriptAnalysis::Request& asked = studio.asks[0].request; { @@ -1357,7 +1313,7 @@ namespace INFO("with its modules"); REQUIRE(asked.modules); REQUIRE(asked.modules->modules.size() == 1); - REQUIRE(asked.modules->modules[0].key == LIB); + CHECK(asked.modules->modules[0].key == LIB); REQUIRE(asked.modules->reaches.size() == 1); CHECK(asked.modules->reaches[0].name == "./lib"); } @@ -1370,7 +1326,7 @@ namespace return place.file == OTHER && place.fileName == "b.luau" && place.span.line == 1 && place.span.column == 10; })); UNSCOPED_INFO("each once: the script's, the module's, the other's"); - REQUIRE(doc.lookup->places.size() == size_t(3)); + CHECK(doc.lookup->places.size() == size_t(3)); } TEST_CASE_METHOD(alscriptlookup_data, "alscriptlookup: a file open under another path to it is read once as its tab has it", "[alscriptlookup]") @@ -1410,11 +1366,8 @@ namespace studio.expands[0].expanded(expansion("lib.luau", LIB_TAB, TYPED)); UNSCOPED_INFO("the home itself, asked at its declaration"); REQUIRE(studio.asks.size() == size_t(1)); - { - INFO("there"); - CHECK(studio.asks[0].request.line == 1); - CHECK(studio.asks[0].request.column == 11); - } + CHECK(studio.asks[0].request.line == 1); + CHECK(studio.asks[0].request.column == 11); std::error_code ec; fs::remove_all(root, ec); } @@ -1453,7 +1406,7 @@ namespace unit->start(doc, ALEditorCommand::FindReferences, refsOf("twice"), true, LIB, span(1, 11, 5), { place("", 1, 10) }, doc.editor->document().version()); UNSCOPED_INFO("nothing read here"); - REQUIRE(studio.expands.empty()); + CHECK(studio.expands.empty()); { INFO("held open for the walk"); CHECK(doc.lookup->pending == 1); @@ -1491,7 +1444,7 @@ namespace unit.reset(); pumped([] { return false; }, std::chrono::milliseconds(300)); UNSCOPED_INFO("nothing comes of it"); - REQUIRE(studio.expands.size() == size_t(2)); + CHECK(studio.expands.size() == size_t(2)); std::error_code ec; fs::remove_all(root, ec); } @@ -1504,28 +1457,28 @@ namespace const ALScriptPlaces::Lines tab(&open); { INFO("as many as the tab's"); - REQUIRE(held.has(4)); - REQUIRE_FALSE(held.has(5)); - REQUIRE(tab.has(4)); - REQUIRE_FALSE(tab.has(5)); + CHECK(held.has(4)); + CHECK_FALSE(held.has(5)); + CHECK(tab.has(4)); + CHECK_FALSE(tab.has(5)); } for (S32 line = 0; line < 5; ++line) { - UNSCOPED_INFO("line " + std::to_string(line) + " the tab's"); + CAPTURE(line); REQUIRE(held.line(line) == tab.line(line)); } { INFO("each as it is"); CHECK(held.line(1) == "two"); - REQUIRE(held.line(3).empty()); + CHECK(held.line(3).empty()); CHECK(held.line(4) == "five"); } const ALScriptPlaces::Lines here(text); { INFO("read where it is, the same"); CHECK(here.line(2) == "three"); - REQUIRE(here.has(4)); - REQUIRE_FALSE(here.has(5)); + CHECK(here.has(4)); + CHECK_FALSE(here.has(5)); } } } diff --git a/indra/newview/tests/alscriptnavigation_test.cpp b/indra/newview/tests/alscriptnavigation_test.cpp index 683440d2fc..b5688d568c 100644 --- a/indra/newview/tests/alscriptnavigation_test.cpp +++ b/indra/newview/tests/alscriptnavigation_test.cpp @@ -130,6 +130,8 @@ namespace static void waitToSettle() { std::this_thread::sleep_for(std::chrono::milliseconds(400)); } }; + // A view of a line is a place of its own, and a place noted drops the + // way forward. TEST_CASE_METHOD(alscriptnavigation_data, "alscriptnavigation: the history notes a line once and keeps the fifty latest places", "[alscriptnavigation]") { ALNavHistory history; @@ -176,6 +178,7 @@ namespace CHECK_FALSE(history.canGo(true)); } + // Where it goes from is put on the other way. TEST_CASE_METHOD(alscriptnavigation_data, "alscriptnavigation: back and forward pass closed tabs over and follow renamed ones", "[alscriptnavigation]") { ALNavHistory history; @@ -195,10 +198,10 @@ namespace UNSCOPED_INFO("forward again"); CHECK(lines(history.take(true, at("a", 1), open)) == "b:3"); history.rekey("c", "renamed"); - UNSCOPED_INFO("followed"); + UNSCOPED_INFO("the renamed tab followed"); CHECK(lines(history.take(true, std::nullopt, open)) == "renamed:4"); UNSCOPED_INFO("nowhere left"); - REQUIRE_FALSE(history.take(true, std::nullopt, open)); + CHECK_FALSE(history.take(true, std::nullopt, open)); } TEST_CASE_METHOD(alscriptnavigation_data, "alscriptnavigation: a walk is noted as one jump and back and forward are shown by the window", "[alscriptnavigation]") @@ -231,7 +234,7 @@ namespace a.loaded = false; unit.noteJump(); UNSCOPED_INFO("a tab not loaded: nothing noted"); - REQUIRE((!unit.canGo(false) || studio.shown.size() == 3)); + CHECK((!unit.canGo(false) || studio.shown.size() == 3)); } TEST_CASE_METHOD(alscriptnavigation_data, "alscriptnavigation: a row stayed on opens as a preview unless already open or passed or left", "[alscriptnavigation]") @@ -289,7 +292,7 @@ namespace INFO("typed in: held"); CHECK_FALSE(b.preview); CHECK(studio.tabs == 1); - REQUIRE(studio.letGo.size() == 1); + CHECK(studio.letGo.size() == 1); } Doc& c = tab("c"); c.preview = true; @@ -298,7 +301,7 @@ namespace { INFO("worked from: held"); CHECK_FALSE(c.preview); - REQUIRE(studio.letGo.size() == 1); + CHECK(studio.letGo.size() == 1); } Doc& d = tab("d"); d.preview = true; diff --git a/indra/newview/tests/alscriptobjectcheck_test.cpp b/indra/newview/tests/alscriptobjectcheck_test.cpp index b97ad27148..b8547080a5 100644 --- a/indra/newview/tests/alscriptobjectcheck_test.cpp +++ b/indra/newview/tests/alscriptobjectcheck_test.cpp @@ -171,9 +171,7 @@ namespace { house(); check.check(root, "House"); - UNSCOPED_INFO("listed"); CHECK(window.listedFor == std::vector{ root }); - UNSCOPED_INFO("running"); CHECK(check.running()); UNSCOPED_INFO("two at once"); REQUIRE(window.asks.size() == size_t(2)); @@ -200,11 +198,8 @@ namespace UNSCOPED_INFO("B checked"); REQUIRE(window.checked.size() == size_t(1)); const Check::Script& b = window.checked[0]; - { - INFO("by its name"); - CHECK(b.name == "B"); - CHECK(b.ref.item == id(11)); - } + CHECK(b.name == "B"); + CHECK(b.ref.item == id(11)); UNSCOPED_INFO("the lints as chosen applied"); REQUIRE(b.rows.size() == size_t(1)); { @@ -222,24 +217,17 @@ namespace REQUIRE(window.done.empty()); window.asks[1].answered(answer({})); - UNSCOPED_INFO("done"); REQUIRE(window.done.size() == size_t(1)); const Check::Done& done = window.done[0]; - { - INFO("of the house"); - CHECK(done.root == root); - CHECK(done.name == "House"); - CHECK(done.present); - } - UNSCOPED_INFO("checked"); + CHECK(done.root == root); + CHECK(done.name == "House"); + CHECK(done.present); CHECK(done.checked == 2); UNSCOPED_INFO("left to its tab"); CHECK(done.open == 1); UNSCOPED_INFO("prims that did not answer"); CHECK(done.unlisted == 1); - UNSCOPED_INFO("the one not read, by name"); CHECK(done.unread == std::vector{ "D" }); - UNSCOPED_INFO("no longer running"); CHECK_FALSE(check.running()); } @@ -249,7 +237,6 @@ namespace window.listing.scripts.push_back({ ALScriptRef(root, id(20)), "Main" }); window.texts = { { id(20), "#include \"lib\"\ndefault {}\n" } }; check.check(root, "Shed"); - UNSCOPED_INFO("expanded"); REQUIRE(window.expands.size() == size_t(1)); { INFO("apart, as a tab's check"); @@ -281,13 +268,11 @@ namespace said.message = "from the preprocessor"; result.problems.push_back(said); window.expands[0].expanded(result); - UNSCOPED_INFO("asked"); REQUIRE(window.asks.size() == size_t(1)); UNSCOPED_INFO("about the expansion"); CHECK(*window.asks[0].request.text == std::string("integer x;\ndefault {}\n")); window.asks[0].answered(answer({ problem(0, "in the library"), problem(1, "in the script") })); - UNSCOPED_INFO("checked"); REQUIRE(window.checked.size() == size_t(1)); const std::vector& rows = window.checked[0].rows; UNSCOPED_INFO("the preprocessor's and the analyzers'"); @@ -308,7 +293,6 @@ namespace REQUIRE(rows[2].file.empty()); CHECK(rows[2].line == 1); } - UNSCOPED_INFO("done"); REQUIRE(window.done.size() == size_t(1)); } diff --git a/indra/newview/tests/alscriptoutlinepane_test.cpp b/indra/newview/tests/alscriptoutlinepane_test.cpp index 729feed77a..ea2467aa97 100644 --- a/indra/newview/tests/alscriptoutlinepane_test.cpp +++ b/indra/newview/tests/alscriptoutlinepane_test.cpp @@ -168,12 +168,10 @@ namespace { INFO("not in front: nothing"); CHECK(outline->list()->getItemCount() == 0); - REQUIRE(told().shown.empty()); + CHECK(told().shown.empty()); } outline->show(doc); - UNSCOPED_INFO("the tree"); - CHECK(rows() == std::string("count, ^default, .touch_start, .state_entry, alpha")); - UNSCOPED_INFO("told"); + REQUIRE(rows() == std::string("count, ^default, .touch_start, .state_entry, alpha")); CHECK(joined(told().shown) == std::string("a")); const std::vector items = outline->list()->getAllData(); UNSCOPED_INFO("what it is"); @@ -182,16 +180,13 @@ namespace CHECK(items[0]->getColumn(1)->getToolTip() == std::string("variable\ninteger")); UNSCOPED_INFO("by its index"); CHECK(items[4]->getValue().asInteger() == 4); - UNSCOPED_INFO("nothing said over it"); - REQUIRE(comment().empty()); + CHECK(comment().empty()); doc.outline.clear(); outline->show(doc); - UNSCOPED_INFO("nothing to outline"); CHECK(comment() == std::string("Nothing in this script to outline yet.")); doc.loaded = false; outline->show(doc); - UNSCOPED_INFO("not loaded yet"); CHECK(comment() == std::string("Still loading.")); } @@ -228,7 +223,7 @@ namespace { INFO("the list kept"); REQUIRE_FALSE(window.services().reveals.empty()); - REQUIRE_FALSE(window.services().reveals.back()); + CHECK_FALSE(window.services().reveals.back()); } outline->fold(0, true); UNSCOPED_INFO("a leaf at the top: nowhere"); @@ -249,7 +244,6 @@ namespace CHECK(rows() == std::string("touch_start, state_entry")); filter->setText(std::string("zz")); outline->show(doc); - UNSCOPED_INFO("none"); CHECK(comment() == std::string("No symbol names match what you typed.")); filter->setText(std::string()); @@ -264,7 +258,6 @@ namespace sort->onCommit(); UNSCOPED_INFO("by kind, then name"); CHECK(rows() == std::string("count, alpha, ^default, .state_entry, .touch_start")); - UNSCOPED_INFO("the window told"); CHECK(told().sorts == 1); filter->setText(std::string("t")); outline->show(doc); @@ -303,7 +296,7 @@ namespace UNSCOPED_INFO("followed as it is shown"); CHECK(chosen() == 2); UNSCOPED_INFO("going nowhere"); - REQUIRE(told().chosen.empty()); + CHECK(told().chosen.empty()); } TEST_CASE_METHOD(alscriptoutlinepane_data, "alscriptoutlinepane: the list is made again only when what it shows changes", "[alscriptoutlinepane]") @@ -329,7 +322,6 @@ namespace CHECK(cell(outline->list()->getFirstData(), 1) != "marked"); window.services().front = 0; outline->forget(); - UNSCOPED_INFO("nothing listed"); CHECK(outline->list()->getItemCount() == 0); outline->show(doc); UNSCOPED_INFO("the same rows back"); @@ -347,37 +339,31 @@ namespace { INFO("gone to"); CHECK(joined(told().chosen) == "count"); - REQUIRE(window.services().reveals.back() == false); + CHECK_FALSE(window.services().reveals.back()); } { - INFO("return"); + INFO("return: gone to, to type there"); CHECK(list->handleKeyHere(KEY_RETURN, MASK_NONE)); CHECK(told().chosen.back() == "count editor"); } UNSCOPED_INFO("the keyboard taken"); - REQUIRE(window.services().reveals.back()); + CHECK(window.services().reveals.back()); { - INFO("escape"); + INFO("escape: back without going"); CHECK(list->handleKeyHere(KEY_ESCAPE, MASK_NONE)); - REQUIRE(told().chosen.size() == 2); - REQUIRE(window.services().reveals.size() == 3); + CHECK(told().chosen.size() == 2); + CHECK(window.services().reveals.size() == 3); } { INFO("with a key held: the list's"); CHECK_FALSE(list->handleKeyHere(KEY_RETURN, MASK_CONTROL)); - REQUIRE(told().chosen.size() == 2); + CHECK(told().chosen.size() == 2); } list->selectByValue(LLSD(1)); - { - INFO("left"); - CHECK(list->handleKeyHere(KEY_LEFT, MASK_NONE)); - CHECK(doc.outlineFolded.contains("default")); - } - { - INFO("right"); - CHECK(list->handleKeyHere(KEY_RIGHT, MASK_NONE)); - CHECK_FALSE(doc.outlineFolded.contains("default")); - } + CHECK(list->handleKeyHere(KEY_LEFT, MASK_NONE)); + CHECK(doc.outlineFolded.contains("default")); + CHECK(list->handleKeyHere(KEY_RIGHT, MASK_NONE)); + CHECK_FALSE(doc.outlineFolded.contains("default")); // The mouse only reaches what is shown. window.floater->setVisible(true); @@ -400,7 +386,6 @@ namespace list->localPointToOtherView(rect.mLeft + icon->getWidth() + list->getColumnPadding() + 2, row_y, &x, &y, outline); UNSCOPED_INFO("an arrow clicked"); CHECK(outline->handleMouseDown(x, y, MASK_NONE)); - UNSCOPED_INFO("folds"); CHECK(doc.outlineFolded.contains("default")); list->localPointToOtherView(rect.mRight - 4, row_y, &x, &y, outline); outline->handleMouseDown(x, y, MASK_NONE); @@ -423,9 +408,7 @@ namespace Doc& doc = tab("a"); window.floater->setVisible(false); outline->show(doc); - UNSCOPED_INFO("told"); CHECK(joined(told().shown) == "a"); - UNSCOPED_INFO("not listed"); CHECK(outline->list()->getItemCount() == 0); outline->pump(); UNSCOPED_INFO("nor while unseen"); diff --git a/indra/newview/tests/alscriptoutputpane_test.cpp b/indra/newview/tests/alscriptoutputpane_test.cpp index a4a0fc5ab6..28d97a5a96 100644 --- a/indra/newview/tests/alscriptoutputpane_test.cpp +++ b/indra/newview/tests/alscriptoutputpane_test.cpp @@ -98,7 +98,7 @@ namespace FakeWindow& studio = window.pane(); ALScriptOutputPane* pane = nullptr; - ALScriptOutputPane& make() + ALScriptOutputPane& require_pane() { if (!window.floater) { @@ -106,7 +106,7 @@ namespace } // The tab as the skin built it. pane = window.find("output_tab"); - UNSCOPED_INFO("the skin builds the tab as the pane"); + INFO("the skin builds the tab as the pane"); REQUIRE(pane != nullptr); return *pane; } @@ -158,10 +158,10 @@ namespace return out; } // A filter chosen, as a click on it would. - void whose(const std::string& value) + void require_whose(const std::string& value) { LLComboBox* combo = window.find("output_filter"); - UNSCOPED_INFO("offered: " + value); + CAPTURE(value); REQUIRE(combo->selectByValue(LLSD(value))); combo->onCommit(); } @@ -176,7 +176,7 @@ namespace TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: the kind filter picks errors or owner words or debug or the studio's", "[ALScriptOutputPane]") { - ALScriptOutputPane& out = make(); + ALScriptOutputPane& out = require_pane(); const LLUUID door = fresh(); out.heard(said(door, "Door", "opening", Event::Channel::OwnerSay)); out.heard(said(door, "Door", "tick\n")); @@ -185,27 +185,23 @@ namespace UNSCOPED_INFO("everything, a trailing newline gone"); CHECK(shown() == std::string("|opening|tick|Stack-Heap Collision|Saved.")); out.showKind("error"); - UNSCOPED_INFO("the error"); CHECK(shown() == std::string("|Stack-Heap Collision")); UNSCOPED_INFO("kept as chosen"); CHECK(out.kind() == std::string("error")); out.showKind("owner"); - UNSCOPED_INFO("what the owner was told"); CHECK(shown() == std::string("|opening")); out.showKind("debug"); - UNSCOPED_INFO("the debug channel"); CHECK(shown() == std::string("|tick")); out.showKind("studio"); - UNSCOPED_INFO("the studio"); CHECK(shown() == std::string("|Saved.")); out.showKind(""); UNSCOPED_INFO("everything again"); - REQUIRE(shownTexts().size() == size_t(4)); + CHECK(shownTexts().size() == size_t(4)); } TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: filters by whose it is and by words in either case", "[ALScriptOutputPane]") { - ALScriptOutputPane& out = make(); + ALScriptOutputPane& out = require_pane(); const LLUUID door = fresh(); const LLUUID lamp = fresh(); const LLUUID crate = fresh(); @@ -218,18 +214,18 @@ namespace out.heard(said(crate, "Crate", "crate tells its owner", Event::Channel::OwnerSay)); out.said("Saved door.lsl.", false, nullptr, {}); - whose(lamp.asString()); + require_whose(lamp.asString()); UNSCOPED_INFO("one object's alone, not the studio's"); CHECK(shown() == std::string("|lamp speaks")); - whose("open"); + require_whose("open"); UNSCOPED_INFO("the open script's, and the studio's"); CHECK(shown() == std::string("|door speaks|Saved door.lsl.")); - whose("mine"); + require_whose("mine"); UNSCOPED_INFO("the agent's object's, what an owner was told, and the studio's"); CHECK(shown() == std::string("|lamp speaks|crate tells its owner|Saved door.lsl.")); - whose(""); + require_whose(""); find("DOOR"); UNSCOPED_INFO("the words, in the text or whose it is"); CHECK(shown() == std::string("|door speaks|Saved door.lsl.")); @@ -238,10 +234,10 @@ namespace CHECK(shown() == std::string("|lamp speaks")); find(""); UNSCOPED_INFO("everything"); - REQUIRE(shownTexts().size() == size_t(4)); + CHECK(shownTexts().size() == size_t(4)); // The script closed: the filter by open scripts follows. - whose("open"); + require_whose("open"); services.docs.clear(); out.openChanged(); UNSCOPED_INFO("the studio's alone"); @@ -250,14 +246,13 @@ namespace TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: the objects offered stop at forty dropping the stalest but the chosen", "[ALScriptOutputPane]") { - ALScriptOutputPane& out = make(); + ALScriptOutputPane& out = require_pane(); std::vector roots; for (S32 i = 0; i < 45; ++i) { roots.push_back(fresh()); out.heard(said(roots.back(), llformat("Object %02d", i), "hello")); } - UNSCOPED_INFO("forty"); REQUIRE(out.objects().size() == size_t(40)); UNSCOPED_INFO("the first five gone"); CHECK(out.objects().front().first == roots[5]); @@ -265,16 +260,13 @@ namespace out.heard(said(roots[5], "Object 05", "again")); UNSCOPED_INFO("heard again, last"); CHECK(out.objects().back().first == roots[5]); - UNSCOPED_INFO("still forty"); REQUIRE(out.objects().size() == size_t(40)); // Renamed, and heard from under its new name. out.heard(said(roots[9], "Renamed", "again")); - UNSCOPED_INFO("its new name"); CHECK(out.objects().back().second == std::string("Renamed")); // The one chosen stays, least lately heard from as it is. - whose(roots[6].asString()); + require_whose(roots[6].asString()); out.heard(said(fresh(), "Newcomer", "hello")); - UNSCOPED_INFO("forty still"); REQUIRE(out.objects().size() == size_t(40)); UNSCOPED_INFO("the one chosen stayed"); CHECK(out.objects().front().first == roots[6]); @@ -286,7 +278,7 @@ namespace TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: an error or failure out of sight is unread until seen or cleared", "[ALScriptOutputPane]") { - ALScriptOutputPane& out = make(); + ALScriptOutputPane& out = require_pane(); const LLUUID door = fresh(); out.heard(said(door, "Door", "tick")); out.said("Saved.", false, nullptr, {}); @@ -319,12 +311,12 @@ namespace UNSCOPED_INFO("cleared"); CHECK_FALSE(out.unread()); UNSCOPED_INFO("with what was said"); - REQUIRE(out.view()->entries().empty()); + CHECK(out.view()->entries().empty()); } TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: the studio's words link to the tab they name and to its actions", "[ALScriptOutputPane]") { - ALScriptOutputPane& out = make(); + ALScriptOutputPane& out = require_pane(); ALScriptStudioDoc& doc = services.addDoc("door-script", ALScriptRef(fresh(), fresh()), "door.lsl"); out.said("Could not save door.lsl.", true, &doc, { "retry", "copy" }); const ALOutputView::Entry& entry = last(); @@ -351,25 +343,22 @@ namespace CHECK(studio.shown[0] == std::string("door-script:problems")); UNSCOPED_INFO("what to do, by name"); REQUIRE(studio.actions.size() == size_t(2)); - UNSCOPED_INFO("try again"); CHECK(studio.actions[0] == std::string("door-script:retry")); - UNSCOPED_INFO("a copy"); CHECK(studio.actions[1] == std::string("door-script:copy")); // Said of no tab: nothing to link. out.said("Nothing open.", false, nullptr, { "retry" }); - UNSCOPED_INFO("no links"); - REQUIRE(last().links.empty()); + CHECK(last().links.empty()); // The tab closed since: nothing asked of the window. services.docs.clear(); out.choose(chosen); UNSCOPED_INFO("nothing more"); - REQUIRE(studio.actions.size() == size_t(2)); + CHECK(studio.actions.size() == size_t(2)); } TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: a run's lines map back to the script or an include for each frame", "[ALScriptOutputPane]") { - ALScriptOutputPane& out = make(); + ALScriptOutputPane& out = require_pane(); const LLUUID object = fresh(); const LLUUID item = fresh(); // Ten lines out: the first four the include's, the rest the @@ -397,7 +386,7 @@ namespace UNSCOPED_INFO("the error's line, the script's"); CHECK(at.line == 4); UNSCOPED_INFO("in the script"); - REQUIRE(at.file.empty()); + CHECK(at.file.empty()); const ALOutputView::Entry& entry = last(); UNSCOPED_INFO("a link to it"); CHECK(entry.link); @@ -421,7 +410,7 @@ namespace { INFO("the script"); CHECK(studio.went[0].ref == ALScriptRef(object, item)); - REQUIRE(studio.went[0].file.empty()); + CHECK(studio.went[0].file.empty()); } UNSCOPED_INFO("at the error's line"); CHECK(studio.went[0].line == 4); @@ -450,7 +439,7 @@ namespace TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: a run's line past the envelope's lines maps back through the code", "[ALScriptOutputPane]") { - ALScriptOutputPane& out = make(); + ALScriptOutputPane& out = require_pane(); const LLUUID object = fresh(); const LLUUID item = fresh(); ALSourceMap map; @@ -484,12 +473,12 @@ namespace TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: an error the filters hide is not unread", "[ALScriptOutputPane]") { - ALScriptOutputPane& out = make(); + ALScriptOutputPane& out = require_pane(); const LLUUID lamp = fresh(); const LLUUID crate = fresh(); out.heard(said(lamp, "Lamp", "lamp speaks")); out.heard(said(crate, "Crate", "crate speaks")); - whose(lamp.asString()); + require_whose(lamp.asString()); out.heard(failed(crate, fresh(), "crate.lsl", "Math Error", -1)); { INFO("a stranger's, hidden: not unread"); @@ -507,7 +496,7 @@ namespace TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: what objects say aloud or to the agent or in IMs gets its own kind", "[ALScriptOutputPane]") { - ALScriptOutputPane& out = make(); + ALScriptOutputPane& out = require_pane(); const LLUUID lamp = fresh(); Event aloud = said(lamp, "Lamp", "hello", Event::Channel::Said); aloud.primName = "Bulb"; @@ -515,31 +504,28 @@ namespace out.heard(said(lamp, "Lamp", "just you", Event::Channel::SaidTo)); out.heard(said(lamp, "Lamp", "an IM", Event::Channel::Instant)); const auto& entries = out.view()->entries(); - UNSCOPED_INFO("three"); REQUIRE(entries.size() == size_t(3)); UNSCOPED_INFO("the prim that spoke, after its object"); CHECK(entries[0].source == std::string("Lamp \xE2\x96\xB8 Bulb")); - UNSCOPED_INFO("said"); CHECK(entries[0].kind == window.services().words("KindSaid")); UNSCOPED_INFO("said to the agent"); CHECK(entries[1].kind == window.services().words("KindSaidTo")); UNSCOPED_INFO("an IM"); CHECK(entries[2].kind == window.services().words("KindInstant")); - whose("mine"); + require_whose("mine"); UNSCOPED_INFO("the agent's own, all of them"); - REQUIRE(shownTexts().size() == size_t(3)); - whose(""); + CHECK(shownTexts().size() == size_t(3)); + require_whose(""); out.showKind("said"); UNSCOPED_INFO("aloud and to the agent"); CHECK(shown() == std::string("|hello|just you")); out.showKind("im"); - UNSCOPED_INFO("IMs"); CHECK(shown() == std::string("|an IM")); } TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: the controls row keeps buttons right and narrows the lists first", "[ALScriptOutputPane]") { - ALScriptOutputPane& out = make(); + ALScriptOutputPane& out = require_pane(); const LLRect whose = out.getChild("output_filter")->getRect(); const LLRect kind = out.getChild("output_kind")->getRect(); const auto row = [&]() { @@ -594,7 +580,7 @@ namespace TEST_CASE_METHOD(alscriptoutputpane_data, "ALScriptOutputPane: a lone CR breaks a line and links follow it to the shown line", "[ALScriptOutputPane]") { - ALScriptOutputPane& out = make(); + ALScriptOutputPane& out = require_pane(); const LLUUID object = fresh(); const LLUUID item = fresh(); Event error = failed(object, item, "Counter", "bad\rvalue", -1); diff --git a/indra/newview/tests/alscriptproblemspane_test.cpp b/indra/newview/tests/alscriptproblemspane_test.cpp index 17199c9c2b..998c2d11f0 100644 --- a/indra/newview/tests/alscriptproblemspane_test.cpp +++ b/indra/newview/tests/alscriptproblemspane_test.cpp @@ -237,7 +237,7 @@ namespace void pick(const char* combo, const std::string& value) { LLComboBox* box = window.find(combo); - UNSCOPED_INFO("offered: " + value); + INFO("the combo offers " << value); REQUIRE(box->selectByValue(LLSD(value))); box->onCommit(); } @@ -278,7 +278,6 @@ namespace { messages.push_back(row.message); } - UNSCOPED_INFO("six rows"); REQUIRE(made.rows.size() == size_t(6)); UNSCOPED_INFO("the weight first, at no line"); CHECK(made.rows[0].origin == services.words("OriginWeight")); @@ -317,12 +316,9 @@ namespace } UNSCOPED_INFO("the run-time mark on its line"); REQUIRE(std::find(made.marks.begin(), made.marks.end(), std::make_pair(S32(8), ALCodeEditor::Mark::Runtime)) != made.marks.end()); - { - INFO("each level's mark"); - CHECK(ALScriptProblemsPane::markOf(Doc::Level::Error) == ALCodeEditor::Mark::Error); - CHECK(ALScriptProblemsPane::markOf(Doc::Level::Warning) == ALCodeEditor::Mark::Warning); - CHECK(ALScriptProblemsPane::markOf(Doc::Level::Note) == ALCodeEditor::Mark::Note); - } + CHECK(ALScriptProblemsPane::markOf(Doc::Level::Error) == ALCodeEditor::Mark::Error); + CHECK(ALScriptProblemsPane::markOf(Doc::Level::Warning) == ALCodeEditor::Mark::Warning); + CHECK(ALScriptProblemsPane::markOf(Doc::Level::Note) == ALCodeEditor::Mark::Note); UNSCOPED_INFO("the lint's line offers its fix"); REQUIRE(made.fixable.size() == size_t(1)); UNSCOPED_INFO("which changes the script"); @@ -333,7 +329,6 @@ namespace // again. d.editor->setText("line 0\nline 1\n"); made = gather(d); - UNSCOPED_INFO("no fix offered"); REQUIRE(made.fixable.empty()); UNSCOPED_INFO("the compiler's error said"); CHECK(std::any_of(made.rows.begin(), made.rows.end(), [](const Doc::Shown& row) { return row.message == "syntax error"; })); @@ -356,7 +351,6 @@ namespace out.fill(&door); UNSCOPED_INFO("the one in front's"); CHECK(shown() == std::string("|door error|door warning|door note")); - UNSCOPED_INFO("three to list"); CHECK(out.held() == 3); UNSCOPED_INFO("said on the tab"); CHECK(studio.counts > 0); @@ -390,7 +384,6 @@ namespace "|#door.lsl \xC2\xB7 " + services.counted("ProblemErrors", 1) + ", " + services.counted("ProblemWarnings", 1) + ", " + services.counted("ProblemNotes", 1) + "|door error|door warning|door note|#lamp.lsl \xC2\xB7 " + services.counted("ProblemErrors", 1) + "|lamp error"); - UNSCOPED_INFO("four to list"); CHECK(out.held() == 4); // Another script's problems gathered again: listed, since every // one's are. @@ -407,7 +400,6 @@ namespace // Closed, it is let go of. out.closed("door"); - UNSCOPED_INFO("forgotten"); REQUIRE(out.listedId().empty()); LLSD state; out.saveState(state); @@ -442,7 +434,6 @@ namespace out.selectFirstError(true); UNSCOPED_INFO("the checkers' own"); CHECK(studio.chosen.back().line == 5); - UNSCOPED_INFO("its stretch"); CHECK(studio.chosen.back().endColumn == 6); choose("a warning before"); @@ -451,7 +442,6 @@ namespace CHECK(studio.chosen.back().line == 0); UNSCOPED_INFO("the keyboard left in the list"); REQUIRE_FALSE(studio.toEditor.back()); - UNSCOPED_INFO("whose it is"); CHECK(studio.chosen.back().doc == std::string("door")); // The list's keys: return goes there to type, escape back to the @@ -526,23 +516,19 @@ namespace UNSCOPED_INFO("and back"); CHECK_FALSE(out.lintIsError()); out.act("off"); - UNSCOPED_INFO("turned off"); CHECK(studio.levels["LocalShadow"] == ALScriptLints::Level::Off); out.act("settings"); - UNSCOPED_INFO("the settings"); CHECK(studio.settings == 1); UNSCOPED_INFO("every one of its kind"); CHECK(out.fixShown("kind")); out.act("fix:0"); UNSCOPED_INFO("its fix made"); REQUIRE(studio.fixed.size() == size_t(1)); - UNSCOPED_INFO("which"); CHECK(studio.fixed[0] == std::string("door:Rename")); out.act("fix_kind"); out.act("fix_all"); UNSCOPED_INFO("of its kind, then of all"); REQUIRE(studio.kinds.size() == size_t(2)); - UNSCOPED_INFO("by its kind"); CHECK(studio.kinds[0] == std::string("door:shadow")); UNSCOPED_INFO("then every kind"); CHECK(studio.kinds[1] == std::string("door:")); @@ -555,7 +541,6 @@ namespace UNSCOPED_INFO("run-time errors to let go of"); CHECK(out.enabled("clear_runtime")); out.act("clear_runtime"); - UNSCOPED_INFO("let go of"); REQUIRE(d.runtime.empty()); UNSCOPED_INFO("and not recalled when it is opened again"); CHECK(studio.cleared == std::vector{ d.id }); @@ -648,7 +633,6 @@ namespace std::vector rows = weights(gather(d)); UNSCOPED_INFO("near: one row"); REQUIRE(rows.size() == size_t(1)); - UNSCOPED_INFO("a warning"); CHECK(rows[0].level == Doc::Level::Warning); UNSCOPED_INFO("what is left"); CHECK(rows[0].message == services.words("WeightNear", { { "[SIZE]", "14.0" }, { "[LIMIT]", "16" }, { "[LEFT]", "2.0" }, { "[TARGET]", "LSL (LSO)" } })); @@ -676,15 +660,10 @@ namespace d.check->analysis = { made_here }; d.check->analysisVersion = d.editor->document().version(); const ALScriptProblemsPane::Made made = gather(d); - UNSCOPED_INFO("one row"); REQUIRE(made.rows.size() == size_t(1)); - UNSCOPED_INFO("named so"); CHECK(made.rows[0].fileName == services.words("InGeneratedCode")); - { - INFO("no mark, no squiggle"); - REQUIRE(made.marks.empty()); - REQUIRE(made.decorations.empty()); - } + REQUIRE(made.marks.empty()); + REQUIRE(made.decorations.empty()); } TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: a checked script with no tab is listed after open ones and chosen by its item", "[ALScriptProblemsPane]") @@ -728,7 +707,6 @@ namespace CHECK(at >= 0); list()->selectNthItem(at); pane->choose(false); - UNSCOPED_INFO("chosen"); REQUIRE_FALSE(studio.chosen.empty()); const ALScriptProblemsPane::Place& place = studio.chosen.back(); { @@ -779,12 +757,8 @@ namespace pane->checkedScript(closed, "hinge.lsl", false, { row("the check's", "Lint") }, "House"); pane->compiledScript(closed, "hinge.lsl", false, { row("the compiler's", "Compiler") }, "House"); - { - INFO("both listed"); - REQUIRE(shown().find("the check's") != std::string::npos); - REQUIRE(shown().find("the compiler's") != std::string::npos); - } - UNSCOPED_INFO("counted"); + REQUIRE(shown().find("the check's") != std::string::npos); + REQUIRE(shown().find("the compiler's") != std::string::npos); CHECK(pane->held() == 2); pane->compiledScript(closed, "hinge.lsl", false, { row("again", "Compiler") }, "House"); @@ -805,10 +779,8 @@ namespace other.generate(); const ALScriptRef lone(object, other); pane->compiledScript(lone, "latch.lsl", false, { row("latch", "Compiler") }, "House"); - UNSCOPED_INFO("listed"); CHECK(pane->checkedCount() == size_t(2)); pane->compiledScript(lone, "latch.lsl", false, {}, "House"); - UNSCOPED_INFO("gone"); CHECK(pane->checkedCount() == size_t(1)); } @@ -821,7 +793,6 @@ namespace Doc& door = doc("door"); door.check->analysis = { problem(S::Parser, V::Error, 1, "door error"), problem(S::Lint, V::Warning, 3, "door warning") }; tabs->selectTabByName("references_tab"); - UNSCOPED_INFO("out of sight"); CHECK_FALSE(ALPaneFolds::inSight(&out)); const S32 said = studio.counts; gather(door); @@ -879,16 +850,13 @@ namespace door.check->analysis = { problem(S::Parser, V::Error, 1, "first"), problem(S::Lint, V::Warning, 3, "second") }; gather(door); LLScrollListItem* second = row_saying("second"); - { - INFO("listed"); - REQUIRE(second != nullptr); - CHECK(second->getColumn(3)->getValue().asString().rfind("4:", 0) == 0); - } + REQUIRE(second != nullptr); + CHECK(second->getColumn(3)->getValue().asString().rfind("4:", 0) == 0); choose("second"); door.check->analysis = { problem(S::Parser, V::Error, 2, "first"), problem(S::Lint, V::Warning, 4, "second") }; gather(door); UNSCOPED_INFO("moved a line: the same row"); - CHECK(row_saying("second") == second); + REQUIRE(row_saying("second") == second); UNSCOPED_INFO("where it is now"); CHECK(second->getColumn(3)->getValue().asString().rfind("5:", 0) == 0); UNSCOPED_INFO("still chosen"); @@ -908,7 +876,6 @@ namespace { rows += item->getValue().has("heading") ? 0 : 1; } - UNSCOPED_INFO("a thousand listed"); CHECK(rows == 1000); UNSCOPED_INFO("the rest said"); REQUIRE(shown().find(services.counted("ProblemsUnlisted", 5)) != std::string::npos); @@ -1013,7 +980,6 @@ namespace UNSCOPED_INFO("the three"); CHECK(from_lsl == std::string("a no;a nu;llco;")); d.setShown(made.rows); - UNSCOPED_INFO("counted"); CHECK(d.shownMigration == 3); pane->showOrigin("OriginMigration"); LLComboBox* origins = window.find("problems_origin"); @@ -1042,14 +1008,10 @@ namespace UNSCOPED_INFO("not of another"); CHECK_FALSE(out.fixShown("migration")); choose("reads nothing at 0 [SlZeroIndex]"); - UNSCOPED_INFO("offered"); CHECK(out.fixShown("migration")); out.act("fix_migration"); - { - INFO("asked"); - REQUIRE_FALSE(studio.kinds.empty()); - CHECK(studio.kinds.back() == "door:from LSL"); - } + REQUIRE_FALSE(studio.kinds.empty()); + CHECK(studio.kinds.back() == "door:from LSL"); } TEST_CASE_METHOD(alscriptproblemspane_data, "ALScriptProblemsPane: a problem naming no line is listed and chosen at none and marked nowhere", "[ALScriptProblemsPane]") @@ -1060,7 +1022,6 @@ namespace d.problems.push_back({ 3, 0, false, std::string(), "WARN", "the compiler's, at 3" }); d.runtime.push_back({ -1, -1, std::string(), "Stack-Heap Collision", 1 }); const ALScriptProblemsPane::Made made = gather(d); - UNSCOPED_INFO("all three"); REQUIRE(made.rows.size() == size_t(3)); { INFO("at none, first"); @@ -1086,7 +1047,7 @@ namespace { const std::string message = item->getColumn(1)->getValue().asString(); const std::string where = item->getColumn(3)->getValue().asString(); - UNSCOPED_INFO("where: " + message + " " + where); + CAPTURE(message, where); REQUIRE((message == "the compiler's, at 3" ? where == "4" : where.empty())); } choose("the compiler's, nowhere"); diff --git a/indra/newview/tests/alscriptrecompile_test.cpp b/indra/newview/tests/alscriptrecompile_test.cpp index 935afcbbac..fe67d2fabf 100644 --- a/indra/newview/tests/alscriptrecompile_test.cpp +++ b/indra/newview/tests/alscriptrecompile_test.cpp @@ -149,33 +149,28 @@ namespace } }; + // SLua goes up as SLua, and what is known of whether each runs is given. TEST_CASE_METHOD(alscriptrecompile_data, "alscriptrecompile: a prim's scripts and one chosen go up a few at a time each once", "[alscriptrecompile]") { house(); window.runs = { { id(11), false } }; run.recompile({ one(10, "A") }, { { prim, "House" } }, "mono"); - { - INFO("listed"); - REQUIRE(window.listedFor.size() == 1); - CHECK(window.listedFor[0].front().first == prim); - } - UNSCOPED_INFO("running"); + REQUIRE(window.listedFor.size() == 1); + CHECK(window.listedFor[0].front().first == prim); CHECK(run.running()); - UNSCOPED_INFO("four at once"); REQUIRE(window.asked.size() == size_t(Recompile::AT_ONCE)); { INFO("A once, chosen and in its prim"); CHECK(window.asked[0].ref.item == id(10)); CHECK(window.asked[1].ref.item == id(11)); } - UNSCOPED_INFO("for the target"); CHECK(window.asked[0].target == std::string("mono")); UNSCOPED_INFO("the SLua one as it compiles"); CHECK(window.asked[2].target == std::string("auto")); UNSCOPED_INFO("B known stopped, stays so"); CHECK(window.asked[1].running == false); UNSCOPED_INFO("A not known: the save asks"); - REQUIRE_FALSE(window.asked[0].running.has_value()); + CHECK_FALSE(window.asked[0].running.has_value()); for (size_t i = 0; i < 4; ++i) { @@ -185,22 +180,19 @@ namespace REQUIRE(window.asked.size() == size_t(6)); window.asked[4].told(compiled()); UNSCOPED_INFO("not done yet"); - REQUIRE(window.done.empty()); + CHECK(window.done.empty()); window.asked[5].told(compiled()); - UNSCOPED_INFO("done once"); REQUIRE(window.done.size() == size_t(1)); - { - INFO("all compiled"); - CHECK(window.done[0].compiled == 6); - CHECK(window.done[0].failed == 0); - CHECK(window.done[0].target == "mono"); - } - UNSCOPED_INFO("no longer running"); + CHECK(window.done[0].compiled == 6); + CHECK(window.done[0].failed == 0); + CHECK(window.done[0].target == "mono"); CHECK_FALSE(run.running()); UNSCOPED_INFO("each said"); - REQUIRE(window.scripts.size() == size_t(6)); + CHECK(window.scripts.size() == size_t(6)); } + // Changes not saved are said too, and a closed script's result carries + // its rows. TEST_CASE_METHOD(alscriptrecompile_data, "alscriptrecompile: a script being saved is skipped and each result is said in Output", "[alscriptrecompile]") { house(); @@ -210,7 +202,7 @@ namespace run.recompile({}, { { prim, "House" } }, "auto"); UNSCOPED_INFO("B left alone"); CHECK(std::none_of(window.asked.begin(), window.asked.end(), [](const auto& a) { return a.ref.item == id(11); })); - UNSCOPED_INFO("and said"); + UNSCOPED_INFO("B's save on its way said"); CHECK(said("RecompileSkippedSaving", true)); UNSCOPED_INFO("C's unsaved changes said"); CHECK(said("RecompileUnsaved", true)); @@ -228,9 +220,7 @@ namespace } window.asked[4].told(compiled()); // F - UNSCOPED_INFO("compiled said"); CHECK(said("Compiled", false)); - UNSCOPED_INFO("a failure said"); CHECK(said("CompileFailed", true)); UNSCOPED_INFO("one not sent said with why"); CHECK(said("SaveFailed", true)); @@ -245,18 +235,15 @@ namespace { INFO("E is open: its tab says it"); CHECK(window.scripts[3].open); - REQUIRE(window.scripts[3].rows.empty()); + CHECK(window.scripts[3].rows.empty()); } UNSCOPED_INFO("D's why"); CHECK(window.scripts[2].error == "no such object"); const Recompile::Done& done = window.done.at(0); - { - INFO("counted"); - CHECK(done.compiled == 2); - CHECK(done.failed == 2); - CHECK(done.notSent == 1); - CHECK(done.skipped == 1); - } + CHECK(done.compiled == 2); + CHECK(done.failed == 2); + CHECK(done.notSent == 1); + CHECK(done.skipped == 1); } TEST_CASE_METHOD(alscriptrecompile_data, "alscriptrecompile: rowsOf reads a compiler's lines back to the source and its includes", "[alscriptrecompile]") @@ -269,7 +256,6 @@ namespace return ALPreprocessor::Found::Yes; }; const ALPreprocessor::Result expanded = ALPreprocessor::run("#include \"lib.lsl\"\ndefault\n{\nstate_entry() { x; }\n}\n", options); - UNSCOPED_INFO("expanded"); REQUIRE(expanded.problems.empty()); // The lines of the expansion that hold each. S32 entry = -1, second = -1, line = 0; @@ -296,12 +282,11 @@ namespace result.diagnostics.push_back(failed(second + 7, "b again").diagnostics[0]); result.diagnostics.push_back(failed(5000, "somewhere made").diagnostics[0]); const std::vector rows = Recompile::rowsOf(result, "Compiler", "made"); - UNSCOPED_INFO("three"); REQUIRE(rows.size() == size_t(3)); { INFO("the script's own line"); CHECK(rows[0].line == 3); - REQUIRE(rows[0].file.empty()); + CHECK(rows[0].file.empty()); CHECK(rows[0].origin == "Compiler"); } { @@ -318,10 +303,10 @@ namespace // Nothing expanded: as the compiler said it. const std::vector plain = Recompile::rowsOf(failed(4, "as is"), "Compiler", "made"); { - INFO("as said"); + INFO("as the compiler said it"); REQUIRE(plain.size() == 1); CHECK(plain[0].line == 4); - REQUIRE(plain[0].file.empty()); + CHECK(plain[0].file.empty()); } } @@ -337,8 +322,8 @@ namespace window.asked[0].told(compiled()); { INFO("the old one's answer passed over"); - REQUIRE(window.scripts.empty()); - REQUIRE(window.done.empty()); + CHECK(window.scripts.empty()); + CHECK(window.done.empty()); } window.asked[first].told(compiled()); { @@ -368,7 +353,6 @@ namespace return ALPreprocessor::Found::Yes; }; const ALPreprocessor::Result expanded = ALPreprocessor::run("#include \"lib.lsl\"\ndefault\n{\nstate_entry() { x; }\n}\n", options); - UNSCOPED_INFO("expanded"); REQUIRE(expanded.problems.empty()); S32 entry = -1, second = -1, line = 0; for (size_t at = 0, next; at < expanded.text.size(); at = next + 1, ++line) @@ -408,7 +392,6 @@ namespace result.diagnostics.push_back(one); } const std::vector rows = Recompile::rowsOf(result, "Compiler", "made"); - UNSCOPED_INFO("three"); REQUIRE(rows.size() == size_t(3)); { INFO("the line, the source's"); @@ -423,7 +406,7 @@ namespace { INFO("no line named, none"); CHECK(rows[2].line == -1); - REQUIRE(rows[2].file.empty()); + CHECK(rows[2].file.empty()); CHECK(rows[2].message == "Math Error"); } diff --git a/indra/newview/tests/alscriptreferencespane_test.cpp b/indra/newview/tests/alscriptreferencespane_test.cpp index 638bbae231..46e7f84b33 100644 --- a/indra/newview/tests/alscriptreferencespane_test.cpp +++ b/indra/newview/tests/alscriptreferencespane_test.cpp @@ -151,40 +151,33 @@ namespace { ALScriptReferencesPane* refs = pane(); refs->show(found()); - UNSCOPED_INFO("the head"); CHECK(head() == std::string("3 occurrences of count in 2 scripts.")); UNSCOPED_INFO("the window told"); CHECK(window.pane().counts == 1); - UNSCOPED_INFO("each place"); CHECK(lines() == joined(Names{ "A 1:9", "A 2:5", "B 1:9" })); const std::vector rows = refs->list()->getAllData(); - UNSCOPED_INFO("the declaration"); CHECK(cell(rows[0], 2) == std::string("declaration")); UNSCOPED_INFO("in the script it is declared in only"); CHECK(cell(rows[2], 2) == std::string()); UNSCOPED_INFO("its text"); CHECK(cell(rows[1], 3) == std::string("x = count;")); UNSCOPED_INFO("kept"); - REQUIRE(refs->found().places.size() == size_t(3)); + CHECK(refs->found().places.size() == size_t(3)); Found twice = found(); twice.places.push_back(place("", 0, 20, "integer count; count")); refs->show(twice); UNSCOPED_INFO("on the declaration's line, not it"); - REQUIRE(cell(refs->list()->getAllData()[3], 2).empty()); + CHECK(cell(refs->list()->getAllData()[3], 2).empty()); Found in_b = found(); in_b.home = B; refs->show(in_b); UNSCOPED_INFO("declared in B: A's first line not it"); - REQUIRE(cell(refs->list()->getAllData()[0], 2).empty()); + CHECK(cell(refs->list()->getAllData()[0], 2).empty()); refs->forget(); - UNSCOPED_INFO("nothing"); CHECK(head() == std::string("Nothing to show yet. Put the caret on a name and choose Find References.")); - { - INFO("no rows"); - REQUIRE(refs->list()->getItemCount() == 0); - REQUIRE(refs->found().from.empty()); - } + CHECK(refs->list()->getItemCount() == 0); + CHECK(refs->found().from.empty()); UNSCOPED_INFO("told each time"); CHECK(window.pane().counts == 4); } @@ -258,7 +251,7 @@ namespace refs->show(found()); refs->choose(false); UNSCOPED_INFO("nothing chosen, nothing gone to"); - REQUIRE(window.pane().chosen.empty()); + CHECK(window.pane().chosen.empty()); // A row is known by its place's number, counted from one. refs->list()->selectByValue(LLSD(3)); refs->list()->onCommit(); @@ -276,18 +269,12 @@ namespace // The list's keys: return goes to the place chosen, to type there, // escape back to the script; and the rows copy. - { - INFO("return"); - CHECK(refs->list()->handleKeyHere(KEY_RETURN, MASK_NONE)); - CHECK(window.pane().chosen.back() == "a2||0 editor"); - } + CHECK(refs->list()->handleKeyHere(KEY_RETURN, MASK_NONE)); + CHECK(window.pane().chosen.back() == "a2||0 editor"); const size_t gone = window.pane().chosen.size(); - { - INFO("escape"); - CHECK(refs->list()->handleKeyHere(KEY_ESCAPE, MASK_NONE)); - REQUIRE(window.services().reveals.back()); - REQUIRE(window.pane().chosen.size() == gone); - } + CHECK(refs->list()->handleKeyHere(KEY_ESCAPE, MASK_NONE)); + CHECK(window.services().reveals.back()); + CHECK(window.pane().chosen.size() == gone); UNSCOPED_INFO("copied"); CHECK(refs->list()->handleKeyHere('C', MASK_CONTROL)); } @@ -301,7 +288,6 @@ namespace ALPaneList* list = refs->list(); list->sortByColumn("text", true); list->updateSort(); - UNSCOPED_INFO("by text"); CHECK(lines() == joined(Names{ "A 3:1", "B 1:9", "A 1:9", "A 2:5" })); list->sortByColumn("where", false); list->updateSort(); @@ -334,7 +320,7 @@ namespace // again until the frame is drawn. a.editor->replaceAll({ { ALTextRange(ALTextPos(0, 8), ALTextPos(0, 13)), "total" } }); UNSCOPED_INFO("one place fewer"); - REQUIRE(refs->found().places.size() == size_t(2)); + CHECK(refs->found().places.size() == size_t(2)); window.pane().chosen.clear(); refs->choose(false); UNSCOPED_INFO("A's second, not what took its index"); @@ -353,7 +339,6 @@ namespace made = kept; applied = true; }); - UNSCOPED_INFO("previewing"); CHECK(refs->previewing()); UNSCOPED_INFO("what it will do over them"); CHECK(head() == std::string("Rename 3 places")); @@ -438,7 +423,7 @@ namespace CHECK_FALSE(changes->getVisible()); { INFO("each row as found"); - REQUIRE(cell(refs->list()->getAllData()[0], 3) == "integer count;"); + CHECK(cell(refs->list()->getAllData()[0], 3) == "integer count;"); CHECK(refs->list()->getAllData()[0]->getColumn(2)->getValue().asString() != "1"); } } @@ -483,7 +468,7 @@ namespace CHECK(lines() == joined(Names{ "A 2:9", "A 3:5", "B 1:9" })); { INFO("the same rows"); - REQUIRE(refs->list()->rowWithKey("2") == second); + CHECK(refs->list()->rowWithKey("2") == second); CHECK(refs->list()->rowWithKey("3") == in_b); } UNSCOPED_INFO("one not moved, its cells as they were"); @@ -502,9 +487,8 @@ namespace refs->show(many); UNSCOPED_INFO("a thousand and one row saying the rest"); CHECK(refs->list()->getItemCount() == 1001); - UNSCOPED_INFO("the rest"); CHECK(cell(refs->list()->getAllData().back(), 3) == window.services().counted("ReferencesUnlisted", 3)); UNSCOPED_INFO("all of them counted over the list"); - REQUIRE(head().find("1003") != std::string::npos); + CHECK(head().find("1003") != std::string::npos); } } diff --git a/indra/newview/tests/alscriptregionusage_test.cpp b/indra/newview/tests/alscriptregionusage_test.cpp index 30e38450eb..5e1c3d1616 100644 --- a/indra/newview/tests/alscriptregionusage_test.cpp +++ b/indra/newview/tests/alscriptregionusage_test.cpp @@ -109,7 +109,6 @@ namespace const LLDate when(1.8e9); Usage::usages_t read; Usage::readAttachments(attachments, when, read); - UNSCOPED_INFO("both"); REQUIRE(read.size() == 2U); { INFO("the chest's"); @@ -167,13 +166,10 @@ namespace answer["attachments"][0]["objects"].append(object(id(1), 65536, 2)); answer["attachments"][0]["objects"].append(object(id(2), 16384, 0)); attachmentAsks[0](answer); - { - INFO("heard"); - CHECK(heard == 1); - REQUIRE(usage.usageOf(id(1))); - REQUIRE(usage.usageOf(id(1))->urls == 2); - CHECK(usage.usageOf(id(2))->memory == 16384); - } + CHECK(heard == 1); + REQUIRE(usage.usageOf(id(1))); + REQUIRE(usage.usageOf(id(1))->urls == 2); + CHECK(usage.usageOf(id(2))->memory == 16384); LLSD parcel; parcel["parcels"][0]["objects"].append(object(id(3), 131072, 0)); parcel["parcels"][0]["objects"].append(object(id(4), 65536, 0)); @@ -191,7 +187,6 @@ namespace kinds[id(3)] = Kind::Land; kinds[id(4)] = Kind::Land; usage.ask({ id(3) }, 100.0); - UNSCOPED_INFO("asked"); REQUIRE(landAsks.size() == 1U); usage.ask({ id(3) }, 130.0); UNSCOPED_INFO("not again within the minute"); @@ -276,17 +271,13 @@ namespace times[id(5)] = 2.0f; const S32 before = heard; timeAsks[0].second(times); - UNSCOPED_INFO("heard"); CHECK(heard == before + 1); const ALScriptRegionUsage::Usage* one = usage.usageOf(id(1)); - { - INFO("its time and its memory"); - REQUIRE(one); - REQUIRE(one->hasTime()); - REQUIRE(one->time == 0.125f); - REQUIRE(one->hasMemory()); - CHECK(one->memory == 65536); - } + REQUIRE(one); + REQUIRE(one->hasTime()); + REQUIRE(one->time == 0.125f); + REQUIRE(one->hasMemory()); + CHECK(one->memory == 65536); { INFO("an object not asked about kept too, time alone"); REQUIRE(usage.usageOf(id(5))); diff --git a/indra/newview/tests/alscriptsaveflow_test.cpp b/indra/newview/tests/alscriptsaveflow_test.cpp index fd01f967f6..f02c827727 100644 --- a/indra/newview/tests/alscriptsaveflow_test.cpp +++ b/indra/newview/tests/alscriptsaveflow_test.cpp @@ -74,12 +74,10 @@ namespace TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: a Save asked during a send runs once after it however often it was asked", "[ALScriptSaveFlow]") { - UNSCOPED_INFO("goes"); CHECK(flow.ask(false, false) == Flow::Start::Go); UNSCOPED_INFO("straight up"); CHECK(flow.route(script(1)) == Route::Send); send(); - UNSCOPED_INFO("sending"); CHECK(flow.sending()); UNSCOPED_INFO("asked again: queued"); CHECK(flow.ask(false, false) == Flow::Start::Queued); @@ -92,7 +90,6 @@ namespace CHECK(landing.markSaved); CHECK_FALSE(landing.stopped); } - UNSCOPED_INFO("nothing on its way"); CHECK_FALSE(flow.underway()); UNSCOPED_INFO("the one asked for meanwhile"); CHECK(flow.takeAgain()); @@ -110,7 +107,6 @@ namespace { UNSCOPED_INFO("the analyzers' errors stop it"); CHECK(flow.route(expanded(1, true, true, 2)) == Route::StoppedByAnalyzers); - UNSCOPED_INFO("and nothing waits"); CHECK_FALSE(flow.underway()); flow.letPast(1); UNSCOPED_INFO("asked again: past the errors, on to the preprocessor"); @@ -122,7 +118,6 @@ namespace UNSCOPED_INFO("a changed text asks afresh"); CHECK(flow.route(expanded(2, true, true, 2)) == Route::StoppedByAnalyzers); flow.letPast(2); - UNSCOPED_INFO("let past"); CHECK(flow.route(expanded(2, true, true, 2)) == Route::Preprocess); flow.preprocessed(run(2, 2)); send(); @@ -135,7 +130,6 @@ namespace { UNSCOPED_INFO("not checked yet"); CHECK(flow.route(script(4, true, false)) == Route::Check); - UNSCOPED_INFO("waiting"); CHECK(flow.stage() == Flow::Stage::Checking); UNSCOPED_INFO("the check came: asked again"); CHECK(flow.checked()); @@ -147,17 +141,14 @@ namespace TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: a text changed while preprocessed starts over and a running pass is joined", "[ALScriptSaveFlow]") { - UNSCOPED_INFO("run"); CHECK(flow.route(expanded(1)) == Route::Preprocess); UNSCOPED_INFO("typed in meanwhile: from the start"); CHECK(flow.preprocessed(run(1, 2)) == Flow::Landed::MovedOn); - UNSCOPED_INFO("nothing on its way"); CHECK_FALSE(flow.underway()); UNSCOPED_INFO("a view's run, nobody saving"); CHECK(flow.preprocessed(run(2, 2)) == Flow::Landed::NotForSave); UNSCOPED_INFO("a run on its way already: joined"); CHECK(flow.route(expanded(2, false, true, 0, true)) == Route::JoinPreprocessor); - UNSCOPED_INFO("waiting on it"); CHECK(flow.stage() == Flow::Stage::Preprocessing); UNSCOPED_INFO("and sent when it comes"); CHECK(flow.preprocessed(run(2, 2)) == Flow::Landed::Send); @@ -212,39 +203,29 @@ namespace TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: an external editor's save skips every check and out of reach nothing goes", "[ALScriptSaveFlow]") { flow.fromExternal(3); - UNSCOPED_INFO("the editor's"); CHECK(flow.external()); UNSCOPED_INFO("past the errors"); CHECK(flow.route(expanded(3, true, true, 5)) == Route::Preprocess); UNSCOPED_INFO("and sent"); CHECK(flow.preprocessed(run(3, 3)) == Flow::Landed::Send); flow.endExternal(); - UNSCOPED_INFO("ended"); CHECK_FALSE(flow.external()); flow.setCloseAfter(true); - { - INFO("out of reach"); - CHECK(flow.ask(true, false) == Flow::Start::OutOfReach); - CHECK_FALSE(flow.closeAfter()); - } + CHECK(flow.ask(true, false) == Flow::Start::OutOfReach); + CHECK_FALSE(flow.closeAfter()); flow.setCloseAfter(true); - { - INFO("detached"); - CHECK(flow.ask(false, true) == Flow::Start::Detached); - CHECK_FALSE(flow.closeAfter()); - } + CHECK(flow.ask(false, true) == Flow::Start::Detached); + CHECK_FALSE(flow.closeAfter()); } TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: files and notecards go as they stand and errors stop only a held save", "[ALScriptSaveFlow]") { Flow::Tab file = expanded(1, true, false, 3); file.file = true; - UNSCOPED_INFO("a file"); CHECK(flow.route(file) == Route::File); Flow::Tab card = expanded(1, true, false, 3); card.notecard = true; - UNSCOPED_INFO("a notecard"); CHECK(flow.route(card) == Route::Notecard); UNSCOPED_INFO("not held: sent over errors"); CHECK(flow.route(script(1, false, true, 3)) == Route::Send); @@ -254,7 +235,6 @@ namespace TEST_CASE_METHOD(alscriptsaveflow_data, "ALScriptSaveFlow: fixOnce is true once a save and again for the next", "[ALScriptSaveFlow]") { - UNSCOPED_INFO("once"); CHECK(flow.fixOnce()); flow.route(script(1, true, false)); flow.checked(); @@ -278,23 +258,17 @@ namespace LLUUID item; item.generate(); flow.sent(at, ALSourceMap(), { item }); - UNSCOPED_INFO("the save point"); CHECK(flow.savePoint().serial == 7); - UNSCOPED_INFO("the map"); - REQUIRE(flow.sentMap().has_value()); - { - INFO("the items"); - REQUIRE(flow.sentItems().size() == 1); - CHECK(flow.sentItems().front() == item); - } + CHECK(flow.sentMap().has_value()); + REQUIRE(flow.sentItems().size() == 1); + CHECK(flow.sentItems().front() == item); flow.forgetSentItems(); UNSCOPED_INFO("let go of"); - REQUIRE(flow.sentItems().empty()); + CHECK(flow.sentItems().empty()); compile(true, true); UNSCOPED_INFO("the map stays after, for what the script says as it runs"); - REQUIRE(flow.sentMap().has_value()); + CHECK(flow.sentMap().has_value()); flow.setWarnWeightFor(9); - UNSCOPED_INFO("the weight to warn of"); CHECK(flow.warnWeightFor() == 9); } diff --git a/indra/newview/tests/alscriptsearchpane_test.cpp b/indra/newview/tests/alscriptsearchpane_test.cpp index 4c81e61afc..c79d345d47 100644 --- a/indra/newview/tests/alscriptsearchpane_test.cpp +++ b/indra/newview/tests/alscriptsearchpane_test.cpp @@ -240,14 +240,13 @@ namespace } { INFO("escape"); - CHECK(out.list()->handleKeyHere(KEY_ESCAPE, MASK_NONE)); - REQUIRE(services.reveals.back()); + REQUIRE(out.list()->handleKeyHere(KEY_ESCAPE, MASK_NONE)); + CHECK(services.reveals.back()); } UNSCOPED_INFO("copied"); CHECK(out.list()->handleKeyHere('C', MASK_CONTROL)); UNSCOPED_INFO("the line as listed, trimmed"); CHECK(out.search().found()[0].lines[1] == std::string("timer two")); - UNSCOPED_INFO("counted"); CHECK(counted() == services.words("SearchCount", { { "[HITS]", services.counted("Matches", 2) }, { "[FILES]", services.counted("Files", 1) }, { "[SHOWN]", "2000" } })); @@ -284,7 +283,6 @@ namespace // No object in hand: none guessed at. studio.inHand.setNull(); find("timer", "object"); - UNSCOPED_INFO("said"); CHECK(counted() == services.words("SearchNoObject")); } @@ -300,7 +298,7 @@ namespace REQUIRE(studio.fetches.size() == size_t(2)); out.fetched(studio.fetches[0].generation, "Thing", away, "away.lsl", std::make_shared("timer\nother\n"), false); UNSCOPED_INFO("the first search's answer dropped"); - REQUIRE(out.search().found().empty()); + CHECK(out.search().found().empty()); UNSCOPED_INFO("still waiting on the second's"); CHECK(out.search().pending() == 1); out.fetched(studio.fetches[1].generation, "Thing", away, "away.lsl", std::make_shared("timer\nother\n"), false); @@ -366,7 +364,7 @@ namespace out.fetched(studio.fetches[0].generation, "Thing", away, "away.lsl", std::make_shared("timer\n"), false); out.fetched(studio.fetches[1].generation, "Thing", card, "card", std::make_shared("a timer\n"), true); UNSCOPED_INFO("three found"); - REQUIRE(out.search().found().size() == size_t(3)); + CHECK(out.search().found().size() == size_t(3)); services.whenOpened = [this, card](const ALScriptRef& ref, const std::string&) { Doc& opened = ref == card ? doc("card", "a timer\n", true) : doc("away", "timer\n"); opened.ref = ref; @@ -402,8 +400,7 @@ namespace CHECK(notecard->pendingEdits[0].now == "clock"); } UNSCOPED_INFO("and each is made"); - REQUIRE(studio.applied.size() == size_t(2)); - UNSCOPED_INFO("said"); + CHECK(studio.applied.size() == size_t(2)); CHECK(services.reports.back().text == services.words("SearchReplaced", { { "[PLACES]", services.counted("Places", 3) }, { "[SCRIPTS]", services.counted("ScriptsNotecards", 3) } }) + "; " + @@ -483,9 +480,9 @@ namespace studio.includes["gate.lsl"] = lib; find("timer"); UNSCOPED_INFO("alone: the script's own"); - REQUIRE(out.search().found().size() == size_t(1)); + CHECK(out.search().found().size() == size_t(1)); UNSCOPED_INFO("nothing asked of what it includes"); - REQUIRE(studio.askedIncludes.empty()); + CHECK(studio.askedIncludes.empty()); out.bar()->setValue("includes", "yes"); const S32 before = studio.apart; find("timer"); @@ -501,8 +498,8 @@ namespace CHECK(found.file == std::string("disk:/scripts/lib.lsl")); { INFO("said to be included"); - REQUIRE(found.where.find(services.words("SearchIncluded")) != std::string::npos); - REQUIRE(found.where.find("lib.lsl") != std::string::npos); + CHECK(found.where.find(services.words("SearchIncluded")) != std::string::npos); + CHECK(found.where.find("lib.lsl") != std::string::npos); } UNSCOPED_INFO("a row for its place"); CHECK(out.list()->getItemCount() == 2); @@ -526,7 +523,7 @@ namespace studio.holdListing = true; find("timer", "object"); UNSCOPED_INFO("nothing fetched while its prims are asked"); - REQUIRE(studio.fetches.empty()); + CHECK(studio.fetches.empty()); UNSCOPED_INFO("waited for"); CHECK(out.search().pending() == 1); studio.heldListing(); @@ -537,7 +534,7 @@ namespace UNSCOPED_INFO("none to wait for"); CHECK(out.search().pending() == 0); UNSCOPED_INFO("one read"); - REQUIRE(out.search().found().size() == size_t(1)); + CHECK(out.search().found().size() == size_t(1)); const std::string said = services.words("SearchCount", { { "[HITS]", services.counted("Matches", 1) }, { "[FILES]", services.counted("Files", 1) }, { "[SHOWN]", "2000" } }); @@ -555,10 +552,10 @@ namespace find("other", "object"); first(); UNSCOPED_INFO("the earlier listing dropped"); - REQUIRE(studio.fetches.empty()); + CHECK(studio.fetches.empty()); studio.heldListing(); UNSCOPED_INFO("the later one searched"); - REQUIRE(studio.fetches.size() == size_t(2)); + CHECK(studio.fetches.size() == size_t(2)); } TEST_CASE_METHOD(alscriptsearchpane_data, "ALScriptSearchPane: Sources keeps a script by its text and drops the oldest past the limit", "[ALScriptSearchPane]") @@ -575,19 +572,19 @@ namespace { INFO("found by its text"); REQUIRE(kept); - REQUIRE(*kept->text == "timer"); + CHECK(*kept->text == "timer"); CHECK(kept->name == "one.lsl"); } { INFO("not for another"); - REQUIRE_FALSE(sources.find(one, LLUUID::generateNewID())); - REQUIRE_FALSE(sources.find(one, LLUUID::null)); + CHECK_FALSE(sources.find(one, LLUUID::generateNewID())); + CHECK_FALSE(sources.find(one, LLUUID::null)); } sources.keep(one, LLUUID::generateNewID(), { std::make_shared("saved since"), "one.lsl", false }); { INFO("saved since: in its place"); - REQUIRE_FALSE(sources.find(one, asset)); - REQUIRE(sources.bytes() == std::string("saved since").size()); + CHECK_FALSE(sources.find(one, asset)); + CHECK(sources.bytes() == std::string("saved since").size()); } sources.clear(); @@ -609,9 +606,9 @@ namespace CHECK(sources.bytes() <= ALScriptSearch::Sources::MOST); { INFO("the one used longest ago gone"); - REQUIRE_FALSE(sources.find(refs[1], assets[1])); - REQUIRE(sources.find(refs[0], assets[0])); - REQUIRE(sources.find(refs[2], assets[2])); + CHECK_FALSE(sources.find(refs[1], assets[1])); + CHECK(sources.find(refs[0], assets[0])); + CHECK(sources.find(refs[2], assets[2])); } sources.clear(); } @@ -622,13 +619,12 @@ namespace const ALScriptRef away(LLUUID::generateNewID(), LLUUID::generateNewID()); studio.objects = { { LLUUID::generateNewID(), "Thing", { away } } }; find("timer", "listed"); - UNSCOPED_INFO("fetched"); REQUIRE(studio.fetches.size() == size_t(1)); out.fetched(studio.fetches[0].generation, "Thing", away, "away.lsl", std::make_shared("timer\n"), false); { INFO("sought apart"); CHECK(studio.apart == 1); - REQUIRE(out.search().found().size() == 1); + CHECK(out.search().found().size() == 1); CHECK(out.search().pending() == 0); } const S32 before = studio.apart; diff --git a/indra/newview/tests/alscriptsnippets_test.cpp b/indra/newview/tests/alscriptsnippets_test.cpp index b699988f23..5fde82db5a 100644 --- a/indra/newview/tests/alscriptsnippets_test.cpp +++ b/indra/newview/tests/alscriptsnippets_test.cpp @@ -112,10 +112,8 @@ namespace CHECK(ALScriptSnippets::readFrom(file, false, none)); REQUIRE(none.empty()); } - UNSCOPED_INFO("written"); CHECK(ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"$1\");"), snippet("half", "") })); std::vector back; - UNSCOPED_INFO("read"); REQUIRE(ALScriptSnippets::readFrom(file, false, back)); { INFO("the one with a body"); @@ -134,7 +132,6 @@ namespace out << broken; } std::vector held; - UNSCOPED_INFO("it does not read"); CHECK_FALSE(ALScriptSnippets::readFrom(file, false, held)); UNSCOPED_INFO("written all the same"); CHECK(ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"hi\");") })); @@ -155,7 +152,6 @@ namespace llofstream out(file, std::ios::binary); out << "again"; } - UNSCOPED_INFO("written"); CHECK(ALScriptSnippets::writeTo(file, { snippet("say", "x") })); UNSCOPED_INFO("the first kept still"); CHECK(read(file + ".unreadable") == broken); @@ -166,7 +162,6 @@ namespace TEST_CASE_METHOD(alscriptsnippets_data, "alscriptsnippets: a write replaces the file whole and a failed one leaves it as it was", "[alscriptsnippets]") { const std::string file = folder + "/lsl.xml"; - UNSCOPED_INFO("written"); CHECK(ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"one\");") })); const std::string first = read(file); UNSCOPED_INFO("written again, over it"); @@ -174,7 +169,7 @@ namespace { INFO("replaced"); CHECK(read(file) != first); - REQUIRE(read(file).find("two") != std::string::npos); + CHECK(read(file).find("two") != std::string::npos); } UNSCOPED_INFO("and nothing half-written beside it"); CHECK_FALSE(LLFile::isfile(ALFileWrite::besideOf(file))); @@ -195,7 +190,6 @@ namespace const bool wrote = ALScriptSnippets::writeTo(file, { snippet("say", "llSay(0, \"three\");") }); std::filesystem::permissions(fsyspath(file), std::filesystem::perms::owner_read | std::filesystem::perms::owner_write, std::filesystem::perm_options::replace, ec); - UNSCOPED_INFO("not written"); CHECK_FALSE(wrote); UNSCOPED_INFO("and the file as it was"); CHECK(read(file) == written); @@ -211,23 +205,16 @@ namespace const std::string text = ALScriptSnippets::notecardText({ say, builtin, snippet("", "no name") }, { snippet("print", "print(${1})") }); std::vector lsl; std::vector slua; - UNSCOPED_INFO("read"); REQUIRE(ALScriptSnippets::readNotecard(text, false, lsl, slua)); UNSCOPED_INFO("the LSL one, and not the viewer's or the unnamed"); REQUIRE(lsl.size() == 1U); - UNSCOPED_INFO("its name"); CHECK(lsl[0].name == std::string("say")); - UNSCOPED_INFO("its prefix"); CHECK(lsl[0].prefix == std::string("say")); - UNSCOPED_INFO("its detail"); CHECK(lsl[0].detail == std::string("Say something")); - UNSCOPED_INFO("its body"); CHECK(lsl[0].body == say.body); - UNSCOPED_INFO("not the viewer's"); CHECK_FALSE(lsl[0].builtin); UNSCOPED_INFO("the SLua one in SLua's"); REQUIRE(slua.size() == 1U); - UNSCOPED_INFO("its body"); CHECK(slua[0].body == std::string("print(${1})")); // Written by hand or by an older viewer: no language, and a key @@ -236,7 +223,6 @@ namespace "colourred"; lsl.clear(); slua.clear(); - UNSCOPED_INFO("read"); CHECK(ALScriptSnippets::readNotecard(plain, true, lsl, slua)); { INFO("into the language shown"); @@ -253,7 +239,7 @@ namespace for (const char* text : { "Dear diary, today I scripted a door.", "namex", "titlex", "", "" }) { - UNSCOPED_INFO(std::string("not snippets: ") + text); + CAPTURE(text); REQUIRE_FALSE(ALScriptSnippets::readNotecard(text, false, lsl, slua)); { INFO("and nothing added"); @@ -275,13 +261,9 @@ namespace CHECK(merged.renamed == 1U); UNSCOPED_INFO("one the same"); CHECK(merged.skipped == 1U); - UNSCOPED_INFO("four now"); REQUIRE(own.size() == 4U); - UNSCOPED_INFO("numbered"); CHECK(own[2].name == std::string("say (2)")); - UNSCOPED_INFO("with its body"); CHECK(own[2].body == std::string("llSay(0, \"b\");")); - UNSCOPED_INFO("and the new one"); CHECK(own[3].name == std::string("new")); // The same notecard again brings nothing in. @@ -292,7 +274,6 @@ namespace CHECK(merged.renamed == 0); CHECK(merged.skipped == 3); } - UNSCOPED_INFO("still four"); REQUIRE(own.size() == 4U); // A third body takes the next number free. @@ -308,7 +289,6 @@ namespace "nameloopbodyforlanguageslua" "namebannerbodyx" ""; - UNSCOPED_INFO("followed"); CHECK(ALScriptSnippets::follow(text)); const std::vector& lsl = ALScriptSnippets::followed(false); const std::vector& slua = ALScriptSnippets::followed(true); @@ -340,10 +320,8 @@ namespace // Never written where the scripter's own are, nor carried by their // notecard; copied in, one's own. const std::string file = folder + "/lsl.xml"; - UNSCOPED_INFO("written"); CHECK(ALScriptSnippets::writeTo(file, { snippet("mine", "y"), lsl[0] })); std::vector back; - UNSCOPED_INFO("read"); REQUIRE(ALScriptSnippets::readFrom(file, false, back)); { INFO("one's own alone"); @@ -351,7 +329,7 @@ namespace CHECK(back[0].name == "mine"); } UNSCOPED_INFO("not on one's notecard"); - REQUIRE(ALScriptSnippets::notecardText(lsl, {}).find("banner") == std::string::npos); + CHECK(ALScriptSnippets::notecardText(lsl, {}).find("banner") == std::string::npos); std::vector own; ALScriptSnippets::merge(own, { lsl[1] }); { @@ -374,23 +352,21 @@ namespace for (const char* language : { "lsl.xml", "slua.xml" }) { const std::string file = std::string(LLUI_TEST_APP_DIR) + "/app_settings/snippets/" + language; + CAPTURE(file); std::vector shipped; - { - INFO(std::string("read: ") + file); - REQUIRE(ALScriptSnippets::readFrom(file, true, shipped)); - REQUIRE_FALSE(shipped.empty()); - } + REQUIRE(ALScriptSnippets::readFrom(file, true, shipped)); + REQUIRE_FALSE(shipped.empty()); for (const ALScriptSnippets::Snippet& one : shipped) { - const std::string named = std::string(language) + ", " + one.name; + CAPTURE(one.name); const ALSnippetSession::Expansion expanded = ALSnippetSession::expand(one.body, ALTextPos(0, 0), std::string()); const ALTextDocument text(expanded.text); - UNSCOPED_INFO(named + ": no placeholder left in " + expanded.text); + UNSCOPED_INFO("no placeholder left in " << expanded.text); REQUIRE(expanded.text.find("${") == std::string::npos); for (size_t i = 0; i < expanded.stops.size(); ++i) { const std::string held = text.text(expanded.stops[i]); - UNSCOPED_INFO(named + ": stop " + std::to_string(i + 1) + " holds the whole of its text, not \"" + held + "\""); + UNSCOPED_INFO("stop " << i + 1 << " holds the whole of its text, not \"" << held << "\""); REQUIRE(whole(held)); } } diff --git a/indra/newview/tests/alscriptstudioaccount_test.cpp b/indra/newview/tests/alscriptstudioaccount_test.cpp index 84521e3ad8..ac0b930104 100644 --- a/indra/newview/tests/alscriptstudioaccount_test.cpp +++ b/indra/newview/tests/alscriptstudioaccount_test.cpp @@ -31,6 +31,8 @@ namespace { + // The account's own is taken out of a state written whole, the shape and switches left shared; + // a key it no longer has is taken out of the account's too. TEST_CASE("alscriptstudioaccount: split takes the account's own out of the state and drops what it lost", "[alscriptstudioaccount]") { LLSD state; @@ -63,6 +65,8 @@ namespace REQUIRE_FALSE(mine.has("windows")); } + // Read: the account's own over the shared where it has kept any, a key it has not taken out; + // the shared as it was where it has kept none. TEST_CASE("alscriptstudioaccount: merged lays the account's own over the shared once it has kept any", "[alscriptstudioaccount]") { LLSD shared; diff --git a/indra/newview/tests/alscriptstudiocaret_test.cpp b/indra/newview/tests/alscriptstudiocaret_test.cpp index f2f91fb4e5..0c8de212b1 100644 --- a/indra/newview/tests/alscriptstudiocaret_test.cpp +++ b/indra/newview/tests/alscriptstudiocaret_test.cpp @@ -204,11 +204,10 @@ namespace ALScriptStudioCaret& caret = make(); Doc& doc = tab("a"); const U32 v = ask(doc, ALEditorCommand::GoToDefinition); - UNSCOPED_INFO("asked"); CHECK(joined(studio.asked) == std::string("references 0:8")); { INFO("remembered"); - REQUIRE(doc.caret->symbolCommand == ALEditorCommand::GoToDefinition); + CHECK(doc.caret->symbolCommand == ALEditorCommand::GoToDefinition); CHECK(doc.caret->symbolVersion == v); } caret.answered(doc, references(v + 1), ALTextPos(0, 8)); @@ -216,7 +215,6 @@ namespace UNSCOPED_INFO("of another text or place: nothing"); REQUIRE(studio.said.empty()); caret.answered(doc, references(v), ALTextPos(0, 8)); - UNSCOPED_INFO("gone"); CHECK(joined(studio.said) == std::string("go a 0:8-0:13")); UNSCOPED_INFO("a jump noted, for Back"); CHECK(navigation->unit.places(false) == size_t(1)); @@ -240,17 +238,13 @@ namespace none.version = v; none.understood = true; caret.answered(doc, none, ALTextPos(0, 8)); - UNSCOPED_INFO("nothing known of it"); CHECK(services.statuses.back() == std::string("NothingKnown [NAME]=count")); - UNSCOPED_INFO("not a failure"); - REQUIRE_FALSE(services.statusFailures.back()); + CHECK_FALSE(services.statusFailures.back()); ask(doc, ALEditorCommand::FindReferences); none.understood = false; caret.answered(doc, none, ALTextPos(0, 8)); - UNSCOPED_INFO("nothing read"); CHECK(services.statuses.back() == std::string("NothingKnownBroken [NAME]=count")); - UNSCOPED_INFO("a failure"); - REQUIRE(services.statusFailures.back()); + CHECK(services.statusFailures.back()); } TEST_CASE_METHOD(alscriptstudiocaret_data, "alscriptstudiocaret: a language word shows its reference unless the script defines it", "[alscriptstudiocaret]") @@ -263,7 +257,6 @@ namespace result.version = v; result.understood = true; caret.answered(doc, result, ALTextPos(1, 37)); - UNSCOPED_INFO("the reference"); CHECK(joined(studio.said) == std::string("reference llSay")); caret.ask(doc, ALEditorCommand::FindReferences, ALTextRange(ALTextPos(1, 37), ALTextPos(1, 42))); caret.answered(doc, result, ALTextPos(1, 37)); @@ -305,7 +298,6 @@ namespace doc.expanded.version = v; ALScriptAnalysis::Result result = references(v); caret.answered(doc, result, ALTextPos(0, 8)); - UNSCOPED_INFO("opened in the include"); CHECK(joined(studio.said) == std::string("open disk:/inc.lsl inc.lsl 4:8+5")); UNSCOPED_INFO("a jump noted"); CHECK(navigation->unit.places(false) == size_t(1)); @@ -313,7 +305,6 @@ namespace ask(doc, ALEditorCommand::FindReferences); result.references.references = { span(0, 8, 5), span(2, 26, 5), span(7, 0, 5) }; caret.answered(doc, result, ALTextPos(0, 8)); - UNSCOPED_INFO("the lookup started"); CHECK(started(doc) == "find in a declared disk:/inc.lsl@4 v" + std::to_string(v)); UNSCOPED_INFO("the places that map"); REQUIRE(doc.lookup->places.size() == size_t(2)); @@ -321,15 +312,15 @@ namespace { INFO("the include's, as held"); REQUIRE(included); - REQUIRE(included->fileName == "inc.lsl"); - REQUIRE(included->text == "integer count; // held"); + CHECK(included->fileName == "inc.lsl"); + CHECK(included->text == "integer count; // held"); CHECK(included->at == 6); } const Doc::Place* own = placeIn(doc, std::string()); { INFO("the script's own, as typed"); REQUIRE(own); - REQUIRE(own->span.line == 1); + CHECK(own->span.line == 1); CHECK(own->at == 26); } studio.held.clear(); @@ -339,12 +330,11 @@ namespace { INFO("the include not held: the expansion's line"); REQUIRE(included); - REQUIRE(included->text == "integer count;"); + CHECK(included->text == "integer count;"); CHECK(included->at == -1); } UNSCOPED_INFO("where the include has it"); CHECK(included->span.line == 4); - UNSCOPED_INFO("to rename"); CHECK(started(doc).find("rename in a") == 0); doc.expanded.version = v + 7; @@ -378,7 +368,6 @@ namespace doc.editor->setCaret(ALTextPos(0, 10)); doc.editor->setHighlights(ALCodeEditor::Highlight::References, { ALTextRange(ALTextPos(0, 8), ALTextPos(0, 13)), ALTextRange(ALTextPos(1, 26), ALTextPos(1, 31)) }); caret.pump(10.0); - UNSCOPED_INFO("told"); CHECK(joined(studio.said) == std::string("path 0:10")); UNSCOPED_INFO("the places kept while it is on one"); REQUIRE(doc.editor->highlights().size() == 2); @@ -393,7 +382,7 @@ namespace CHECK(joined(studio.asked) == std::string("inspect 0:8")); { INFO("remembered"); - REQUIRE(doc.caret->inspectAt == ALTextPos(0, 8)); + CHECK(doc.caret->inspectAt == ALTextPos(0, 8)); CHECK(doc.caret->inspectVersion == doc.editor->document().version()); } doc.editor->setCaret(ALTextPos(0, 12)); @@ -441,7 +430,6 @@ namespace doc.loaded = true; doc.notecard = true; caret.pump(1.0); - UNSCOPED_INFO("nothing"); REQUIRE(studio.said.empty()); doc.notecard = false; doc.expandedEditor = editor("expanded_a", "integer count;\n"); @@ -484,7 +472,6 @@ namespace UNSCOPED_INFO("brought out: asked"); CHECK(joined(studio.asked) == std::string("inspect 0:8")); caret.pump(22.0); - UNSCOPED_INFO("once"); REQUIRE(studio.asked.size() == size_t(1)); } @@ -564,7 +551,7 @@ namespace CHECK(studio.asked.back() == std::string("inspect 1:26")); { INFO("which is what it was last told"); - REQUIRE(doc.caret->inspectAt == ALTextPos(1, 26)); + CHECK(doc.caret->inspectAt == ALTextPos(1, 26)); CHECK(doc.caret->inspectDue == 0.0); } } @@ -603,7 +590,6 @@ namespace result.references.definitionFile = "disk:/lib/util.luau"; result.references.references = { span(1, 8, 5) }; caret.answered(doc, result, ALTextPos(0, 8)); - UNSCOPED_INFO("opened in the module"); CHECK(joined(studio.said) == std::string("open disk:/lib/util.luau util.luau 3:11+5")); UNSCOPED_INFO("a jump noted"); CHECK(navigation->unit.places(false) == size_t(1)); @@ -672,7 +658,6 @@ namespace result.references.references = { span(1, 26, 5) }; result.references.elsewhere = { { "held", span(4, 8, 5) }, { "other", span(1, 12, 5) }, { "gone", span(0, 0, 5) } }; caret.answered(doc, result, ALTextPos(0, 8)); - UNSCOPED_INFO("declared in the held module"); CHECK(started(doc) == "find in a declared disk:/held.luau@4 v" + std::to_string(v)); UNSCOPED_INFO("the script's, each module's; none of a module not had"); REQUIRE(doc.lookup->places.size() == size_t(3)); @@ -680,21 +665,21 @@ namespace { INFO("as the file reads"); REQUIRE(held); - REQUIRE(held->fileName == "held.luau"); - REQUIRE(held->text == "integer count; // held"); + CHECK(held->fileName == "held.luau"); + CHECK(held->text == "integer count; // held"); CHECK(held->at == 6); } const Doc::Place* other = placeIn(doc, "disk:/other.luau"); { INFO("as the module's text read, the name not placed"); REQUIRE(other); - REQUIRE(other->fileName == "other.luau"); - REQUIRE(other->text == "return util.count"); + CHECK(other->fileName == "other.luau"); + CHECK(other->text == "return util.count"); CHECK(other->at == -1); } { INFO("in the module's lines"); - REQUIRE(other->span.line == 1); + CHECK(other->span.line == 1); CHECK(other->span.column == 12); } diff --git a/indra/newview/tests/alscriptstudiochecking_test.cpp b/indra/newview/tests/alscriptstudiochecking_test.cpp index 4e052971c2..69f0babf54 100644 --- a/indra/newview/tests/alscriptstudiochecking_test.cpp +++ b/indra/newview/tests/alscriptstudiochecking_test.cpp @@ -381,16 +381,16 @@ namespace const ALScriptAnalysis::Request& asked = studio.asks[0].request; { INFO("a check of the text as it stands"); - REQUIRE(asked.kind == Kind::Check); - REQUIRE(asked.id == "a"); - REQUIRE(asked.version == version(doc)); + CHECK(asked.kind == Kind::Check); + CHECK(asked.id == "a"); + CHECK(asked.version == version(doc)); CHECK(*asked.text == doc.editor->text()); } UNSCOPED_INFO("with the window's settings"); CHECK(asked.hintTypes); { INFO("remembered"); - REQUIRE(doc.check->requestedVersion == version(doc)); + CHECK(doc.check->requestedVersion == version(doc)); CHECK(doc.check->analysisDue == 0.0); } checking.pump(1e9); @@ -400,7 +400,7 @@ namespace checking.pump(1.0); UNSCOPED_INFO("at once"); REQUIRE(studio.asks.size() == size_t(2)); - // A notecard is checked here, as scripts read it (test 20). + // A notecard is checked here, as scripts read it (the notecard case below). doc.notecard = true; checking.schedule(doc, true); checking.pump(1e9); @@ -523,7 +523,7 @@ namespace { INFO("taken"); REQUIRE(doc.expanded.valid); - REQUIRE(doc.expanded.version == version(doc)); + CHECK(doc.expanded.version == version(doc)); CHECK(doc.check->expansions == 1); } UNSCOPED_INFO("then asked"); @@ -558,7 +558,7 @@ namespace studio.asks[2].answered(answer(doc)); { INFO("an answer of an expansion since replaced: the check asked again"); - REQUIRE(doc.check->analysisDue == 1.0); + CHECK(doc.check->analysisDue == 1.0); REQUIRE(doc.check->analysis.empty()); } preprocessing = false; @@ -693,12 +693,11 @@ namespace Doc& doc = tab("disk:/lib.lsl", "integer helper;\nhelp() { }\n"); doc.file = "/lib.lsl"; doc.editor->setSyntax("lsl"); - UNSCOPED_INFO("a fragment"); CHECK(checking.lslFragment(doc)); { INFO("kept for the text it was asked of"); REQUIRE(doc.check->fragment); - REQUIRE(doc.check->fragment->first == doc.editor->document().version()); + CHECK(doc.check->fragment->first == doc.editor->document().version()); CHECK(doc.check->fragment->second); } checking.ask(doc, Kind::Check, ALTextPos(), ALTextPos()); @@ -867,7 +866,7 @@ namespace Doc& marked = tab("m", "integer f() inline { return 1; }\n"); checking.ask(marked, Kind::Check, ALTextPos(), ALTextPos()); studio.asks.back().answered(answer(marked, { problem(0, "syntax error") })); - UNSCOPED_INFO("inline explained: " + marked.check->analysis[0].message); + UNSCOPED_INFO("inline explained: " << marked.check->analysis[0].message); CHECK(marked.check->analysis[0].message.find("syntax error PreprocHintInline [WORD]=inline") == 0); preprocessing = true; marked.expanded.valid = false; @@ -886,7 +885,7 @@ namespace Doc& constant = tab("c", "f(const integer n) { }\n"); checking.ask(constant, Kind::Check, ALTextPos(), ALTextPos()); studio.asks.back().answered(answer(constant, { problem(0, "syntax error") })); - UNSCOPED_INFO("const explained: " + constant.check->analysis[0].message); + UNSCOPED_INFO("const explained: " << constant.check->analysis[0].message); CHECK(constant.check->analysis[0].message.find("syntax error PreprocHintConst [WORD]=const") == 0); // A script with a directive is preprocessed, the setting off or @@ -920,9 +919,9 @@ namespace missing.fixes.push_back(fix("Insert '('", 0, 2, 2, "(")); studio.asks.back().answered(answer(stray, { missing, problem(1, "syntax error") })); { - INFO("the line explained: " + (stray.check->analysis.empty() ? std::string() : stray.check->analysis[0].message)); + INFO("the line explained: " << (stray.check->analysis.empty() ? std::string() : stray.check->analysis[0].message)); REQUIRE(stray.check->analysis.size() == 2); - REQUIRE(stray.check->analysis[0].message == "Missing '('. PreprocHintDirective"); + CHECK(stray.check->analysis[0].message == "Missing '('. PreprocHintDirective"); REQUIRE(stray.check->analysis[0].fixes.empty()); } UNSCOPED_INFO("a line of code: as the parser said"); @@ -952,7 +951,7 @@ namespace { INFO("said, checked again"); CHECK(services.statuses.back() == "FixStale"); - REQUIRE(services.statusFailures.back()); + CHECK(services.statusFailures.back()); CHECK(doc.check->analysisDue == 1.0); } UNSCOPED_INFO("past the end: refused"); @@ -961,7 +960,7 @@ namespace refactor.kind = ALScriptFix::Kind::Refactor; { INFO("a refactor"); - REQUIRE(checking.applyFix(doc, refactor, version(doc))); + CHECK(checking.applyFix(doc, refactor, version(doc))); CHECK(doc.editor->undoJournal().undoLabel() == "refactor"); } doc.modifiable = false; @@ -985,7 +984,7 @@ namespace studio.asks[0].answered(answer(doc, { one })); { INFO("then made"); - REQUIRE(doc.editor->document().line(0) == "float count;"); + CHECK(doc.editor->document().line(0) == "float count;"); REQUIRE_FALSE(doc.check->fixAllAfterCheck); } @@ -1007,7 +1006,7 @@ namespace studio.confirm(); { INFO("made"); - REQUIRE(doc.editor->document().line(0) == "integer count;"); + CHECK(doc.editor->document().line(0) == "integer count;"); CHECK(doc.editor->document().line(3) == " touch_start() { count = 1; }"); } { @@ -1018,7 +1017,6 @@ namespace checking.pump(1.0); studio.asks.back().answered(answer(doc)); checking.askFixAll(doc, Doc::FixPick{}); - UNSCOPED_INFO("none"); CHECK(services.statuses.back() == std::string("FixNone")); unit.reset(); studio.confirm(); @@ -1085,7 +1083,7 @@ namespace checking.pump(10.1 + 0.35); { INFO("afresh"); - REQUIRE_FALSE(doc.expanded.valid); + CHECK_FALSE(doc.expanded.valid); CHECK_FALSE(doc.weighing->sent); } UNSCOPED_INFO("run for a save"); @@ -1110,7 +1108,7 @@ namespace CHECK(studio.asks[0].request.endColumn == 13); { INFO("kept, to offer them over"); - REQUIRE(doc.check->actionsAsked.begin == ALTextPos(0, 8)); + CHECK(doc.check->actionsAsked.begin == ALTextPos(0, 8)); CHECK(doc.check->actionsAsked.end == ALTextPos(0, 13)); } ALScriptAnalysis::Result result; @@ -1127,7 +1125,7 @@ namespace { INFO("kept"); REQUIRE(doc.check->actions.size() == 1); - REQUIRE(doc.check->actions[0].title == "Rename"); + CHECK(doc.check->actions[0].title == "Rename"); CHECK(doc.check->actionsVersion == version(doc)); } result.version = version(doc) + 1; @@ -1330,7 +1328,7 @@ namespace { INFO("and which require reaches it"); REQUIRE(asked.modules->reaches.size() == 1); - REQUIRE(asked.modules->reaches[0].name == "util"); + CHECK(asked.modules->reaches[0].name == "util"); CHECK(asked.modules->reaches[0].key == "object:util"); } { @@ -1463,18 +1461,17 @@ namespace checking.pump(2.0); UNSCOPED_INFO("no analyzer asked"); REQUIRE(studio.asks.empty()); - UNSCOPED_INFO("two"); REQUIRE(card.check->analysis.size() == size_t(2)); { INFO("the items, at the first"); - REQUIRE(card.check->analysis[0].line == 0); - REQUIRE(card.check->analysis[0].column == 4); + CHECK(card.check->analysis[0].line == 0); + CHECK(card.check->analysis[0].column == 4); CHECK(card.check->analysis[0].severity == ALScriptProblem::Severity::Warning); } { INFO("the long line, from where it is cut"); - REQUIRE(card.check->analysis[1].line == 1); - REQUIRE(card.check->analysis[1].column == 1024); + CHECK(card.check->analysis[1].line == 1); + CHECK(card.check->analysis[1].column == 1024); CHECK(card.check->analysis[1].endColumn == 1030); } UNSCOPED_INFO("no outline as plain text"); @@ -1522,7 +1519,7 @@ namespace CHECK(doc.editor->wholeText() == before); const std::string& compared = studio.told.back(); { - INFO("the text now beside it after" + compared); + INFO("the text now beside it after: " << compared); CHECK(compared.rfind("compare a: " + before + " | float count;", 0) == 0); REQUIRE(compared.find(" touch_start() { count = 1; }") != std::string::npos); REQUIRE(compared.find("(CompareNow | FixAllAfter [FIXES]=Fixes [COUNT]=2") != std::string::npos); @@ -1534,8 +1531,8 @@ namespace } { INFO("made"); - REQUIRE(checking.applyPreviewed(doc)); - REQUIRE(doc.editor->document().line(0) == "float count;"); + CHECK(checking.applyPreviewed(doc)); + CHECK(doc.editor->document().line(0) == "float count;"); CHECK(doc.editor->undoJournal().undoLabel() == "fix"); } UNSCOPED_INFO("once"); @@ -1555,13 +1552,13 @@ namespace doc.editor->setText("default {}\n"); { INFO("changed since: not made"); - REQUIRE_FALSE(checking.applyPreviewed(doc)); + CHECK_FALSE(checking.applyPreviewed(doc)); CHECK(doc.editor->wholeText() == "default {}\n"); } { INFO("said"); CHECK(services.statuses.back() == "FixAllChangedSince"); - REQUIRE(services.statusFailures.back()); + CHECK(services.statusFailures.back()); } } @@ -1606,7 +1603,7 @@ namespace } { INFO("made"); - REQUIRE(checking.applyFix(doc, said[0].fixes[0], version(doc))); + CHECK(checking.applyFix(doc, said[0].fixes[0], version(doc))); CHECK(doc.editor->wholeText() == "local s = \"abc\"\nprint(ll.GetSubString(s, 1, 3))\n-- LSL: something else\nprint(s)\n"); } @@ -1652,7 +1649,7 @@ namespace REQUIRE_FALSE(studio.preview); const std::string& compared = studio.told.back(); { - INFO("the two from LSL, not the other: " + compared); + INFO("the two from LSL, not the other: " << compared); REQUIRE(compared.find("FixAllAfter [FIXES]=Fixes [COUNT]=2") != std::string::npos); REQUIRE(compared.find("float count;") != std::string::npos); } @@ -1660,7 +1657,7 @@ namespace CHECK(services.reports.back().actions == Names{ "apply_fixes" }); { INFO("made"); - REQUIRE(checking.applyPreviewed(doc)); + CHECK(checking.applyPreviewed(doc)); CHECK(doc.editor->document().line(0) == "float count;"); } @@ -1707,7 +1704,7 @@ namespace INFO("Apply again: nothing waiting, and said"); CHECK_FALSE(checking.applyPreviewed(doc)); CHECK(services.statuses.back() == "FixAllNotPreviewed"); - REQUIRE(services.statusFailures.back()); + CHECK(services.statusFailures.back()); } } @@ -1759,11 +1756,11 @@ namespace { INFO("said"); CHECK(services.statuses.back().find("AliasTaken [NAME]=inc") == 0); - REQUIRE(services.statusFailures.back()); + CHECK(services.statusFailures.back()); } { INFO("nothing changed"); - REQUIRE(version(doc) == was_at); + CHECK(version(doc) == was_at); CHECK(doc.editor->document().line(0) == "integer total;"); } UNSCOPED_INFO("nothing to redo"); @@ -1790,7 +1787,6 @@ namespace Doc& doc = tab("disk:/lib.lsl", text); doc.file = "/lib.lsl"; doc.editor->setSyntax("lsl"); - UNSCOPED_INFO("a fragment"); CHECK(checking.lslFragment(doc)); ALSyntaxHighlighter& highlighter = doc.editor->highlighter(); const S32 last = doc.editor->document().lineCount() - 1; @@ -1801,13 +1797,13 @@ namespace UNSCOPED_INFO("asked again at once: a fragment"); CHECK(checking.lslFragment(doc)); highlighter.tokens(last); - UNSCOPED_INFO("the text not lexed to its end for it: " + std::to_string(highlighter.lastLexed()) + " of " + std::to_string(last + 1) + " left"); + UNSCOPED_INFO("the text not lexed to its end for it: " << highlighter.lastLexed() << " of " << last + 1 << " left"); CHECK(highlighter.lastLexed() > last / 2); UNSCOPED_INFO("nor kept for the text as it stands"); CHECK(doc.check->fragment->first != version(doc)); { INFO("lexed to its end: what it is, kept"); - REQUIRE(checking.lslFragment(doc)); + CHECK(checking.lslFragment(doc)); CHECK(doc.check->fragment->first == version(doc)); } diff --git a/indra/newview/tests/alscriptstudiocommands_test.cpp b/indra/newview/tests/alscriptstudiocommands_test.cpp index d53a8756c7..6ce86db936 100644 --- a/indra/newview/tests/alscriptstudiocommands_test.cpp +++ b/indra/newview/tests/alscriptstudiocommands_test.cpp @@ -50,12 +50,9 @@ namespace UNSCOPED_INFO("and one saying nothing of either"); CHECK(commands.add("close", [this]() { done.push_back("close"); })); - { - INFO("known"); - REQUIRE(commands.has("save")); - REQUIRE(commands.has("word_wrap")); - REQUIRE(commands.has("close")); - } + REQUIRE(commands.has("save")); + REQUIRE(commands.has("word_wrap")); + REQUIRE(commands.has("close")); UNSCOPED_INFO("not enabled while it says it cannot"); CHECK_FALSE(commands.enabled("save")); can = true; @@ -65,7 +62,6 @@ namespace CHECK(commands.enabled("close")); commands.run("save"); commands.run("close"); - UNSCOPED_INFO("each run"); CHECK(done == std::vector{ "save", "close" }); UNSCOPED_INFO("the toggle on"); @@ -84,7 +80,6 @@ namespace TEST_CASE_METHOD(alscriptstudiocommands_data, "alscriptstudiocommands: a name registers once and keeps its first command", "[alscriptstudiocommands]") { - UNSCOPED_INFO("the first"); CHECK(commands.add("save", [this]() { done.push_back("first"); })); UNSCOPED_INFO("the second refused"); CHECK_FALSE(commands.add("save", [this]() { done.push_back("second"); })); @@ -96,7 +91,6 @@ namespace UNSCOPED_INFO("an unlisted one is a command like any"); CHECK(commands.addUnlisted("reveal", [this]() { done.push_back("reveal"); })); commands.run("reveal"); - UNSCOPED_INFO("run"); CHECK(done.back() == std::string("reveal")); std::vector names = commands.names(); std::sort(names.begin(), names.end()); @@ -107,13 +101,10 @@ namespace TEST_CASE_METHOD(alscriptstudiocommands_data, "alscriptstudiocommands: an unknown name does nothing and is reported once", "[alscriptstudiocommands]") { commands.run("no_such"); - UNSCOPED_INFO("not enabled"); CHECK_FALSE(commands.enabled("no_such")); - UNSCOPED_INFO("off"); CHECK_FALSE(commands.checked("no_such")); UNSCOPED_INFO("not done by a key"); CHECK_FALSE(commands.runIfEnabled("no_such")); - UNSCOPED_INFO("nor known"); REQUIRE_FALSE(commands.has("no_such")); UNSCOPED_INFO("said once however often asked"); CHECK(commands.unknownAsked() == std::vector{ "no_such" }); diff --git a/indra/newview/tests/alscriptstudiocomparepairs_test.cpp b/indra/newview/tests/alscriptstudiocomparepairs_test.cpp index 81721692fc..1c47b0a435 100644 --- a/indra/newview/tests/alscriptstudiocomparepairs_test.cpp +++ b/indra/newview/tests/alscriptstudiocomparepairs_test.cpp @@ -131,16 +131,16 @@ namespace const ALScriptAnalysis::Request& left = studio.asked[0].request; { INFO("the left's shape, as SLua, in front"); - REQUIRE(left.kind == ALScriptAnalysis::Kind::Shape); - REQUIRE(left.lua); - REQUIRE(left.front); + CHECK(left.kind == ALScriptAnalysis::Kind::Shape); + CHECK(left.lua); + CHECK(left.front); CHECK(*left.text == LEFT); CHECK(left.id != studio.asked[1].request.id); } studio.answer(0); { INFO("one answered: nothing yet"); - REQUIRE(doc.compareView->model().pairs().empty()); + CHECK(doc.compareView->model().pairs().empty()); CHECK(beside(doc, 0, 0)); } studio.answerAll(); @@ -153,6 +153,7 @@ namespace } } + // The pairs are carried while the side typed in is asked about. TEST_CASE_METHOD(alscriptstudiocomparepairs_data, "alscriptstudiocomparepairs: a side typed in is asked again alone and a stale answer dropped", "[alscriptstudiocomparepairs]") { Doc& doc = tab("tab"); @@ -162,7 +163,7 @@ namespace { INFO("the right alone asked"); REQUIRE(studio.asked.size() == 1); - REQUIRE(studio.asked[0].request.id.find("right") != std::string::npos); + CHECK(studio.asked[0].request.id.find("right") != std::string::npos); } { INFO("carried meanwhile"); @@ -185,7 +186,7 @@ namespace { INFO("the left alone asked"); REQUIRE(studio.asked.size() == 1); - REQUIRE(studio.asked[0].request.id.find("left") != std::string::npos); + CHECK(studio.asked[0].request.id.find("left") != std::string::npos); } studio.answerAll(); UNSCOPED_INFO("paired again"); @@ -200,18 +201,18 @@ namespace doc.compareView->setTexts(LEFT, RIGHT); { INFO("none asked, paired at once"); - REQUIRE(studio.asked.empty()); - REQUIRE_FALSE(doc.compareView->model().pairs().empty()); + CHECK(studio.asked.empty()); + CHECK_FALSE(doc.compareView->model().pairs().empty()); } doc.compareView->setTexts(LEFT + "\n", RIGHT, { { 0, 0, 0, 0 } }); { INFO("ranges: none asked"); - REQUIRE(studio.asked.empty()); - REQUIRE(doc.compareView->model().pairs().empty()); + CHECK(studio.asked.empty()); + CHECK(doc.compareView->model().pairs().empty()); } Doc& card = tab("card", true); card.compareView->setTexts(LEFT, RIGHT); UNSCOPED_INFO("a notecard: none asked"); - REQUIRE(studio.asked.empty()); + CHECK(studio.asked.empty()); } } diff --git a/indra/newview/tests/alscriptstudiocomparewith_test.cpp b/indra/newview/tests/alscriptstudiocomparewith_test.cpp index 0e736096a9..fe46751c14 100644 --- a/indra/newview/tests/alscriptstudiocomparewith_test.cpp +++ b/indra/newview/tests/alscriptstudiocomparewith_test.cpp @@ -175,11 +175,11 @@ namespace return doc; } // The tab's text changed since it was saved. - void change(Doc& doc, const std::string& text) + void require_changed(Doc& doc, const std::string& text) { doc.editor->selectAll(); doc.editor->insertText(text); - UNSCOPED_INFO("changed since saved"); + INFO("changed since saved"); REQUIRE(doc.editor->isDirty()); } // A file in the test's folder, written as it is given. @@ -199,20 +199,16 @@ namespace SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "default {}\n"); - UNSCOPED_INFO("it may be compared"); CHECK(ALScriptStudioCompareWith::canCompare(doc)); unit->show(doc); UNSCOPED_INFO("asked once"); CHECK(studio.picks == 1); - UNSCOPED_INFO("a file, and nothing else"); - CHECK(listed(studio.values()) == listed(Names{ "file" })); - UNSCOPED_INFO("labelled"); + REQUIRE(listed(studio.values()) == listed(Names{ "file" })); CHECK(studio.candidates[0].label == said("CompareWithFile")); LLStringUtil::format_map_t args; args["[NAME]"] = "door"; UNSCOPED_INFO("titled by the tab"); CHECK(studio.picked == said("CompareWithTitle", args)); - UNSCOPED_INFO("and its hint"); CHECK(studio.hint == said("CompareWithPlaceholder")); Doc& loading = tab("lamp", "", false); @@ -230,25 +226,21 @@ namespace SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "as saved\n"); - change(doc, "as changed\n"); + require_changed(doc, "as changed\n"); unit->show(doc); - UNSCOPED_INFO("first"); CHECK(studio.values().front() == std::string("saved")); - UNSCOPED_INFO("labelled"); CHECK(studio.candidates[0].label == said("CompareSaved")); studio.choose("saved"); - UNSCOPED_INFO("set beside"); CHECK(listed(studio.did) == listed(Names{ "compare door: as saved\n | as changed\n (" + said("CompareSaved") + " | )" })); // A change after an undo past the save: nothing reaches it. doc.editor->undoJournal().markNeverSaved(); studio.choose("saved"); UNSCOPED_INFO("not compared"); - REQUIRE(studio.did.size() == 1U); - UNSCOPED_INFO("said"); + CHECK(studio.did.size() == 1U); CHECK(services().statuses.back() == said("CompareNothingSaved")); UNSCOPED_INFO("as a failure"); - REQUIRE(services().statusFailures.back()); + CHECK(services().statusFailures.back()); } TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: what was saved over it elsewhere is offered until it is settled", "[alscriptstudiocomparewith]") @@ -260,24 +252,21 @@ namespace Doc& doc = tab("door", "mine\n"); unit->show(doc); UNSCOPED_INFO("not where none did"); - REQUIRE(studio.row("saved_there").value.empty()); + CHECK(studio.row("saved_there").value.empty()); doc.savedThere = "theirs\n"; unit->show(doc); - UNSCOPED_INFO("offered"); CHECK(studio.row("saved_there").label == said("CompareSavedThere")); studio.choose("saved_there"); - UNSCOPED_INFO("set beside"); CHECK(listed(studio.did) == listed(Names{ "compare door: theirs\n | mine\n (" + said("CompareSavedThere") + " | )" })); // Settled since the list was made: nothing, and said. doc.savedThere.reset(); studio.choose("saved_there"); UNSCOPED_INFO("nothing more"); - REQUIRE(studio.did.size() == 1U); - UNSCOPED_INFO("said"); + CHECK(studio.did.size() == 1U); CHECK(services().statuses.back() == said("CompareSavedThereGone")); UNSCOPED_INFO("as a failure"); - REQUIRE(services().statusFailures.back()); + CHECK(services().statusFailures.back()); } TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: other loaded tabs are offered in order and compared as they are now", "[alscriptstudiocomparewith]") @@ -288,21 +277,18 @@ namespace } Doc& door = tab("door", "door\n"); Doc& lamp = tab("lamp", "lamp as saved\n"); - change(lamp, "lamp now\n"); + require_changed(lamp, "lamp now\n"); tab("gate", "", false); Doc& sign = tab("sign", "sign\n"); unit->show(door); UNSCOPED_INFO("the others loaded, in order"); CHECK(listed(studio.values()) == listed(Names{ "tab:lamp", "tab:sign", "file" })); - UNSCOPED_INFO("by name"); CHECK(studio.row("tab:lamp").label == std::string("lamp")); - UNSCOPED_INFO("unsaved"); CHECK(studio.row("tab:lamp").detail == said("CompareWithTabUnsaved")); - UNSCOPED_INFO("saved"); CHECK(studio.row("tab:sign").detail == said("CompareWithTab")); // Typed since the list was made: what is set beside is the tab now. - change(lamp, "lamp later\n"); + require_changed(lamp, "lamp later\n"); studio.choose("tab:lamp"); LLStringUtil::format_map_t unsaved; unsaved["[TITLE]"] = "lamp"; @@ -310,7 +296,7 @@ namespace const auto snapshot = [this](const std::string& name) { return this->said("CompareTabSnapshot", { { "[NAME]", name } }); }; UNSCOPED_INFO("unsaved, as it is now"); CHECK(studio.did.back() == - "compare door: lamp later\n | door\n (" + snapshot(said("CompareUnsaved", unsaved)) + " | )"); + "compare door: lamp later\n | door\n (" + snapshot(said("CompareUnsaved", unsaved)) + " | )"); studio.choose("tab:sign"); UNSCOPED_INFO("saved, by its name"); CHECK(studio.did.back() == "compare door: sign\n | door\n (" + snapshot("sign") + " | )"); @@ -321,11 +307,10 @@ namespace services().docs.erase(services().docs.begin() + 3); studio.choose("tab:sign"); UNSCOPED_INFO("nothing more"); - REQUIRE(studio.did.size() == 2U); - UNSCOPED_INFO("said"); + CHECK(studio.did.size() == 2U); CHECK(services().statuses.back() == said("CompareTabClosed", { { "[NAME]", "sign" } })); UNSCOPED_INFO("as a failure"); - REQUIRE(services().statusFailures.back()); + CHECK(services().statusFailures.back()); } TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: the clipboard is offered with its line count when it holds text", "[alscriptstudiocomparewith]") @@ -337,17 +322,15 @@ namespace Doc& doc = tab("door", "door\n"); unit->show(doc); UNSCOPED_INFO("not without text"); - REQUIRE(studio.row("clipboard").value.empty()); + CHECK(studio.row("clipboard").value.empty()); studio.clipboard = std::string(); unit->show(doc); UNSCOPED_INFO("not with none"); - REQUIRE(studio.row("clipboard").value.empty()); + CHECK(studio.row("clipboard").value.empty()); studio.clipboard = "one\ntwo\n"; unit->show(doc); - UNSCOPED_INFO("labelled"); CHECK(studio.row("clipboard").label == said("CompareClipboard")); - UNSCOPED_INFO("two lines"); CHECK(studio.row("clipboard").detail == services().counted("CompareWithLines", 2)); studio.clipboard = "one\ntwo\nthree"; unit->show(doc); @@ -361,8 +344,7 @@ namespace studio.clipboard.reset(); studio.choose("clipboard"); UNSCOPED_INFO("not once emptied"); - REQUIRE(studio.did.size() == 1U); - UNSCOPED_INFO("said"); + CHECK(studio.did.size() == 1U); CHECK(services().statuses.back() == said("CompareWithClipboardEmpty")); } @@ -381,11 +363,11 @@ namespace CHECK_FALSE(studio.manyAsked); studio.files({}); UNSCOPED_INFO("none picked, nothing"); - REQUIRE(studio.did.empty()); + CHECK(studio.did.empty()); const std::string path = file("other.lsl", "one\r\ntwo\r\n"); studio.files({ path }); - UNSCOPED_INFO("set beside"); + UNSCOPED_INFO("its line breaks as an editor keeps them"); CHECK(listed(studio.did) == listed(Names{ "compare door: one\ntwo\n | door\n (other.lsl | )" })); unit->show(doc); @@ -393,13 +375,12 @@ namespace const std::string missing = folder + "/missing.lsl"; studio.files({ missing }); UNSCOPED_INFO("not compared"); - REQUIRE(studio.did.size() == 1U); + CHECK(studio.did.size() == 1U); LLStringUtil::format_map_t args; args["[FILE]"] = missing; - UNSCOPED_INFO("said"); CHECK(services().statuses.back() == said("LoadFromFileFailed", args)); UNSCOPED_INFO("as a failure"); - REQUIRE(services().statusFailures.back()); + CHECK(services().statusFailures.back()); // The tab closed while the files were picked: nothing. unit->show(doc); @@ -407,7 +388,7 @@ namespace services().docs.clear(); studio.files({ path }); UNSCOPED_INFO("nothing more"); - REQUIRE(studio.did.size() == 1U); + CHECK(studio.did.size() == 1U); } TEST_CASE_METHOD(alscriptstudiocomparewith_data, "alscriptstudiocomparewith: recent files but the tab's own are offered by name and folder", "[alscriptstudiocomparewith]") @@ -424,12 +405,9 @@ namespace unit->show(doc); UNSCOPED_INFO("the other alone"); CHECK(listed(studio.values()) == listed(Names{ "file", "recent:0" })); - UNSCOPED_INFO("by name"); CHECK(studio.row("recent:0").label == std::string("lamp.lsl")); - UNSCOPED_INFO("and folder"); CHECK(studio.row("recent:0").detail == gDirUtilp->getDirName(other)); studio.choose("recent:0"); - UNSCOPED_INFO("set beside"); CHECK(listed(studio.did) == listed(Names{ "compare door: lamp\n | door\n (lamp.lsl | )" })); } @@ -442,23 +420,20 @@ namespace Doc& doc = tab("door", "door\n"); unit->show(doc); UNSCOPED_INFO("not with none kept"); - REQUIRE(studio.row("history").value.empty()); + CHECK(studio.row("history").value.empty()); for (const char* text : { "first", "second" }) { ALSavedText one; one.key = ALScriptStudioHistory::keyOf(doc); one.text = text; one.when = LLDate::now(); - UNSCOPED_INFO("kept"); + CAPTURE(text); REQUIRE(history->keep(one)); } unit->show(doc); - UNSCOPED_INFO("labelled"); CHECK(studio.row("history").label == said("CompareWithHistory")); - UNSCOPED_INFO("two kept"); CHECK(studio.row("history").detail == services().counted("CompareWithSaves", 2)); studio.choose("history"); - UNSCOPED_INFO("listed"); CHECK(listed(studio.did) == listed(Names{ "history door" })); } @@ -476,15 +451,13 @@ namespace unit->show(doc); UNSCOPED_INFO("after the rest"); CHECK(listed(studio.values()) == listed(Names{ "clipboard", "file", "item:0", "item:1" })); - UNSCOPED_INFO("by name"); CHECK(studio.row("item:0").label == std::string("door")); - UNSCOPED_INFO("and place"); CHECK(studio.row("item:0").detail == "House" + sep + "Front"); studio.choose("item:0"); studio.choose("item:1"); UNSCOPED_INFO("each under its place and name"); CHECK(listed(studio.did) == - listed(Names{ "item door: door (House" + sep + "Front" + sep + "door)", "item door: door (door)" })); + listed(Names{ "item door: door (House" + sep + "Front" + sep + "door)", "item door: door (door)" })); // Its place is what is typed to find it. const std::vector ranked = ALQuickOpen::rank(studio.candidates, "front"); @@ -506,7 +479,6 @@ namespace unit->show(doc); unit.reset(); studio.choose("clipboard"); - UNSCOPED_INFO("nothing"); - REQUIRE(studio.did.empty()); + CHECK(studio.did.empty()); } } diff --git a/indra/newview/tests/alscriptstudiodoc_test.cpp b/indra/newview/tests/alscriptstudiodoc_test.cpp index 099828b5bb..5fe96f5b05 100644 --- a/indra/newview/tests/alscriptstudiodoc_test.cpp +++ b/indra/newview/tests/alscriptstudiodoc_test.cpp @@ -116,18 +116,14 @@ namespace TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: levelOf reads compiler words and severities and ProblemTraits a row", "[ALScriptStudioDoc]") { - UNSCOPED_INFO("WARNING"); CHECK(Doc::levelOf("WARNING") == Doc::Level::Warning); - UNSCOPED_INFO("WARN"); CHECK(Doc::levelOf("WARN") == Doc::Level::Warning); { INFO("anything else is an error, as the server has two"); CHECK(Doc::levelOf("ERROR") == Doc::Level::Error); CHECK(Doc::levelOf("oops") == Doc::Level::Error); } - UNSCOPED_INFO("a note"); CHECK(Doc::levelOf(ALScriptProblem::Severity::Note) == Doc::Level::Note); - UNSCOPED_INFO("named"); CHECK(std::string(Doc::levelName(Doc::Level::Warning)) == "WARNING"); Doc::Shown shown; @@ -149,7 +145,6 @@ namespace CHECK_FALSE(Doc::ProblemTraits::mentions(shown, "state")); UNSCOPED_INFO("its rule is where it came from"); CHECK(Doc::ProblemTraits::rule(shown) == "Luau"); - UNSCOPED_INFO("its level"); CHECK(Doc::ProblemTraits::level(shown) == ALFindingLevel::Warning); } @@ -163,9 +158,7 @@ namespace al_studio_test::FakeServices services(window.floater); UNSCOPED_INFO("a word of the skin's"); CHECK(services.words("ObjectNameComing") == std::string("\xE2\x80\xA6")); - UNSCOPED_INFO("one"); CHECK(services.counted("Fixes", 1) == std::string("1 fix")); - UNSCOPED_INFO("many"); CHECK(services.counted("Fixes", 3) == std::string("3 fixes")); LLUUID object, item; @@ -181,15 +174,14 @@ namespace CHECK(services.findDoc("disk:/lib.lsl") == &file); UNSCOPED_INFO("by what it holds"); CHECK(services.findDoc(ref) == &script); - UNSCOPED_INFO("none"); - REQUIRE(services.findDoc("nothing") == nullptr); + CHECK(services.findDoc("nothing") == nullptr); services.report("Saved", false, &script, { "retry" }); { INFO("said of the tab"); REQUIRE(services.reports.size() == 1); CHECK(services.reports.front().doc == "script"); - REQUIRE(services.reports.front().actions.size() == 1); + CHECK(services.reports.front().actions.size() == 1); } services.openScript(ref, "Door", std::nullopt, 12); { @@ -207,7 +199,7 @@ namespace { INFO("on its line, before the #"); REQUIRE(util.has_value()); - REQUIRE(util->name == "lib/util.lsl"); + CHECK(util->name == "lib/util.lsl"); CHECK_FALSE(util->require); } UNSCOPED_INFO("the whole line"); @@ -216,8 +208,8 @@ namespace CHECK(Doc::namedIn(lsl, ALTextPos(2, 12), false, none)->name == "sys.lsl"); { INFO("not a string elsewhere"); - REQUIRE_FALSE(Doc::namedIn(lsl, ALTextPos(3, 12), false, none)); - REQUIRE_FALSE(Doc::namedIn(lsl, ALTextPos(0, 3), false, none)); + CHECK_FALSE(Doc::namedIn(lsl, ALTextPos(3, 12), false, none)); + CHECK_FALSE(Doc::namedIn(lsl, ALTextPos(0, 3), false, none)); } const std::string source = "local m = require(\"mod\")\nlocal n = 1\n"; @@ -227,19 +219,19 @@ namespace { INFO("in a require call"); REQUIRE(mod.has_value()); - REQUIRE(mod->name == "mod"); + CHECK(mod->name == "mod"); CHECK(mod->require); } UNSCOPED_INFO("over the call"); CHECK(mod->range == ALTextRange(ALTextPos(0, 10), ALTextPos(0, 24))); UNSCOPED_INFO("not before it"); - REQUIRE_FALSE(Doc::namedIn(lua, ALTextPos(0, 3), true, calls)); + CHECK_FALSE(Doc::namedIn(lua, ALTextPos(0, 3), true, calls)); UNSCOPED_INFO("not in LSL"); - REQUIRE_FALSE(Doc::namedIn(lua, ALTextPos(0, 12), false, calls)); + CHECK_FALSE(Doc::namedIn(lua, ALTextPos(0, 12), false, calls)); Doc doc; UNSCOPED_INFO("no run, nothing found"); - REQUIRE(doc.foundAs("lib/util.lsl").empty()); + CHECK(doc.foundAs("lib/util.lsl").empty()); doc.expanded.valid = true; doc.expanded.resolved = { { "", "lib/util.lsl", false, "disk:/s/lib/util.lsl" }, { "disk:/s/lib/util.lsl", "inner.lsl", false, "disk:/s/inner.lsl" }, @@ -247,11 +239,11 @@ namespace UNSCOPED_INFO("the script's own"); CHECK(doc.foundAs("lib/util.lsl") == std::string("disk:/s/lib/util.lsl")); UNSCOPED_INFO("not an include's own"); - REQUIRE(doc.foundAs("inner.lsl").empty()); + CHECK(doc.foundAs("inner.lsl").empty()); { INFO("a module as a module"); CHECK(doc.foundAs("mod", true) == "inv:mod"); - REQUIRE(doc.foundAs("mod", false).empty()); + CHECK(doc.foundAs("mod", false).empty()); } doc.expanded.valid = false; doc.uploaded.valid = true; @@ -287,8 +279,8 @@ namespace doc.heardRuntime(said, true); { INFO("held"); - REQUIRE(doc.runtime.empty()); - REQUIRE(doc.runtimeHeld.size() == 1); + CHECK(doc.runtime.empty()); + CHECK(doc.runtimeHeld.size() == 1); } doc.heardRuntime(said, true); @@ -305,18 +297,18 @@ namespace doc.placeHeldRuntime(); { INFO("placed, and let go of"); - REQUIRE(doc.runtimeHeld.empty()); + CHECK(doc.runtimeHeld.empty()); REQUIRE(doc.runtime.size() == 1); } { INFO("at the source's line, said twice"); CHECK(doc.runtime[0].line == 2); - REQUIRE(doc.runtime[0].file.empty()); - REQUIRE(doc.runtime[0].count == 2); + CHECK(doc.runtime[0].file.empty()); + CHECK(doc.runtime[0].count == 2); } doc.heardRuntime(said, false); UNSCOPED_INFO("said again: counted"); - REQUIRE(doc.runtime[0].count == 3); + CHECK(doc.runtime[0].count == 3); said.line = 0; doc.heardRuntime(said, false); { @@ -330,7 +322,7 @@ namespace INFO("past the map: code the preprocessor made, at its own line"); CHECK(made.generated); CHECK(made.line == 9); - REQUIRE(made.file.empty()); + CHECK(made.file.empty()); } said.line = 9; doc.heardRuntime(said, false); @@ -351,19 +343,13 @@ namespace rows[2].level = Doc::Level::Warning; rows[3].level = Doc::Level::Note; doc.setShown(rows); - UNSCOPED_INFO("four rows"); - REQUIRE(doc.shown().size() == 4); - UNSCOPED_INFO("one error"); + CHECK(doc.shown().size() == 4); CHECK(doc.shownErrors == 1); - UNSCOPED_INFO("two warnings"); CHECK(doc.shownWarnings == 2); doc.setShown({}); - { - INFO("none"); - REQUIRE(doc.shown().empty()); - CHECK(doc.shownErrors == 0); - CHECK(doc.shownWarnings == 0); - } + CHECK(doc.shown().empty()); + CHECK(doc.shownErrors == 0); + CHECK(doc.shownWarnings == 0); } TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: a notecard's items carry into another tab but a script tab has none", "[ALScriptStudioDoc]") @@ -394,7 +380,7 @@ namespace Doc script, after; script.carryItemsTo(after); UNSCOPED_INFO("a script's tab carries nothing"); - REQUIRE_FALSE(after.carriedEmbedded); + CHECK_FALSE(after.carriedEmbedded); } TEST_CASE_METHOD(alscriptstudiodoc_data, "ALScriptStudioDoc: undo follows the view in front but the tab's own for a comparison of it", "[ALScriptStudioDoc]") @@ -444,7 +430,7 @@ namespace const ALScriptEnvelope plain = doc.envelopeFor(expanded, "Test 1.0"); UNSCOPED_INFO("none unasked"); - REQUIRE(plain.header.empty()); + CHECK(plain.header.empty()); ALScriptHeaderOptions asked; asked.on = true; @@ -456,12 +442,10 @@ namespace REQUIRE(said.has_value()); CHECK(said->ours); } - UNSCOPED_INFO("its hash"); CHECK(said->hash == ALUploadHeader::hashOf("mono", doc.editor->text(), expanded)); - UNSCOPED_INFO("who"); CHECK(said->creator == std::string("Some One")); UNSCOPED_INFO("no file: a tab has no link"); - REQUIRE(said->file.empty()); + CHECK(said->file.empty()); const int lines = static_cast(std::count(with.header.begin(), with.header.end(), '\n')); UNSCOPED_INFO("the code its lines down"); CHECK(with.codeLine() == plain.codeLine() + lines); @@ -469,7 +453,7 @@ namespace { INFO("parsed back with it"); REQUIRE(back.has_value()); - REQUIRE(back->header == with.header); + CHECK(back->header == with.header); CHECK(back->expanded == expanded); } } diff --git a/indra/newview/tests/alscriptstudioexpandedcompare_test.cpp b/indra/newview/tests/alscriptstudioexpandedcompare_test.cpp index 2e87aa38d6..5c42c6bd93 100644 --- a/indra/newview/tests/alscriptstudioexpandedcompare_test.cpp +++ b/indra/newview/tests/alscriptstudioexpandedcompare_test.cpp @@ -163,10 +163,8 @@ namespace map.add(segment(4, 0, 8, 0, 3, 2, false)); map.add(segment(6, 0, 4, 0, 5, 0)); map.finish(); - UNSCOPED_INFO("the ranges"); CHECK(said(ALScriptStudioExpandedCompare::rangesOf(map)) == std::string("[0-0 1-1][1-2 2-2][3-3 3-4][5-5 6-6]")); - UNSCOPED_INFO("none for nothing"); - REQUIRE(ALScriptStudioExpandedCompare::rangesOf(ALSourceMap()).empty()); + CHECK(ALScriptStudioExpandedCompare::rangesOf(ALSourceMap()).empty()); } TEST_CASE_METHOD(alscriptstudioexpandedcompare_data, "alscriptstudioexpandedcompare: the source is lined up beside what a save sends and typing maps back", "[alscriptstudioexpandedcompare]") @@ -176,7 +174,6 @@ namespace SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& door = tab("door"); - UNSCOPED_INFO("it can be compared"); CHECK(ALScriptStudioExpandedCompare::canCompare(door)); unit->compare(door); { @@ -210,7 +207,7 @@ namespace view.right()->goTo(ALTextPos(0, 3)); view.right()->handleUnicodeChar('y', false); UNSCOPED_INFO("an include's line: nowhere"); - REQUIRE(studio.typedAt.size() == 1); + CHECK(studio.typedAt.size() == 1); } TEST_CASE_METHOD(alscriptstudioexpandedcompare_data, "alscriptstudioexpandedcompare: a stale expansion is run again first and shown once current", "[alscriptstudioexpandedcompare]") @@ -233,7 +230,6 @@ namespace CHECK(studio.compares == 0); door.uploaded.version = door.editor->document().version(); unit->expanded(door); - UNSCOPED_INFO("shown"); CHECK(studio.compares == 1); unit->expanded(door); UNSCOPED_INFO("once"); @@ -243,7 +239,6 @@ namespace Doc& gate = tab("gate"); gate.editor->insertText("// "); unit->compare(gate); - UNSCOPED_INFO("waiting"); CHECK(unit->waiting("gate")); services().docs.erase(std::remove_if(services().docs.begin(), services().docs.end(), [](const std::unique_ptr& doc) { return doc->id == "gate"; }), @@ -320,11 +315,11 @@ namespace UNSCOPED_INFO("the macro's call beside what it made"); CHECK(beside(6, where("llOwnerSay"))); UNSCOPED_INFO("the last brace beside the last brace"); - REQUIRE(beside(8, static_cast(out.size()) - (out.back().empty() ? 2 : 1))); + CHECK(beside(8, static_cast(out.size()) - (out.back().empty() ? 2 : 1))); // What the map alone says: the call's line stands for what it made. const S32 call = view.model().rangeAt(ALDiffModel::Column::Left, 6); UNSCOPED_INFO("the call's line in a range"); - CHECK(call >= 0); + REQUIRE(call >= 0); UNSCOPED_INFO("whose output is what it made"); CHECK(view.model().ranges()[static_cast(call)].rightFirst == where("llOwnerSay")); { @@ -344,7 +339,6 @@ namespace door.editor->goTo(ALTextPos(0, 0)); door.editor->insertText("// "); unit->compare(door); - UNSCOPED_INFO("a run asked"); CHECK(studio.runs == 1); UNSCOPED_INFO("said while it waits"); CHECK(services().statuses.back() == services().words("Preprocessing", { { "[NAME]", "door" } })); @@ -369,7 +363,6 @@ namespace door.view = Doc::View::Source; door.editor->insertText("// "); unit->compare(door); - UNSCOPED_INFO("waiting"); CHECK(unit->waiting("door")); studio.compareRanged(door, "other", door.editor->wholeText(), "other", "door", {}); door.view = Doc::View::Compare; @@ -388,7 +381,6 @@ namespace // Asked from a comparison, which is then closed: let go of. door.editor->insertText("// "); unit->compare(door); - UNSCOPED_INFO("waiting again"); CHECK(unit->waiting("door")); door.view = Doc::View::Source; door.uploaded.version = door.editor->document().version(); @@ -407,10 +399,7 @@ namespace door.compareView->setRightText(door.editor->wholeText()); door.uploaded.version = door.editor->document().version(); unit->expanded(door); - { - INFO("shown"); - CHECK(studio.compares == 3); - CHECK_FALSE(unit->waiting("door")); - } + CHECK(studio.compares == 3); + CHECK_FALSE(unit->waiting("door")); } } diff --git a/indra/newview/tests/alscriptstudiofiles_test.cpp b/indra/newview/tests/alscriptstudiofiles_test.cpp index 5aaeaa77e3..d8b9eafdc0 100644 --- a/indra/newview/tests/alscriptstudiofiles_test.cpp +++ b/indra/newview/tests/alscriptstudiofiles_test.cpp @@ -223,7 +223,6 @@ namespace unit.noteFile("/f" + std::to_string(i)); } unit.noteFile("/f5"); - UNSCOPED_INFO("ten"); REQUIRE(unit.recentFiles().size() == size_t(10)); const Names& files = unit.recentFiles(); { @@ -245,7 +244,7 @@ namespace Doc& f = fileTab("f.lsl", "z"); unit.noteScript(f); UNSCOPED_INFO("a file's tab is no script"); - REQUIRE(unit.recentScripts().size() == 2); + CHECK(unit.recentScripts().size() == 2); UNSCOPED_INFO("the window told each time"); CHECK(studio.recentTold == 16); @@ -263,8 +262,8 @@ namespace unit.clearRecent(); { INFO("cleared"); - REQUIRE(unit.recentFiles().empty()); - REQUIRE(unit.recentScripts().empty()); + CHECK(unit.recentFiles().empty()); + CHECK(unit.recentScripts().empty()); CHECK(studio.recentTold == 17); } LLSD odd; @@ -274,7 +273,7 @@ namespace { INFO("read back: each once, none empty, no script without what holds it"); CHECK(again.recentFiles() == Names{ "/x", "/y" }); - REQUIRE(again.recentScripts().empty()); + CHECK(again.recentScripts().empty()); } } @@ -288,28 +287,27 @@ namespace // menus, which there are none of here. studio.menu->setVisible(false); unit.fillMenu(); - UNSCOPED_INFO("nothing"); - REQUIRE(studio.menu->findChild("no_recent") != nullptr); + CHECK(studio.menu->findChild("no_recent") != nullptr); unit.noteFile("/one/same.lsl"); unit.noteFile("/two/same.lsl"); unit.noteFile("/two/other.lsl"); { INFO("files alone: no heading"); - REQUIRE(studio.menu->findChild("recent_heading_RecentFiles") == nullptr); - REQUIRE(studio.menu->findChild("recent_/two/other.lsl") != nullptr); + CHECK(studio.menu->findChild("recent_heading_RecentFiles") == nullptr); + CHECK(studio.menu->findChild("recent_/two/other.lsl") != nullptr); } Doc& a = scriptTab("a", "x"); unit.noteScript(a); { INFO("both: headings"); - REQUIRE(studio.menu->findChild("recent_heading_RecentScripts") != nullptr); - REQUIRE(studio.menu->findChild("recent_heading_RecentFiles") != nullptr); + CHECK(studio.menu->findChild("recent_heading_RecentScripts") != nullptr); + CHECK(studio.menu->findChild("recent_heading_RecentFiles") != nullptr); } LLMenuItemCallGL* same = studio.menu->findChild("recent_/one/same.lsl"); { INFO("a folder after a name two share"); REQUIRE(same); - REQUIRE(same->getLabel().find("(/one)") != std::string::npos); + CHECK(same->getLabel().find("(/one)") != std::string::npos); } LLMenuItemCallGL* other = studio.menu->findChild("recent_/two/other.lsl"); { @@ -335,8 +333,8 @@ namespace studio.menu->findChild("clear_recent")->onCommit(); { INFO("the clear item clears"); - REQUIRE(unit.recentFiles().empty()); - REQUIRE(studio.menu->findChild("no_recent") != nullptr); + CHECK(unit.recentFiles().empty()); + CHECK(studio.menu->findChild("no_recent") != nullptr); } studio.menu->die(); studio.menu = nullptr; @@ -349,11 +347,10 @@ namespace unit.watch(f); f.editor->setText("new"); unit.write(f); - UNSCOPED_INFO("written"); CHECK(contents(f.file) == std::string("new")); { INFO("its own write is no change to the watch"); - REQUIRE_FALSE(f.watch->check()); + CHECK_FALSE(f.watch->check()); CHECK_FALSE(f.watch->check()); } { @@ -369,7 +366,7 @@ namespace INFO("will not go: said and stopped, not settled"); CHECK(said().failure); CHECK(studio.stops == Names{ g.id }); - REQUIRE(studio.settled.size() == 1); + CHECK(studio.settled.size() == 1); } } @@ -394,10 +391,10 @@ namespace // Read in, not written: what it masters is the masters' watch's to // send, not the tab's. UNSCOPED_INFO("not taken for a write of the studio's"); - REQUIRE(studio.written.empty()); + CHECK(studio.written.empty()); unit.changedOutside(f.id, f.file); UNSCOPED_INFO("the same again: nothing"); - REQUIRE(studio.taken.size() == 1); + CHECK(studio.taken.size() == 1); f.editor->setCaret(f.editor->document().end()); f.editor->insertText(" typed"); @@ -407,15 +404,15 @@ namespace INFO("not clean: said and asked, not taken"); CHECK(said().failure); CHECK(studio.asked == Names{ f.id }); - REQUIRE(studio.taken.size() == 1); + CHECK(studio.taken.size() == 1); } unit.changedOutside(f.id, f.file); UNSCOPED_INFO("asked once while the question is up"); - REQUIRE(studio.asked.size() == 1); + CHECK(studio.asked.size() == 1); studio.answer(false); { INFO("kept: nothing read"); - REQUIRE(studio.reverted.empty()); + CHECK(studio.reverted.empty()); CHECK_FALSE(f.askingReload); } unit.changedOutside(f.id, f.file); @@ -427,7 +424,7 @@ namespace std::filesystem::remove(fsyspath(f.file)); unit.changedOutside(f.id, f.file); UNSCOPED_INFO("gone or unknown: nothing"); - REQUIRE(studio.asked.size() == 2); + CHECK(studio.asked.size() == 2); UNSCOPED_INFO("but what is in reach looked at again"); CHECK(studio.reachChanges == before + 1); } @@ -436,7 +433,6 @@ namespace { ALScriptStudioFiles& unit = make(); unit.openFromDisk(); - UNSCOPED_INFO("several"); CHECK(studio.pickedSeveral); studio.toOpen({ "/a.lsl", "/b.luau" }); UNSCOPED_INFO("each opened"); @@ -445,14 +441,13 @@ namespace Doc& a = scriptTab("a", "first"); write(in("load.txt"), "loaded"); unit.load(false); - UNSCOPED_INFO("one"); CHECK_FALSE(studio.pickedSeveral); Doc& b = scriptTab("b", "other"); services.front = 1; studio.toOpen({ in("load.txt") }); { INFO("the tab asked from, brought forward, its text replaced"); - REQUIRE(a.editor->text() == "loaded"); + CHECK(a.editor->text() == "loaded"); CHECK(b.editor->text() == "other"); CHECK(studio.activated == Names{ "a" }); } @@ -465,7 +460,7 @@ namespace unit.chosenToLoad("b", { in("nothing.txt") }, false); { INFO("unreadable: said"); - REQUIRE_FALSE(services.statuses.empty()); + CHECK_FALSE(services.statuses.empty()); CHECK(b.editor->text() == "otloadedher"); } b.modifiable = false; @@ -519,7 +514,7 @@ namespace { INFO("its own file again: a save"); CHECK(contents(f.file) == "changed"); - REQUIRE(studio.became.size() == 1); + CHECK(studio.became.size() == 1); } Doc& other = fileTab("other.lsl", "o"); unit.chosenToSaveAs(f.id, { other.file }); @@ -528,7 +523,7 @@ namespace REQUIRE_FALSE(services.statuses.empty()); CHECK(services.statuses.back().find("FileOpenElsewhere") == 0); CHECK(contents(other.file) == "o"); - REQUIRE(studio.became.size() == 1); + CHECK(studio.became.size() == 1); } } @@ -540,10 +535,8 @@ namespace const fsyspath folder_path = fsyspath(in("J\xC3\xBCrgen")); std::filesystem::create_directories(folder_path); const std::string path = fsyspath(folder_path / fsyspath("\xC3\x9C" "berpr\xC3\xBC" "fung.lsl")).string(); - UNSCOPED_INFO("written"); CHECK(ALFileWrite::temp(path, "default\r\n{\r\n}\r\n")); std::string text; - UNSCOPED_INFO("read back"); REQUIRE(ALScriptFileIO::readWholeFile(path, text)); UNSCOPED_INFO("as an editor keeps it"); CHECK(text == std::string("default\n{\n}\n")); @@ -554,7 +547,6 @@ namespace TEST_CASE_METHOD(alscriptstudiofiles_data, "alscriptstudiofiles: pruneRecent drops scripts said gone and files no longer on disk", "[alscriptstudiofiles]") { ALScriptStudioFiles& unit = make(); - UNSCOPED_INFO("written"); CHECK(ALFileWrite::temp(in("here.lsl"), "x")); unit.noteFile(in("here.lsl")); unit.noteFile(in("gone.lsl")); @@ -567,7 +559,7 @@ namespace INFO("the file no longer there let go of"); CHECK(unit.pruneRecent([](const ALScriptRef&) { return false; })); CHECK(unit.recentFiles() == Names{ in("here.lsl") }); - REQUIRE(unit.recentScripts().size() == 2); + CHECK(unit.recentScripts().size() == 2); CHECK(studio.recentTold == told + 1); } { @@ -576,7 +568,6 @@ namespace CHECK(studio.recentTold == told + 1); } const ALScriptRef lost = b.ref; - UNSCOPED_INFO("pruned"); CHECK(unit.pruneRecent([lost](const ALScriptRef& ref) { return ref == lost; })); { INFO("the gone script let go of"); @@ -595,17 +586,14 @@ namespace SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } typedef ALScriptStudioFiles F; - UNSCOPED_INFO("XML"); CHECK(F::textSyntaxOf("/a/s.XML") == std::string("xml")); UNSCOPED_INFO("a skin's file"); CHECK(F::textSyntaxOf("/a/s.xui") == std::string("xml")); - UNSCOPED_INFO("JSON"); CHECK(F::textSyntaxOf("/a/s.json") == std::string("json")); UNSCOPED_INFO("a notecard of settings"); CHECK(F::textSyntaxOf("/a/door.ini") == std::string("config")); UNSCOPED_INFO("and another way of naming one"); CHECK(F::textSyntaxOf("/a/door.CFG") == std::string("config")); - UNSCOPED_INFO("text"); CHECK(F::textSyntaxOf("/a/s.txt") == std::string("text")); UNSCOPED_INFO("a name no grammar knows"); CHECK(F::textSyntaxOf("/a/s.dat") == std::string("text")); diff --git a/indra/newview/tests/alscriptstudiohistory_test.cpp b/indra/newview/tests/alscriptstudiohistory_test.cpp index e279ac1a08..43586af280 100644 --- a/indra/newview/tests/alscriptstudiohistory_test.cpp +++ b/indra/newview/tests/alscriptstudiohistory_test.cpp @@ -140,14 +140,14 @@ namespace } // A save of a tab's item, so long ago. - void saved(const Doc& doc, const std::string& text, F64 ago, const LLUUID& asset = LLUUID::generateNewID()) + void require_saved(const Doc& doc, const std::string& text, F64 ago, const LLUUID& asset = LLUUID::generateNewID()) { ALSavedText one; one.key = ALScriptStudioHistory::keyOf(doc); one.text = text; one.when = LLDate(LLDate::now().secondsSinceEpoch() - ago); one.asset = asset; - UNSCOPED_INFO("kept"); + INFO("kept in the history"); REQUIRE(history->keep(one)); } }; @@ -185,30 +185,28 @@ namespace CHECK(services().statuses.back() == said("HistoryNone", args)); const LLUUID current = LLUUID::generateNewID(); - saved(doc, "12345", 300.0); - saved(doc, "1234567", 200.0); - saved(doc, "123", 100.0, current); + require_saved(doc, "12345", 300.0); + require_saved(doc, "1234567", 200.0); + require_saved(doc, "123", 100.0, current); doc.assetId = current; unit.show(doc); - UNSCOPED_INFO("three"); REQUIRE(studio.candidates.size() == 3U); - UNSCOPED_INFO("titled"); CHECK(studio.picked == said("HistoryTitle", args)); const std::vector listed = history->list(ALScriptStudioHistory::keyOf(doc)); - UNSCOPED_INFO("labelled by when"); CHECK(studio.candidates[0].label == ALRecoveryEntry::sayWhen(listed[0].when)); const std::string& newest = studio.candidates[0].detail; - UNSCOPED_INFO("its length" + newest); - REQUIRE(newest.find(services().counted("HistoryBytes", 3)) != std::string::npos); - UNSCOPED_INFO("shorter than the one before" + newest); - REQUIRE(newest.find(services().counted("HistoryShorter", 4)) != std::string::npos); - UNSCOPED_INFO("saved now" + newest); - REQUIRE(newest.find(said("HistoryCurrent")) != std::string::npos); + { + CAPTURE(newest); + REQUIRE(newest.find(services().counted("HistoryBytes", 3)) != std::string::npos); + REQUIRE(newest.find(services().counted("HistoryShorter", 4)) != std::string::npos); + REQUIRE(newest.find(said("HistoryCurrent")) != std::string::npos); + } const std::string& middle = studio.candidates[1].detail; - UNSCOPED_INFO("longer" + middle); - REQUIRE(middle.find(services().counted("HistoryLonger", 2)) != std::string::npos); - UNSCOPED_INFO("not saved now" + middle); - REQUIRE(middle.find(said("HistoryCurrent")) == std::string::npos); + { + CAPTURE(middle); + REQUIRE(middle.find(services().counted("HistoryLonger", 2)) != std::string::npos); + REQUIRE(middle.find(said("HistoryCurrent")) == std::string::npos); + } { INFO("the first kept says nothing of one before"); REQUIRE(studio.candidates[2].detail.find(said("HistorySameLength")) == std::string::npos); @@ -223,7 +221,7 @@ namespace SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } Doc& doc = tab("door", "the text now"); - saved(doc, "the text then", 100.0); + require_saved(doc, "the text then", 100.0); unit.show(doc); studio.choose(studio.candidates[0].value); UNSCOPED_INFO("compared"); @@ -243,7 +241,7 @@ namespace CHECK(studio.notices == 1); Doc& loading = tab("lamp", "", false); - saved(loading, "a lamp's text", 50.0); + require_saved(loading, "a lamp's text", 50.0); unit.show(loading); studio.choose(studio.candidates[0].value); UNSCOPED_INFO("not compared yet"); @@ -269,7 +267,6 @@ namespace LLStringUtil::format_map_t args; args["[WHEN]"] = ALRecoveryEntry::sayWhen(shown.when); const ALScriptNoticeBar::Notice notice = ALScriptStudioOrphans::noticeFor(&doc, services()); - UNSCOPED_INFO("said"); CHECK(notice.text == said("NoticeHistory", args)); UNSCOPED_INFO("offered back"); CHECK(notice.buttons[0].first == std::string("restore_saved")); @@ -300,7 +297,6 @@ namespace return out; }; const std::vector listed = ALScriptStudioHistory::candidatesOf(saves, saves[0].asset, words, joined); - UNSCOPED_INFO("each"); REQUIRE(listed.size() == 3U); UNSCOPED_INFO("the newest"); CHECK(listed[0].detail == std::string("HistoryBytes(10) + HistorySameLength + HistoryCurrent")); @@ -308,7 +304,6 @@ namespace CHECK(listed[1].detail == std::string("HistoryBytes(10) + HistoryShorter(2)")); UNSCOPED_INFO("the first says only its length"); CHECK(listed[2].detail == std::string("HistoryBytes(12)")); - UNSCOPED_INFO("by when"); CHECK(listed[2].label == ALRecoveryEntry::sayWhen(saves[2].when)); UNSCOPED_INFO("valued by place"); CHECK(listed[1].value == std::string("1")); @@ -322,9 +317,9 @@ namespace } studio.host = window.floater; Doc& doc = tab("door", "now\nsame"); - saved(doc, "first\nsame", 300.0); - saved(doc, "second\nsame", 200.0); - saved(doc, "third\nsame", 100.0); + require_saved(doc, "first\nsame", 300.0); + require_saved(doc, "second\nsame", 200.0); + require_saved(doc, "third\nsame", 100.0); unit.show(doc); // Listed newest first: the middle one. studio.choose(studio.candidates[1].value); @@ -333,7 +328,6 @@ namespace CHECK(view.bar()->getChild("versions")->getVisible()); UNSCOPED_INFO("at the middle of three, oldest first"); CHECK(view.bar()->versionShown() == 1); - UNSCOPED_INFO("the second"); CHECK(view.leftText() == std::string("second\nsame")); const S32 notices = studio.notices; @@ -364,7 +358,7 @@ namespace ALViewType::as(view.bar()->getChild("older"))->press(); { INFO("the oldest"); - REQUIRE(view.leftText() == "first\nsame"); + CHECK(view.leftText() == "first\nsame"); CHECK(doc.historyShown->text == "first\nsame"); CHECK(view.bar()->versionShown() == 0); } @@ -378,8 +372,8 @@ namespace } studio.host = window.floater; Doc& loading = tab("lamp", "", false); - saved(loading, "one", 200.0); - saved(loading, "two", 100.0); + require_saved(loading, "one", 200.0); + require_saved(loading, "two", 100.0); unit.show(loading); studio.choose(studio.candidates[0].value); { @@ -396,12 +390,12 @@ namespace pending.shown(loading); { INFO("the slider, at the newest"); - REQUIRE(loading.compareView->bar()->getChild("versions")->getVisible()); + CHECK(loading.compareView->bar()->getChild("versions")->getVisible()); CHECK(loading.compareView->bar()->versionShown() == 1); } Doc& alone = tab("gate", "now"); - saved(alone, "only", 100.0); + require_saved(alone, "only", 100.0); unit.show(alone); studio.choose(studio.candidates[0].value); { @@ -419,8 +413,8 @@ namespace } studio.host = window.floater; Doc& doc = tab("door", "now"); - saved(doc, "older", 200.0); - saved(doc, "newer", 100.0); + require_saved(doc, "older", 200.0); + require_saved(doc, "newer", 100.0); unit.show(doc); studio.choose(studio.candidates[0].value); ALDiffView& view = *doc.compareView; @@ -434,7 +428,6 @@ namespace LLStringUtil::format_map_t args; args["[NAME]"] = "door"; args["[WHEN]"] = ALRecoveryEntry::sayWhen(listed[1].when); - UNSCOPED_INFO("said"); CHECK(services().statuses.back() == said("HistoryUnreadable", args)); UNSCOPED_INFO("the slider put back"); CHECK(view.bar()->versionShown() == 1); @@ -453,9 +446,9 @@ namespace } studio.host = window.floater; Doc& doc = tab("door", "now"); - saved(doc, "first", 300.0); - saved(doc, "second", 200.0); - saved(doc, "third", 100.0); + require_saved(doc, "first", 300.0); + require_saved(doc, "second", 200.0); + require_saved(doc, "third", 100.0); unit.show(doc); studio.choose(studio.candidates[1].value); ALDiffView& view = *doc.compareView; @@ -470,7 +463,7 @@ namespace press("older"); { INFO("the oldest again, as it was read"); - REQUIRE(view.leftText() == "first"); + CHECK(view.leftText() == "first"); CHECK(view.bar()->versionShown() == 0); CHECK(doc.historyShown->text == "first"); } @@ -484,14 +477,14 @@ namespace } studio.host = window.floater; Doc& doc = tab("door", "now"); - saved(doc, "first", 300.0); - saved(doc, "second", 200.0); + require_saved(doc, "first", 300.0); + require_saved(doc, "second", 200.0); unit.show(doc); studio.choose(studio.candidates[0].value); ALDiffView& view = *doc.compareView; { INFO("the slider"); - REQUIRE(view.bar()->getChild("versions")->getVisible()); + CHECK(view.bar()->getChild("versions")->getVisible()); CHECK(view.bar()->versionCount() == 2); } // As leaving the comparison does: Escape, or a keystroke typed into diff --git a/indra/newview/tests/alscriptstudiomasters_test.cpp b/indra/newview/tests/alscriptstudiomasters_test.cpp index e924cb4b27..b6e84bf597 100644 --- a/indra/newview/tests/alscriptstudiomasters_test.cpp +++ b/indra/newview/tests/alscriptstudiomasters_test.cpp @@ -327,12 +327,13 @@ namespace typedef std::vector Names; }; + // A tab may be linked where it is an item's, loaded, may be changed and is linked to + // nothing yet. TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: only a loaded changeable item's unlinked tab may be linked", "[alscriptstudiomasters]") { make(); Doc& script = itemTab("door", "default {}\n"); Doc& card = itemTab("card", "notes\n", false, true); - UNSCOPED_INFO("no tab"); CHECK_FALSE(unit->canLink(nullptr)); UNSCOPED_INFO("an item's script"); CHECK(unit->canLink(&script)); @@ -368,6 +369,8 @@ namespace CHECK(unit->mastersAny(services.findDoc("disk:" + in("door.lsl")))); } + // A notecard carrying items is not linked, and says why, before any file is picked; a script, + // or a notecard carrying none, carries nothing. TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a notecard carrying items is refused with a reason before any pick", "[alscriptstudiomasters]") { make(); @@ -403,6 +406,8 @@ namespace REQUIRE_FALSE(disk.linkOf(card.ref)); } + // A file picked of another language is refused, and said, before anything is linked: LSL, SLua, + // a notecard's, and a name with no extension. TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a file picked of another language is refused and its own is linked", "[alscriptstudiomasters]") { make(); @@ -468,6 +473,8 @@ namespace } } + // A clean tab linked gives way to its file's tab; where the file is what it holds the file's + // stamp is taken, else Send File and Compare are offered there. TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a linked clean tab gives way and takes the stamp of a matching file", "[alscriptstudiomasters]") { make(); @@ -477,7 +484,6 @@ namespace write(in("door.lsl"), "default {}\n"); studio->picked = in("door.lsl"); unit->linkToFile(same); - UNSCOPED_INFO("nothing asked"); REQUIRE(studio->asked.empty()); const std::optional link = disk.linkOf(ref); { @@ -537,6 +543,8 @@ namespace } } + // A tab with unsaved changes linked is asked first: Cancel links nothing, Discard holds the + // file up to the text as last saved, Write puts what was typed in the file. TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: linking a tab with unsaved changes asks to cancel or discard or write", "[alscriptstudiomasters]") { make(); @@ -629,6 +637,8 @@ namespace } } + // Linked from elsewhere: a clean tab gives way to its file's once the links have changed; one + // with something typed is kept and told once, with Compare with File, Open File and Unlink. TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a link from elsewhere closes a clean tab and tells a typed one once", "[alscriptstudiomasters]") { make(); @@ -658,7 +668,7 @@ namespace }); }; UNSCOPED_INFO("the one with something typed told once"); - CHECK(told("lamp") == 1); + REQUIRE(told("lamp") == 1); const al_studio_test::FakeServices::Said& lamp = *std::find_if(services.reports.begin(), services.reports.end(), [](const al_studio_test::FakeServices::Said& one) { return one.doc == "lamp"; }); { @@ -690,6 +700,8 @@ namespace CHECK(services.findDoc("gone") == &gone); } + // A tab kept for what was typed gives way once that is saved -- its file's tab offering Send + // File and Compare where the world now differs -- or reverted. TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a tab kept for what was typed gives way once saved or reverted", "[alscriptstudiomasters]") { make(); @@ -699,7 +711,7 @@ namespace const ALScriptRef door_ref = door.ref; ALMasterLink link = linkFromElsewhere(door, in("door.lsl")); settle(); - UNSCOPED_INFO("kept"); + UNSCOPED_INFO("the tab with something typed is kept"); CHECK(services.findDoc("door") == &door); // Saved from here: the world holds what was typed, and the save @@ -751,7 +763,6 @@ namespace const size_t before = services.reports.size(); unit->saved(saved); settle(); - UNSCOPED_INFO("nothing"); REQUIRE(services.reports.size() == before); // Reverted: loaded again, clean. @@ -770,6 +781,8 @@ namespace } } + // The offers on a tab kept for what was typed: its file on disk set beside it, its file's tab + // opened beside it, the link let go of. TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a kept tab's offers compare with its file or open it or unlink it", "[alscriptstudiomasters]") { make(); @@ -780,7 +793,6 @@ namespace settle(); unit->offer(door, "master_compare_file"); - UNSCOPED_INFO("compared once"); REQUIRE(studio->compared.size() == size_t(1)); const FakeMastersWindow::Compared& compared = studio->compared.back(); { @@ -836,6 +848,8 @@ namespace REQUIRE(studio->compared.size() == 1); } + // The file a script names is linked by Link while nothing is typed in its tab; with something + // typed, it is to be saved or reverted first, and nothing is written. TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: the Link offer links a script's named file only while nothing is typed", "[alscriptstudiomasters]") { make(); @@ -887,6 +901,9 @@ namespace } } + // A tab kept for what was typed, made clean by an undo, is kept and offered to switch to + // its file, and told again when typed in; Switch to File gives way, as a revert or a save + // of it does. TEST_CASE_METHOD(alscriptstudiomasters_data, "alscriptstudiomasters: a kept tab made clean by an undo is offered Switch to File", "[alscriptstudiomasters]") { make(); diff --git a/indra/newview/tests/alscriptstudiomerging_test.cpp b/indra/newview/tests/alscriptstudiomerging_test.cpp index 2624eb9d43..98e3df496c 100644 --- a/indra/newview/tests/alscriptstudiomerging_test.cpp +++ b/indra/newview/tests/alscriptstudiomerging_test.cpp @@ -151,7 +151,6 @@ namespace } Doc& doc = tab("door"); doc.savedThere = theirs; - UNSCOPED_INFO("it can be merged"); CHECK(ALScriptStudioMerging::canMerge(doc)); unit->mergeSaved(doc); UNSCOPED_INFO("theirs's line put in, ours kept"); @@ -161,19 +160,14 @@ namespace REQUIRE(studio.titles.size() == 1); CHECK(studio.titles[0] == said("CompareSavedThere")); } - { - INFO("as a merge"); - REQUIRE(doc.compareView); - CHECK(doc.compareView->merging()); - } - UNSCOPED_INFO("one conflict"); + REQUIRE(doc.compareView); + CHECK(doc.compareView->merging()); CHECK(doc.compareView->conflictCount() == 1); { INFO("take and keep done with"); REQUIRE_FALSE(doc.savedThere); CHECK(studio.notices == 1); } - UNSCOPED_INFO("said"); CHECK(services().reports.back().text == services().counted("MergeConflicts", 1, named(doc))); // Settled from the comparison's bar: an edit of the tab. @@ -183,13 +177,11 @@ namespace UNSCOPED_INFO("mine then theirs"); CHECK(doc.editor->wholeText() == lines(9, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "mine 6" }, { 7, "theirs 6" }, { 8, "line 7" } })); - UNSCOPED_INFO("none left"); CHECK(doc.compareView->conflictCount() == 0); // Each a step to undo: the settling, then the merge. doc.editor->undo(); doc.editor->undo(); - UNSCOPED_INFO("back to ours"); CHECK(doc.editor->wholeText() == ours); } @@ -202,14 +194,9 @@ namespace Doc& doc = tab("door"); doc.savedThere = lines(8, { { 0, "theirs 0" } }); unit->mergeSaved(doc); - UNSCOPED_INFO("merged"); CHECK(doc.editor->wholeText() == lines(8, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "mine 6" } })); - { - INFO("no conflicts"); - REQUIRE(doc.compareView->merging()); - CHECK(doc.compareView->conflictCount() == 0); - } - UNSCOPED_INFO("said"); + REQUIRE(doc.compareView->merging()); + CHECK(doc.compareView->conflictCount() == 0); CHECK(services().reports.back().text == said("MergeClean", named(doc))); } @@ -236,13 +223,11 @@ namespace REQUIRE(doc.savedThere); CHECK(studio.notices == 0); } - UNSCOPED_INFO("said"); CHECK(services().statuses.back() == said("MergeNoBase", named(doc))); Doc& locked = tab("lamp"); locked.modifiable = false; locked.savedThere = theirs; - UNSCOPED_INFO("cannot be merged"); CHECK_FALSE(ALScriptStudioMerging::canMerge(locked)); unit->mergeSaved(locked); { @@ -251,7 +236,6 @@ namespace REQUIRE(locked.compareView); CHECK_FALSE(locked.compareView->merging()); } - UNSCOPED_INFO("said"); CHECK(services().statuses.back() == said("MergeReadOnly", named(locked))); } @@ -266,12 +250,10 @@ namespace const LLUUID moved = LLUUID::generateNewID(); doc.assetId = was; unit->mergeWorld(doc); - UNSCOPED_INFO("asked"); CHECK(studio.worldAsked == std::string("door")); UNSCOPED_INFO("nothing yet"); CHECK(doc.editor->wholeText() == ours); studio.world(doc, theirs, moved); - UNSCOPED_INFO("merged"); CHECK(doc.editor->wholeText() == lines(8, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "mine 6" } })); { INFO("under the world's title, as a merge"); @@ -287,7 +269,7 @@ namespace unit.reset(); studio.world(lamp, theirs, moved); { - INFO("nothing"); + INFO("nothing once the merges are gone"); CHECK(lamp.editor->wholeText() == ours); CHECK(lamp.assetId == was); } @@ -319,7 +301,6 @@ namespace const S32 notices = studio.notices; doc.editor->undo(); - UNSCOPED_INFO("back to ours"); CHECK(doc.editor->wholeText() == ours); unit->textChanged(doc); { @@ -328,7 +309,6 @@ namespace CHECK(*doc.savedThere == theirs); REQUIRE_FALSE(doc.merged); } - UNSCOPED_INFO("said"); CHECK(services().reports.back().text == said("MergeTakenBack", named(doc))); UNSCOPED_INFO("take, keep, merge and compare offered again"); CHECK(services().reports.back().actions == std::vector{ "take_saved", "keep_saved", "merge_saved", "compare_saved" }); @@ -409,13 +389,10 @@ namespace doc.compareView->right()->goTo(ALTextPos(6, 0)); UNSCOPED_INFO("where it is in one"); CHECK(ALScriptStudioMerging::canSettle(doc)); - UNSCOPED_INFO("settled with theirs"); CHECK(ALScriptStudioMerging::settle(doc, ALTextMerge::Take::Theirs)); UNSCOPED_INFO("theirs in the tab"); CHECK(doc.editor->wholeText() == lines(8, { { 0, "theirs 0" }, { 2, "mine 2" }, { 6, "theirs 6" } })); - UNSCOPED_INFO("none left"); CHECK(doc.compareView->conflictCount() == 0); - UNSCOPED_INFO("nothing left to settle"); CHECK_FALSE(ALScriptStudioMerging::canSettle(doc)); notice = ALScriptStudioOrphans::noticeFor(&doc, services()); UNSCOPED_INFO("nor to say"); @@ -443,12 +420,8 @@ namespace lines(8, { { 3, " three" }, { 5, "mine 5" }, { 7, " line 7" } })); UNSCOPED_INFO("compared with the tab as merged"); CHECK(doc.compareView->rightText() == doc.editor->wholeText()); - { - INFO("a merge with no conflict"); - REQUIRE(doc.compareView->merging()); - CHECK(doc.compareView->conflictCount() == 0); - } - UNSCOPED_INFO("said"); + REQUIRE(doc.compareView->merging()); + CHECK(doc.compareView->conflictCount() == 0); CHECK(services().reports.back().text == said("MergeClean", named(doc))); } } diff --git a/indra/newview/tests/alscriptstudioorphans_test.cpp b/indra/newview/tests/alscriptstudioorphans_test.cpp index 207ee7e1fb..1203f8fccc 100644 --- a/indra/newview/tests/alscriptstudioorphans_test.cpp +++ b/indra/newview/tests/alscriptstudioorphans_test.cpp @@ -177,13 +177,11 @@ namespace UNSCOPED_INFO("but not once it is gone"); CHECK(Orphans::seen(o, reach) == Orphan::Removed); reach.offline = true; - UNSCOPED_INFO("offline"); CHECK(Orphans::seen(o, reach) == Orphan::Offline); Doc& i = tab("inventory", true); Reach item = inReach(); item.trashed = true; - UNSCOPED_INFO("in the Trash"); CHECK(Orphans::seen(i, item) == Orphan::Trashed); i.orphan->kind = Orphan::Unloaded; UNSCOPED_INFO("an unloaded text stays so in the Trash"); @@ -196,7 +194,6 @@ namespace f.ref = ALScriptRef(); f.file = "/somewhere/f.lsl"; Reach file; - UNSCOPED_INFO("its file gone"); CHECK(Orphans::seen(f, file) == Orphan::FileGone); file.fileThere = true; UNSCOPED_INFO("its file there"); @@ -211,11 +208,8 @@ namespace make(); Doc& o = tab("object"); Doc& i = tab("inventory", true); - UNSCOPED_INFO("not permitted"); CHECK(Orphans::failedAs(o, Failure::NotPermitted, true) == Orphan::Locked); - UNSCOPED_INFO("unreadable"); CHECK(Orphans::failedAs(o, Failure::Unreadable, true) == Orphan::Unloaded); - UNSCOPED_INFO("a fetch that failed"); CHECK(Orphans::failedAs(o, Failure::Fetch, true) == Orphan::Unloaded); UNSCOPED_INFO("gone from its object"); CHECK(Orphans::failedAs(o, Failure::Missing, true) == Orphan::Removed); @@ -236,12 +230,12 @@ namespace CHECK(studio.placed == Names{ "a", "b" }); { INFO("out of sight a moment: not yet away"); - REQUIRE(a.orphan->kind == Orphan::None); + CHECK(a.orphan->kind == Orphan::None); CHECK(a.orphan->awaySince > 0.0); } { INFO("and to be looked at again once the moment is past"); - REQUIRE(due > a.orphan->awaySince); + CHECK(due > a.orphan->awaySince); CHECK(due <= a.orphan->awaySince + 3.0); } a.orphan->awaySince -= 5.0; @@ -249,7 +243,7 @@ namespace unit.check(); { INFO("gone a while: away"); - REQUIRE(a.orphan->kind == Orphan::Away); + CHECK(a.orphan->kind == Orphan::Away); CHECK_FALSE(a.orphan->noticeDismissed); CHECK(studio.toolbars == 1); } @@ -271,7 +265,7 @@ namespace unit.check(); { INFO("back: said"); - REQUIRE(a.orphan->kind == Orphan::None); + CHECK(a.orphan->kind == Orphan::None); CHECK(services().reports.back().text == said("OrphanBack", "[NAME]", "a")); CHECK(a.orphan->awaySince == 0.0); } @@ -279,7 +273,7 @@ namespace unit.check(); { INFO("nothing changed: nothing said"); - REQUIRE(services().reports.size() == said); + CHECK(services().reports.size() == said); CHECK(studio.toolbars == 3); } Doc& c = tab("c"); @@ -290,7 +284,7 @@ namespace { INFO("a detached one back: nothing said, its load will"); CHECK(c.orphan->kind == Orphan::None); - REQUIRE(services().reports.size() == said); + CHECK(services().reports.size() == said); } } @@ -306,31 +300,28 @@ namespace a.orphan->reattachTries = ALRecoveryRetry::TRIES; unit.check(); UNSCOPED_INFO("tried out: waits for a person"); - REQUIRE(studio.loads.empty()); + CHECK(studio.loads.empty()); a.orphan->reattachTries = 1; a.orphan->nextReattach = LLTimer::getTotalSeconds() + 60.0; const F64 next = unit.check(); UNSCOPED_INFO("to be looked at again when its try is due"); CHECK(next == a.orphan->nextReattach); UNSCOPED_INFO("not due yet"); - REQUIRE(studio.loads.empty()); + CHECK(studio.loads.empty()); a.orphan->nextReattach = 0.0; unit.check(); - { - INFO("loaded"); - REQUIRE(studio.loads.size() == 1); - CHECK(studio.loads[0] == a.ref); - } + REQUIRE(studio.loads.size() == 1); + CHECK(studio.loads[0] == a.ref); { INFO("what it holds kept first, and carried over"); - REQUIRE(recovery->keptFor(a.recoveryKey) == 1); + CHECK(recovery->keptFor(a.recoveryKey) == 1); REQUIRE(a.carriedText); CHECK(*a.carriedText == "kept text"); } { INFO("not loaded, and not to be typed in, until it is"); - REQUIRE_FALSE(a.loaded); - REQUIRE(a.editor->isReadOnly()); + CHECK_FALSE(a.loaded); + CHECK(a.editor->isReadOnly()); CHECK_FALSE(a.orphan->detached); } Doc& u = tab("u"); @@ -340,11 +331,11 @@ namespace studio.reaches["u"].heldByPrim = true; unit.check(); UNSCOPED_INFO("an unreadable one is not tried on its own"); - REQUIRE(studio.loads.size() == 1); + CHECK(studio.loads.size() == 1); u.loadFailure = Failure::Fetch; unit.check(); UNSCOPED_INFO("a fetch that failed is"); - REQUIRE(studio.loads.size() == 2); + CHECK(studio.loads.size() == 2); } TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: the notice says a kept text first then each kind's words and buttons", "[alscriptstudioorphans]") @@ -352,10 +343,9 @@ namespace make(); const al_studio_test::FakeServices& words = services(); UNSCOPED_INFO("no tab: nothing"); - REQUIRE(Orphans::noticeFor(nullptr, words).text.empty()); + CHECK(Orphans::noticeFor(nullptr, words).text.empty()); Doc& a = tab("a"); - UNSCOPED_INFO("nothing to say"); - REQUIRE(Orphans::noticeFor(&a, words).text.empty()); + CHECK(Orphans::noticeFor(&a, words).text.empty()); ALRecoveryEntry kept; kept.baseAsset = LLUUID::generateNewID(); a.recoverable = kept; @@ -374,25 +364,22 @@ namespace CHECK(Orphans::noticeFor(&a, words).text == said("NoticeRecoverableStale", "[WHEN]", when)); a.recoverable.reset(); notice = Orphans::noticeFor(&a, words); - { - INFO("away"); - CHECK(notice.text == said("NoticeAway")); - CHECK(notice.buttons[0].first == "copy"); - CHECK(notice.buttons[1].first == "export"); - } + CHECK(notice.text == said("NoticeAway")); + CHECK(notice.buttons[0].first == "copy"); + CHECK(notice.buttons[1].first == "export"); a.orphan->kind = Orphan::Offline; notice = Orphans::noticeFor(&a, words); { INFO("offline: a copy on disk alone"); CHECK(notice.buttons[0].first == "export"); - REQUIRE(notice.buttons[1].first.empty()); + CHECK(notice.buttons[1].first.empty()); } a.orphan->kind = Orphan::Unloaded; a.loadError = "no such asset"; notice = Orphans::noticeFor(&a, words); { INFO("unloaded: why, and to try again"); - REQUIRE(notice.text.find("no such asset") != std::string::npos); + CHECK(notice.text.find("no such asset") != std::string::npos); CHECK(notice.buttons[0].first == "retry_load"); } a.orphan->kind = Orphan::Trashed; @@ -400,14 +387,14 @@ namespace { INFO("in the Trash: said, nothing to do"); CHECK(notice.text == said("NoticeTrashed")); - REQUIRE(notice.buttons[0].first.empty()); + CHECK(notice.buttons[0].first.empty()); } a.orphan->kind = Orphan::FileGone; a.file = "/somewhere/a.lsl"; notice = Orphans::noticeFor(&a, words); { INFO("a file gone: saved again"); - REQUIRE(notice.text.find("/somewhere/a.lsl") != std::string::npos); + CHECK(notice.text.find("/somewhere/a.lsl") != std::string::npos); CHECK(notice.buttons[0].first == "save"); } Doc& i = tab("i", true); @@ -416,7 +403,7 @@ namespace CHECK(Orphans::noticeFor(&i, words).text == said("NoticeRemovedInventory")); i.orphan->noticeDismissed = true; UNSCOPED_INFO("hidden: nothing"); - REQUIRE(Orphans::noticeFor(&i, words).text.empty()); + CHECK(Orphans::noticeFor(&i, words).text.empty()); } TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: the notice's actions act on the tab in front", "[alscriptstudioorphans]") @@ -429,40 +416,34 @@ namespace { INFO("restored, the source in front"); CHECK(studio.did == Names{ "source a", "carried a: restored text" }); - REQUIRE_FALSE(a.recoverable); + CHECK_FALSE(a.recoverable); CHECK(services().reports.back().text == said("RecoveryRestored", "[NAME]", "a")); } a.recoverable = ALRecoveryEntry(); unit.noticeAction("discard_left"); - { - INFO("discarded"); - CHECK(studio.did.back() == "discard"); - REQUIRE_FALSE(a.recoverable); - } + CHECK(studio.did.back() == "discard"); + CHECK_FALSE(a.recoverable); a.recoverable = ALRecoveryEntry(); unit.noticeAction("close"); { INFO("hidden, the kept text let go of here"); CHECK(a.orphan->noticeDismissed); - REQUIRE_FALSE(a.recoverable); + CHECK_FALSE(a.recoverable); } unit.noticeAction("copy"); unit.noticeAction("export"); unit.noticeAction("save"); - { - INFO("a copy, a file, a save"); - CHECK(studio.did == Names{ "source a", "carried a: restored text", "source a", "discard", "copy a", "save a" }); - CHECK(files->picked == Names{ "a" }); - } + CHECK(studio.did == Names{ "source a", "carried a: restored text", "source a", "discard", "copy a", "save a" }); + CHECK(files->picked == Names{ "a" }); a.orphan->reattachTries = 3; unit.noticeAction("retry_load"); UNSCOPED_INFO("not detached: nothing to try"); - REQUIRE(studio.loads.empty()); + CHECK(studio.loads.empty()); a.orphan->detached = true; unit.noticeAction("retry_load"); { INFO("tried again, from the first try"); - REQUIRE(studio.loads.size() == 1); + CHECK(studio.loads.size() == 1); CHECK(a.orphan->reattachTries == 0); } } @@ -479,17 +460,15 @@ namespace a.orphan->kind = Orphan::Away; unit.refreshNotice(); LLView* holder = bar->getParent(); - UNSCOPED_INFO("shown"); CHECK(holder->getVisible()); - UNSCOPED_INFO("its words"); CHECK(bar->getChild("notice_text")->getText() == said("NoticeAway")); LLButton* first = bar->getChild("notice_first"); LLButton* second = bar->getChild("notice_second"); { INFO("its buttons, labelled"); - REQUIRE(first->getVisible()); + CHECK(first->getVisible()); CHECK(second->getVisible()); - REQUIRE(first->getLabelSelected() == said("NoticeCopy")); + CHECK(first->getLabelSelected() == said("NoticeCopy")); CHECK(first->getToolTip() == said("NoticeCopyTip")); } UNSCOPED_INFO("the first left of the second"); @@ -509,7 +488,6 @@ namespace } a.orphan->kind = Orphan::None; unit.refreshNotice(); - UNSCOPED_INFO("hidden"); CHECK_FALSE(holder->getVisible()); } @@ -534,7 +512,7 @@ namespace CHECK(studio.did.back() == "compare a: default { touch_start(integer n) { llDie(); } } | default { } (" + said("CompareCompiled") + " | " + said("CompareMade") + ")"); UNSCOPED_INFO("the notice stays, to act on after looking"); - REQUIRE(a.compiledDiffers.has_value()); + CHECK(a.compiledDiffers.has_value()); studio.did.clear(); a.orphan->kind = Orphan::Away; UNSCOPED_INFO("a tab gone first"); @@ -544,7 +522,7 @@ namespace { INFO("the source back in front, then taken as the source"); CHECK(studio.did == Names{ "source a", "carried a: default { touch_start(integer n) { llDie(); } }" }); - REQUIRE_FALSE(a.compiledDiffers); + CHECK_FALSE(a.compiledDiffers); } UNSCOPED_INFO("and said"); CHECK(services().reports.back().text == said("CompiledTaken", "[NAME]", "a")); @@ -552,11 +530,11 @@ namespace unit.noticeAction("keep_source"); { INFO("kept: let go of, the next save replacing it"); - REQUIRE_FALSE(a.compiledDiffers); + CHECK_FALSE(a.compiledDiffers); CHECK(studio.did.back() == "source a"); } UNSCOPED_INFO("nothing more to say"); - REQUIRE(Orphans::noticeFor(&a, words).text.empty()); + CHECK(Orphans::noticeFor(&a, words).text.empty()); } TEST_CASE_METHOD(alscriptstudioorphans_data, "alscriptstudioorphans: a kept text compares with the tab and restores with the source in front", "[alscriptstudioorphans]") @@ -574,11 +552,11 @@ namespace CHECK(studio.did.back() == "compare a: default {} | default { state_entry() { } } (" + said("CompareNow") + " | " + said("CompareKept", "[WHEN]", kept.whenSaid()) + ")"); UNSCOPED_INFO("still offered"); - REQUIRE(a.recoverable.has_value()); + CHECK(a.recoverable.has_value()); unit.noticeAction("restore"); { INFO("the source in front first"); - REQUIRE(studio.did[studio.did.size() - 2] == "source a"); + CHECK(studio.did[studio.did.size() - 2] == "source a"); CHECK(studio.did.back() == "carried a: default { state_entry() { } }"); } } @@ -610,11 +588,11 @@ namespace { INFO("taken up, and let go of"); CHECK(studio.did.back() == "offer a: retry"); - REQUIRE_FALSE(a.offer); + CHECK_FALSE(a.offer); } a.offer = Doc::Offer{ "Saved elsewhere.", { "take_saved", "keep_saved", "merge_saved", "compare_saved" } }; UNSCOPED_INFO("a conflict with nothing to take: not said"); - REQUIRE(Orphans::noticeFor(&a, words).text.empty()); + CHECK(Orphans::noticeFor(&a, words).text.empty()); a.savedThere = std::string("theirs"); notice = Orphans::noticeFor(&a, words); { @@ -627,7 +605,7 @@ namespace unit.noticeAction("close"); { INFO("hidden: let go of, and nothing else"); - REQUIRE_FALSE(a.offer); + CHECK_FALSE(a.offer); CHECK_FALSE(a.orphan->noticeDismissed); CHECK(studio.did.back() == "offer a: retry"); } @@ -646,14 +624,14 @@ namespace { INFO("what a tab gone says of itself, hidden with it"); CHECK(a.orphan->noticeDismissed); - REQUIRE_FALSE(a.offer); + CHECK_FALSE(a.offer); } a.orphan->noticeDismissed = false; a.offer = Doc::Offer{ "Saving a failed.", { "retry", "copy", "export" } }; unit.noticeAction("close"); { INFO("more than that: said next"); - REQUIRE(a.offer); + CHECK(a.offer); CHECK(Orphans::noticeFor(&a, words).text == "Saving a failed."); } } @@ -685,8 +663,8 @@ namespace Orphans::become(a, Doc::Orphan::Removed); { INFO("removed, and said"); - REQUIRE(a.orphan->kind == Doc::Orphan::Removed); - REQUIRE_FALSE(a.orphan->noticeDismissed); + CHECK(a.orphan->kind == Doc::Orphan::Removed); + CHECK_FALSE(a.orphan->noticeDismissed); CHECK_FALSE(a.orphan->detached); } a.orphan->noticeDismissed = true; @@ -696,7 +674,7 @@ namespace Orphans::detach(a, Doc::Orphan::Unloaded); { INFO("an item's kept text detached"); - REQUIRE(a.orphan->detached); + CHECK(a.orphan->detached); CHECK(a.orphan->kind == Doc::Orphan::Unloaded); } Doc& f = tab("f"); @@ -704,7 +682,7 @@ namespace Orphans::detach(f, Doc::Orphan::FileGone); { INFO("a file's not: nothing is loaded under it"); - REQUIRE_FALSE(f.orphan->detached); + CHECK_FALSE(f.orphan->detached); CHECK(f.orphan->kind == Doc::Orphan::FileGone); } @@ -736,7 +714,7 @@ namespace { INFO("the source back in front, then taken"); CHECK(studio.did == Names{ "source a", "carried a: default { }" }); - REQUIRE_FALSE(a.historyShown); + CHECK_FALSE(a.historyShown); } LLStringUtil::format_map_t args; args["[NAME]"] = "a"; @@ -750,11 +728,11 @@ namespace unit.noticeAction("restore_saved"); { INFO("not into a tab that may not be changed"); - REQUIRE(studio.did.empty()); - REQUIRE(a.historyShown); + CHECK(studio.did.empty()); + CHECK(a.historyShown); } unit.noticeAction("close"); UNSCOPED_INFO("let go of with the notice"); - REQUIRE_FALSE(a.historyShown); + CHECK_FALSE(a.historyShown); } } diff --git a/indra/newview/tests/alscriptstudiorecovery_test.cpp b/indra/newview/tests/alscriptstudiorecovery_test.cpp index ab0b489d16..a40420d655 100644 --- a/indra/newview/tests/alscriptstudiorecovery_test.cpp +++ b/indra/newview/tests/alscriptstudiorecovery_test.cpp @@ -179,7 +179,7 @@ namespace } // An entry another session left for a tab's script. - Entry leftFor(const Doc& doc, const std::string& text, const std::string& session = "old-session") + Entry require_left_for(const Doc& doc, const std::string& text, const std::string& session = "old-session") { ALRecoveryStore other(folder, session); Entry entry = ALScriptStudioRecovery::entryOf(doc); @@ -222,11 +222,8 @@ namespace type(a, "// one"); type(a, " two"); const Entry entry = ALScriptStudioRecovery::entryOf(a); - { - INFO("the text"); - CHECK(entry.text == "default {}\n// one two"); - CHECK(entry.key == a.recoveryKey); - } + CHECK(entry.text == "default {}\n// one two"); + CHECK(entry.key == a.recoveryKey); { INFO("where it came from"); CHECK(entry.object == a.ref.object); @@ -234,34 +231,24 @@ namespace CHECK(entry.name == "a"); CHECK_FALSE(entry.notecard); } - { - INFO("the caret"); - CHECK(entry.caretLine == 1); - CHECK(entry.caretColumn == 10); - } + CHECK(entry.caretLine == 1); + CHECK(entry.caretColumn == 10); { INFO("and the steps, as the journal writes them"); - REQUIRE(entry.historyOf().isMap()); + CHECK(entry.historyOf().isMap()); REQUIRE_FALSE(entry.historyWritten.empty()); } Doc& b = tab("b", "default {}\n", a.ref); - UNSCOPED_INFO("put back"); CHECK(r.restoreHistory(b, entry)); - { - INFO("its text"); - REQUIRE(b.editor->text() == entry.text); - CHECK(b.editor->isDirty()); - } - { - INFO("its caret"); - REQUIRE(b.editor->caret().line == 1); - CHECK(b.editor->caret().column == 10); - } + CHECK(b.editor->text() == entry.text); + CHECK(b.editor->isDirty()); + CHECK(b.editor->caret().line == 1); + CHECK(b.editor->caret().column == 10); b.editor->undo(); { INFO("and the steps that led to it, to take back"); - REQUIRE(b.editor->text() != entry.text); + CHECK(b.editor->text() != entry.text); CHECK(b.editor->text().starts_with("default {}\n")); } UNSCOPED_INFO("the tabs told"); @@ -275,7 +262,7 @@ namespace wrong.text = "not where the steps lead\n"; { INFO("nor where the history is not of its text"); - REQUIRE_FALSE(r.restoreHistory(c, wrong)); + CHECK_FALSE(r.restoreHistory(c, wrong)); CHECK(c.editor->text() == "something else\n"); } } @@ -290,11 +277,8 @@ namespace CHECK(keptFor(doc.recoveryKey) == 0); } type(doc, "y"); - { - INFO("kept"); - CHECK(r.keep(doc)); - CHECK(keptFor(doc.recoveryKey) == 1); - } + CHECK(r.keep(doc)); + CHECK(keptFor(doc.recoveryKey) == 1); doc.editor->resetDirty(); { INFO("clean again: forgotten"); @@ -302,7 +286,7 @@ namespace CHECK(keptFor(doc.recoveryKey) == 0); } - doc.recovering = leftFor(doc, "an old session's"); + doc.recovering = require_left_for(doc, "an old session's"); UNSCOPED_INFO("the old session's there"); CHECK(keptFor(doc.recoveryKey, "old-session") == 1); type(doc, "z"); @@ -336,15 +320,11 @@ namespace ALRecoveryStore nowhere(blocked, "this-session"); ALRecovery::useStore(&nowhere); type(doc, "y"); - UNSCOPED_INFO("not kept"); CHECK_FALSE(r.keep(doc)); - { - INFO("said"); - REQUIRE(services().reports.size() == 1); - CHECK(services().reports[0].failure); - CHECK(services().reports[0].doc == "a"); - REQUIRE(services().reports[0].text.find("a") != std::string::npos); - } + REQUIRE(services().reports.size() == 1); + CHECK(services().reports[0].failure); + CHECK(services().reports[0].doc == "a"); + CHECK(services().reports[0].text.find("a") != std::string::npos); type(doc, "z"); { INFO("not said again"); @@ -381,12 +361,12 @@ namespace { ALScriptStudioRecovery& r = make(); Doc& doc = tab("a", "old\n"); - const Entry kept = leftFor(doc, "kept\n"); + const Entry kept = require_left_for(doc, "kept\n"); doc.loaded = false; r.takeUp(doc, kept); { INFO("waiting"); - REQUIRE(doc.carriedText == std::optional("kept\n")); + CHECK(doc.carriedText == std::optional("kept\n")); REQUIRE(doc.recovering); CHECK(doc.editor->text() == "old\n"); } @@ -395,12 +375,9 @@ namespace doc.carriedText.reset(); doc.recovering.reset(); r.takeUp(doc, kept); - { - INFO("in"); - REQUIRE(doc.editor->text() == "kept\n"); - CHECK(doc.editor->isDirty()); - REQUIRE_FALSE(doc.carriedText); - } + CHECK(doc.editor->text() == "kept\n"); + CHECK(doc.editor->isDirty()); + REQUIRE_FALSE(doc.carriedText); { INFO("kept by this session, the old entry let go of"); CHECK(keptFor(doc.recoveryKey) == 1); @@ -414,7 +391,7 @@ namespace Doc& locked = tab("b", "locked\n"); locked.modifiable = false; - r.takeUp(locked, leftFor(locked, "kept too\n")); + r.takeUp(locked, require_left_for(locked, "kept too\n")); { INFO("held on its own"); REQUIRE(studio().became.size() == 1); @@ -517,10 +494,9 @@ namespace type(mine, "b"); r.keep(mine); Doc& theirs = tab("theirs", "c\n"); - const Entry left = leftFor(theirs, "left\n"); + const Entry left = require_left_for(theirs, "left\n"); Doc& gone = tab("gone", "d\n"); type(gone, "e"); - UNSCOPED_INFO("set aside"); CHECK(r.setAside(gone)); r.show(); UNSCOPED_INFO("theirs and what was set aside"); @@ -644,7 +620,6 @@ namespace Doc& clean = tab("c", "three\n"); type(a, "x"); type(b, "y"); - UNSCOPED_INFO("kept"); CHECK(r.keepAll({ &a, &b, &clean }, Entry::State::Kept)); { INFO("both written"); @@ -668,12 +643,11 @@ namespace ALRecovery::useStore(&nowhere); type(a, "z"); type(b, "w"); - UNSCOPED_INFO("not kept"); CHECK_FALSE(r.keepAll({ &a, &b })); { INFO("each said once"); REQUIRE(services().reports.size() == 2); - REQUIRE(a.recovery->failed); + CHECK(a.recovery->failed); CHECK(b.recovery->failed); } ALRecovery::useStore(store.get()); @@ -684,11 +658,8 @@ namespace ALScriptStudioRecovery& r = make(); Doc& a = tab("a", "one\n"); type(a, "x"); - { - INFO("kept"); - CHECK(r.keep(a)); - CHECK(keptFor(a.recoveryKey) == 1); - } + CHECK(r.keep(a)); + CHECK(keptFor(a.recoveryKey) == 1); // Taken away behind its back: not written again while nothing moved. for (const Entry& entry : store->list()) { @@ -736,11 +707,8 @@ namespace Entry lost = entry("item:lost", "typed, then a crash"); Entry kept = entry("item:kept", "kept for next time"); kept.state = Entry::State::Kept; - { - INFO("written"); - CHECK(earlier.write(lost)); - CHECK(earlier.write(kept)); - } + CHECK(earlier.write(lost)); + CHECK(earlier.write(kept)); const ALRecovery::Offers closed = ALRecovery::offersAt(*store, false); { INFO("both offered"); @@ -777,7 +745,6 @@ namespace CHECK(written.pickedTarget == std::optional("lsl2")); CHECK(written.pickedExperience == std::optional(experience)); } - UNSCOPED_INFO("kept"); CHECK(r.keep(a)); std::optional back = store->leftFor(a.recoveryKey); UNSCOPED_INFO("not another session's"); @@ -868,11 +835,8 @@ namespace ALScriptStudioRecovery& r = make(); Doc& a = tab("a", "one\n"); type(a, "x"); - { - INFO("kept"); - CHECK(r.keep(a)); - CHECK(keptFor(a.recoveryKey) == 1); - } + CHECK(r.keep(a)); + CHECK(keptFor(a.recoveryKey) == 1); const std::string was = a.recoveryKey; ALScriptStudioRecovery::rekey(a, ALRecoveryStore::keyOf(LLUUID::null, LLUUID::null, "/somewhere/a.lsl")); store->flush(); @@ -928,7 +892,6 @@ namespace ALRecovery::keepSaved(save("task:p:old", "a", 20.0)); ALRecovery::keepSaved(save("task:p:new", "b", 10.0), "task:p:old"); written(); - UNSCOPED_INFO("kept"); REQUIRE(history->list("item:x").size() == 1U); UNSCOPED_INFO("the old item's moved"); REQUIRE(history->list("task:p:old").empty()); diff --git a/indra/newview/tests/alscriptstudiosaving_test.cpp b/indra/newview/tests/alscriptstudiosaving_test.cpp index 4dc5d114d4..c41f2ac5fa 100644 --- a/indra/newview/tests/alscriptstudiosaving_test.cpp +++ b/indra/newview/tests/alscriptstudiosaving_test.cpp @@ -274,7 +274,7 @@ namespace CHECK(files->settled == Names{ "file" }); CHECK(ALScriptFileIO::readWholeFile(file.file, written)); CHECK(written == "x = 1"); - REQUIRE(studio.sent.empty()); + CHECK(studio.sent.empty()); } Doc& card = tab("card", "some words"); @@ -286,8 +286,8 @@ namespace saving.save(card); UNSCOPED_INFO("a notecard sent as it stands"); CHECK(studio.notecards == Names{ "some words" }); - UNSCOPED_INFO("and not tidied"); - REQUIRE(studio.tidied.size() == 1); + UNSCOPED_INFO("the notecard not tidied: the one tidy the file's"); + CHECK(studio.tidied.size() == 1); CompileResult saved = answer(card); saved.kind = ALScriptKind::Notecard; saving.compiled(saved); @@ -310,7 +310,7 @@ namespace CHECK(studio.stops == 1); CHECK(studio.notices == 1); CHECK_FALSE(away.save.underway()); - REQUIRE(studio.sent.empty()); + CHECK(studio.sent.empty()); } Doc& detached = tab("detached", "default {}"); @@ -320,12 +320,14 @@ namespace INFO("loaded under its item first"); REQUIRE(orphans->loads.size() == 1); CHECK(orphans->loads[0] == detached.ref); - REQUIRE(studio.sent.empty()); + CHECK(studio.sent.empty()); } UNSCOPED_INFO("and said to wait"); CHECK(lastStatus() == std::string("SaveWaitsForLoad")); } + // Tidied as the settings say, and fixed once a save however many checks + // it waits on. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save is tidied first with fixes only over the text last checked", "[alscriptstudiosaving]") { ALScriptStudioSaving& saving = make(); @@ -348,7 +350,7 @@ namespace { INFO("checked again"); CHECK(studio.analysed.back() == "a"); - REQUIRE(studio.sent.empty()); + CHECK(studio.sent.empty()); } checked(doc); UNSCOPED_INFO("the check waited on"); @@ -363,6 +365,8 @@ namespace } } + // Checked first, their errors stop it with Save Anyway and the first in + // sight; asked again, it goes past them and the offer is answered. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save held on the analyzers stops at their errors until asked again", "[alscriptstudiosaving]") { ALScriptStudioSaving& saving = make(); @@ -373,7 +377,7 @@ namespace { INFO("checked first"); CHECK(studio.analysed == Names{ "a" }); - REQUIRE(studio.sent.empty()); + CHECK(studio.sent.empty()); } UNSCOPED_INFO("and said so"); CHECK(lastStatus() == std::string("Preflight")); @@ -399,32 +403,33 @@ namespace { INFO("stopped"); CHECK(studio.stops == 1); - REQUIRE(studio.sent.empty()); + CHECK(studio.sent.empty()); CHECK_FALSE(doc.save.underway()); } doc.offer = Doc::Offer{ "held", { "save_anyway" } }; saving.saveAsked(doc); UNSCOPED_INFO("asked again over the same text: past them"); - REQUIRE(studio.sent.size() == 1); + CHECK(studio.sent.size() == 1); UNSCOPED_INFO("what was offered answered"); - REQUIRE_FALSE(doc.offer); + CHECK_FALSE(doc.offer); doc.offer = Doc::Offer{ "saved elsewhere", { "take_saved", "keep_saved", "compare_saved" } }; saving.save(doc); UNSCOPED_INFO("a conflict's offer stays"); - REQUIRE(doc.offer.has_value()); + CHECK(doc.offer.has_value()); // Not held, the errors go with the text, said. studio.options.holdOnErrors = false; Doc& free = tab("free", "default {}"); checked(free, { anError() }); saving.save(free); - UNSCOPED_INFO("sent"); - REQUIRE(studio.sent.size() == 2); + CHECK(studio.sent.size() == 2); UNSCOPED_INFO("with its errors said"); CHECK(lastSaid() == std::string("SentWithErrors")); } + // Its target, whether it runs and its experience; marked saved as it + // went. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save sends the tab's own options and stops when too large or refused", "[alscriptstudiosaving]") { ALScriptStudioSaving& saving = make(); @@ -438,7 +443,6 @@ namespace doc.experienceChosen = true; type(doc, "\n// more"); saving.save(doc); - UNSCOPED_INFO("one sent"); REQUIRE(studio.sent.size() == size_t(1)); const FakeSavingWindow::Sent& sent = studio.sent.back(); UNSCOPED_INFO("the text as it stands"); @@ -451,13 +455,11 @@ namespace } UNSCOPED_INFO("on its way"); CHECK(doc.save.sending()); - UNSCOPED_INFO("said"); CHECK(lastStatus() == std::string("Saving")); // Typed while it was on its way: that is still to be saved. type(doc, "\n// later"); saving.compiled(answer(doc)); - UNSCOPED_INFO("compiled"); CHECK(lastSaid() == std::string("Compiled")); UNSCOPED_INFO("what was typed since still unsaved"); CHECK(doc.editor->isDirty()); @@ -473,7 +475,7 @@ namespace type(clean, " "); saving.save(clean); UNSCOPED_INFO("whether it runs not heard yet: not said, for the save to ask"); - REQUIRE_FALSE(studio.sent.back().options.running.has_value()); + CHECK_FALSE(studio.sent.back().options.running.has_value()); saving.compiled(answer(clean)); UNSCOPED_INFO("nothing typed since: saved"); CHECK_FALSE(clean.unsaved()); @@ -488,11 +490,11 @@ namespace UNSCOPED_INFO("too large: said"); CHECK(lastSaid() == std::string("SaveTooLarge")); UNSCOPED_INFO("with what would shrink it"); - REQUIRE(services.reports.back().text.find("SaveTooLargePlain") != std::string::npos); + CHECK(services.reports.back().text.find("SaveTooLargePlain") != std::string::npos); { INFO("its size kept, nothing sent, stopped"); - REQUIRE(big.weighing->assetBytes == too_much.size()); - REQUIRE(studio.sent.size() == 2); + CHECK(big.weighing->assetBytes == too_much.size()); + CHECK(studio.sent.size() == 2); CHECK_FALSE(big.save.underway()); CHECK(studio.stops == 1); } @@ -511,6 +513,8 @@ namespace } } + // Preprocessed first, its errors said, what it made in the envelope with + // its map; a text moved on meanwhile is run again. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a preprocessed save goes with its errors and what it made enveloped", "[alscriptstudiosaving]") { ALScriptStudioSaving& saving = make(); @@ -521,7 +525,7 @@ namespace { INFO("run first"); CHECK(studio.runs == Names{ "a" }); - REQUIRE(studio.sent.empty()); + CHECK(studio.sent.empty()); CHECK(doc.preprocessing); } @@ -533,13 +537,13 @@ namespace UNSCOPED_INFO("what waited on the map it made told"); CHECK(studio.known == Names{ "a" }); UNSCOPED_INFO("sent all the same"); - REQUIRE(studio.sent.size() == size_t(1)); + CHECK(studio.sent.size() == size_t(1)); UNSCOPED_INFO("said as it went"); CHECK(lastSaid() == std::string("SavingWithErrors")); { INFO("a failure of the tab, nothing to press"); CHECK(services.reports.back().failure); - REQUIRE(services.reports.back().actions.empty()); + CHECK(services.reports.back().actions.empty()); } { INFO("not stopped, the problems in sight"); @@ -556,7 +560,6 @@ namespace ALPreprocessor::Result made; made.text = "default { state_entry() {} }"; studio.answerRun(made); - UNSCOPED_INFO("sent"); REQUIRE(studio.sent.size() == size_t(2)); const std::optional envelope = ALScriptEnvelope::parse(studio.sent.back().text); UNSCOPED_INFO("in the envelope"); @@ -566,7 +569,7 @@ namespace UNSCOPED_INFO("by this viewer"); CHECK(envelope->programVersion == studio.options.program); UNSCOPED_INFO("with its map, for the compiler's lines"); - REQUIRE(doc.save.sentMap().has_value()); + CHECK(doc.save.sentMap().has_value()); UNSCOPED_INFO("weighed as each went"); CHECK(std::count(weighing->weighs.begin(), weighing->weighs.end(), "sent") == 2); saving.compiled(answer(doc)); @@ -574,7 +577,6 @@ namespace // The text moved on while the includes came: checked, and run again. type(doc, "\n// a"); saving.save(doc); - UNSCOPED_INFO("run"); REQUIRE(studio.runs.size() == 3); type(doc, "\n// b"); studio.answerRun(made); @@ -582,11 +584,12 @@ namespace CHECK(studio.analysed.back() == "a"); { INFO("and run again, nothing sent"); - REQUIRE(studio.runs.size() == 4); - REQUIRE(studio.sent.size() == 2); + CHECK(studio.runs.size() == 4); + CHECK(studio.sent.size() == 2); } } + // And a tab saved to close is let go of. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: the compiler's answer keeps its errors and sends a save asked meanwhile", "[alscriptstudiosaving]") { ALScriptStudioSaving& saving = make(); @@ -602,10 +605,9 @@ namespace diagnostic.message = "syntax error"; failed.diagnostics.push_back(diagnostic); saving.compiled(failed); - UNSCOPED_INFO("said"); CHECK(lastSaid() == std::string("CompileFailed")); { - INFO("kept"); + INFO("its errors kept"); REQUIRE(doc.problems.size() == 1); CHECK(doc.problems[0].line == 3); CHECK(doc.problems[0].message == "syntax error"); @@ -623,29 +625,29 @@ namespace type(doc, " "); saving.save(doc); UNSCOPED_INFO("one on its way at a time"); - REQUIRE(studio.sent.size() == size_t(2)); + CHECK(studio.sent.size() == size_t(2)); saving.compiled(answer(doc)); { INFO("the one asked meanwhile sent after it"); - REQUIRE(studio.sent.size() == 3); + CHECK(studio.sent.size() == 3); CHECK(doc.save.sending()); } UNSCOPED_INFO("what the last said gone with it"); - REQUIRE(doc.problems.empty()); + CHECK(doc.problems.empty()); saving.compiled(answer(doc)); type(doc, " "); saving.saveToClose("a"); { INFO("sent to close"); - REQUIRE(studio.sent.size() == 4); + CHECK(studio.sent.size() == 4); CHECK(doc.save.closeAfter()); } saving.compiled(answer(doc)); { INFO("let go of"); CHECK(studio.closed == Names{ "a" }); - REQUIRE_FALSE(services.findDoc(std::string_view("a"))); + CHECK_FALSE(services.findDoc(std::string_view("a"))); } UNSCOPED_INFO("and a window closing gone on with"); CHECK(studio.continues == 1); @@ -688,10 +690,9 @@ namespace saving.compiled(answer(copy)); UNSCOPED_INFO("the original let go of"); CHECK(studio.closed == Names{ "original" }); - UNSCOPED_INFO("said"); CHECK(lastSaid() == std::string("CopiedTo")); UNSCOPED_INFO("the copy is no copy now"); - REQUIRE(copy.copyOf.empty()); + CHECK(copy.copyOf.empty()); Doc& typed = tab("typed", "default {}"); Doc& other = tab("other", "default {}"); @@ -703,15 +704,17 @@ namespace saving.compiled(answer(other)); { INFO("typed in since: kept open"); - REQUIRE(studio.closed.size() == 1); - REQUIRE(services.findDoc(std::string_view("typed"))); + CHECK(studio.closed.size() == 1); + CHECK(services.findDoc(std::string_view("typed"))); } UNSCOPED_INFO("and said so"); CHECK(lastSaid() == std::string("CopiedToKeptOpen")); - UNSCOPED_INFO("of it"); + UNSCOPED_INFO("said of the tab kept open"); CHECK(services.reports.back().doc == std::string("typed")); } + // What a save sends is weighed as it goes, and its weight over the limit + // said where it is exact. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save over its target's limit is said once and an estimate as one", "[alscriptstudiosaving]") { ALScriptStudioSaving& saving = make(); @@ -719,7 +722,6 @@ namespace Doc& doc = tab("a", "default {}"); type(doc, " "); saving.save(doc); - UNSCOPED_INFO("weighed"); CHECK(weighing->weighs == Names{ "text" }); ALScriptWeight weight; weight.target = ALScriptWeight::Target::Mono; @@ -731,12 +733,11 @@ namespace saving.warnOverWeight(doc); UNSCOPED_INFO("over: said"); CHECK(lastSaid() == std::string("SaveOverWeight")); - UNSCOPED_INFO("as a failure"); CHECK(services.reports.back().failure); const size_t said = services.reports.size(); saving.warnOverWeight(doc); - UNSCOPED_INFO("once"); - REQUIRE(services.reports.size() == said); + UNSCOPED_INFO("not said again"); + CHECK(services.reports.size() == said); Doc& guessed = tab("guessed", "default {}"); type(guessed, " "); @@ -749,10 +750,10 @@ namespace UNSCOPED_INFO("an estimate said as one"); CHECK(lastSaid() == std::string("SaveOverWeightEstimate")); UNSCOPED_INFO("once too"); - REQUIRE(services.reports.size() == said + 1); + CHECK(services.reports.size() == said + 1); saving.warnOverWeight(guessed); UNSCOPED_INFO("and only once"); - REQUIRE(services.reports.size() == said + 1); + CHECK(services.reports.size() == said + 1); } TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save the external editor made is not tidied but one made here after is", "[alscriptstudiosaving]") @@ -763,10 +764,9 @@ namespace Doc& doc = tab("a", "default {}"); doc.save.fromExternal(doc.editor->document().version()); saving.save(doc); - UNSCOPED_INFO("not tidied"); - REQUIRE(studio.tidied.empty()); + CHECK(studio.tidied.empty()); UNSCOPED_INFO("sent as it came"); - REQUIRE(studio.sent.size() == 1); + CHECK(studio.sent.size() == 1); saving.compiled(answer(doc)); // Ended as the answer ends it where the editor is watched. doc.save.endExternal(); @@ -774,9 +774,10 @@ namespace doc.editor->insertText(" "); saving.save(doc); UNSCOPED_INFO("tidied, made here"); - REQUIRE(studio.tidied.size() == size_t(1)); + CHECK(studio.tidied.size() == size_t(1)); } + // Its first run as it loaded is held up to its compiled half. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a wrapped script offers a compiled half its source cannot have made", "[alscriptstudiosaving]") { ALScriptStudioSaving& saving = make(); @@ -807,27 +808,27 @@ namespace INFO("ours, edited outside: offered"); REQUIRE(here.compiledDiffers); CHECK(*here.compiledDiffers == edited); - REQUIRE_FALSE(here.compareCompiledAt); + CHECK_FALSE(here.compareCompiledAt); } Doc& same = loaded("same", "default{state_entry(){llSay(0,\"hi\");}}", "Alchemy Release 7.2.0"); ran(same); UNSCOPED_INFO("what the source makes, spaced otherwise: nothing"); - REQUIRE_FALSE(same.compiledDiffers); + CHECK_FALSE(same.compiledDiffers); Doc& firestorm = loaded("fs", edited, "Firestorm-Releasex64 7.1.11.76496"); ran(firestorm); UNSCOPED_INFO("Firestorm's, untransformed: told"); - REQUIRE(firestorm.compiledDiffers.has_value()); + CHECK(firestorm.compiledDiffers.has_value()); Doc& switched = loaded("sw", edited, "Firestorm-Releasex64 7.1.11.76496"); ran(switched, true); UNSCOPED_INFO("Firestorm's, with a transform whose names ours need not share: not told"); - REQUIRE_FALSE(switched.compiledDiffers); + CHECK_FALSE(switched.compiledDiffers); Doc& typed = loaded("typed", edited, "Alchemy Release 7.2.0"); type(typed, " "); ran(typed); { INFO("typed in before the run: not the text as it came"); - REQUIRE_FALSE(typed.compiledDiffers); - REQUIRE_FALSE(typed.compareCompiledAt); + CHECK_FALSE(typed.compiledDiffers); + CHECK_FALSE(typed.compareCompiledAt); } } @@ -845,6 +846,9 @@ namespace UNSCOPED_INFO("one Undo takes back all of it"); CHECK(doc.editor->text() == std::string("default {}")); } + + // An include not found, or one that never came, said by name with the + // disk's route, and the other errors said besides. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save goes up without includes missing or pending and names them", "[alscriptstudiosaving]") { ALScriptStudioSaving& saving = make(); @@ -863,22 +867,22 @@ namespace wrong.problems = { missing, nowhere, anError() }; studio.answerRun(wrong); UNSCOPED_INFO("sent: the save keeps the work"); - REQUIRE(studio.sent.size() == size_t(1)); + CHECK(studio.sent.size() == size_t(1)); const auto going = std::find_if(services.reports.begin(), services.reports.end(), [](const al_studio_test::FakeServices::Said& s) { return alscriptstudiosaving_data::nameOf(s.text) == "SavingWithout"; }); { INFO("said as it went, by name, a failure of the tab"); REQUIRE(going != services.reports.end()); - REQUIRE(going->text.find("[FILES]=lib.lsl, x.lsl") != std::string::npos); - REQUIRE(going->failure); + CHECK(going->text.find("[FILES]=lib.lsl, x.lsl") != std::string::npos); + CHECK(going->failure); CHECK(going->doc == "a"); } UNSCOPED_INFO("with where includes come from"); - REQUIRE(going->text.find("PreprocessMissingDiskRoute") != std::string::npos); + CHECK(going->text.find("PreprocessMissingDiskRoute") != std::string::npos); UNSCOPED_INFO("and the error besides them"); CHECK(lastSaid() == std::string("SavingWithErrors")); UNSCOPED_INFO("counted without them"); - REQUIRE(services.reports.back().text.find("[COUNT]=1") != std::string::npos); + CHECK(services.reports.back().text.find("[COUNT]=1") != std::string::npos); saving.compiled(answer(doc)); // Only the other errors: those said. @@ -890,7 +894,7 @@ namespace studio.answerRun(plain); { INFO("sent, its errors said"); - REQUIRE(studio.sent.size() == 2); + CHECK(studio.sent.size() == 2); CHECK(lastSaid() == "SavingWithErrors"); } saving.compiled(answer(doc)); @@ -903,11 +907,11 @@ namespace waiting.pending = { "far.lsl" }; studio.answerRun(waiting); UNSCOPED_INFO("sent without it"); - REQUIRE(studio.sent.size() == size_t(3)); + CHECK(studio.sent.size() == size_t(3)); { INFO("and said so"); CHECK(services.reports.back().text.find("SavingWithout") == 0); - REQUIRE(services.reports.back().text.find("[FILES]=far.lsl") != std::string::npos); + CHECK(services.reports.back().text.find("[FILES]=far.lsl") != std::string::npos); } } @@ -938,11 +942,13 @@ namespace saving.compiled(answer(doc)); { INFO("its own lands"); - REQUIRE_FALSE(doc.save.sending()); + CHECK_FALSE(doc.save.sending()); CHECK_FALSE(doc.editor->isDirty()); } } + // Taken in by a tab with nothing typed, asked about by one with changes, + // let be where it saved what the tab last had. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save from elsewhere is taken in or asked about or let be", "[alscriptstudiosaving]") { ALScriptStudioSaving& saving = make(); @@ -972,16 +978,16 @@ namespace { INFO("nothing taken yet"); CHECK(dirty.editor->wholeText() == "default {}\n// mine"); - REQUIRE(dirty.savedThere); + CHECK(dirty.savedThere); } saving.takeSaved(dirty); { INFO("theirs taken, and nothing to save"); - REQUIRE(dirty.editor->wholeText() == "default {}\n// theirs"); + CHECK(dirty.editor->wholeText() == "default {}\n// theirs"); CHECK_FALSE(dirty.editor->isDirty()); } UNSCOPED_INFO("asked no more"); - REQUIRE_FALSE(dirty.savedThere); + CHECK_FALSE(dirty.savedThere); // A recompile of what the tab last had: nothing changes, nothing asked. Doc& kept = tab("kept", "default {}"); @@ -990,8 +996,8 @@ namespace saving.savedElsewhere(saved(kept, "default {}", ALScriptOrigin::Recompile)); { INFO("not asked"); - REQUIRE(services.reports.size() == said); - REQUIRE_FALSE(kept.savedThere); + CHECK(services.reports.size() == said); + CHECK_FALSE(kept.savedThere); CHECK(kept.editor->isDirty()); } @@ -1004,7 +1010,7 @@ namespace { INFO("the same as here: saved"); CHECK_FALSE(kept.editor->isDirty()); - REQUIRE(services.reports.size() == said); + CHECK(services.reports.size() == said); } // Its own save lands as its answer, not as a save from elsewhere. @@ -1015,7 +1021,7 @@ namespace saving.savedElsewhere(mine); { INFO("its own let be"); - REQUIRE_FALSE(own.savedThere); + CHECK_FALSE(own.savedThere); CHECK(own.editor->wholeText() == "default {} "); } @@ -1025,12 +1031,14 @@ namespace saving.keepSaved(dirty); { INFO("kept"); - REQUIRE_FALSE(dirty.savedThere); + CHECK_FALSE(dirty.savedThere); CHECK(dirty.editor->isDirty()); CHECK(lastStatus() == "SavedElsewhereKept"); } } + // It asks what the item holds now, and stops with Save Anyway, Reload and + // Compare. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a save stops where the item was saved elsewhere since until asked again", "[alscriptstudiosaving]") { ALScriptStudioSaving& saving = make(); @@ -1041,7 +1049,7 @@ namespace UNSCOPED_INFO("asked once"); CHECK(studio.worldAsks == 1); UNSCOPED_INFO("nothing moved: sent"); - REQUIRE(studio.sent.size() == size_t(1)); + CHECK(studio.sent.size() == size_t(1)); saving.compiled(answer(doc)); LLUUID elsewhere; @@ -1055,14 +1063,16 @@ namespace CHECK(services.reports.back().actions == Names{ "save_anyway", "reload_world", "merge_world", "compare_world" }); { INFO("and not sent"); - REQUIRE(studio.sent.size() == 1); + CHECK(studio.sent.size() == 1); CHECK_FALSE(doc.save.underway()); } saving.saveAsked(doc); UNSCOPED_INFO("asked again: sent over it"); - REQUIRE(studio.sent.size() == size_t(2)); + CHECK(studio.sent.size() == size_t(2)); } + // As every editor of the item decides it: the same text, taken, kept or + // asked about. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: heard sorts a save from elsewhere and reads the last save only if needed", "[alscriptstudiosaving]") { using Heard = ALScriptSaved::Heard; @@ -1089,6 +1099,7 @@ namespace CHECK(asked == 3); } + // A save sent before it leaves it to be undone. TEST_CASE_METHOD(alscriptstudiosaving_data, "alscriptstudiosaving: a merge is kept for good once a save carrying it is saved", "[alscriptstudiosaving]") { ALScriptStudioSaving& saving = make(); @@ -1107,7 +1118,7 @@ namespace saving.save(doc); saving.compiled(answer(doc)); UNSCOPED_INFO("saved with it: kept for good"); - REQUIRE_FALSE(doc.merged); + CHECK_FALSE(doc.merged); Doc& early = tab("b", "default {}"); type(early, "\n// typed"); diff --git a/indra/newview/tests/alscriptstudioselections_test.cpp b/indra/newview/tests/alscriptstudioselections_test.cpp index 34acca2524..d2450aa493 100644 --- a/indra/newview/tests/alscriptstudioselections_test.cpp +++ b/indra/newview/tests/alscriptstudioselections_test.cpp @@ -153,7 +153,6 @@ namespace UNSCOPED_INFO("something to hold"); CHECK(ALScriptStudioSelections::canHold(door)); unit->hold(door); - UNSCOPED_INFO("held"); REQUIRE(unit->held().has_value()); UNSCOPED_INFO("its text, whichever way it was selected"); CHECK(unit->held()->text == std::string("line 2\nline 3\n")); @@ -161,7 +160,6 @@ namespace CHECK(unit->held()->title == titled("SelectionLines", "door", 3, 4)); LLStringUtil::format_map_t args; args["[TITLE]"] = unit->held()->title; - UNSCOPED_INFO("said"); CHECK(services().statuses.back() == said("SelectionHeld", args)); door.editor->goTo(ALTextRange(ALTextPos(5, 0), ALTextPos(5, 4))); @@ -236,7 +234,6 @@ namespace // Compared again, a change taken back: the stretch made the held's. door.editor->goTo(ALTextRange(ALTextPos(5, 0), ALTextPos(7, 0))); unit->compare(door); - UNSCOPED_INFO("taken back"); CHECK(view.takeBack(0)); UNSCOPED_INFO("the stretch made the held's"); CHECK(door.editor->text() == lines(10, { { 5, "line 1" }, { 6, "line 2" } })); @@ -254,7 +251,6 @@ namespace unit->compare(door); UNSCOPED_INFO("two lines made one"); CHECK(view.takeBack(0)); - UNSCOPED_INFO("the source"); CHECK(door.editor->text() == lines(9, { { 5, "line 0" }, { 6, "line 7" }, { 7, "line 8" }, { 8, "line 9" } })); // The source moved under a comparison: nothing taken back, typing diff --git a/indra/newview/tests/alscriptstudiovim_test.cpp b/indra/newview/tests/alscriptstudiovim_test.cpp index bcd92d0bed..b37ba2a8e2 100644 --- a/indra/newview/tests/alscriptstudiovim_test.cpp +++ b/indra/newview/tests/alscriptstudiovim_test.cpp @@ -341,28 +341,25 @@ namespace for (const char* name : { "w", "write", "w!" }) { - UNSCOPED_INFO(name); + CAPTURE(name); REQUIRE(ex(a, name)); } UNSCOPED_INFO("written by the menus' Save"); CHECK(ran == Names{ "save", "save", "save" }); ran.clear(); - { - INFO("q"); - CHECK(ex(a, "q")); - CHECK(ex(a, "wa")); - CHECK(ex(a, "format")); - CHECK(ex(a, "fix")); - CHECK(ex(a, "fixall")); - CHECK(ex(a, "problems")); - } + CHECK(ex(a, "q")); + CHECK(ex(a, "wa")); + CHECK(ex(a, "format")); + CHECK(ex(a, "fix")); + CHECK(ex(a, "fixall")); + CHECK(ex(a, "problems")); UNSCOPED_INFO("each by its menu name"); CHECK(ran == Names{ "close", "save_all", "format", "quick_fix", "fix_all", "problems" }); ran.clear(); { INFO("one that cannot be done now is taken, and not done"); CHECK(ex(a, "revert")); - REQUIRE(ran.empty()); + CHECK(ran.empty()); } { @@ -374,7 +371,7 @@ namespace INFO("wq over nothing unsaved closes it"); CHECK(ex(a, "wq")); CHECK(studio.asked == Names{ "a" }); - REQUIRE(studio.savedToClose.empty()); + CHECK(studio.savedToClose.empty()); } a.editor->setCaret(a.editor->document().end()); a.editor->insertText(" "); @@ -401,7 +398,7 @@ namespace { INFO("nor from an editor of no tab"); CHECK_FALSE(vim.command(*stray, "w", std::string())); - REQUIRE(ran.empty()); + CHECK(ran.empty()); } } @@ -409,33 +406,24 @@ namespace { make(); Doc& a = tab("a"); - { - INFO("on"); - CHECK(ex(a, "set", "number")); - CHECK(lineNumbers); - CHECK(ran == Names{ "line_numbers" }); - } + CHECK(ex(a, "set", "number")); + CHECK(lineNumbers); + CHECK(ran == Names{ "line_numbers" }); { INFO("on already: left"); CHECK(ex(a, "set", "nu")); - REQUIRE(ran.size() == 1); - } - { - INFO("off"); - CHECK(ex(a, "set", "nonu")); - CHECK_FALSE(lineNumbers); - REQUIRE(ran.size() == 2); - } - { - INFO("relative"); - CHECK(ex(a, "set", "rnu")); - CHECK(relativeNumbers); + CHECK(ran.size() == 1); } + CHECK(ex(a, "set", "nonu")); + CHECK_FALSE(lineNumbers); + CHECK(ran.size() == 2); + CHECK(ex(a, "set", "rnu")); + CHECK(relativeNumbers); { INFO("off already: left"); CHECK(ex(a, "set", "norelativenumber")); CHECK_FALSE(relativeNumbers); - REQUIRE(ran.size() == 4); + CHECK(ran.size() == 4); } UNSCOPED_INFO("an option it does not know is vim's"); CHECK_FALSE(ex(a, "set", "hlsearch")); @@ -450,11 +438,8 @@ namespace UNSCOPED_INFO("the : ones"); CHECK(ex(a, "history")); - UNSCOPED_INFO("one entry"); REQUIRE(studio.entries.size() == size_t(1)); - UNSCOPED_INFO("numbered"); CHECK(studio.entries[0].text == std::string("cmd history:\n 1 w\n 2 set nu")); - UNSCOPED_INFO("from vim"); CHECK(studio.entries[0].source == std::string("OutputSourceVim")); UNSCOPED_INFO("the tab in sight"); CHECK(studio.outputShown == 1); @@ -467,11 +452,8 @@ namespace CHECK(studio.entries[0].text == "search history:\n 1 foo"); } studio.entries.clear(); - { - INFO("both"); - CHECK(ex(a, "history", "all")); - REQUIRE(studio.entries.size() == 2); - } + CHECK(ex(a, "history", "all")); + CHECK(studio.entries.size() == 2); } TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: q: lists lines last first to run or to put back on the line", "[alscriptstudiovim]") @@ -492,7 +474,7 @@ namespace UNSCOPED_INFO("run, and put back"); CHECK(chosen == std::vector>{ { "second", true }, { "first", false } }); UNSCOPED_INFO("none picked is nothing chosen"); - REQUIRE((studio.cancel(), chosen.size() == 2)); + CHECK((studio.cancel(), chosen.size() == 2)); vim.historyWindow(*a.editor, '/', Names(20, "x"), [](const std::string&, bool) {}); UNSCOPED_INFO("no taller than eight"); @@ -519,7 +501,7 @@ namespace a.expandedEditor = editor("expanded_a", "one"); vim.format(*a.expandedEditor, 0, 0); UNSCOPED_INFO("not the expansion"); - REQUIRE(studio.formatted.size() == 2); + CHECK(studio.formatted.size() == 2); Doc& card = tab("card"); card.notecard = true; vim.format(*card.editor, 0, 0); @@ -527,7 +509,7 @@ namespace locked.modifiable = false; vim.format(*locked.editor, 0, 0); UNSCOPED_INFO("nor a notecard, nor one that cannot change"); - REQUIRE(studio.formatted.size() == 2); + CHECK(studio.formatted.size() == 2); UNSCOPED_INFO("the expansion's editor is its tab's"); CHECK(vim.docOf(*a.expandedEditor) == &a); } @@ -540,7 +522,7 @@ namespace vim.pump(); { INFO("no vim, nothing said"); - REQUIRE(vim.banner().empty()); + CHECK(vim.banner().empty()); CHECK(studio.trailers == 0); } @@ -558,15 +540,14 @@ namespace std::vector words; connected.hooks().complete(*a.editor, std::string(), std::string(), words); UNSCOPED_INFO("Tab completes the studio's names"); - REQUIRE(std::find(words.begin(), words.end(), "fixall") != words.end()); + CHECK(std::find(words.begin(), words.end(), "fixall") != words.end()); vim.pump(); - UNSCOPED_INFO("vim, said"); CHECK(vim.banner() == std::string("VimNormal")); UNSCOPED_INFO("the strip told"); CHECK(studio.trailers == 1); vim.pump(); - UNSCOPED_INFO("once"); + UNSCOPED_INFO("told once"); CHECK(studio.trailers == 1); // Gone, the keymap's hooks do nothing. @@ -574,7 +555,7 @@ namespace { INFO("asked of nothing"); CHECK_FALSE(connected.hooks().command(*a.editor, "w", std::string())); - REQUIRE(ran.size() == 1); + CHECK(ran.size() == 1); } } @@ -591,34 +572,27 @@ namespace vim.complete("q", std::string(), none); { INFO("vim's own and the menus'"); - REQUIRE(std::find(names.begin(), names.end(), "wall") != names.end()); - REQUIRE(std::find(names.begin(), names.end(), "go_to_line") != names.end()); + CHECK(std::find(names.begin(), names.end(), "wall") != names.end()); + CHECK(std::find(names.begin(), names.end(), "go_to_line") != names.end()); } - UNSCOPED_INFO("the options"); CHECK(options == Names{ "number", "nonumber", "relativenumber", "norelativenumber", "spell", "nospell", "list", "nolist" }); - UNSCOPED_INFO("the kinds"); CHECK(kinds == Names{ "all", "cmd", "search" }); - UNSCOPED_INFO("the tabs"); CHECK(tabs == Names{ "alpha", "beta" }); UNSCOPED_INFO("nothing after anything else"); - REQUIRE(none.empty()); + CHECK(none.empty()); } TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: :b and :tab commands move between tabs round the strip", "[alscriptstudiovim]") { make(); ALVimKeymap* vim = fourTabs(); - UNSCOPED_INFO(":bn"); CHECK(go("bn") == std::string("beta")); - UNSCOPED_INFO(":bnext 2"); CHECK(go("bnext", "2") == std::string("delta")); UNSCOPED_INFO("round past the end"); CHECK(go("bn") == std::string("alpha")); UNSCOPED_INFO(":bp round past the start"); CHECK(go("bp") == std::string("delta")); - UNSCOPED_INFO(":bN 3"); CHECK(go("bN", "3") == std::string("alpha")); - UNSCOPED_INFO(":b 3"); CHECK(go("b", "3") == std::string("gamma")); UNSCOPED_INFO(":b # the one before"); CHECK(go("b", "#") == std::string("alpha")); @@ -626,25 +600,16 @@ namespace CHECK(go("buffer", "#") == std::string("gamma")); UNSCOPED_INFO(":b by a part of its name, in any case"); CHECK(go("b", "ELT") == std::string("delta")); - UNSCOPED_INFO(":b by its whole name"); CHECK(go("b", "beta") == std::string("beta")); - UNSCOPED_INFO(":bf"); CHECK(go("bf") == std::string("alpha")); - UNSCOPED_INFO(":blast"); CHECK(go("blast") == std::string("delta")); - UNSCOPED_INFO(":tabfirst"); CHECK(go("tabfirst") == std::string("alpha")); - UNSCOPED_INFO(":tabl"); CHECK(go("tabl") == std::string("delta")); UNSCOPED_INFO(":tabn round past the end"); CHECK(go("tabn") == std::string("alpha")); - UNSCOPED_INFO(":tabn 3 the third"); CHECK(go("tabn", "3") == std::string("gamma")); - UNSCOPED_INFO(":tabn +1"); CHECK(go("tabnext", "+1") == std::string("delta")); - UNSCOPED_INFO(":tabn $"); CHECK(go("tabn", "$") == std::string("delta")); - UNSCOPED_INFO(":tabp 2"); CHECK(go("tabp", "2") == std::string("beta")); UNSCOPED_INFO(":tabN round past the start"); CHECK(go("tabN", "2") == std::string("delta")); @@ -653,13 +618,10 @@ namespace CHECK(go("b", "a") == std::string("delta")); UNSCOPED_INFO("said as vim says it"); CHECK(vim->message() == std::string("VimTabsMatch [NAME]=a")); - UNSCOPED_INFO("an error"); CHECK(vim->messageIsError()); go("b", "zeta"); - UNSCOPED_INFO("none"); CHECK(vim->message() == std::string("VimNoTabMatch [NAME]=zeta")); go("b", "9"); - UNSCOPED_INFO("no ninth"); CHECK(vim->message() == std::string("VimNoSuchTab [NUMBER]=9")); go("tabn", "9"); UNSCOPED_INFO("nor to go to"); @@ -696,7 +658,6 @@ namespace CHECK((go("tabmove"), order()) == std::string("alpha gamma delta beta")); UNSCOPED_INFO(":tabm 2 after the second"); CHECK((go("tabm", "2"), order()) == std::string("alpha gamma beta delta")); - UNSCOPED_INFO(":tabm -1"); CHECK((go("tabm", "-1"), order()) == std::string("alpha beta gamma delta")); UNSCOPED_INFO(":tabm 3 after the third, past itself"); CHECK((go("tabm", "3"), order()) == std::string("alpha gamma beta delta")); @@ -719,17 +680,14 @@ namespace gamma.editor->setCaret(gamma.editor->document().end()); gamma.editor->insertText("\n\n"); services.findDoc(std::string_view("delta"))->modifiable = false; - UNSCOPED_INFO("taken"); CHECK(ex(*services.docs[0], "ls")); - UNSCOPED_INFO("one entry"); REQUIRE(studio.entries.size() == size_t(1)); - UNSCOPED_INFO("the tabs"); CHECK(studio.entries[0].text == - std::string("tabs:\n" - " 1 h \"alpha\" line 1\n" - " 2 %a \"beta\" line 1\n" - " 3 #h + \"gamma\" line 3\n" - " 4 h- \"delta\" line 1")); + std::string("tabs:\n" + " 1 h \"alpha\" line 1\n" + " 2 %a \"beta\" line 1\n" + " 3 #h + \"gamma\" line 3\n" + " 4 h- \"delta\" line 1")); UNSCOPED_INFO("the tab in sight"); CHECK(studio.outputShown == 1); } @@ -744,7 +702,6 @@ namespace tab("beta"); vim.pump(); - UNSCOPED_INFO("taken"); CHECK(ex(a, "e", "main.lsl")); { INFO("an LSL file as LSL"); @@ -771,12 +728,12 @@ namespace } ex(a, "tabe", "main.lsl"); UNSCOPED_INFO(":tabedit the same"); - REQUIRE(studio.openedFiles.size() == 5); + CHECK(studio.openedFiles.size() == 5); ex(a, "e", "nowhere.lsl"); UNSCOPED_INFO("nowhere: said"); CHECK(said->message() == std::string("VimNoFile [FILE]=nowhere.lsl")); UNSCOPED_INFO("and nothing opened"); - REQUIRE(studio.openedFiles.size() == 5); + CHECK(studio.openedFiles.size() == 5); ex(a, "tabnew"); UNSCOPED_INFO(":tabnew wants a file"); CHECK(said->message() == std::string("VimArgumentRequired")); @@ -794,7 +751,7 @@ namespace { INFO("a file open already is gone to"); CHECK(services.frontDoc() == &main); - REQUIRE(studio.openedFiles.size() == 5); + CHECK(studio.openedFiles.size() == 5); } ex(a, "e"); @@ -806,7 +763,7 @@ namespace UNSCOPED_INFO("not over unsaved work"); CHECK(said->message() == std::string("VimNotSaved")); UNSCOPED_INFO("left"); - REQUIRE(studio.reverted.size() == 1); + CHECK(studio.reverted.size() == 1); ex(a, "e!"); UNSCOPED_INFO("but with !"); CHECK(studio.reverted == Names{ "alpha", "alpha" }); @@ -832,20 +789,17 @@ namespace a.expandedEditor = editor("expanded_alpha", "x"); { INFO("not into the expansion"); - REQUIRE(vim->command(*a.expandedEditor, "r", "main.lsl")); + CHECK(vim->command(*a.expandedEditor, "r", "main.lsl")); CHECK(a.expandedEditor->text() == "x"); } ex(a, "w", "out.lsl"); - UNSCOPED_INFO("written"); CHECK(contents(in("out.lsl")) == a.editor->text()); const std::string written = "VimWritten [BYTES]=" + std::to_string(a.editor->text().size()) + " [FILE]=" + in("out.lsl") + " [LINES]=4 [QUOTED]=\"" + in("out.lsl") + "\""; - UNSCOPED_INFO("and said"); CHECK(said->message() == written); - UNSCOPED_INFO("not as an error"); CHECK_FALSE(said->messageIsError()); UNSCOPED_INFO("the tab left as it was"); - REQUIRE(ran.empty()); + CHECK(ran.empty()); a.editor->setCaret(a.editor->document().end()); a.editor->insertText("!"); ex(a, "w", "out.lsl"); @@ -866,7 +820,7 @@ namespace a.editor->resetDirty(); ex(a, "up"); UNSCOPED_INFO("over none, nothing"); - REQUIRE(ran.size() == 1); + CHECK(ran.size() == 1); tab("beta"); type(a, "?"); ex(a, "wqa"); @@ -901,7 +855,7 @@ namespace UNSCOPED_INFO("where a whole path says"); CHECK(offered("tabe", folder + "/li") == Names{ folder + "/lib/" }); UNSCOPED_INFO("not after anything else"); - REQUIRE(offered("q", std::string()).empty()); + CHECK(offered("q", std::string()).empty()); } TEST_CASE_METHOD(alscriptstudiovim_data, "alscriptstudiovim: the quickfix and location commands step through the Problems tab", "[alscriptstudiovim]") @@ -913,24 +867,18 @@ namespace UNSCOPED_INFO("none: said"); CHECK(said->message() == std::string("VimNoErrors")); UNSCOPED_INFO("nothing run"); - REQUIRE(ran.empty()); + CHECK(ran.empty()); problemsThere = true; - { - INFO(":cn, :cnext 2, :lne"); - CHECK(ex(a, "cn")); - CHECK(ex(a, "cnext", "2")); - CHECK(ex(a, "lne")); - } + CHECK(ex(a, "cn")); + CHECK(ex(a, "cnext", "2")); + CHECK(ex(a, "lne")); UNSCOPED_INFO("each a step"); CHECK(ran == Names(4, "next_problem")); ran.clear(); - { - INFO(":cp, :cN, :lprevious 2"); - CHECK(ex(a, "cp")); - CHECK(ex(a, "cN")); - CHECK(ex(a, "lprevious", "2")); - } + CHECK(ex(a, "cp")); + CHECK(ex(a, "cN")); + CHECK(ex(a, "lprevious", "2")); UNSCOPED_INFO("each a step back"); CHECK(ran == Names(4, "previous_problem")); ex(a, "cn", "x"); @@ -941,7 +889,7 @@ namespace std::pair{ "cfirst", "" }, std::pair{ "cr", "" }, std::pair{ "lfir", "" }, std::pair{ "clast", "" }, std::pair{ "lla", "" } }) { - UNSCOPED_INFO(name); + CAPTURE(name, args); REQUIRE(ex(a, name, args)); } UNSCOPED_INFO("by number: 0 at the caret, 1 the first, -1 the last"); @@ -960,16 +908,16 @@ namespace } ex(a, "cw"); UNSCOPED_INFO("shown already: left"); - REQUIRE(ran.size() == 1); + CHECK(ran.size() == 1); ex(a, "ccl"); { INFO(":cclose folds it"); - REQUIRE(ran.size() == 2); + CHECK(ran.size() == 2); CHECK_FALSE(problemsShown); } ex(a, "lcl"); UNSCOPED_INFO("folded already: left"); - REQUIRE(ran.size() == 2); + CHECK(ran.size() == 2); ex(a, "clist"); UNSCOPED_INFO(":clist shows it"); CHECK(problemsShown); @@ -991,15 +939,12 @@ namespace { INFO("Ctrl-O, Ctrl-I, K"); - REQUIRE(said->hooks().command(*a.editor, "back", std::string())); - REQUIRE(said->hooks().command(*a.editor, "forward", std::string())); + CHECK(said->hooks().command(*a.editor, "back", std::string())); + CHECK(said->hooks().command(*a.editor, "forward", std::string())); CHECK(said->hooks().command(*a.editor, "reference", std::string())); } - { - INFO(":tag, :pop"); - CHECK(ex(a, "tag")); - CHECK(ex(a, "po")); - } + CHECK(ex(a, "tag")); + CHECK(ex(a, "po")); UNSCOPED_INFO("each its command"); CHECK(ran == Names{ "back", "forward", "reference", "go_to_definition", "back" }); ex(a, "tag", "llSay"); @@ -1010,7 +955,6 @@ namespace ex(a, "file"); UNSCOPED_INFO(":file"); CHECK(said->message() == std::string("VimFileInfo [LINES]=4 [NAME]=a [PERCENT]=50 [QUOTED]=\"a\" [STATE]=")); - UNSCOPED_INFO("not as an error"); CHECK_FALSE(said->messageIsError()); a.editor->insertText("!"); ex(a, "f"); @@ -1033,12 +977,11 @@ namespace Doc& a = tab("a"); ALVimKeymap* said = vimOver(a); studio.included = { "lib/util.lsl" }; - UNSCOPED_INFO("taken"); CHECK(ex(a, "find", "lib/util.lsl")); { INFO("the include, by the name written"); CHECK(studio.includedAsked == Names{ "lib/util.lsl" }); - REQUIRE(studio.openedFiles.empty()); + CHECK(studio.openedFiles.empty()); } ex(a, "fin", "main.lsl"); { @@ -1047,7 +990,6 @@ namespace CHECK(studio.openedFiles.back().first == in("main.lsl")); } ex(a, "tabfind", "nowhere.lsl"); - UNSCOPED_INFO("nowhere"); CHECK(said->message() == std::string("VimNotInPath [NAME]=nowhere.lsl")); ex(a, "find"); UNSCOPED_INFO("a name wanted"); @@ -1059,27 +1001,18 @@ namespace make(); Doc& a = tab("a"); ALVimKeymap* said = vimOver(a); - { - INFO(":set spell"); - CHECK(ex(a, "set", "spell")); - CHECK(spellCheck); - CHECK(ran == Names{ "spell_check" }); - } + CHECK(ex(a, "set", "spell")); + CHECK(spellCheck); + CHECK(ran == Names{ "spell_check" }); { INFO("on already: left"); CHECK(ex(a, "set", "spell")); - REQUIRE(ran.size() == 1); - } - { - INFO(":set nospell"); - CHECK(ex(a, "set", "nospell")); - CHECK_FALSE(spellCheck); - } - { - INFO(":set list, :set nolist"); - CHECK(ex(a, "set", "list")); - CHECK(ex(a, "set", "nolist")); + CHECK(ran.size() == 1); } + CHECK(ex(a, "set", "nospell")); + CHECK_FALSE(spellCheck); + CHECK(ex(a, "set", "list")); + CHECK(ex(a, "set", "nolist")); UNSCOPED_INFO("the blanks all, then none"); CHECK(ran == Names{ "spell_check", "spell_check", "blanks_all", "blanks_none" }); @@ -1119,55 +1052,43 @@ namespace UNSCOPED_INFO("not read yet"); CHECK_FALSE(vim->sourced()); vim->source(); - { - INFO("read"); - CHECK(vim->sourced()); - CHECK(lineNumbers); - CHECK(wrapped); - } + CHECK(vim->sourced()); + CHECK(lineNumbers); + CHECK(wrapped); UNSCOPED_INFO("the window's editors told"); CHECK(studio.editorsRefreshed == 1); const ALVimMappings& maps = vim->shared().mappings; { INFO("its mapping, and its leader"); - REQUIRE(maps.match(ALVimMappings::INSERT, maps.keysOf("jk"), true).full); + CHECK(maps.match(ALVimMappings::INSERT, maps.keysOf("jk"), true).full); CHECK(maps.leader() == ","); } { INFO("what it did not take in the Output tab, not brought up"); REQUIRE_FALSE(studio.entries.empty()); - REQUIRE(studio.entries.back().text.find("line 4:") != std::string::npos); - REQUIRE(studio.entries.back().text.find("the vimrc") != std::string::npos); + CHECK(studio.entries.back().text.find("line 4:") != std::string::npos); + CHECK(studio.entries.back().text.find("the vimrc") != std::string::npos); CHECK(studio.outputShown == 0); } vim->applyViewOptions(*a.editor); { INFO("each editor's own set on it"); - REQUIRE(a.editor->getTabWidth() == 2); + CHECK(a.editor->getTabWidth() == 2); CHECK(a.editor->getSoftTabs()); } // :set's ? shown, and the toggles. ALVimKeymap* said = vimOver(a); - { - INFO(":set nu?"); - CHECK(ex(a, "set", "nu?")); - CHECK(said->message() == " number"); - } - { - INFO(":set invwrap"); - CHECK(ex(a, "set", "invwrap")); - CHECK_FALSE(wrapped); - } + CHECK(ex(a, "set", "nu?")); + CHECK(said->message() == " number"); + CHECK(ex(a, "set", "invwrap")); + CHECK_FALSE(wrapped); // :source reads it again, or a tab as it; :e $MYVIMRC opens it. studio.vimrcText = "nnoremap Q gq\n"; - { - INFO(":so"); - CHECK(ex(a, "so")); - REQUIRE(maps.match(ALVimMappings::NORMAL, maps.keysOf("Q"), true).full); - REQUIRE_FALSE(maps.match(ALVimMappings::INSERT, maps.keysOf("jk"), true).full); - } + CHECK(ex(a, "so")); + CHECK(maps.match(ALVimMappings::NORMAL, maps.keysOf("Q"), true).full); + CHECK_FALSE(maps.match(ALVimMappings::INSERT, maps.keysOf("jk"), true).full); type(a, "\nbad line"); const bool read = ex(a, "source", "%"); const std::string& entry = studio.entries.back().text; @@ -1175,14 +1096,11 @@ namespace INFO(":so % reads the tab, and brings up what it did not take"); CHECK(read); CHECK(studio.outputShown == 1); - REQUIRE(entry.find("line 2:") != std::string::npos); - REQUIRE(entry.find("the vimrc") == std::string::npos); - } - { - INFO(":e $MYVIMRC"); - CHECK(ex(a, "e", "$MYVIMRC")); - CHECK(studio.vimrcEdited == 1); + CHECK(entry.find("line 2:") != std::string::npos); + CHECK(entry.find("the vimrc") == std::string::npos); } + CHECK(ex(a, "e", "$MYVIMRC")); + CHECK(studio.vimrcEdited == 1); { INFO(":so of a file that is not there"); CHECK(ex(a, "so", "nowhere.vim")); diff --git a/indra/newview/tests/alscriptstudioweighing_test.cpp b/indra/newview/tests/alscriptstudioweighing_test.cpp index 71c0e2573a..751d5ff9d3 100644 --- a/indra/newview/tests/alscriptstudioweighing_test.cpp +++ b/indra/newview/tests/alscriptstudioweighing_test.cpp @@ -129,37 +129,34 @@ namespace } }; + // And the others while it is in front and the Weights tab looked at. TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: the target a tab is weighed for and none where it has no weigher", "[alscriptstudioweighing]") { ALScriptStudioWeighing& unit = make(); - UNSCOPED_INFO("Mono"); CHECK(unit.target(tab("mono", "x")) == Target::Mono); UNSCOPED_INFO("no target said is Mono"); CHECK(unit.target(tab("none", "x", "")) == Target::Mono); - UNSCOPED_INFO("LSO"); CHECK(unit.target(tab("lso", "x", "lsl2")) == Target::LSO); - UNSCOPED_INFO("LSL on Luau"); CHECK(unit.target(tab("ll", "x", "lsl-luau")) == Target::LSLLuau); - UNSCOPED_INFO("SLua"); CHECK(unit.target(tab("slua", "x", "luau")) == Target::SLua); UNSCOPED_INFO("a target with no weigher"); - REQUIRE_FALSE(unit.target(tab("odd", "x", "something"))); + CHECK_FALSE(unit.target(tab("odd", "x", "something"))); Doc& note = tab("note", "x"); note.notecard = true; UNSCOPED_INFO("a notecard"); - REQUIRE_FALSE(unit.target(note)); + CHECK_FALSE(unit.target(note)); Doc& loading = tab("loading", "x"); loading.loaded = false; UNSCOPED_INFO("not loaded"); - REQUIRE_FALSE(unit.target(loading)); + CHECK_FALSE(unit.target(loading)); studio.fragment = true; UNSCOPED_INFO("a fragment"); - REQUIRE_FALSE(unit.target(tab("fragment", "x"))); + CHECK_FALSE(unit.target(tab("fragment", "x"))); studio.fragment = false; services.front = 0; UNSCOPED_INFO("its own alone"); - REQUIRE(unit.targets(*services.docs[0]).size() == 1); + CHECK(unit.targets(*services.docs[0]).size() == 1); studio.shown = true; const std::vector all = unit.targets(*services.docs[0]); { @@ -168,43 +165,41 @@ namespace CHECK(all[0] == Target::Mono); } UNSCOPED_INFO("not in front: its own"); - REQUIRE(unit.targets(*services.docs[2]).size() == 1); + CHECK(unit.targets(*services.docs[2]).size() == 1); services.front = 4; UNSCOPED_INFO("SLua has no others"); - REQUIRE(unit.targets(*services.docs[4]).size() == 1); + CHECK(unit.targets(*services.docs[4]).size() == 1); } + // Exact where nothing after the check changes it. TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: a weight with its check is kept and told and an older answer dropped", "[alscriptstudioweighing]") { ALScriptStudioWeighing& unit = make(); Doc& a = tab("a", "default {}"); unit.weigh(a); - { - INFO("asked"); - CHECK(a.weighing->asking); - CHECK(studio.asked == Names{ "a" }); - } + CHECK(a.weighing->asking); + CHECK(studio.asked == Names{ "a" }); ALScriptAnalysis::Result old = answerFor(a, { weightOf(Target::Mono, 100) }); old.version -= 1; unit.weighed(a, old); { INFO("older: dropped"); - REQUIRE_FALSE(a.weighing->asking); - REQUIRE_FALSE(a.weighing->weight); - REQUIRE(a.weighing->all.empty()); + CHECK_FALSE(a.weighing->asking); + CHECK_FALSE(a.weighing->weight); + CHECK(a.weighing->all.empty()); } unit.weighed(a, answerFor(a, { weightOf(Target::Mono, 100), weightOf(Target::LSO, 200) })); { INFO("kept, its own first"); REQUIRE(a.weighing->weight); - REQUIRE(a.weighing->weight->total == 100); - REQUIRE(a.weighing->all.size() == 2); - REQUIRE(a.weighing->allVersion == versionOf(a)); + CHECK(a.weighing->weight->total == 100); + CHECK(a.weighing->all.size() == 2); + CHECK(a.weighing->allVersion == versionOf(a)); CHECK(a.weighing->version == versionOf(a)); } { INFO("exact: no optimizer after the check"); - REQUIRE(a.weighing->exact); + CHECK(a.weighing->exact); CHECK_FALSE(a.weighing->sent); } { @@ -217,7 +212,7 @@ namespace unit.weighed(a, answerFor(a, { weightOf(Target::Mono, 90) })); { INFO("the optimizer after the check: not exact"); - REQUIRE_FALSE(a.weighing->exact); + CHECK_FALSE(a.weighing->exact); CHECK(a.weighing->weight->total == 90); } Doc& none = tab("none", "x"); @@ -226,18 +221,19 @@ namespace unit.weigh(none); { INFO("nothing to weigh it for: its weight let go, nothing asked"); - REQUIRE_FALSE(none.weighing->weight); - REQUIRE(studio.asked.size() == 1); + CHECK_FALSE(none.weighing->weight); + CHECK(studio.asked.size() == 1); } } + // An answer for older text is dropped. TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: a sent text's weight stands over the check's of the same text", "[alscriptstudioweighing]") { ALScriptStudioWeighing& unit = make(); Doc& a = tab("a", "default {}"); unit.weighSent(a); UNSCOPED_INFO("nothing sent yet: nothing asked"); - REQUIRE(studio.requests.empty()); + CHECK(studio.requests.empty()); a.uploaded.valid = true; a.uploaded.version = versionOf(a); a.uploaded.text = std::make_shared("sent text"); @@ -252,20 +248,20 @@ namespace { INFO("kept as sent, and exact"); REQUIRE(a.weighing->weight); - REQUIRE(a.weighing->weight->total == 300); - REQUIRE(a.weighing->sent); + CHECK(a.weighing->weight->total == 300); + CHECK(a.weighing->sent); CHECK(a.weighing->exact); } { - INFO("told"); + INFO("the Problems and the save told"); CHECK(studio.problems == Names{ "a" }); CHECK(studio.warned == Names{ "a" }); } unit.weighed(a, answerFor(a, { weightOf(Target::Mono, 100) })); { INFO("the check's of the same text does not replace it"); - REQUIRE(a.weighing->weight->total == 300); - REQUIRE(a.weighing->all.size() == 1); + CHECK(a.weighing->weight->total == 300); + CHECK(a.weighing->all.size() == 1); } a.uploaded.disabled = true; unit.weighSent(a); @@ -287,14 +283,13 @@ namespace a.weighing->all = { weightOf(Target::Mono, 100), weightOf(Target::LSO, 200) }; a.weighing->allVersion = versionOf(a); unit.keepSaved(a); - UNSCOPED_INFO("kept"); - REQUIRE(a.weighing->saved.size() == 2); + CHECK(a.weighing->saved.size() == 2); a.weighing->all = { weightOf(Target::Mono, 150) }; unit.keepSaved(a); { INFO("each target's replaced, the others kept"); REQUIRE(a.weighing->saved.size() == 2); - REQUIRE(a.weighing->saved[0].total == 150); + CHECK(a.weighing->saved[0].total == 150); CHECK(a.weighing->saved[1].total == 200); } a.editor->setCaret(a.editor->document().end()); @@ -306,6 +301,7 @@ namespace CHECK(a.weighing->saved[0].total == 150); } + // Neither where it is off or out of date. TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: a weight shows each part's bytes and each line's heat in the editor", "[alscriptstudioweighing]") { ALScriptStudioWeighing& unit = make(); @@ -326,9 +322,9 @@ namespace a.weighing->exact = true; unit.showInEditor(a); UNSCOPED_INFO("its part's bytes after its line"); - REQUIRE(a.editor->noteAt(0).find("WeightNote") != std::string::npos); + CHECK(a.editor->noteAt(0).find("WeightNote") != std::string::npos); UNSCOPED_INFO("the included file's own not"); - REQUIRE(a.editor->noteAt(1).empty()); + CHECK(a.editor->noteAt(1).empty()); UNSCOPED_INFO("the warmest line the heat's own colour"); CHECK(a.editor->heatAt(0) == 1.f); UNSCOPED_INFO("a quarter as warm by bytes, half by their square root"); @@ -337,7 +333,7 @@ namespace unit.showInEditor(a); { INFO("notes off: gone, the heat kept"); - REQUIRE(a.editor->noteAt(0).empty()); + CHECK(a.editor->noteAt(0).empty()); CHECK(a.editor->heatAt(0) == 1.f); } studio.heat = false; @@ -350,7 +346,7 @@ namespace unit.showInEditor(a); { INFO("out of date: nothing new said"); - REQUIRE(a.editor->noteAt(0).empty()); + CHECK(a.editor->noteAt(0).empty()); CHECK(a.editor->heatAt(0) == 0.f); } } @@ -385,10 +381,10 @@ namespace p.expanded.generation = 1; p.expanded.text = std::make_shared("default { }\n"); unit.measureAsset(p); - UNSCOPED_INFO("the envelope's length"); - REQUIRE(p.weighing->assetBytes == p.envelopeFor(*p.expanded.text, studio.programVersion()).wrap().size()); + CHECK(p.weighing->assetBytes == p.envelopeFor(*p.expanded.text, studio.programVersion()).wrap().size()); } + // Each against the text as it stands. TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: listed fixes are weighed once settled and told what each would change", "[alscriptstudioweighing]") { ALScriptStudioWeighing& unit = make(); @@ -415,7 +411,7 @@ namespace e.setFixable(0, true, true); e.setFocus(true); { - INFO("listed"); + INFO("Ctrl+. lists the fixes"); CHECK(e.handleKeyHere('.', MASK_CONTROL)); CHECK(e.fixesOpen()); } @@ -439,14 +435,15 @@ namespace CHECK(e.fixes()[0].note.find("FixLighterEstimate") == 0); { INFO("the same: nothing said"); - REQUIRE(e.fixes()[1].note.empty()); - REQUIRE(e.fixes()[2].note.empty()); + CHECK(e.fixes()[1].note.empty()); + CHECK(e.fixes()[2].note.empty()); } unit.pump(); UNSCOPED_INFO("weighed once"); - REQUIRE(studio.requests.size() == 1); + CHECK(studio.requests.size() == 1); } + // While the Weights tab is looked at, and the tab checked as it stands. TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: the tab in front is weighed once for the targets it lacks", "[alscriptstudioweighing]") { ALScriptStudioWeighing& unit = make(); @@ -465,19 +462,21 @@ namespace } unit.pump(); UNSCOPED_INFO("once, while it is asked"); - REQUIRE(studio.asked.size() == 1); + CHECK(studio.asked.size() == 1); a.weighing->asking = false; a.weighing->all = { weightOf(Target::Mono, 1), weightOf(Target::LSO, 2), weightOf(Target::LSLLuau, 3) }; unit.pump(); UNSCOPED_INFO("all there: nothing more"); - REQUIRE(studio.asked.size() == 1); + CHECK(studio.asked.size() == 1); studio.shown = false; a.weighing->all.clear(); unit.pump(); UNSCOPED_INFO("not looked at: nothing"); - REQUIRE(studio.asked.size() == 1); + CHECK(studio.asked.size() == 1); } + // Checked but not weighed with it; one asked for an older text is not + // waited on. TEST_CASE_METHOD(alscriptstudioweighing_data, "alscriptstudioweighing: a tab come to the front unweighed is weighed once for its text", "[alscriptstudioweighing]") { ALScriptStudioWeighing& unit = make(); @@ -489,7 +488,7 @@ namespace services.front = 0; unit.pump(); UNSCOPED_INFO("weighed with its check already: nothing"); - REQUIRE(studio.asked.empty()); + CHECK(studio.asked.empty()); services.front = 1; unit.pump(); { @@ -498,8 +497,8 @@ namespace CHECK(ALScriptStudioWeighing::asking(b)); } unit.pump(); - UNSCOPED_INFO("once"); - REQUIRE(studio.asked.size() == 1); + UNSCOPED_INFO("weighed once"); + CHECK(studio.asked.size() == 1); // Typed in while it was weighed: the answer for the older text is // passed over, and the check of the new one weighs it again. b.editor->insertText("x"); @@ -507,7 +506,7 @@ namespace CHECK_FALSE(ALScriptStudioWeighing::asking(b)); unit.pump(); UNSCOPED_INFO("not before its check"); - REQUIRE(studio.asked.size() == 1); + CHECK(studio.asked.size() == 1); b.check->analysisVersion = versionOf(b); unit.pump(); UNSCOPED_INFO("then, for the new text"); diff --git a/indra/newview/tests/alscriptstudiowords_test.cpp b/indra/newview/tests/alscriptstudiowords_test.cpp index 72eb1a0bd5..378661423b 100644 --- a/indra/newview/tests/alscriptstudiowords_test.cpp +++ b/indra/newview/tests/alscriptstudiowords_test.cpp @@ -124,15 +124,13 @@ namespace TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: the vocabulary gives each kind's detail sorted and skips unknown groups", "[alscriptstudiowords]") { const std::vector& words = Words::vocabulary(false); - UNSCOPED_INFO("six"); - REQUIRE(words.size() == size_t(6)); - UNSCOPED_INFO("sorted"); + CHECK(words.size() == size_t(6)); CHECK(std::is_sorted(words.begin(), words.end(), [](const Vocab& a, const Vocab& b) { return a.text < b.text; })); const Vocab* say = Words::word(false, "llSay"); { INFO("a function's call, with its arguments' types"); REQUIRE(say); - REQUIRE(say->kind == ALSyntaxKind::Function); + CHECK(say->kind == ALSyntaxKind::Function); CHECK(say->detail == "llSay(integer channel, string msg)"); } { @@ -146,13 +144,12 @@ namespace CHECK(Words::word(false, "PI")->detail == std::string("float PI = 3.14159265")); UNSCOPED_INFO("a type's tooltip's first line"); CHECK(Words::word(false, "integer")->detail == std::string("A whole number.")); - UNSCOPED_INFO("a control"); CHECK(Words::word(false, "jump")->kind == ALSyntaxKind::Control); { INFO("not a word"); - REQUIRE_FALSE(Words::word(false, "x")); - REQUIRE_FALSE(Words::word(false, "")); - REQUIRE_FALSE(Words::word(false, "nothing")); + CHECK_FALSE(Words::word(false, "x")); + CHECK_FALSE(Words::word(false, "")); + CHECK_FALSE(Words::word(false, "nothing")); } UNSCOPED_INFO("SLua's () returns nothing worth saying"); CHECK(Words::word(true, "ll.Say")->detail == std::string("ll.Say(number channel)")); @@ -160,27 +157,26 @@ namespace TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: the vocabulary is kept until forgotten and then built again", "[alscriptstudiowords]") { - UNSCOPED_INFO("there"); REQUIRE(Words::word(false, "llSay") != nullptr); lsl["functions"].erase("llSay"); lsl["functions"]["llShout"] = LLSD().with("return", ""); { INFO("kept"); - REQUIRE(Words::word(false, "llSay") != nullptr); - REQUIRE_FALSE(Words::word(false, "llShout")); + CHECK(Words::word(false, "llSay") != nullptr); + CHECK_FALSE(Words::word(false, "llShout")); } Words::forget(); { INFO("built again"); - REQUIRE_FALSE(Words::word(false, "llSay")); - REQUIRE(Words::word(false, "llShout") != nullptr); + CHECK_FALSE(Words::word(false, "llSay")); + CHECK(Words::word(false, "llShout") != nullptr); } viewer.slots.keywords = [](bool) { return LLSD("not a map"); }; Words::forget(); { INFO("definitions that are not: no words"); - REQUIRE(Words::vocabulary(false).empty()); - REQUIRE_FALSE(Words::word(false, "llShout")); + CHECK(Words::vocabulary(false).empty()); + CHECK_FALSE(Words::word(false, "llShout")); } } @@ -190,31 +186,24 @@ namespace extra = { "switch", "case" }; Words::teach(e, false); const ALSyntaxWords& tables = e.highlighter().words(); - { - INFO("functions"); - REQUIRE(tables.has("function", "llSay")); - REQUIRE_FALSE(tables.has("function", "llOld")); - } - UNSCOPED_INFO("the deprecated"); - REQUIRE(tables.has("deprecated", "llOld")); - { - INFO("events, constants, types, controls"); - REQUIRE(tables.has("event", "touch_start")); - REQUIRE(tables.has("constant", "PI")); - REQUIRE(tables.has("type", "integer")); - REQUIRE(tables.has("control", "jump")); - } + CHECK(tables.has("function", "llSay")); + CHECK_FALSE(tables.has("function", "llOld")); + CHECK(tables.has("deprecated", "llOld")); + CHECK(tables.has("event", "touch_start")); + CHECK(tables.has("constant", "PI")); + CHECK(tables.has("type", "integer")); + CHECK(tables.has("control", "jump")); { INFO("the preprocessor's"); - REQUIRE(tables.has("control", "switch")); - REQUIRE(tables.has("control", "case")); + CHECK(tables.has("control", "switch")); + CHECK(tables.has("control", "case")); } ALCodeEditor& s = editor("x", true); Words::teach(s, true); { INFO("SLua's own, and none of the preprocessor's"); - REQUIRE(s.highlighter().words().has("function", "ll.Say")); - REQUIRE_FALSE(s.highlighter().words().has("control", "switch")); + CHECK(s.highlighter().words().has("function", "ll.Say")); + CHECK_FALSE(s.highlighter().words().has("control", "switch")); } } @@ -243,18 +232,18 @@ namespace CHECK(slua.snippet == std::string("function LLEvents.touch_start(detected)\n $0\nend")); UNSCOPED_INFO("typed where asked, as the definitions type it"); CHECK(Words::completionFor(*Words::word(true, "touch_start"), true, true).snippet == - std::string("function LLEvents.touch_start(detected: {DetectedEvent})\n $0\nend")); + std::string("function LLEvents.touch_start(detected: {DetectedEvent})\n $0\nend")); UNSCOPED_INFO("each parameter typed"); CHECK(Words::completionFor(*Words::word(true, "listen"), true, true).snippet == - std::string("function LLEvents.listen(channel: number, name: string, id: uuid, msg: string)\n $0\nend")); + std::string("function LLEvents.listen(channel: number, name: string, id: uuid, msg: string)\n $0\nend")); UNSCOPED_INFO("each untyped"); CHECK(Words::completionFor(*Words::word(true, "listen"), true).snippet == - std::string("function LLEvents.listen(channel, name, id, msg)\n $0\nend")); + std::string("function LLEvents.listen(channel, name, id, msg)\n $0\nend")); const ALCodeEditor::Completion say = Words::completionFor(*Words::word(false, "llSay"), false); { INFO("a function as itself"); - REQUIRE(say.snippet.empty()); - REQUIRE(say.text == "llSay"); + CHECK(say.snippet.empty()); + CHECK(say.text == "llSay"); REQUIRE(say.documentation); CHECK(*say.documentation == "Says msg on channel.\nMore."); } @@ -267,7 +256,7 @@ namespace std::vector out; Words::complete(false, e, ALTextPos(2, 5), "t", { snippet }, "Snippet", out); UNSCOPED_INFO("inside the state: the handler and the snippet"); - CHECK(texts(out) == std::vector{ "touch_start", "timer" }); + REQUIRE(texts(out) == std::vector{ "touch_start", "timer" }); UNSCOPED_INFO("the snippet said so"); CHECK(out[1].detail == std::string("Snippet Timer")); out.clear(); @@ -288,7 +277,7 @@ namespace std::string text; { INFO("ll.Say under Say"); - REQUIRE(Words::hoverText(true, s.document(), ALTextPos(0, 4), "Say", text)); + CHECK(Words::hoverText(true, s.document(), ALTextPos(0, 4), "Say", text)); CHECK(text == "ll.Say(number channel)"); } { @@ -331,8 +320,7 @@ namespace CHECK(functions[0].detail == "Deprecated"); CHECK(functions[1].detail == "Says msg on channel."); } - UNSCOPED_INFO("the events"); - REQUIRE(Words::library(false, "event", {}, "") .size() == 1); + CHECK(Words::library(false, "event", {}, "") .size() == 1); UNSCOPED_INFO("an LSL name"); CHECK(Words::helpUrl(false, "llSay") == std::string("https://wiki.example/llSay")); @@ -346,7 +334,7 @@ namespace CHECK(Words::helpUrl(false, "") == std::string("https://wiki.example/LSL_Portal")); UNSCOPED_INFO("the reference's words"); CHECK(Words::referenceText(*Words::word(false, "PI"), false) == - std::string("float PI = 3.14159265\n\nThe ratio.\nhttps://wiki.example/PI")); + std::string("float PI = 3.14159265\n\nThe ratio.\nhttps://wiki.example/PI")); } TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: a tab's mark follows what it is and a symbol's its kind", "[alscriptstudiowords]") @@ -366,7 +354,6 @@ namespace doc.name = ".luaurc"; UNSCOPED_INFO("a config"); CHECK(std::string(Words::imageNameOf(doc)) == std::string("Studio_Config")); - UNSCOPED_INFO("a function"); CHECK(std::string(Words::imageNameOf(ALScriptSymbolKind::Function)) == std::string("Symbol_Function")); UNSCOPED_INFO("a state as a label"); CHECK(std::string(Words::imageNameOf(ALScriptSymbolKind::State)) == std::string("Symbol_Label")); @@ -382,16 +369,13 @@ namespace for (S32 kind = static_cast(ALScriptSymbolKind::Keyword); kind <= static_cast(ALScriptSymbolKind::Module); ++kind) { const char* word = Words::kindWordOf(static_cast(kind)); - { - INFO("a word for each"); - REQUIRE(word != nullptr); - REQUIRE(window.floater->hasString(word)); - } + CAPTURE(kind); + REQUIRE(word != nullptr); + REQUIRE(window.floater->hasString(word)); said.insert(window.floater->getString(word)); } UNSCOPED_INFO("each its own"); - REQUIRE(said.size() == size_t(static_cast(ALScriptSymbolKind::Module) + 1)); - UNSCOPED_INFO("a function"); + CHECK(said.size() == size_t(static_cast(ALScriptSymbolKind::Module) + 1)); CHECK(window.floater->getString(Words::kindWordOf(ALScriptSymbolKind::Function)) == std::string("function")); } @@ -402,36 +386,33 @@ namespace slua["functions"]["type"] = LLSD().with("return", "string").with("tooltip", "What a value is."); Words::forget(); const Vocab* email = Words::word(false, "llEmail"); - { - INFO("the email"); - REQUIRE(email); - REQUIRE(email->sleep == "20.0"); - CHECK_FALSE(email->godMode); - } + REQUIRE(email); + CHECK(email->sleep == "20.0"); + CHECK_FALSE(email->godMode); const std::string notes = Words::notesOf(*email); { - INFO("its words and its delay: " + notes); + INFO("its words and its delay: " << notes); CHECK(notes.find("Sends an email.") == 0); - REQUIRE(notes.find("20.0") != std::string::npos); + CHECK(notes.find("20.0") != std::string::npos); } const Vocab* god = Words::word(false, "llGodLikeRezObject"); { INFO("a god's, no delay said for none"); REQUIRE(god); - REQUIRE(god->godMode); - REQUIRE(god->sleep.empty()); + CHECK(god->godMode); + CHECK(god->sleep.empty()); } - UNSCOPED_INFO("said"); - REQUIRE_FALSE(Words::notesOf(*god).empty()); + UNSCOPED_INFO("that only a god may call it, said"); + CHECK_FALSE(Words::notesOf(*god).empty()); // `type` under the mouse in `obj.type` is some table's field. ALCodeEditor& s = editor("local t = obj.type\nlocal u = type(t)\n", true); std::string text; UNSCOPED_INFO("a member: not the global"); - REQUIRE_FALSE(Words::hoverText(true, s.document(), ALTextPos(0, 15), "type", text)); + CHECK_FALSE(Words::hoverText(true, s.document(), ALTextPos(0, 15), "type", text)); { INFO("the global itself"); CHECK(Words::hoverText(true, s.document(), ALTextPos(1, 11), "type", text)); - REQUIRE(text.find("What a value is.") != std::string::npos); + CHECK(text.find("What a value is.") != std::string::npos); } } @@ -443,13 +424,10 @@ namespace slua["functions"]["ll.MessageLinked"] = LLSD().with("return", "()").with("arguments", LLSD().with(0, argument("link", "number")).with(1, argument("num", "number"))); Words::forget(); - UNSCOPED_INFO("llSetLinkAlpha's first"); CHECK(Words::linkArgument(false, "llSetLinkAlpha", 0)); - UNSCOPED_INFO("not its second"); CHECK_FALSE(Words::linkArgument(false, "llSetLinkAlpha", 1)); UNSCOPED_INFO("nor past its last"); CHECK_FALSE(Words::linkArgument(false, "llSetLinkAlpha", 3)); - UNSCOPED_INFO("llSay has none"); CHECK_FALSE(Words::linkArgument(false, "llSay", 0)); UNSCOPED_INFO("a word not known, none"); CHECK_FALSE(Words::linkArgument(false, "llNothing", 0)); @@ -459,6 +437,7 @@ namespace CHECK_FALSE(Words::linkArgument(true, "ll.MessageLinked", 1)); } } + TEST_CASE_METHOD(alscriptstudiowords_data, "alscriptstudiowords: word tables are shared per language and rebuilt when their sources change", "[alscriptstudiowords]") { S32 asked = 0; @@ -493,7 +472,7 @@ namespace { INFO("and shared still, with the new word"); CHECK(&a.highlighter().words() == &b.highlighter().words()); - REQUIRE(a.highlighter().words().has("function", "llShout")); + CHECK(a.highlighter().words().has("function", "llShout")); } const ALSyntaxWords* before = &a.highlighter().words(); @@ -502,7 +481,7 @@ namespace { INFO("new preprocessor words, new tables"); CHECK(&a.highlighter().words() != before); - REQUIRE(a.highlighter().words().has("control", "switch")); + CHECK(a.highlighter().words().has("control", "switch")); } } @@ -531,7 +510,7 @@ namespace " - touch\n", found); UNSCOPED_INFO("only functions, and those with categories"); - REQUIRE(found.size() == size_t(1)); + CHECK(found.size() == size_t(1)); UNSCOPED_INFO("by the first"); CHECK(found["llSay"] == std::string("avatar_communication")); @@ -541,13 +520,13 @@ namespace UNSCOPED_INFO("LSL, in words"); CHECK(Words::word(false, "llSay")->group == std::string("Avatar communication")); UNSCOPED_INFO("none where none is said"); - REQUIRE(Words::word(false, "llOld")->group.empty()); + CHECK(Words::word(false, "llOld")->group.empty()); UNSCOPED_INFO("an event none"); - REQUIRE(Words::word(false, "touch_start")->group.empty()); + CHECK(Words::word(false, "touch_start")->group.empty()); UNSCOPED_INFO("a constant by family"); CHECK(Words::word(false, "PRIM_POSITION")->group == std::string("PRIM_...")); UNSCOPED_INFO("one without a family none"); - REQUIRE(Words::word(false, "PI")->group.empty()); + CHECK(Words::word(false, "PI")->group.empty()); UNSCOPED_INFO("SLua's ll function as its twin"); CHECK(Words::word(true, "ll.Say")->group == std::string("Avatar communication")); UNSCOPED_INFO("another SLua function by library"); @@ -561,18 +540,11 @@ namespace CHECK(&asked == &viewer); UNSCOPED_INFO("its words"); CHECK(asked.lslHelpUrl() == "https://wiki.example/[LSL_STRING]"); - { - INFO("no definitions as YAML, no version"); - REQUIRE(asked.definitionsYaml().empty()); - REQUIRE(asked.definitionsVersion().empty()); - } - { - INFO("no preprocessor, no transform"); - CHECK_FALSE(asked.preprocessing()); - CHECK_FALSE(asked.transformOn(ALPreprocessor::Transform::Switch)); - } + CHECK(asked.definitionsYaml().empty()); + CHECK(asked.definitionsVersion().empty()); + CHECK_FALSE(asked.preprocessing()); + CHECK_FALSE(asked.transformOn(ALPreprocessor::Transform::Switch)); ALPreprocessor::Include found; - UNSCOPED_INFO("no include"); CHECK(asked.lookUp(ALScriptPreprocessor::Request(), ALPreprocessor::Ask(), found) == ALPreprocessor::Found::No); viewer.slots.lslHelpUrl = nullptr; UNSCOPED_INFO("the wiki as nothing says it"); @@ -655,7 +627,7 @@ namespace CHECK(handler("mapped", false) == std::string("function LLEvents.mapped(pairs, n)\n $0\nend")); UNSCOPED_INFO("a function type's arrow, a table type's colon"); CHECK(handler("called", true) == - std::string("function LLEvents.called(back: (number) -> (), data: {[string]: any})\n $0\nend")); + std::string("function LLEvents.called(back: (number) -> (), data: {[string]: any})\n $0\nend")); UNSCOPED_INFO("a variadic typed"); CHECK(handler("varied", true) == std::string("function LLEvents.varied(first: number, ...: any)\n $0\nend")); UNSCOPED_INFO("and not"); diff --git a/indra/newview/tests/alscripttheme_test.cpp b/indra/newview/tests/alscripttheme_test.cpp index b98048d388..298010d193 100644 --- a/indra/newview/tests/alscripttheme_test.cpp +++ b/indra/newview/tests/alscripttheme_test.cpp @@ -68,28 +68,24 @@ namespace continue; } ++shipped; - UNSCOPED_INFO("a name: " + theme.path); + CAPTURE(theme.path); REQUIRE_FALSE(theme.name.empty()); - UNSCOPED_INFO("colours: " + theme.name); REQUIRE_FALSE(theme.colors.empty()); for (const auto& [name, color] : theme.colors) { - UNSCOPED_INFO(theme.name + " colours " + name + ", which no editor is painted by"); + UNSCOPED_INFO("it colours " << name << ", which no editor is painted by"); REQUIRE(spoken(name)); } } - UNSCOPED_INFO("the viewer ships themes"); CHECK(shipped > 1); } TEST_CASE_METHOD(alscripttheme_data, "alscripttheme: editor colours come first and every colour name has a label", "[alscripttheme]") { const std::vector& names = ALScriptTheme::names(); - UNSCOPED_INFO("names"); REQUIRE_FALSE(names.empty()); UNSCOPED_INFO("the text first"); CHECK(names.front() == std::string("ScriptText")); - UNSCOPED_INFO("an editor colour"); CHECK(ALScriptTheme::isEditorColor("ScriptBackground")); UNSCOPED_INFO("read as a person reads it"); CHECK(ALScriptTheme::labelOf("ScriptBackground") == std::string("Background")); @@ -99,7 +95,7 @@ namespace CHECK(ALScriptTheme::labelOf("ScriptDocComment") == std::string("Doc comment")); for (const std::string& name : names) { - UNSCOPED_INFO("a label for " + name); + CAPTURE(name); REQUIRE_FALSE(ALScriptTheme::labelOf(name).empty()); } } @@ -128,10 +124,11 @@ namespace UNSCOPED_INFO("and so does the theme"); CHECK(ALScriptTheme::chosen() == std::string("Monokai")); ALScriptTheme::setChosen(std::string()); - UNSCOPED_INFO("none"); REQUIRE(ALScriptTheme::chosen().empty()); } + // What reads less than it should: code against both grounds, the text against its bands, the line numbers + // against the gutter. TEST_CASE_METHOD(alscripttheme_data, "alscripttheme: illegible reports each colour too faint against its ground", "[alscripttheme]") { ALScriptTheme theme; @@ -189,6 +186,8 @@ namespace } } + // Every theme the viewer ships reads: the text and each kind of code at 4.5:1, the line numbers at 3:1; the + // high-contrast ones at 7 and 4.5. TEST_CASE_METHOD(alscripttheme_data, "alscripttheme: every shipped theme reads at its contrast thresholds", "[alscripttheme]") { if (!ui.ok()) @@ -202,6 +201,7 @@ namespace { continue; } + CAPTURE(theme.name); const bool contrast = theme.name.find("High Contrast") != std::string::npos; high += contrast; std::string said; @@ -209,7 +209,7 @@ namespace { said += "\n " + each.name + " on " + each.against + ": " + std::to_string(each.contrast); } - UNSCOPED_INFO(theme.name + " reads:" + said); + UNSCOPED_INFO("colours that read too faintly:" << said); REQUIRE(said.empty()); } UNSCOPED_INFO("a dark and a light high-contrast theme"); @@ -227,7 +227,7 @@ namespace const std::string strings((std::istreambuf_iterator(in)), std::istreambuf_iterator()); for (const std::string& name : ALScriptTheme::names()) { - UNSCOPED_INFO("a label for " + name); + CAPTURE(name); REQUIRE(strings.find("name=\"ScriptColorLabel_" + name + "\"") != std::string::npos); } #else @@ -251,12 +251,12 @@ namespace } for (const char* skin : { "default", "alchemy", "gemini", "heretic", "ionic" }) { + CAPTURE(skin); ALColorSheet sheet; sheet.read(default_root, "default/colors.xml"); if (std::string(skin) != "default") { LLXMLNodePtr root; - UNSCOPED_INFO(std::string(skin) + " parses"); REQUIRE(LLXMLNode::parseFile(skins + skin + "/colors.xml", root, nullptr)); sheet.read(root, std::string(skin) + "/colors.xml"); } @@ -270,26 +270,23 @@ namespace { said += "\n " + each.name + " on " + each.against + ": " + std::to_string(each.contrast); } - UNSCOPED_INFO(std::string(skin) + "'s script colours read:" + said); + UNSCOPED_INFO("script colours that read too faintly:" << said); REQUIRE(said.empty()); // And the studios' parts told apart by what they are: a divider // from the panes it divides, a tab not chosen from the chosen // one, the notice and the strips from the panes. - const auto apart = [&](const char* a, const char* b, F32 least) { + const auto require_apart = [&](const char* a, const char* b, F32 least) { + CAPTURE(a, b); const LLColor4* x = sheet.find(a); const LLColor4* y = sheet.find(b); - { - INFO(std::string(skin) + " has " + a + " and " + b); - REQUIRE(x); - REQUIRE(y); - } - UNSCOPED_INFO(std::string(skin) + ": " + a + " apart from " + b); + REQUIRE(x); + REQUIRE(y); REQUIRE(ALSurface::contrast(*x, *y) >= least); }; - apart("StudioDividerColor", "StudioPaneColor", 1.3f); - apart("StudioTabColor", "PanelDefaultBackgroundColor", 1.08f); - apart("StudioNoticeColor", "StudioPaneColor", 1.08f); - apart("StudioStripColor", "StudioPaneColor", 1.05f); + require_apart("StudioDividerColor", "StudioPaneColor", 1.3f); + require_apart("StudioTabColor", "PanelDefaultBackgroundColor", 1.08f); + require_apart("StudioNoticeColor", "StudioPaneColor", 1.08f); + require_apart("StudioStripColor", "StudioPaneColor", 1.05f); } #else SKIP("no LLUI_TEST_APP_DIR"); diff --git a/indra/newview/tests/alscripttypes_test.cpp b/indra/newview/tests/alscripttypes_test.cpp index 6fe94da356..95f9f63ff9 100644 --- a/indra/newview/tests/alscripttypes_test.cpp +++ b/indra/newview/tests/alscripttypes_test.cpp @@ -55,7 +55,6 @@ TEST_CASE_METHOD(alscripttypes_data, "alscripttypes: inSource maps diagnostics b return ALPreprocessor::Found::Yes; }; const ALPreprocessor::Result expanded = ALPreprocessor::run("#include \"lib.lsl\"\ndefault\n{\nstate_entry() { x; }\n}\n", options); - UNSCOPED_INFO("expanded"); REQUIRE(expanded.problems.empty()); // The lines of the expansion that hold each, and the column of `x`. S32 entry = -1, second = -1, column = -1, line = 0; @@ -93,7 +92,6 @@ TEST_CASE_METHOD(alscripttypes_data, "alscripttypes: inSource maps diagnostics b result.diagnostics.push_back(unplaced); const std::vector source = result.inSource(); - UNSCOPED_INFO("four"); REQUIRE(source.size() == size_t(4)); { INFO("the script's own line and column"); diff --git a/indra/newview/tests/alscriptweightspane_test.cpp b/indra/newview/tests/alscriptweightspane_test.cpp index cc4928f697..11aec4dba9 100644 --- a/indra/newview/tests/alscriptweightspane_test.cpp +++ b/indra/newview/tests/alscriptweightspane_test.cpp @@ -55,10 +55,10 @@ namespace LLPanel* tab() const { return floater ? floater->findChild("weights_tab", true) : nullptr; } // The tab as the skin built it, in its window's words. - ALScriptWeightsPane& weights() const + ALScriptWeightsPane& require_pane() const { ALScriptWeightsPane* pane = floater->findChild("weights_tab", true); - UNSCOPED_INFO("the skin builds the tab as the pane"); + INFO("the skin builds the tab as the pane"); REQUIRE(pane != nullptr); return *pane; } @@ -146,12 +146,11 @@ namespace } UNSCOPED_INFO("the studio's window builds with its Weights tab"); REQUIRE(tab() != nullptr); - ALScriptWeightsPane& pane = weights(); + ALScriptWeightsPane& pane = require_pane(); pane.show(lsl()); ALPaneList* targets = list("weights_targets"); ALPaneList* parts = list("weights_parts"); - UNSCOPED_INFO("three targets"); - CHECK(targets->getItemCount() == 3); + REQUIRE(targets->getItemCount() == 3); UNSCOPED_INFO("its own first"); CHECK(cell(targets->getAllData()[0], 0) == std::string("LSL (LSO)")); UNSCOPED_INFO("its code"); @@ -168,23 +167,22 @@ namespace CHECK(targets->getFirstSelected()->getValue().asInteger() == S32(ALScriptWeight::Target::LSO)); } - UNSCOPED_INFO("its parts"); CHECK(parts->getItemCount() == 5); const std::vector names = column(parts, 0); UNSCOPED_INFO("the registers in words" + joined(names)); - REQUIRE(std::find(names.begin(), names.end(), "Registers") != names.end()); + CHECK(std::find(names.begin(), names.end(), "Registers") != names.end()); UNSCOPED_INFO("a handler in its state" + joined(names)); - REQUIRE(std::find(names.begin(), names.end(), "touch_start in default") != names.end()); + CHECK(std::find(names.begin(), names.end(), "touch_start in default") != names.end()); const std::vector lines = column(parts, 5); UNSCOPED_INFO("an include's part at the include's line" + joined(lines)); - REQUIRE(std::find(lines.begin(), lines.end(), "lib.lsl:1") != lines.end()); + CHECK(std::find(lines.begin(), lines.end(), "lib.lsl:1") != lines.end()); UNSCOPED_INFO("the script's own at its line" + joined(lines)); - REQUIRE(std::find(lines.begin(), lines.end(), "8") != lines.end()); + CHECK(std::find(lines.begin(), lines.end(), "8") != lines.end()); const std::string head = floater->findChild("weights_head", true)->getText(); { INFO("the head says whose and on what: " + head); - REQUIRE(head.find("Door") != std::string::npos); - REQUIRE(head.find("LSO") != std::string::npos); + CHECK(head.find("Door") != std::string::npos); + CHECK(head.find("LSO") != std::string::npos); } } @@ -196,7 +194,7 @@ namespace { SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } - ALScriptWeightsPane& pane = weights(); + ALScriptWeightsPane& pane = require_pane(); pane.show(lsl()); ALPaneList* targets = list("weights_targets"); ALPaneList* parts = list("weights_parts"); @@ -205,17 +203,13 @@ namespace std::optional place = pane.chosenPlace(parts); UNSCOPED_INFO("the include's function has a place"); REQUIRE(place.has_value()); - UNSCOPED_INFO("in the include"); CHECK(place->file == std::string("disk:/lib.lsl")); - UNSCOPED_INFO("by its name"); CHECK(place->fileName == std::string("lib.lsl")); - UNSCOPED_INFO("at its line"); CHECK(place->line == 0); - UNSCOPED_INFO("and column"); CHECK(place->column == 4); parts->selectByValue(LLSD(0)); UNSCOPED_INFO("the registers are nowhere"); - REQUIRE_FALSE(pane.chosenPlace(parts)); + CHECK_FALSE(pane.chosenPlace(parts)); targets->selectByValue(LLSD(S32(ALScriptWeight::Target::Mono))); targets->onCommit(); @@ -241,7 +235,7 @@ namespace { SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } - ALScriptWeightsPane& pane = weights(); + ALScriptWeightsPane& pane = require_pane(); ALScriptWeightsPane::Shown shown = lsl(); ALScriptWeight saved = shown.weights[0]; saved.total = 4000; @@ -288,26 +282,21 @@ namespace } } - // Nothing to show says why, and holds nothing to choose. TEST_CASE_METHOD(alscriptweightspane_data, "ALScriptWeightsPane: showNothing says why and holds nothing to choose", "[ALScriptWeightsPane]") { if (!ui.ok()) { SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } - ALScriptWeightsPane& pane = weights(); + ALScriptWeightsPane& pane = require_pane(); pane.show(lsl()); pane.showNothing("Nothing open to weigh."); - UNSCOPED_INFO("no targets"); CHECK(list("weights_targets")->getItemCount() == 0); - UNSCOPED_INFO("no parts"); CHECK(list("weights_parts")->getItemCount() == 0); - UNSCOPED_INFO("nothing chosen"); - REQUIRE_FALSE(pane.chosenPlace(pane.partsList())); - UNSCOPED_INFO("why"); + CHECK_FALSE(pane.chosenPlace(pane.partsList())); CHECK(floater->findChild("weights_head", true)->getText() == std::string("Nothing open to weigh.")); UNSCOPED_INFO("and whose it is forgotten"); - REQUIRE(pane.shownId().empty()); + CHECK(pane.shownId().empty()); } // Anonymous functions share an empty name: each is matched to the one @@ -319,7 +308,7 @@ namespace SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } using Kind = ALScriptWeight::Part::Kind; - ALScriptWeightsPane& pane = weights(); + ALScriptWeightsPane& pane = require_pane(); ALScriptWeightsPane::Shown shown; shown.id = "script-3"; shown.name = "Handlers"; @@ -333,7 +322,7 @@ namespace shown.saved = { slua }; pane.show(shown); std::vector changes = column(list("weights_parts"), 4); - UNSCOPED_INFO("nothing changed" + joined(changes)); + UNSCOPED_INFO("nothing changed"); CHECK(joined(changes) == std::string("|||")); // The middle one heavier, and one added after them. ALScriptWeight now = slua; @@ -342,7 +331,7 @@ namespace shown.weights = { now }; pane.show(shown); changes = column(list("weights_parts"), 4); - UNSCOPED_INFO("the middle one, and one new" + joined(changes)); + UNSCOPED_INFO("the middle one, and one new"); CHECK(joined(changes) == std::string("||+50||new")); } @@ -353,7 +342,7 @@ namespace SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } using Kind = ALScriptWeight::Part::Kind; - ALScriptWeightsPane& pane = weights(); + ALScriptWeightsPane& pane = require_pane(); ALScriptWeightsPane::Shown shown; shown.id = "script-6"; shown.name = "Handlers"; @@ -368,9 +357,9 @@ namespace pane.show(shown); const std::string names = joined(column(list("weights_parts"), 0)); UNSCOPED_INFO("the handler by its event: " + names); - REQUIRE(names.find("touch_start") != std::string::npos); + CHECK(names.find("touch_start") != std::string::npos); UNSCOPED_INFO("the other with none: " + names); - REQUIRE(names.find(window.find("weights_tab")->getString("WeightsPartUnnamed")) != std::string::npos); + CHECK(names.find(window.find("weights_tab")->getString("WeightsPartUnnamed")) != std::string::npos); } // What the region reserves for the script's object, where it has said: @@ -383,12 +372,12 @@ namespace { SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } - ALScriptWeightsPane& pane = weights(); + ALScriptWeightsPane& pane = require_pane(); ALScriptWeightsPane::Shown shown = lsl(); LLTextBox* head = floater->findChild("weights_head", true); pane.show(shown); UNSCOPED_INFO("nothing of the region"); - REQUIRE(head->getText().find("region") == std::string::npos); + CHECK(head->getText().find("region") == std::string::npos); ALScriptRegionUsage::Usage reserved; reserved.memory = 131072; reserved.when = LLDate(1.8e9); @@ -397,32 +386,32 @@ namespace pane.show(shown); const std::string said = head->getText(); UNSCOPED_INFO("reserved, in KB" + said); - REQUIRE(said.find("reserves 128 KB for all its scripts") != std::string::npos); + CHECK(said.find("reserves 128 KB for all its scripts") != std::string::npos); UNSCOPED_INFO("as of when" + said); - REQUIRE(said.find(ALRecoveryEntry::sayWhen(reserved.when)) != std::string::npos); + CHECK(said.find(ALRecoveryEntry::sayWhen(reserved.when)) != std::string::npos); UNSCOPED_INFO("no URLs said where there are none" + said); - REQUIRE(said.find("URLs") == std::string::npos); + CHECK(said.find("URLs") == std::string::npos); UNSCOPED_INFO("the tip says how it counts"); - REQUIRE(head->getToolTip().find("64 KB for Mono") != std::string::npos); + CHECK(head->getToolTip().find("64 KB for Mono") != std::string::npos); UNSCOPED_INFO("and nothing of time unasked"); - REQUIRE(head->getToolTip().find("Top Scripts") == std::string::npos); + CHECK(head->getToolTip().find("Top Scripts") == std::string::npos); shown.region->urls = 3; shown.id = "script-3"; pane.show(shown); UNSCOPED_INFO("and URLs where there are" + head->getText()); - REQUIRE(head->getText().find("128 KB and 3 URLs") != std::string::npos); + CHECK(head->getText().find("128 KB and 3 URLs") != std::string::npos); UNSCOPED_INFO("no time where the region said none" + head->getText()); - REQUIRE(head->getText().find("ms of the region") == std::string::npos); + CHECK(head->getText().find("ms of the region") == std::string::npos); shown.region->time = 0.125f; shown.region->timeWhen = LLDate(1.8e9); shown.id = "script-4"; pane.show(shown); UNSCOPED_INFO("its time, said to an estate manager" + head->getText()); - REQUIRE(head->getText().find("take 0.125 ms of the region's time") != std::string::npos); + CHECK(head->getText().find("take 0.125 ms of the region's time") != std::string::npos); { INFO("the tip says how both are counted"); - REQUIRE(head->getToolTip().find("64 KB for Mono") != std::string::npos); - REQUIRE(head->getToolTip().find("Top Scripts") != std::string::npos); + CHECK(head->getToolTip().find("64 KB for Mono") != std::string::npos); + CHECK(head->getToolTip().find("Top Scripts") != std::string::npos); } ALScriptRegionUsage::Usage timed; timed.time = 0.5f; @@ -432,13 +421,13 @@ namespace pane.show(shown); { INFO("time alone: no memory said" + head->getText()); - REQUIRE(head->getText().find("reserves") == std::string::npos); - REQUIRE(head->getText().find("take 0.500 ms") != std::string::npos); + CHECK(head->getText().find("reserves") == std::string::npos); + CHECK(head->getText().find("take 0.500 ms") != std::string::npos); } { INFO("and the tip of the time alone"); - REQUIRE(head->getToolTip().find("64 KB for Mono") == std::string::npos); - REQUIRE(head->getToolTip().find("Top Scripts") != std::string::npos); + CHECK(head->getToolTip().find("64 KB for Mono") == std::string::npos); + CHECK(head->getToolTip().find("Top Scripts") != std::string::npos); } } @@ -453,7 +442,7 @@ namespace } UNSCOPED_INFO("the studio's window builds with its Weights tab"); REQUIRE(tab() != nullptr); - ALScriptWeightsPane& pane = weights(); + ALScriptWeightsPane& pane = require_pane(); ALScriptWeightsPane::Shown shown = lsl(); shown.weights[2].compiled = true; shown.weights[2].error.clear(); @@ -462,11 +451,11 @@ namespace pane.show(shown); const std::string luau = floater->findChild("weights_head", true)->getText(); UNSCOPED_INFO("said for LSL on Luau: " + luau); - REQUIRE(luau.find("records no lines") != std::string::npos); + CHECK(luau.find("records no lines") != std::string::npos); pane.show(lsl()); const std::string lso = floater->findChild("weights_head", true)->getText(); UNSCOPED_INFO("not for LSO: " + lso); - REQUIRE(lso.find("records no lines") == std::string::npos); + CHECK(lso.find("records no lines") == std::string::npos); } // A Luau target's strings beside its parts: the starts several share @@ -479,7 +468,7 @@ namespace { SKIP("no UI: LLUI_TEST_APP_DIR does not point at the source tree"); } - ALScriptWeightsPane& pane = weights(); + ALScriptWeightsPane& pane = require_pane(); ALScriptWeightsPane::Shown shown; shown.id = "script-2"; shown.name = "Greeter"; @@ -516,13 +505,13 @@ namespace CHECK(strings->getParent()->getVisible()); } UNSCOPED_INFO("a start, then each string"); - CHECK(strings->getItemCount() == 5); + REQUIRE(strings->getItemCount() == 5); const std::vector texts = column(strings, 0); { INFO("the start first: " + texts[0]); CHECK(texts[0].find("Shared start") == 0); - REQUIRE(texts[0].find("\"You have touched me, \"") != std::string::npos); - REQUIRE(texts[0].find("2 strings") != std::string::npos); + CHECK(texts[0].find("\"You have touched me, \"") != std::string::npos); + CHECK(texts[0].find("2 strings") != std::string::npos); } UNSCOPED_INFO("what it saves, as less"); CHECK(column(strings, 1)[0] == std::string("-9")); @@ -531,7 +520,7 @@ namespace UNSCOPED_INFO("at the first of them"); CHECK(column(strings, 4)[0] == std::string("3")); UNSCOPED_INFO("then the heaviest first, a break shown as one"); - REQUIRE(joined(texts).substr(joined({ texts[0] }).size()) == + CHECK(joined(texts).substr(joined({ texts[0] }).size()) == std::string("|\"You have touched me, alpha\"|\"You have touched me, bravo\"|\"greet\"|\"x\\ny\"")); UNSCOPED_INFO("each one's uses, a function's name said as one"); CHECK(joined(column(strings, 2)) == std::string("|3|1|2|name|1")); @@ -541,7 +530,7 @@ namespace { INFO("a string chosen: where it is first named"); REQUIRE(place); - REQUIRE(place->file.empty()); + CHECK(place->file.empty()); CHECK(place->line == 2); } strings->selectByValue(LLSD(0)); @@ -552,7 +541,7 @@ namespace CHECK(place->line == 2); } UNSCOPED_INFO("not the parts' choice"); - REQUIRE_FALSE(pane.chosenPlace(list("weights_parts"))); + CHECK_FALSE(pane.chosenPlace(list("weights_parts"))); // Kept chosen through a refill, by what it is. strings->selectByValue(LLSD(1)); @@ -570,13 +559,13 @@ namespace }; { INFO("the start's strings named: " + tip(0)); - REQUIRE(tip(0).find("\"You have touched me, alpha\"") != std::string::npos); - REQUIRE(tip(0).find("\"You have touched me, bravo\"") != std::string::npos); + CHECK(tip(0).find("\"You have touched me, alpha\"") != std::string::npos); + CHECK(tip(0).find("\"You have touched me, bravo\"") != std::string::npos); } UNSCOPED_INFO("a string of it says so: " + tip(1)); - REQUIRE(tip(1).find("shares its start") != std::string::npos); + CHECK(tip(1).find("shares its start") != std::string::npos); UNSCOPED_INFO("one that is not, nothing: " + tip(4)); - REQUIRE(tip(4).find("shares its start") == std::string::npos); + CHECK(tip(4).find("shares its start") == std::string::npos); // Since the save: a string not there then, new; a start by how its // saving moved, said as its bytes are, as less: saving more since, @@ -608,19 +597,19 @@ namespace strings->selectByValue(LLSD(1)); floater->findChild("weights_keep_start", true)->onCommit(); UNSCOPED_INFO("not for a string"); - REQUIRE(kept.empty()); + CHECK(kept.empty()); // Nor in a script that cannot be written to. pane.setKeepStart([&](const std::string& start, const std::vector&) { kept = start; }, []() { return false; }); strings->selectByValue(LLSD(0)); floater->findChild("weights_keep_start", true)->onCommit(); UNSCOPED_INFO("not where the script cannot be written to"); - REQUIRE(kept.empty()); + CHECK(kept.empty()); // Nothing to show hides the list with the rest. pane.showNothing("Nothing open to weigh."); { INFO("hidden with nothing shown"); - REQUIRE_FALSE(strings->getParent()->getVisible()); + CHECK_FALSE(strings->getParent()->getVisible()); CHECK(strings->getItemCount() == 0); } pane.show(shown); @@ -631,7 +620,7 @@ namespace pane.show(lsl()); { INFO("hidden for LSO"); - REQUIRE_FALSE(strings->getParent()->getVisible()); + CHECK_FALSE(strings->getParent()->getVisible()); CHECK(strings->getItemCount() == 0); } } diff --git a/indra/newview/tests/alselectionoutline_gl_test.cpp b/indra/newview/tests/alselectionoutline_gl_test.cpp index de1f3dee71..295e8f8388 100644 --- a/indra/newview/tests/alselectionoutline_gl_test.cpp +++ b/indra/newview/tests/alselectionoutline_gl_test.cpp @@ -114,8 +114,6 @@ namespace return count; } - // Of the frame `px`, the sum of a column's coverage in red from row `y0` to `y1` - 1, in pixels: the width - // of a line across it. // The rows a column's runs of drawn pixels cover, bottom up, each as its first row and one past its last. std::vector> columnRuns(const std::vector& px, S32 x) { @@ -138,6 +136,8 @@ namespace return found; } + // Of the frame `px`, the sum of a column's coverage in red from row `y0` to `y1` - 1, in pixels: the width + // of a line across it. F32 ink(const std::vector& px, S32 x, S32 y0, S32 y1) { F32 sum = 0.f; @@ -227,11 +227,6 @@ namespace return reverse; } - static std::string named(bool reverse, const std::string& what) - { - return what + (reverse ? " (reverse-Z)" : " (forward)"); - } - void setConvention(bool reverse) { LLRender::sReverseZ = reverse; @@ -256,12 +251,11 @@ namespace std::map defines = { { "MAX_JOINTS_PER_MESH_OBJECT", "110" } }; for (const char* object : { "avatar/objectSkinV.glsl", "deferred/textureUtilV.glsl", "objects/nonindexedTextureV.glsl" }) { + CAPTURE(object); S32 level = 1; - UNSCOPED_INFO(std::string("compiled ") + object); REQUIRE(mShaders.loadShaderFile(object, level, GL_VERTEX_SHADER, &defines) != 0); } S32 level = 1; - UNSCOPED_INFO("compiled deferred/globalF.glsl"); REQUIRE(mShaders.loadShaderFile("deferred/globalF.glsl", level, GL_FRAGMENT_SHADER, &defines) != 0); mIdProgram.mName = "Selection Id Shader"; @@ -271,13 +265,9 @@ namespace mIdProgram.mShaderFiles.push_back(std::make_pair("interface/selectionAlphaF.glsl", GL_FRAGMENT_SHADER)); mIdProgram.mShaderFiles.push_back(std::make_pair("interface/selectionUtilF.glsl", GL_FRAGMENT_SHADER)); mIdProgram.mShaderLevel = 1; - UNSCOPED_INFO("id program builds with its rigged variant"); REQUIRE(mIdProgram.createShader(LLGLSLShader::VARIANT_RIGGED)); - { - INFO("id program has a rigged variant"); - REQUIRE(mIdProgram.mRiggedVariant); - REQUIRE(mIdProgram.mRiggedVariant != &mIdProgram); - } + REQUIRE(mIdProgram.mRiggedVariant); + REQUIRE(mIdProgram.mRiggedVariant != &mIdProgram); mWireProgram.mName = "Selection Wireframe Shader"; mWireProgram.mShaderFiles.clear(); @@ -287,13 +277,9 @@ namespace mWireProgram.mShaderFiles.push_back(std::make_pair("interface/selectionAlphaF.glsl", GL_FRAGMENT_SHADER)); mWireProgram.mShaderFiles.push_back(std::make_pair("interface/selectionUtilF.glsl", GL_FRAGMENT_SHADER)); mWireProgram.mShaderLevel = 1; - UNSCOPED_INFO("wireframe program builds with its rigged variant"); REQUIRE(mWireProgram.createShader(LLGLSLShader::VARIANT_RIGGED)); - { - INFO("wireframe program has a rigged variant"); - REQUIRE(mWireProgram.mRiggedVariant); - REQUIRE(mWireProgram.mRiggedVariant != &mWireProgram); - } + REQUIRE(mWireProgram.mRiggedVariant); + REQUIRE(mWireProgram.mRiggedVariant != &mWireProgram); // The final blit's depth copy, as LLViewerShaderMgr builds gCopyDepthProgram. mCopyDepthProgram.mName = "Copy Depth Shader"; @@ -304,7 +290,6 @@ namespace mCopyDepthProgram.addPermutation("COPY_DEPTH", "1"); mCopyDepthProgram.addPermutation("DEPTH_ONLY", "1"); mCopyDepthProgram.mShaderLevel = 1; - UNSCOPED_INFO("copy depth program builds"); REQUIRE(mCopyDepthProgram.createShader()); const std::pair passes[] = { { &mJumpProgram, "selectionJumpF.glsl" }, @@ -330,41 +315,31 @@ namespace // The edge pass searching the disk for the glow too: the full search. program->addPermutation("GLOW_DISK", "1"); } - UNSCOPED_INFO(std::string(fragment) + "'s program builds"); + CAPTURE(fragment); REQUIRE(program->createShader()); } const LLRenderTarget::eDepthFormat depth = mReverse ? LLRenderTarget::DEPTH_FMT_32F : LLRenderTarget::DEPTH_FMT_24; - UNSCOPED_INFO("id target"); REQUIRE(mIdMap.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); - UNSCOPED_INFO("jump target"); REQUIRE(mJumps.allocate(W, H, GL_R8)); - UNSCOPED_INFO("glow reach target"); REQUIRE(mGlowReach.allocate(Outline::tileCount(W), Outline::tileCount(H), GL_RGBA16)); - UNSCOPED_INFO("glow row target"); REQUIRE(mGlowRows.allocate(W, H, GL_R8)); - UNSCOPED_INFO("frame target"); REQUIRE(mFrame.allocate(W, H, GL_RGBA8)); - UNSCOPED_INFO("window target"); REQUIRE(mWindow.allocate(W, H, GL_RGBA8, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); - UNSCOPED_INFO("tile target"); REQUIRE(mTiles.allocate(Outline::tileCount(W), Outline::tileCount(H), GL_RGBA16)); // Every tile holding every id and a jump: the edge pass searches every pixel's disk, as it did before // the tiles. - UNSCOPED_INFO("all tiles target"); REQUIRE(mAllTiles.allocate(Outline::tileCount(W), Outline::tileCount(H), GL_RGBA16)); mAllTiles.bindTarget(); gGL.setClearColor(LLColor4(1.f, 1.f, 1.f, 1.f)); mAllTiles.clear(); gGL.setClearColor(LLColor4(0.f, 0.f, 0.f, 0.f)); mAllTiles.flush(); - UNSCOPED_INFO("far depth"); REQUIRE(mFar.allocate(W, H, 0, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); clearDepth(mFar); sceneAt(W, H); mTriangle = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX); - UNSCOPED_INFO("triangle"); REQUIRE(mTriangle->allocateBuffer(3, 0)); LLStrider vert; mTriangle->getVertexStrider(vert); @@ -386,7 +361,6 @@ namespace void sceneAt(S32 width, S32 height) { const LLRenderTarget::eDepthFormat depth = mReverse ? LLRenderTarget::DEPTH_FMT_32F : LLRenderTarget::DEPTH_FMT_24; - UNSCOPED_INFO("scene depth"); REQUIRE(mScene.allocate(width, height, 0, true, false, ALTextureSlot::TT_TEXTURE, LLRenderTarget::MIPS_NONE, depth)); clearDepth(mScene); } @@ -430,7 +404,6 @@ namespace const U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | (weights ? LLVertexBuffer::MAP_WEIGHT4 : 0); LLPointer buffer = new LLVertexBuffer(mask); - UNSCOPED_INFO("quad"); REQUIRE(buffer->allocateBuffer(4, 6)); LLStrider vert; LLStrider texcoord; @@ -949,63 +922,64 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); idPass({ { quadA(), ID_A }, { quadB(), ID_B } }); const std::vector ids = read(mIdMap); - UNSCOPED_INFO(named(reverse, "A's id")); + UNSCOPED_INFO("A's id"); REQUIRE(idAt(ids, 20, 32) == ID_A); - UNSCOPED_INFO(named(reverse, "B's id, past one byte")); + UNSCOPED_INFO("B's id, past one byte"); REQUIRE(idAt(ids, 40, 32) == ID_B); - UNSCOPED_INFO(named(reverse, "nothing selected outside")); + UNSCOPED_INFO("nothing selected outside"); REQUIRE(idAt(ids, 2, 2) == 0U); - UNSCOPED_INFO(named(reverse, "the priority in alpha")); + UNSCOPED_INFO("the priority in alpha"); REQUIRE((U32)at(ids, 20, 32).a == (U32)Outline::PRIORITY_ROOT); palette({ { ID_A, RED }, { ID_B, GREEN } }, true); const std::vector px = edgePass(); - UNSCOPED_INFO(named(reverse, "A outlined at full strength beside its contour")); + UNSCOPED_INFO("A outlined at full strength beside its contour"); REQUIRE((U32)at(px, 8, 32).r == 255U); - UNSCOPED_INFO(named(reverse, "and a pixel further")); + UNSCOPED_INFO("and a pixel further"); REQUIRE((U32)at(px, 7, 32).r == 255U); - UNSCOPED_INFO(named(reverse, "and in its colour")); + UNSCOPED_INFO("and in its colour"); REQUIRE(red(at(px, 7, 32))); - UNSCOPED_INFO(named(reverse, "nothing past the line")); + UNSCOPED_INFO("nothing past the line"); REQUIRE(black(at(px, 6, 32))); { - INFO(named(reverse, "A outlined above")); + INFO("A outlined above"); REQUIRE(red(at(px, 20, 45))); REQUIRE(black(at(px, 20, 46))); } { - INFO(named(reverse, "A outlined below")); + INFO("A outlined below"); REQUIRE(red(at(px, 20, 18))); REQUIRE(black(at(px, 20, 17))); } { - INFO(named(reverse, "B outlined right of its contour")); + INFO("B outlined right of its contour"); REQUIRE(green(at(px, 56, 32))); REQUIRE(black(at(px, 57, 32))); } - UNSCOPED_INFO(named(reverse, "B outlined above")); + UNSCOPED_INFO("B outlined above"); REQUIRE(green(at(px, 40, 45))); - UNSCOPED_INFO(named(reverse, "nothing far away")); + UNSCOPED_INFO("nothing far away"); REQUIRE(black(at(px, 2, 2))); const Pixel edge = at(px, 31, 32); - UNSCOPED_INFO(named(reverse, "the shared edge on A's side, in A's colour")); + UNSCOPED_INFO("the shared edge on A's side, in A's colour"); REQUIRE(red(edge)); { - INFO(named(reverse, "fainter than the contour")); + INFO("fainter than the contour"); REQUIRE(edge.r >= 150); REQUIRE(edge.r <= 156); } - UNSCOPED_INFO(named(reverse, "and not on B's")); + UNSCOPED_INFO("and not on B's"); REQUIRE(black(at(px, 32, 32))); - UNSCOPED_INFO(named(reverse, "A's inside left alone")); + UNSCOPED_INFO("A's inside left alone"); REQUIRE(black(at(px, 20, 32))); - UNSCOPED_INFO(named(reverse, "B's inside left alone")); + UNSCOPED_INFO("B's inside left alone"); REQUIRE(black(at(px, 44, 32))); } } @@ -1016,18 +990,19 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); idPass({ { quadA(), ID_A }, { quadB(), ID_A } }); palette({ { ID_A, RED } }, true); const std::vector px = edgePass(); - UNSCOPED_INFO(named(reverse, "contour still outlined")); + UNSCOPED_INFO("contour still outlined"); REQUIRE(red(at(px, 8, 32))); - UNSCOPED_INFO(named(reverse, "contour still outlined on the far side")); + UNSCOPED_INFO("contour still outlined on the far side"); REQUIRE(red(at(px, 55, 32))); - UNSCOPED_INFO(named(reverse, "no edge between them on one side")); + UNSCOPED_INFO("no edge between them on one side"); REQUIRE(black(at(px, 31, 32))); - UNSCOPED_INFO(named(reverse, "no edge between them on the other")); + UNSCOPED_INFO("no edge between them on the other"); REQUIRE(black(at(px, 32, 32))); } } @@ -1038,6 +1013,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // An occluder three metres out over columns 0 to 19, which covers A's left part. @@ -1053,21 +1029,21 @@ namespace idPass({ { quadA(), ID_A } }); std::vector ids = read(mIdMap); - UNSCOPED_INFO(named(reverse, "covered part marked hidden and drawn")); + UNSCOPED_INFO("covered part marked hidden and drawn"); REQUIRE(drawnHidden(at(ids, 12, 32))); - UNSCOPED_INFO(named(reverse, "uncovered part marked visible")); + UNSCOPED_INFO("uncovered part marked visible"); REQUIRE((U32)at(ids, 25, 32).b == 255U); - UNSCOPED_INFO(named(reverse, "hidden parts keep their id")); + UNSCOPED_INFO("hidden parts keep their id"); REQUIRE(idAt(ids, 12, 32) == ID_A); palette({ { ID_A, RED } }, true); std::vector px = edgePass(); const U32 hidden = at(px, 8, 32).r; const U32 visible = at(px, 25, 44).r; - UNSCOPED_INFO(named(reverse, "visible outline at full strength")); + UNSCOPED_INFO("visible outline at full strength"); REQUIRE(visible == 255U); { - INFO(named(reverse, "hidden outline dimmed to the hidden alpha")); + INFO("hidden outline dimmed to the hidden alpha"); REQUIRE(hidden >= 90); REQUIRE(hidden <= 115); } @@ -1076,15 +1052,15 @@ namespace left_out.mShowHidden = false; idPass({ left_out }); ids = read(mIdMap); - UNSCOPED_INFO(named(reverse, "covered part marked not drawn")); + UNSCOPED_INFO("covered part marked not drawn"); REQUIRE((U32)at(ids, 12, 32).b == 0U); - UNSCOPED_INFO(named(reverse, "uncovered part still visible")); + UNSCOPED_INFO("uncovered part still visible"); REQUIRE((U32)at(ids, 25, 32).b == 255U); palette({ { ID_A, RED } }, false); px = edgePass(); - UNSCOPED_INFO(named(reverse, "hidden outline left out")); + UNSCOPED_INFO("hidden outline left out"); REQUIRE(black(at(px, 8, 32))); - UNSCOPED_INFO(named(reverse, "visible outline kept")); + UNSCOPED_INFO("visible outline kept"); REQUIRE((U32)at(px, 25, 44).r == 255U); } } @@ -1096,10 +1072,12 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); for (S32 divisor : { 1, 2 }) { + CAPTURE(divisor); sceneAt(W / divisor, H / divisor); // Turned about 60 degrees from the eye: five metres deep across its width. LLVertexBuffer* tilted = quad(-1.5f, 1.5f, -1.f, 1.f, -3.5f, -8.5f); @@ -1122,10 +1100,9 @@ namespace } } } - const std::string at_divisor = " at render resolution / " + std::to_string(divisor); - UNSCOPED_INFO(named(reverse, "the surface covers pixels" + at_divisor)); + UNSCOPED_INFO("the surface covers pixels"); REQUIRE(covered > 200); - UNSCOPED_INFO(named(reverse, "none of its own pixels hidden by itself" + at_divisor)); + UNSCOPED_INFO("none of its own pixels hidden by itself"); REQUIRE(hidden == size_t(0)); } } @@ -1137,36 +1114,37 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); idPass({ { quadA(), ID_A }, { quadB(), ID_B } }); palette({ { ID_A, RED }, { ID_B, GREEN } }, true); const std::vector full = edgePass(); const S32 reach = Outline::lineReach(view().mWidth); - UNSCOPED_INFO(named(reverse, "the contour reaches its width and a pixel")); + UNSCOPED_INFO("the contour reaches its width and a pixel"); REQUIRE(reach == 3); const LLRect rect = boxRect(reach); - UNSCOPED_INFO(named(reverse, "left: column 8.57 floored, less the reach")); + UNSCOPED_INFO("left: column 8.57 floored, less the reach"); REQUIRE(rect.mLeft == 8 - reach); - UNSCOPED_INFO(named(reverse, "right: column 55.43 ceiled, plus the reach")); + UNSCOPED_INFO("right: column 55.43 ceiled, plus the reach"); REQUIRE(rect.mRight == 56 + reach); - UNSCOPED_INFO(named(reverse, "bottom: row 20.28 floored, less the reach")); + UNSCOPED_INFO("bottom: row 20.28 floored, less the reach"); REQUIRE(rect.mBottom == 20 - reach); - UNSCOPED_INFO(named(reverse, "top: row 43.72 ceiled, plus the reach")); + UNSCOPED_INFO("top: row 43.72 ceiled, plus the reach"); REQUIRE(rect.mTop == 44 + reach); const std::vector scissored = edgePass(&rect); - UNSCOPED_INFO(named(reverse, "something is outlined")); + UNSCOPED_INFO("something is outlined"); REQUIRE(lit(full) > 0); - UNSCOPED_INFO(named(reverse, "the scissored pass draws every outline pixel")); + UNSCOPED_INFO("the scissored pass draws every outline pixel"); REQUIRE(scissored == full); const LLRect tight = boxRect(0); const std::vector clipped = edgePass(&tight); - UNSCOPED_INFO(named(reverse, "a box without the reach clips the line")); + UNSCOPED_INFO("a box without the reach clips the line"); REQUIRE(lit(clipped) < lit(full)); { - INFO(named(reverse, "the line's outer pixels are what it loses")); + INFO("the line's outer pixels are what it loses"); REQUIRE_FALSE(black(at(full, 7, 32))); REQUIRE(black(at(clipped, 7, 32))); } @@ -1204,34 +1182,35 @@ namespace for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); LLVertexBuffer* bound = quad(-0.5f, 0.5f, -0.5f, 0.5f, QUAD_Z, QUAD_Z, true); idPass({ { bound, ID_A } }, right); std::vector ids = read(mIdMap); - UNSCOPED_INFO(named(reverse, "posed right")); + UNSCOPED_INFO("posed right"); REQUIRE(idAt(ids, 49, 32) == ID_A); - UNSCOPED_INFO(named(reverse, "not at the bind pose")); + UNSCOPED_INFO("not at the bind pose"); REQUIRE(idAt(ids, 32, 32) == 0U); - UNSCOPED_INFO(named(reverse, "not posed left")); + UNSCOPED_INFO("not posed left"); REQUIRE(idAt(ids, 14, 32) == 0U); idPass({ { bound, ID_A } }, left); ids = read(mIdMap); - UNSCOPED_INFO(named(reverse, "posed left")); + UNSCOPED_INFO("posed left"); REQUIRE(idAt(ids, 14, 32) == ID_A); - UNSCOPED_INFO(named(reverse, "gone from the right")); + UNSCOPED_INFO("gone from the right"); REQUIRE(idAt(ids, 49, 32) == 0U); // Posed, it covers columns 9 to 20 and rows 26 to 37. palette({ { ID_A, RED } }, true); const std::vector px = edgePass(); - UNSCOPED_INFO(named(reverse, "outlined above where it is posed")); + UNSCOPED_INFO("outlined above where it is posed"); REQUIRE(red(at(px, 14, 39))); - UNSCOPED_INFO(named(reverse, "outlined below where it is posed")); + UNSCOPED_INFO("outlined below where it is posed"); REQUIRE(red(at(px, 14, 24))); { - INFO(named(reverse, "not where it is not")); + INFO("not where it is not"); REQUIRE(black(at(px, 49, 39))); REQUIRE(black(at(px, 49, 24))); } @@ -1304,17 +1283,15 @@ namespace { const Outline::View in_world = Outline::makeView(identity(), world, setting, ui_scale, false); const Outline::View on_hud = Outline::makeView(identity(), hud, setting, ui_scale, true); - const std::string with = " for " + std::to_string(setting) + " at UI scale " + std::to_string(ui_scale); - UNSCOPED_INFO("the contour" + with); + CAPTURE(setting, ui_scale); REQUIRE(in_world.mWidth == Outline::contourWidth(setting, ui_scale)); - UNSCOPED_INFO("the edges" + with); REQUIRE(in_world.mInnerWidth == Outline::lineWidth(Outline::INNER_WIDTH, ui_scale)); - UNSCOPED_INFO("the HUD's contour as the world's" + with); + UNSCOPED_INFO("the HUD's contour as the world's"); REQUIRE(on_hud.mWidth == in_world.mWidth); - UNSCOPED_INFO("the HUD's edges as the world's" + with); + UNSCOPED_INFO("the HUD's edges as the world's"); REQUIRE(on_hud.mInnerWidth == in_world.mInnerWidth); { - INFO("the HUD's view is the HUD's" + with); + INFO("only the HUD's view is the HUD's"); REQUIRE(on_hud.mHUD); REQUIRE_FALSE(in_world.mHUD); } @@ -1328,6 +1305,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // An occluder three metres out over the whole view, in front of A. @@ -1341,7 +1319,7 @@ namespace mScene.flush(); idPass({ { quadA(), ID_A } }); - UNSCOPED_INFO(named(reverse, "the world's pass hides A behind it")); + UNSCOPED_INFO("the world's pass hides A behind it"); REQUIRE(drawnHidden(at(read(mIdMap), 20, 32))); idPass(mIdMap, nullptr, { { quadA(), ID_A } }, nullptr, &mScene); @@ -1359,14 +1337,14 @@ namespace } } } - UNSCOPED_INFO(named(reverse, "the HUD's pass draws A")); + UNSCOPED_INFO("the HUD's pass draws A"); REQUIRE(covered > 200); - UNSCOPED_INFO(named(reverse, "and hides none of it")); + UNSCOPED_INFO("and hides none of it"); REQUIRE(hidden == size_t(0)); palette({ { ID_A, RED } }, false); const std::vector px = edgePass(); - UNSCOPED_INFO(named(reverse, "outlined at full strength")); + UNSCOPED_INFO("outlined at full strength"); REQUIRE((U32)at(px, 8, 32).r == 255U); } } @@ -1383,6 +1361,7 @@ namespace for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // Columns and rows 19 to 44, and 6 to 57: the farther shows only around the nearer. LLVertexBuffer* nearer = quad(-0.2f, 0.2f, -0.2f, 0.2f, -2.f, -2.f); @@ -1395,16 +1374,16 @@ namespace const LLMatrix4a* projections[] = { &ortho, &flattened }; for (const LLMatrix4a* projection : projections) { - const std::string which = projection == &ortho ? "al_ortho" : "the HUD's flattened row"; + INFO((projection == &ortho ? "al_ortho" : "the HUD's flattened row")); for (bool near_first : { true, false }) { + CAPTURE(near_first); const std::vector ids = near_first ? projectedIds(*projection, { { nearer, ID_NEAR }, { farther, ID_FAR } }) : projectedIds(*projection, { { farther, ID_FAR }, { nearer, ID_NEAR } }); - const std::string order = near_first ? ", nearer drawn first" : ", farther drawn first"; - UNSCOPED_INFO(named(reverse, which + ": the nearer kept" + order)); + UNSCOPED_INFO("the nearer kept"); REQUIRE(idAt(ids, 32, 32) == ID_NEAR); - UNSCOPED_INFO(named(reverse, which + ": the farther around it" + order)); + UNSCOPED_INFO("the farther around it"); REQUIRE(idAt(ids, 10, 32) == ID_FAR); } } @@ -1413,7 +1392,7 @@ namespace { const LLMatrix4a unreversed = LLMatrix4a::orthoZO(-0.5f, 0.5f, -0.5f, 0.5f, 0.f, HUD_DEPTH); const std::vector ids = projectedIds(unreversed, { { farther, ID_FAR }, { nearer, ID_NEAR } }); - UNSCOPED_INFO(named(reverse, "unreversed, the farther wins")); + UNSCOPED_INFO("unreversed, the farther wins"); REQUIRE(idAt(ids, 32, 32) == ID_FAR); } } @@ -1428,11 +1407,12 @@ namespace { 4.f, 1.f }, { 1.f, 1.f }, { 2.5f, 1.f }, { 0.25f, 1.f }, { 40.f, 1.f } }; for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED } }, true); for (const auto& [setting, ui_scale] : settings) { - const std::string with = " for " + std::to_string(setting) + " at UI scale " + std::to_string((S32)ui_scale); + CAPTURE(setting, ui_scale); const S32 width = Outline::contourWidth(setting, ui_scale); // The HUD's: its left edge is column 20. @@ -1443,9 +1423,9 @@ namespace { ++hud_band; } - UNSCOPED_INFO(named(reverse, "the HUD's contour is the setting's width" + with)); + UNSCOPED_INFO("the HUD's contour is the setting's width"); REQUIRE(hud_band == width); - UNSCOPED_INFO(named(reverse, "nothing past it" + with)); + UNSCOPED_INFO("nothing past it"); REQUIRE(black(at(px, 19 - width - 1, 32))); // The world's: A's left edge is column 9, room for a line eight pixels wide. @@ -1458,7 +1438,7 @@ namespace { ++world_band; } - UNSCOPED_INFO(named(reverse, "the world's is the same" + with)); + UNSCOPED_INFO("the world's is the same"); REQUIRE(world_band == hud_band); } } @@ -1479,15 +1459,11 @@ namespace CHECK(Outline::legacyAlphaCutoff(false, 0, 0, true) == Outline::BLEND_ALPHA_CUTOFF); UNSCOPED_INFO("opaque"); CHECK(Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_NONE, 64, true) == Outline::NO_ALPHA_TEST); - UNSCOPED_INFO("emissive"); CHECK(Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE, 64, true) == Outline::NO_ALPHA_TEST); UNSCOPED_INFO("a texture without alpha"); CHECK(Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_MASK, 64, false) == Outline::NO_ALPHA_TEST); - UNSCOPED_INFO("GLTF mask"); CHECK(Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_MASK, 0.25f) == 0.25f); - UNSCOPED_INFO("GLTF blend"); CHECK(Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_BLEND, 0.25f) == Outline::BLEND_ALPHA_CUTOFF); - UNSCOPED_INFO("GLTF opaque"); CHECK(Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_OPAQUE, 0.25f) == Outline::NO_ALPHA_TEST); // Halved along u, as a GLTF transform and as a texture animation: column c samples 2c + 1. The transform is @@ -1502,6 +1478,7 @@ namespace for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); const U32 texture = ramp(); const F32 mask = Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_MASK, 64, true); @@ -1510,55 +1487,55 @@ namespace // Column 15 samples alpha 62, column 16 alpha 66. std::vector ids = pixelIds({ { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, mask, texture } }); - UNSCOPED_INFO(named(reverse, "a mask cuts under its cutoff")); + UNSCOPED_INFO("a mask cuts under its cutoff"); REQUIRE(idAt(ids, 15, 32) == 0U); - UNSCOPED_INFO(named(reverse, "and keeps over it")); + UNSCOPED_INFO("and keeps over it"); REQUIRE(idAt(ids, 16, 32) == ID_A); - UNSCOPED_INFO(named(reverse, "and keeps the opaque end")); + UNSCOPED_INFO("and keeps the opaque end"); REQUIRE(idAt(ids, 63, 32) == ID_A); // Column 5 samples alpha 22, column 6 alpha 26: either side of a tenth. ids = pixelIds({ { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, blend, texture } }); - UNSCOPED_INFO(named(reverse, "a blend cuts what is all but clear")); + UNSCOPED_INFO("a blend cuts what is all but clear"); REQUIRE(idAt(ids, 5, 32) == 0U); - UNSCOPED_INFO(named(reverse, "and keeps the faintest it draws")); + UNSCOPED_INFO("and keeps the faintest it draws"); REQUIRE(idAt(ids, 6, 32) == ID_A); ids = pixelIds({ { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, opaque, texture } }); - UNSCOPED_INFO(named(reverse, "an opaque face keeps its transparent texels")); + UNSCOPED_INFO("an opaque face keeps its transparent texels"); REQUIRE(idAt(ids, 0, 32) == ID_A); - UNSCOPED_INFO(named(reverse, "and the rest")); + UNSCOPED_INFO("and the rest"); REQUIRE(idAt(ids, 40, 32) == ID_A); ids = pixelIds({ { pixels(0, W, 16, 48, &invisible), ID_A, Outline::PRIORITY_ROOT, mask, texture } }); - UNSCOPED_INFO(named(reverse, "a transparent face colour cuts nothing more")); + UNSCOPED_INFO("a transparent face colour cuts nothing more"); REQUIRE(idAt(ids, 16, 32) == ID_A); - UNSCOPED_INFO(named(reverse, "and its texture still cuts")); + UNSCOPED_INFO("and its texture still cuts"); REQUIRE(idAt(ids, 15, 32) == 0U); // Column 20 samples alpha 41 halved, 82 not; column 40 81 halved. Draw transformed = { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, mask, texture }; transformed.mTransform = &halved_pack; ids = pixelIds({ transformed }); - UNSCOPED_INFO(named(reverse, "the base colour transform moves the cut")); + UNSCOPED_INFO("the base colour transform moves the cut"); REQUIRE(idAt(ids, 20, 32) == 0U); - UNSCOPED_INFO(named(reverse, "and keeps past it")); + UNSCOPED_INFO("and keeps past it"); REQUIRE(idAt(ids, 40, 32) == ID_A); Draw animated = { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, mask, texture }; animated.mTextureMatrix = &halved_matrix; ids = pixelIds({ animated }); - UNSCOPED_INFO(named(reverse, "the texture animation moves the cut")); + UNSCOPED_INFO("the texture animation moves the cut"); REQUIRE(idAt(ids, 20, 32) == 0U); - UNSCOPED_INFO(named(reverse, "and keeps past it")); + UNSCOPED_INFO("and keeps past it"); REQUIRE(idAt(ids, 40, 32) == ID_A); // A cut-out face shows what is behind it: here another object, which is outlined through the hole. ids = pixelIds({ { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, mask, texture }, { quad(0.f, (F32)W, 0.f, (F32)H, PIXEL_Z - 1.f, PIXEL_Z - 1.f), ID_B } }); - UNSCOPED_INFO(named(reverse, "the one behind shows through the cut")); + UNSCOPED_INFO("the one behind shows through the cut"); REQUIRE(idAt(ids, 15, 32) == ID_B); - UNSCOPED_INFO(named(reverse, "and not through the rest")); + UNSCOPED_INFO("and not through the rest"); REQUIRE(idAt(ids, 16, 32) == ID_A); } } @@ -1570,6 +1547,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // A diamond about (32.25, 32.25), 24 pixels to each point: its edge from (32.25, 8.25) to // (8.25, 32.25) runs through x = 40 - y, between pixel centres, so the pixels it covers are not left to @@ -1585,30 +1563,30 @@ namespace S32 between = 0; for (S32 y = 14; y <= 28; ++y) { - const std::string row = ", row " + std::to_string(y); + CAPTURE(y); S32 first = -1; for (S32 x = 0; x < W && first < 0; ++x) { first = idAt(ids, x, y) == ID_A ? x : -1; } - UNSCOPED_INFO(named(reverse, "the diamond's edge" + row)); + UNSCOPED_INFO("the diamond's edge"); REQUIRE(first == 40 - y); U32 last = 255; for (S32 x = first - 1; x >= first - walk; --x) { const U32 r = at(px, x, y).r; - UNSCOPED_INFO(named(reverse, "coverage never rises away from the edge" + row)); + UNSCOPED_INFO("coverage never rises away from the edge"); REQUIRE(r <= last); between += (r > 0 && r < 255) ? 1 : 0; last = r; } - UNSCOPED_INFO(named(reverse, "solid beside the edge" + row)); + UNSCOPED_INFO("solid beside the edge"); REQUIRE((U32)at(px, first - 1, y).r == 255U); - UNSCOPED_INFO(named(reverse, "nothing past the reach" + row)); + UNSCOPED_INFO("nothing past the reach"); REQUIRE(last == 0U); } - UNSCOPED_INFO(named(reverse, "the edge is anti-aliased")); + UNSCOPED_INFO("the edge is anti-aliased"); REQUIRE(between >= 15); } } @@ -1619,6 +1597,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); pixelIds({ { pixels(32, 33, 32, 33), ID_A } }); palette({ { ID_A, RED } }, true); @@ -1636,29 +1615,27 @@ namespace } const F32 dist = sqrtf((F32)(dx * dx + dy * dy)); const U32 r = at(px, 32 + dx, 32 + dy).r; - const std::string where = " at (" + std::to_string(dx) + ", " + std::to_string(dy) + ")"; + CAPTURE(dx, dy); if (dist <= (F32)lines.mWidth) { - UNSCOPED_INFO(named(reverse, "solid within the width" + where)); + UNSCOPED_INFO("solid within the width"); REQUIRE(r == 255U); } else if (dist < (F32)lines.mWidth + 0.9f) { - { - INFO(named(reverse, "anti-aliased past it" + where)); - REQUIRE(r > 0); - REQUIRE(r < 255); - } + INFO("anti-aliased past it"); + REQUIRE(r > 0); + REQUIRE(r < 255); } else if (dist >= (F32)reach) { - UNSCOPED_INFO(named(reverse, "nothing at the reach" + where)); + UNSCOPED_INFO("nothing at the reach"); REQUIRE(r == 0U); } } } // Two across and one up: off every line of taps in eight directions. - UNSCOPED_INFO(named(reverse, "the knight's move is outlined")); + UNSCOPED_INFO("the knight's move is outlined"); REQUIRE(at(px, 34, 33).r > 0); } } @@ -1682,11 +1659,12 @@ namespace constexpr U32 CHILD = 2; for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // The root over columns 16 to 31, the child 32 to 47, both rows 16 to 47. const std::vector ids = pixelIds({ { pixels(16, 32, 16, 48), ROOT, Outline::PRIORITY_ROOT }, { pixels(32, 48, 16, 48), CHILD, Outline::PRIORITY_CHILD } }); - UNSCOPED_INFO(named(reverse, "the child's priority in alpha")); + UNSCOPED_INFO("the child's priority in alpha"); REQUIRE((U32)at(ids, 40, 32).a == (U32)Outline::PRIORITY_CHILD); palette({ { ROOT, RED }, { CHILD, GREEN } }, true); const std::vector px = edgePass(); @@ -1694,38 +1672,38 @@ namespace // Above the child, a pixel from it and the root's corner a knight's move away. const Pixel over = at(px, 33, 48); { - INFO(named(reverse, "the root's contour over the child's")); + INFO("the root's contour over the child's"); REQUIRE(over.r > over.g); REQUIRE(over.r > 200); } - UNSCOPED_INFO(named(reverse, "the child's under it where it fades")); + UNSCOPED_INFO("the child's under it where it fades"); REQUIRE(over.g > 0); { - INFO(named(reverse, "the root's alone beside it")); + INFO("the root's alone beside it"); REQUIRE(red(at(px, 31, 48))); REQUIRE(at(px, 31, 48).r == 255); } { - INFO(named(reverse, "the child's alone past the root's reach")); + INFO("the child's alone past the root's reach"); REQUIRE(green(at(px, 36, 48))); REQUIRE(at(px, 36, 48).g == 255); } const Pixel edge = at(px, 31, 32); const U32 faint = (U32)ll_round(255.f * Outline::INNER_OPACITY); - UNSCOPED_INFO(named(reverse, "the edge on the root's side, in its colour")); + UNSCOPED_INFO("the edge on the root's side, in its colour"); REQUIRE(red(edge)); { - INFO(named(reverse, "at INNER_OPACITY")); + INFO("at INNER_OPACITY"); REQUIRE((U32)edge.r + 2 >= faint); REQUIRE((U32)edge.r <= faint + 2); } - UNSCOPED_INFO(named(reverse, "a pixel wide, where the contour is two")); + UNSCOPED_INFO("a pixel wide, where the contour is two"); REQUIRE(black(at(px, 30, 32))); - UNSCOPED_INFO(named(reverse, "and not on the child's side")); + UNSCOPED_INFO("and not on the child's side"); REQUIRE(black(at(px, 32, 32))); { - INFO(named(reverse, "the insides left alone")); + INFO("the insides left alone"); REQUIRE(black(at(px, 20, 32))); REQUIRE(black(at(px, 40, 32))); } @@ -1742,6 +1720,7 @@ namespace const std::pair line_widths[] = { { 1, 1 }, { 2, 1 }, { 4, 1 }, { 8, 2 }, { 16, 2 } }; for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { 1, RED }, { 2, GREEN }, { 3, LLColor4(0.f, 0.f, 1.f, 1.f) }, { 4, LLColor4(1.f, 1.f, 0.f, 0.5f) } }, true); @@ -1779,16 +1758,17 @@ namespace for (const auto& [name, draws] : scenes) { + INFO(name); pixelIds(draws); for (const auto& [width, inner_width] : line_widths) { + CAPTURE(width, inner_width); const Outline::View lines = widths(width, inner_width); - const std::string what = name + ", lines " + std::to_string(width) + " and " + std::to_string(inner_width); const std::vector untiled = edgePass(lines, nullptr, true); const std::vector tiled = edgePass(lines); - UNSCOPED_INFO(named(reverse, what + ": something is drawn")); + UNSCOPED_INFO("something is drawn"); REQUIRE(lit(untiled) > 0); - UNSCOPED_INFO(named(reverse, what + ": tiled as untiled")); + UNSCOPED_INFO("tiled as untiled"); REQUIRE(tiled == untiled); } @@ -1798,7 +1778,7 @@ namespace { empty += records[i + 1] == 0 ? 1 : 0; } - UNSCOPED_INFO(named(reverse, name + ": some tiles hold nothing")); + UNSCOPED_INFO("some tiles hold nothing"); REQUIRE(empty > 0); } @@ -1810,28 +1790,28 @@ namespace const S32 columns = (S32)Outline::tileCount(W); auto record = [&](S32 column, S32 row, S32 i) { return (U32)records[((size_t)row * columns + column) * 4 + i]; }; { - INFO(named(reverse, "the tile left of the root holds nothing")); + INFO("the tile left of the root holds nothing"); REQUIRE(record(1, 2, 0) == 0); REQUIRE(record(1, 2, 1) == 0); } { - INFO(named(reverse, "the tile inside the root holds the root alone")); + INFO("the tile inside the root holds the root alone"); REQUIRE(record(2, 2, 0) == 1); REQUIRE(record(2, 2, 1) == 1); } { - INFO(named(reverse, "the tile inside the child beside it, the child alone")); + INFO("the tile inside the child beside it, the child alone"); REQUIRE(record(4, 2, 0) == 2); REQUIRE(record(4, 2, 1) == 2); } { - INFO(named(reverse, "the tile under the child above, the root alone")); + INFO("the tile under the child above, the root alone"); REQUIRE(record(2, 4, 0) == 1); REQUIRE(record(2, 4, 1) == 1); } - UNSCOPED_INFO(named(reverse, "no jump in it")); + UNSCOPED_INFO("no jump in it"); REQUIRE(record(2, 2, 2) == 0); - UNSCOPED_INFO(named(reverse, "a tile far away holds nothing")); + UNSCOPED_INFO("a tile far away holds nothing"); REQUIRE(record(0, 0, 1) == 0); // The second, across tile borders: the tile at column and row 3 holds both the root and the child. @@ -1839,7 +1819,7 @@ namespace markPasses(view()); records = tileRecords(); { - INFO(named(reverse, "a tile across the edge holds both")); + INFO("a tile across the edge holds both"); REQUIRE(record(3, 3, 0) == 1); REQUIRE(record(3, 3, 1) == 2); } @@ -1850,9 +1830,9 @@ namespace const LLRect around(12, 62, 54, 20); for (const auto& [width, inner_width] : line_widths) { + CAPTURE(width, inner_width); const Outline::View lines = widths(width, inner_width); - const std::string what = "under a rect, lines " + std::to_string(width); - UNSCOPED_INFO(named(reverse, what)); + UNSCOPED_INFO("the tiles under a rect draw as every tile does"); REQUIRE(edgePass(lines, nullptr, false, &around) == edgePass(lines, nullptr, true)); } } @@ -1866,6 +1846,7 @@ namespace constexpr U32 REAR = 2; for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { FRONT, RED }, { REAR, GREEN } }, true); // The rear over columns and rows 16 to 47; the front over 24 to 39, nearer, wound clockwise: its back. @@ -1875,26 +1856,26 @@ namespace LLVertexBuffer* front = quadAt(back_on); std::vector ids = pixelIds({ { rear, REAR, Outline::PRIORITY_CHILD }, { front, FRONT, Outline::PRIORITY_ROOT } }); - UNSCOPED_INFO(named(reverse, "a single-sided face from behind takes no pixel")); + UNSCOPED_INFO("a single-sided face from behind takes no pixel"); REQUIRE(idAt(ids, 32, 32) == REAR); std::vector px = edgePass(); { - INFO(named(reverse, "nothing traces it")); + INFO("nothing traces it"); REQUIRE(black(at(px, 23, 32))); REQUIRE(black(at(px, 24, 32))); REQUIRE(black(at(px, 40, 32))); } - UNSCOPED_INFO(named(reverse, "the rear's contour is whole")); + UNSCOPED_INFO("the rear's contour is whole"); REQUIRE((U32)at(px, 15, 32).g == 255U); Draw double_sided = { front, FRONT, Outline::PRIORITY_ROOT }; double_sided.mDoubleSided = true; ids = pixelIds({ { rear, REAR, Outline::PRIORITY_CHILD }, double_sided }); - UNSCOPED_INFO(named(reverse, "a double-sided face from behind is drawn")); + UNSCOPED_INFO("a double-sided face from behind is drawn"); REQUIRE(idAt(ids, 32, 32) == FRONT); px = edgePass(); { - INFO(named(reverse, "and outlined over the rear")); + INFO("and outlined over the rear"); REQUIRE(red(at(px, 23, 32))); REQUIRE(at(px, 23, 32).r == 255); } @@ -1910,6 +1891,7 @@ namespace constexpr U32 FROND = 2; for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // The root, six metres out over columns 12 to 51 and rows 18 to 46, behind something five metres out; // the frond four metres out over columns and rows 25 to 38, in front of it. @@ -1919,7 +1901,7 @@ namespace for (bool show_hidden : { false, true }) { - const std::string hidden_parts = show_hidden ? ", hidden parts drawn" : ", hidden parts left out"; + CAPTURE(show_hidden); Draw hidden_root = { root, ROOT, Outline::PRIORITY_ROOT }; hidden_root.mShowHidden = show_hidden; idPass({ hidden_root, { frond, FROND, Outline::PRIORITY_CHILD } }); @@ -1927,21 +1909,21 @@ namespace const std::vector px = edgePass(); { - INFO(named(reverse, "the frond's contour over the root" + hidden_parts)); + INFO("the frond's contour over the root"); REQUIRE(green(at(px, 24, 32))); REQUIRE(at(px, 24, 32).g == 255); REQUIRE(green(at(px, 23, 32))); REQUIRE(at(px, 23, 32).g == 255); } { - INFO(named(reverse, "above it too" + hidden_parts)); + INFO("above it too"); REQUIRE(green(at(px, 32, 39))); REQUIRE(at(px, 32, 39).g == 255); } - UNSCOPED_INFO(named(reverse, "as wide as a contour" + hidden_parts)); + UNSCOPED_INFO("as wide as a contour"); REQUIRE(black(at(px, 21, 32))); { - INFO(named(reverse, "nothing inside the frond" + hidden_parts)); + INFO("nothing inside the frond"); REQUIRE(black(at(px, 32, 32))); REQUIRE(black(at(px, 25, 32))); } @@ -1949,7 +1931,7 @@ namespace { const U32 dimmed = at(px, 11, 32).r; { - INFO(named(reverse, "the hidden root's contour dimmed")); + INFO("the hidden root's contour dimmed"); REQUIRE(red(at(px, 11, 32))); REQUIRE(dimmed >= 90); REQUIRE(dimmed <= 115); @@ -1957,7 +1939,7 @@ namespace } else { - UNSCOPED_INFO(named(reverse, "the hidden root's contour left out")); + UNSCOPED_INFO("the hidden root's contour left out"); REQUIRE(black(at(px, 11, 32))); } } @@ -1972,6 +1954,7 @@ namespace const LLColor4 BLUE(0.f, 0.f, 1.f, 1.f); for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // Six metres out over columns 12 to 51, and four metres out over columns and rows 25 to 38. @@ -1981,17 +1964,17 @@ namespace std::vector px = edgePass(); const Pixel over = at(px, 24, 32); { - INFO(named(reverse, "the front child's contour over the rear")); + INFO("the front child's contour over the rear"); REQUIRE(over.b == 255); REQUIRE(over.r == 0); REQUIRE(over.g == 0); } { - INFO(named(reverse, "its full width")); + INFO("its full width"); REQUIRE(at(px, 23, 32).b == 255); REQUIRE(at(px, 32, 39).b == 255); } - UNSCOPED_INFO(named(reverse, "nothing inside it")); + UNSCOPED_INFO("nothing inside it"); REQUIRE(black(at(px, 32, 32))); // A wall from four metres out at the left to twelve at the right, split at eight, columns 31 and 32. @@ -2002,17 +1985,17 @@ namespace const Pixel edge = at(px, 31, 32); const U32 faint = (U32)ll_round(255.f * Outline::INNER_OPACITY); { - INFO(named(reverse, "the edge on the root's side")); + INFO("the edge on the root's side"); REQUIRE(red(edge)); REQUIRE((U32)edge.r + 2 >= faint); REQUIRE((U32)edge.r <= faint + 2); } { - INFO(named(reverse, "no contour on the child's side")); + INFO("no contour on the child's side"); REQUIRE(black(at(px, 32, 32))); REQUIRE(black(at(px, 33, 32))); } - UNSCOPED_INFO(named(reverse, "none on the root's")); + UNSCOPED_INFO("none on the root's"); REQUIRE(black(at(px, 30, 32))); } } @@ -2026,6 +2009,7 @@ namespace constexpr U32 FROND = 2; for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // The root six metres out over columns 12 to 51; the frond five metres out over columns and rows 26 to // 37, behind a rock four and a half metres out over exactly those. @@ -2034,18 +2018,19 @@ namespace frond.mShowHidden = false; idPass({ { quad(-2.f, 2.f, -1.5f, 1.5f, -6.f, -6.f), ROOT, Outline::PRIORITY_ROOT }, frond }); const std::vector ids = read(mIdMap); - UNSCOPED_INFO(named(reverse, "the frond is over the root")); + UNSCOPED_INFO("the frond is over the root"); REQUIRE(idAt(ids, 32, 32) == FROND); - UNSCOPED_INFO(named(reverse, "and not drawn")); + UNSCOPED_INFO("and not drawn"); REQUIRE((U32)at(ids, 32, 32).b == 0U); palette({ { ROOT, RED }, { FROND, GREEN } }, false); std::vector px = edgePass(); for (const auto& [x, y] : { std::pair{ 25, 32 }, { 24, 32 }, { 38, 32 }, { 39, 32 }, { 32, 25 }, { 32, 38 }, { 31, 31 } }) { - UNSCOPED_INFO(named(reverse, "nothing traces the frond at (" + std::to_string(x) + ", " + std::to_string(y) + ")")); + CAPTURE(x, y); + UNSCOPED_INFO("nothing traces the frond"); REQUIRE(black(at(px, x, y))); } - UNSCOPED_INFO(named(reverse, "the root's own contour drawn")); + UNSCOPED_INFO("the root's own contour drawn"); REQUIRE((U32)at(px, 11, 32).r == 255U); // A root five metres out over columns 9 to 31, hidden, and a child beside it over 32 to 54, visible, both @@ -2059,7 +2044,7 @@ namespace px = edgePass(); const Pixel above = at(px, 30, 44); { - INFO(named(reverse, "the child's contour where the hidden root is nearer")); + INFO("the child's contour where the hidden root is nearer"); REQUIRE(green(above)); REQUIRE(above.g > 200); } @@ -2069,12 +2054,12 @@ namespace const Pixel edge = at(px, 32, 32); const U32 faint = (U32)ll_round(255.f * Outline::INNER_OPACITY); { - INFO(named(reverse, "the edge on the drawn side")); + INFO("the edge on the drawn side"); REQUIRE(green(edge)); REQUIRE((U32)edge.g + 2 >= faint); REQUIRE((U32)edge.g <= faint + 2); } - UNSCOPED_INFO(named(reverse, "not on the hidden root's")); + UNSCOPED_INFO("not on the hidden root's"); REQUIRE(black(at(px, 31, 32))); } } @@ -2087,6 +2072,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED } }, true); // The far part six metres out over columns 12 to 51; the near part over columns and rows 25 to 38 at @@ -2094,36 +2080,36 @@ namespace for (F32 near_z : { -4.f, -5.8f }) { const F32 half = 0.125f * -near_z; - const std::string at_z = " at " + std::to_string(-near_z) + " m"; + CAPTURE(near_z); idPass({ { quad(-2.f, 2.f, -1.5f, 1.5f, -6.f, -6.f), ID_A }, { quad(-half, half, -half, half, near_z, near_z), ID_A } }); const std::vector px = edgePass(); { - INFO(named(reverse, "the near side of the step marked" + at_z)); + INFO("the near side of the step marked"); REQUIRE(markedAt(25, 32)); REQUIRE(markedAt(32, 38)); } { - INFO(named(reverse, "not the far side, nor inside" + at_z)); + INFO("not the far side, nor inside"); REQUIRE_FALSE(markedAt(24, 32)); REQUIRE_FALSE(markedAt(32, 32)); } { - INFO(named(reverse, "the near part's contour over the far part" + at_z)); + INFO("the near part's contour over the far part"); REQUIRE(red(at(px, 24, 32))); REQUIRE(at(px, 24, 32).r == 255); REQUIRE(at(px, 23, 32).r == 255); REQUIRE(at(px, 32, 39).r == 255); } - UNSCOPED_INFO(named(reverse, "as wide as a contour" + at_z)); + UNSCOPED_INFO("as wide as a contour"); REQUIRE(black(at(px, 21, 32))); { - INFO(named(reverse, "nothing inside the near part" + at_z)); + INFO("nothing inside the near part"); REQUIRE(black(at(px, 25, 32))); REQUIRE(black(at(px, 26, 32))); REQUIRE(black(at(px, 32, 32))); } - UNSCOPED_INFO(named(reverse, "nothing over the far part away from it" + at_z)); + UNSCOPED_INFO("nothing over the far part away from it"); REQUIRE(black(at(px, 15, 32))); } @@ -2133,9 +2119,9 @@ namespace markPasses(view()); const std::vector records = tileRecords(); const S32 columns = (S32)Outline::tileCount(W); - UNSCOPED_INFO(named(reverse, "a tile on the near side's edge records the jump")); + UNSCOPED_INFO("a tile on the near side's edge records the jump"); REQUIRE(records[((size_t)3 * columns + 3) * 4 + 2] != 0); - UNSCOPED_INFO(named(reverse, "a tile of the far part alone none")); + UNSCOPED_INFO("a tile of the far part alone none"); REQUIRE(records[((size_t)1 * columns + 1) * 4 + 2] == 0); } } @@ -2147,6 +2133,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED } }, true); @@ -2181,6 +2168,7 @@ namespace for (const auto& [name, draws] : surfaces) { + INFO(name); idPass(draws); const std::vector ids = read(mIdMap); const std::vector px = edgePass(); @@ -2202,11 +2190,11 @@ namespace } } } - UNSCOPED_INFO(named(reverse, name + ": it covers pixels")); + UNSCOPED_INFO("it covers pixels"); REQUIRE(covered > 200); - UNSCOPED_INFO(named(reverse, name + ": no jump marked")); + UNSCOPED_INFO("no jump marked"); REQUIRE(marks == size_t(0)); - UNSCOPED_INFO(named(reverse, name + ": nothing drawn across it")); + UNSCOPED_INFO("nothing drawn across it"); REQUIRE(drawn == size_t(0)); } } @@ -2229,6 +2217,7 @@ namespace for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED } }, true); windowDepth(nullptr); @@ -2240,16 +2229,16 @@ namespace const F32 far_end = diagonal(near_px, 34); // The line's slope down the screen is about 0.91: a width of 1 reads as about 1.35 down a column. { - INFO(named(reverse, "the width down the diagonal, near: " + std::to_string(near_end))); + INFO("the width down the diagonal, near"); REQUIRE(near_end > 1.15f); REQUIRE(near_end < 1.55f); } - UNSCOPED_INFO(named(reverse, "the same along the receding edge, far: " + std::to_string(far_end))); + UNSCOPED_INFO("the same along the receding edge, far: " << far_end); REQUIRE(fabsf(far_end - near_end) < 0.1f); const std::vector far_px = worldWireframe({ { quad(-4.f, 6.f, -4.f, 4.f, -12.f, -48.f), ID_A } }); { - INFO(named(reverse, "the same four times as far")); + INFO("the same four times as far"); REQUIRE(fabsf(diagonal(far_px, 26) - near_end) < 0.1f); REQUIRE(fabsf(diagonal(far_px, 34) - far_end) < 0.1f); } @@ -2258,7 +2247,7 @@ namespace const F32 narrow = diagonal(near_px, 30); const F32 wide = diagonal(wide_px, 30); { - INFO(named(reverse, "twice as wide at twice the width: " + std::to_string(wide))); + INFO("twice as wide at twice the width"); REQUIRE(wide > 1.8f * narrow); REQUIRE(wide < 2.2f * narrow); } @@ -2270,6 +2259,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED } }, true); windowDepth(nullptr); @@ -2277,8 +2267,8 @@ namespace const std::vector px = wireframe({ Outline::WIRE_VISIBLE }, pixelProjection(), { { pixels(8, 56, 8, 56), ID_A } }); for (S32 y = 16; y < 48; ++y) { - const std::string row = ", row " + std::to_string(y); - UNSCOPED_INFO(named(reverse, "the line is drawn" + row)); + CAPTURE(y); + UNSCOPED_INFO("the line is drawn"); REQUIRE(at(px, y, y).r > 127); for (S32 step : { -1, 1 }) { @@ -2286,11 +2276,11 @@ namespace for (S32 x = y + step; x != y + 4 * step; x += step) { const U32 r = at(px, x, y).r; - UNSCOPED_INFO(named(reverse, "coverage falls away from the line" + row)); + UNSCOPED_INFO("coverage falls away from the line"); REQUIRE(r <= last); last = r; } - UNSCOPED_INFO(named(reverse, "and is gone" + row)); + UNSCOPED_INFO("and is gone"); REQUIRE(last == 0U); } } @@ -2303,6 +2293,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // The brightest of a row's pixels between two columns. @@ -2321,7 +2312,7 @@ namespace windowDepth(nullptr); std::vector px = worldWireframe({ { quadA(), ID_A } }); const U32 open = brightest(px, 25, 11, 18); - UNSCOPED_INFO(named(reverse, "the line drawn with nothing in front")); + UNSCOPED_INFO("the line drawn with nothing in front"); REQUIRE(open > 127); // Then with something three metres out over columns 0 to 19, in front of A's left part. @@ -2329,10 +2320,10 @@ namespace windowDepth(&mScene); px = worldWireframe({ { quadA(), ID_A } }); const U32 hidden = brightest(px, 25, 11, 18); - UNSCOPED_INFO(named(reverse, "the line in front drawn")); + UNSCOPED_INFO("the line in front drawn"); REQUIRE(brightest(px, 38, 22, 30) > 127); { - INFO(named(reverse, "the line behind dimmed: " + std::to_string(hidden) + " of " + std::to_string(open))); + INFO("the line behind dimmed: " << hidden << " of " << open); REQUIRE(hidden * 100 >= open * 35); REQUIRE(hidden * 100 <= open * 45); } @@ -2341,9 +2332,9 @@ namespace left_out.mShowHidden = false; palette({ { ID_A, RED } }, false); px = worldWireframe({ left_out }); - UNSCOPED_INFO(named(reverse, "the line behind left out")); + UNSCOPED_INFO("the line behind left out"); REQUIRE(brightest(px, 25, 11, 18) == 0U); - UNSCOPED_INFO(named(reverse, "the line in front kept")); + UNSCOPED_INFO("the line in front kept"); REQUIRE(brightest(px, 38, 22, 30) > 127); } } @@ -2356,6 +2347,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED } }, true); // Turned about 60 degrees from the eye, five metres deep across its width. @@ -2379,9 +2371,9 @@ namespace lost += at(alone, x, y).r != at(on_surface, x, y).r ? 1 : 0; } } - UNSCOPED_INFO(named(reverse, "lines are drawn")); + UNSCOPED_INFO("lines are drawn"); REQUIRE(drawn > 100); - UNSCOPED_INFO(named(reverse, "every line pixel drawn on its own surface as on nothing")); + UNSCOPED_INFO("every line pixel drawn on its own surface as on nothing"); REQUIRE(lost == size_t(0)); } } @@ -2394,6 +2386,7 @@ namespace const F32 right[12] = { 1.f, 0.f, 0.f, 1.5f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f }; for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED } }, true); windowDepth(nullptr); @@ -2403,12 +2396,12 @@ namespace const F32 mask = Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_MASK, 64, true); std::vector px = wireframe({ Outline::WIRE_VISIBLE }, pixelProjection(), { { pixels(0, W, 16, 48), ID_A, Outline::PRIORITY_ROOT, mask, ramp() } }); - UNSCOPED_INFO(named(reverse, "no line across the cut-out texels")); + UNSCOPED_INFO("no line across the cut-out texels"); REQUIRE(ink(px, 8, 17, 24) == 0.f); - UNSCOPED_INFO(named(reverse, "nor along their edge")); + UNSCOPED_INFO("nor along their edge"); REQUIRE(black(at(px, 8, 16))); { - INFO(named(reverse, "lines across the kept ones")); + INFO("lines across the kept ones"); REQUIRE(ink(px, 40, 33, 40) > 0.5f); REQUIRE_FALSE(black(at(px, 40, 16))); } @@ -2416,9 +2409,9 @@ namespace // Posed, the quad covers columns 43 to 54 and rows 26 to 37. LLVertexBuffer* bound = quad(-0.5f, 0.5f, -0.5f, 0.5f, QUAD_Z, QUAD_Z, true); px = worldWireframe({ { bound, ID_A } }, 1, 1.f, right); - UNSCOPED_INFO(named(reverse, "the rigged face's lines where it is posed")); + UNSCOPED_INFO("the rigged face's lines where it is posed"); REQUIRE(ink(px, 49, 26, 38) > 0.5f); - UNSCOPED_INFO(named(reverse, "not at its bind pose")); + UNSCOPED_INFO("not at its bind pose"); REQUIRE(ink(px, 32, 26, 38) == 0.f); // A face seen from behind, wound clockwise, as the id pass culls it: no lines unless double-sided. @@ -2426,11 +2419,11 @@ namespace LLVector3(48.f, 48.f, PIXEL_Z), LLVector3(48.f, 16.f, PIXEL_Z) }; Draw back = { quadAt(back_on), ID_A }; px = wireframe({ Outline::WIRE_VISIBLE }, pixelProjection(), { back }); - UNSCOPED_INFO(named(reverse, "no lines on a face from behind")); + UNSCOPED_INFO("no lines on a face from behind"); REQUIRE(lit(px) == size_t(0)); back.mDoubleSided = true; px = wireframe({ Outline::WIRE_VISIBLE }, pixelProjection(), { back }); - UNSCOPED_INFO(named(reverse, "lines on a double-sided one")); + UNSCOPED_INFO("lines on a double-sided one"); REQUIRE(lit(px) > 50); } } @@ -2444,6 +2437,7 @@ namespace constexpr U32 FRONT = 2; for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // The rear from 16 to 47 each way, its diagonal through x = y; the front nearer, over columns 28 to 43 // and rows 20 to 35, its diagonal through x = y + 8. The rear's diagonal passes behind the front at @@ -2462,7 +2456,7 @@ namespace for (bool show_hidden : { false, true }) { - const std::string hidden_parts = show_hidden ? ", hidden parts drawn" : ", hidden parts left out"; + CAPTURE(show_hidden); std::vector shown = draws; for (Draw& draw : shown) { @@ -2471,12 +2465,12 @@ namespace palette({ { REAR, RED }, { FRONT, GREEN } }, show_hidden); const std::vector px = wireframe({ Outline::WIRE_ID_DEPTH }, pixelProjection(), shown); { - INFO(named(reverse, "the rear's line in the open" + hidden_parts)); + INFO("the rear's line in the open"); REQUIRE(red(at(px, 20, 20))); REQUIRE(at(px, 20, 20).r > 200); } { - INFO(named(reverse, "the front's line" + hidden_parts)); + INFO("the front's line"); REQUIRE(green(at(px, 40, 32))); REQUIRE(at(px, 40, 32).g > 200); } @@ -2485,7 +2479,7 @@ namespace const U32 dimmed = at(px, 32, 32).r; const U32 open = at(px, 20, 20).r; { - INFO(named(reverse, "the rear's line behind the front dimmed: " + std::to_string(dimmed))); + INFO("the rear's line behind the front dimmed: " << dimmed << " of " << open); REQUIRE(red(at(px, 32, 32))); REQUIRE(dimmed * 100 >= open * 35); REQUIRE(dimmed * 100 <= open * 45); @@ -2493,7 +2487,7 @@ namespace } else { - UNSCOPED_INFO(named(reverse, "the rear's line behind the front left out")); + UNSCOPED_INFO("the rear's line behind the front left out"); REQUIRE(black(at(px, 32, 32))); } } @@ -2504,12 +2498,11 @@ namespace // the polygon offset its lines need over a resampled depth. TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the wireframe is a pixel wide at UI scale 1 and scales with it", "[ALSelectionOutline]") { - UNSCOPED_INFO("a pixel at 1"); CHECK(Outline::lineWidth(Outline::WIRE_WIDTH, 1.f) == 1); - UNSCOPED_INFO("two at 2"); CHECK(Outline::lineWidth(Outline::WIRE_WIDTH, 2.f) == 2); for (bool hud : { false, true }) { + CAPTURE(hud); const Outline::View scaled = Outline::makeView(identity(), identity(), 2.f, 2.f, hud); UNSCOPED_INFO("its width at the UI scale"); REQUIRE(scaled.mWireWidth == 2); @@ -2529,6 +2522,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED } }, true); windowDepth(nullptr); @@ -2541,18 +2535,18 @@ namespace LLVertexBuffer* reaching = quadAt(one_behind); std::vector px = worldWireframe({ { reaching, ID_A } }); std::vector> found = columnRuns(px, 40); - UNSCOPED_INFO(named(reverse, "column 40 crosses the bottom edge, the diagonal and the top edge")); + UNSCOPED_INFO("column 40 crosses the bottom edge, the diagonal and the top edge"); REQUIRE(found.size() == size_t(3)); // The diagonal's slope down the screen is about a third: a width of 1 reads as about 1.05 down a column. const F32 across = ink(px, 40, found[1].first, found[1].second); { - INFO(named(reverse, "the diagonal at its width: " + std::to_string(across))); + INFO("the diagonal at its width"); REQUIRE(across > 0.9f); REQUIRE(across < 1.25f); } // The top edge, along row 41.8, has one triangle, which draws the half of its line inside the quad. { - INFO(named(reverse, "the top edge drawn inside the quad")); + INFO("the top edge drawn inside the quad"); REQUIRE(at(px, 40, 41).r > 127); REQUIRE(black(at(px, 40, 42))); } @@ -2573,18 +2567,18 @@ namespace at_edges += black(at(px, x, y)) ? 0 : 1; } } - UNSCOPED_INFO(named(reverse, "no line along the near plane's cut")); + UNSCOPED_INFO("no line along the near plane's cut"); REQUIRE(at_cut == size_t(0)); - UNSCOPED_INFO(named(reverse, "the edges in front drawn: " + std::to_string(at_edges))); + UNSCOPED_INFO("the edges in front drawn"); REQUIRE(at_edges > 40); // The first quad textured with the ramp, masked at half: its diagonal's texture coordinate runs from 0 // behind the eye to 1, about 0.43 at column 20 and 0.57 at column 40. const F32 mask = Outline::legacyAlphaCutoff(true, LLMaterial::DIFFUSE_ALPHA_MODE_MASK, 128, true); px = worldWireframe({ { reaching, ID_A, Outline::PRIORITY_ROOT, mask, ramp() } }); - UNSCOPED_INFO(named(reverse, "no line where the clipped triangle's texture is cut")); + UNSCOPED_INFO("no line where the clipped triangle's texture is cut"); REQUIRE(ink(px, 20, 24, 32) == 0.f); - UNSCOPED_INFO(named(reverse, "a line where it is kept")); + UNSCOPED_INFO("a line where it is kept"); REQUIRE(ink(px, 40, 32, 38) > 0.5f); } } @@ -2597,28 +2591,28 @@ namespace { for (bool hud : { false, true }) { - const std::string where = hud ? " on the HUD" : " in the world"; + CAPTURE(hud); Outline::Wants wants; wants.mContour = true; Outline::Passes passes = Outline::passesFor(wants, hud, true); - UNSCOPED_INFO("the outline alone runs the id pass" + where); + UNSCOPED_INFO("the outline alone runs the id pass"); REQUIRE(passes.mIds); - UNSCOPED_INFO("and the edge passes" + where); + UNSCOPED_INFO("and the edge passes"); REQUIRE(passes.mEdges); - UNSCOPED_INFO("and no wireframe" + where); + UNSCOPED_INFO("and no wireframe"); REQUIRE_FALSE(passes.mWireframe); wants.mWireframe = true; passes = Outline::passesFor(wants, hud, true); { - INFO("both run everything" + where); + INFO("both run everything"); REQUIRE(passes.mIds); REQUIRE(passes.mEdges); REQUIRE(passes.mWireframe); } passes = Outline::passesFor(wants, hud, false); { - INFO("a wireframe program that did not load leaves the outline" + where); + INFO("a wireframe program that did not load leaves the outline"); REQUIRE(passes.mIds); REQUIRE(passes.mEdges); REQUIRE_FALSE(passes.mWireframe); @@ -2626,20 +2620,20 @@ namespace wants.mContour = false; passes = Outline::passesFor(wants, hud, true); - UNSCOPED_INFO("the wireframe alone is drawn" + where); + UNSCOPED_INFO("the wireframe alone is drawn"); REQUIRE(passes.mWireframe); - UNSCOPED_INFO("without the edge passes" + where); + UNSCOPED_INFO("without the edge passes"); REQUIRE_FALSE(passes.mEdges); - UNSCOPED_INFO("with the id pass only on the HUD" + where); + UNSCOPED_INFO("with the id pass only on the HUD"); REQUIRE(passes.mIds == hud); passes = Outline::passesFor(wants, hud, false); - UNSCOPED_INFO("nothing when its program did not load" + where); + UNSCOPED_INFO("nothing when its program did not load"); REQUIRE_FALSE(passes.any()); wants.mGlow = true; passes = Outline::passesFor(wants, hud, true); { - INFO("a glow beside a wireframe runs everything" + where); + INFO("a glow beside a wireframe runs everything"); REQUIRE(passes.mIds); REQUIRE(passes.mEdges); REQUIRE(passes.mWireframe); @@ -2648,16 +2642,16 @@ namespace wants.mWireframe = false; passes = Outline::passesFor(wants, hud, true); { - INFO("a glow with the outline and the wireframe off runs the id and edge passes" + where); + INFO("a glow with the outline and the wireframe off runs the id and edge passes"); REQUIRE(passes.mIds); REQUIRE(passes.mEdges); REQUIRE_FALSE(passes.mWireframe); } - UNSCOPED_INFO("and whether or not the wireframe loaded" + where); + UNSCOPED_INFO("and whether or not the wireframe loaded"); REQUIRE(Outline::passesFor(wants, hud, false).mEdges); wants.mGlow = false; - UNSCOPED_INFO("nothing with all three off" + where); + UNSCOPED_INFO("nothing with all three off"); REQUIRE_FALSE(Outline::passesFor(wants, hud, true).any()); } @@ -2682,6 +2676,7 @@ namespace for (Outline::EWirePass pass : { Outline::WIRE_VISIBLE, Outline::WIRE_HIDDEN, Outline::WIRE_ID_DEPTH }) { + CAPTURE(pass); UNSCOPED_INFO("what glows has no wireframe in any pass"); REQUIRE_FALSE(Outline::inWirePass(Outline::partsFor(Outline::PRIORITY_HOVER, both), true, pass)); UNSCOPED_INFO("nor an outline alone"); @@ -2711,7 +2706,6 @@ namespace TEST_CASE_METHOD(alselectionoutline_data, "ALSelectionOutline: the glow's reach and falloff and the hover fades and target lifetimes", "[ALSelectionOutline]") { const F32 nan = std::numeric_limits::quiet_NaN(); - UNSCOPED_INFO("9 pixels at the default thickness"); CHECK(Outline::glowRadius(Outline::DEFAULT_GLOW_THICKNESS, 1.f) == 9); UNSCOPED_INFO("scaled with the UI"); CHECK(Outline::glowRadius(Outline::DEFAULT_GLOW_THICKNESS, 2.f) == 18); @@ -2728,10 +2722,10 @@ namespace CHECK(defaults.mGlowBrightness == Outline::DEFAULT_GLOW_BRIGHTNESS); UNSCOPED_INFO("a brightness that is not a number is the default"); CHECK(Outline::makeView(identity(), identity(), 2.f, 1.f, false, 0.6f, nan).mGlowBrightness == - Outline::DEFAULT_GLOW_BRIGHTNESS); + Outline::DEFAULT_GLOW_BRIGHTNESS); UNSCOPED_INFO("and one past the brightest held to it"); CHECK(Outline::makeView(identity(), identity(), 2.f, 1.f, false, 0.6f, 1000.f).mGlowBrightness == - Outline::MAX_GLOW_BRIGHTNESS); + Outline::MAX_GLOW_BRIGHTNESS); // The silhouette is half a texel out from its texel's centre. UNSCOPED_INFO("opaque at the silhouette at the default brightness"); @@ -2739,8 +2733,7 @@ namespace UNSCOPED_INFO("half as opaque at half of it"); CHECK_THAT(Outline::glowOpacity(0.5f, 9, 2.f), Catch::Matchers::WithinAbs(0.5f, 1e-6f)); UNSCOPED_INFO("half way out, half of the silhouette's"); - CHECK_THAT(Outline::glowOpacity(5.f, 9, 4.f), Catch::Matchers::WithinAbs(0.5f, - 1e-6f)); + CHECK_THAT(Outline::glowOpacity(5.f, 9, 4.f), Catch::Matchers::WithinAbs(0.5f, 1e-6f)); UNSCOPED_INFO("nothing at its reach"); CHECK(Outline::glowOpacity(9.5f, 9, 4.f) == 0.f); UNSCOPED_INFO("nor past it"); @@ -2749,7 +2742,7 @@ namespace CHECK(Outline::glowOpacity(2.f, 9, Outline::MAX_GLOW_BRIGHTNESS) == 1.f); const F32 last_step = Outline::glowOpacity(9.25f, 9, 4.f); { - INFO("fading smoothly into nothing: " + std::to_string(last_step)); + INFO("fading smoothly into nothing"); CHECK(last_step > 0.f); CHECK(last_step < 0.01f); } @@ -2765,8 +2758,7 @@ namespace CHECK(falling); UNSCOPED_INFO("half way in half the fade time"); - CHECK_THAT(ALHoverGlow::stepFade(0.f, 0.05f, 0.1f, true), - Catch::Matchers::WithinAbs(0.5f, 1e-6f)); + CHECK_THAT(ALHoverGlow::stepFade(0.f, 0.05f, 0.1f, true), Catch::Matchers::WithinAbs(0.5f, 1e-6f)); UNSCOPED_INFO("out as fast"); CHECK_THAT(ALHoverGlow::stepFade(0.5f, 0.05f, 0.1f, false), Catch::Matchers::WithinAbs(0.f, 1e-6f)); UNSCOPED_INFO("held to one"); @@ -2914,13 +2906,14 @@ namespace constexpr S32 RADIUS = 6; for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // Columns 20 to 39 and rows 20 to 43, and a fold of the same object nearer over its middle, columns 25 to // 34: selected, the near side of a jump in its own surface. pixelIds({ { pixels(20, 40, 20, 44), ID_A }, { quad(25.f, 35.f, 25.f, 39.f, -1.f, -1.f), ID_A } }); markPasses(glowView(RADIUS)); { - INFO(named(reverse, "selected, the fold's edge is the near side of a jump")); + INFO("selected, the fold's edge is the near side of a jump"); REQUIRE(markedAt(25, 32)); REQUIRE(markedAt(34, 32)); } @@ -2930,10 +2923,10 @@ namespace for (F32 brightness : { Outline::DEFAULT_GLOW_BRIGHTNESS, 2.f }) { - const std::string at_brightness = " at brightness " + std::to_string(brightness); + CAPTURE(brightness); const std::vector px = edgePass(glowView(RADIUS, brightness), nullptr, false, nullptr, true); { - INFO(named(reverse, "glowing, its fold's edge is not marked")); + INFO("glowing, its fold's edge is not marked"); REQUIRE_FALSE(markedAt(25, 32)); REQUIRE_FALSE(markedAt(34, 32)); } @@ -2943,8 +2936,7 @@ namespace const F32 expected = 255.f * Outline::glowOpacity((F32)(k + 1), RADIUS, brightness); const Pixel p = at(px, 40 + k, 32); { - INFO(named(reverse, "the glow " + std::to_string(k + 1) + " pixels out" + at_brightness + ": " + - std::to_string(p.g) + " for " + std::to_string(expected))); + INFO("the glow " << k + 1 << " pixels out: " << (U32)p.g << " for " << expected); REQUIRE(std::fabs((F32)p.g - expected) <= 2.f); REQUIRE(p.r == 0); REQUIRE(p.b == 0); @@ -2952,18 +2944,18 @@ namespace } const U8 between = at(px, 43, 32).g; { - INFO(named(reverse, "soft, not a solid band" + at_brightness)); + INFO("soft, not a solid band"); REQUIRE(between > 10); REQUIRE(between < 245); } { - INFO(named(reverse, "nothing over the object" + at_brightness)); + INFO("nothing over the object"); REQUIRE(black(at(px, 30, 32))); REQUIRE(black(at(px, 39, 32))); REQUIRE(black(at(px, 20, 20))); } { - INFO(named(reverse, "nor over its far side beside its fold" + at_brightness)); + INFO("nor over its far side beside its fold"); REQUIRE(black(at(px, 24, 32))); REQUIRE(black(at(px, 35, 32))); } @@ -2978,6 +2970,7 @@ namespace constexpr U32 ID_GLOW = 400; for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED }, { ID_B, RED }, { ID_GLOW, GREEN } }, true); @@ -2986,15 +2979,14 @@ namespace std::vector px = edgePass(glowView(9), nullptr, false, nullptr, true); for (S32 x : { 38, 39 }) { + CAPTURE(x); const Pixel p = at(px, x, 32); - { - INFO(named(reverse, "the contour opaque over the glow at column " + std::to_string(x))); - REQUIRE(p.r == 255); - REQUIRE(p.g == 0); - } + INFO("the contour opaque over the glow"); + REQUIRE(p.r == 255); + REQUIRE(p.g == 0); } { - INFO(named(reverse, "the glow past the contour")); + INFO("the glow past the contour"); REQUIRE(green(at(px, 37, 32))); REQUIRE(green(at(px, 36, 32))); } @@ -3007,15 +2999,14 @@ namespace px = edgePass(glowView(9), nullptr, false, nullptr, true); for (S32 x : { 37, 38, 39, 40, 41 }) { + CAPTURE(x); const Pixel p = at(px, x, 32); const Pixel q = at(alone, x, 32); - { - INFO(named(reverse, "the contour beside it as without it at column " + std::to_string(x))); - REQUIRE(p.r == q.r); - REQUIRE(p.g == q.g); - REQUIRE(p.b == q.b); - REQUIRE(p.a == q.a); - } + INFO("the contour beside it as without it"); + REQUIRE(p.r == q.r); + REQUIRE(p.g == q.g); + REQUIRE(p.b == q.b); + REQUIRE(p.a == q.a); } // Two selected objects touching at column 30, their edge on A's side, and a glowing one nearer below @@ -3026,11 +3017,11 @@ namespace // Pixel (29, 20) is a pixel from B and three from the glowing object's top row. const F32 glow = Outline::glowOpacity(3.f, 9, Outline::DEFAULT_GLOW_BRIGHTNESS); const Pixel edge = at(px, 29, 20); - UNSCOPED_INFO(named(reverse, "the edge over the glow: red " + std::to_string(edge.r))); + UNSCOPED_INFO("the edge over the glow: red " << (U32)edge.r); REQUIRE(std::fabs((F32)edge.r - 255.f * Outline::INNER_OPACITY) <= 2.f); - UNSCOPED_INFO(named(reverse, "the glow under it: green " + std::to_string(edge.g))); + UNSCOPED_INFO("the glow under it: green " << (U32)edge.g); REQUIRE(std::fabs((F32)edge.g - 255.f * glow * (1.f - Outline::INNER_OPACITY)) <= 2.f); - UNSCOPED_INFO(named(reverse, "the glow over A's surface, which lies behind it")); + UNSCOPED_INFO("the glow over A's surface, which lies behind it"); REQUIRE(green(at(px, 20, 21))); } } @@ -3040,28 +3031,29 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); // A, columns 9 to 31, behind something in the scene over columns 0 to 20. occlude(3.f, 0, 0, 21, H); idPass({ hoverDraw(quadA(), ID_A) }); const std::vector ids = read(mIdMap); - UNSCOPED_INFO(named(reverse, "its hidden part left out")); + UNSCOPED_INFO("its hidden part left out"); REQUIRE((U32)at(ids, 12, 32).b == 0U); palette({ { ID_A, GREEN } }, false); const std::vector px = edgePass(glowView(6), nullptr, false, nullptr, true); { - INFO(named(reverse, "a glow past its visible side")); + INFO("a glow past its visible side"); REQUIRE(green(at(px, 32, 32))); REQUIRE(at(px, 32, 32).g > 200); } { - INFO(named(reverse, "none past its hidden one")); + INFO("none past its hidden one"); REQUIRE(black(at(px, 8, 32))); REQUIRE(black(at(px, 5, 32))); } - UNSCOPED_INFO(named(reverse, "nor above it")); + UNSCOPED_INFO("nor above it"); REQUIRE(black(at(px, 12, 46))); - UNSCOPED_INFO(named(reverse, "but above the part shown")); + UNSCOPED_INFO("but above the part shown"); REQUIRE(green(at(px, 26, 45))); } } @@ -3071,6 +3063,7 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED }, { ID_B, GREEN } }, true); windowDepth(nullptr); @@ -3086,9 +3079,9 @@ namespace glowing += p.g > 0 ? 1 : 0; } } - UNSCOPED_INFO(named(reverse, "the selection's lines")); + UNSCOPED_INFO("the selection's lines"); REQUIRE(selected > 20); - UNSCOPED_INFO(named(reverse, "none for what glows")); + UNSCOPED_INFO("none for what glows"); REQUIRE(glowing == size_t(0)); } } @@ -3102,6 +3095,7 @@ namespace constexpr S32 RADIUS = 9; for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED }, { ID_B, RED }, { ID_GLOW, GREEN }, { ID_FRONT, GREEN } }, true); // Two selections, a glowing object apart from them, and another nearer, over a corner of one. @@ -3109,21 +3103,21 @@ namespace hoverDraw(quad(44.f, 58.f, 22.f, 36.f, -1.f, -1.f), ID_FRONT) }); const std::vector tiled = edgePass(glowView(RADIUS), nullptr, false, nullptr, true); const std::vector untiled = edgePass(glowView(RADIUS), nullptr, true, nullptr, true); - UNSCOPED_INFO(named(reverse, "the glow reaches past the lines")); + UNSCOPED_INFO("the glow reaches past the lines"); REQUIRE(green(at(tiled, 28, 15))); - UNSCOPED_INFO(named(reverse, "the tiles change nothing it draws")); + UNSCOPED_INFO("the tiles change nothing it draws"); REQUIRE(tiled == untiled); const LLVector4a extents[2] = { LLVector4a(6.f, 6.f, PIXEL_Z), LLVector4a(22.f, 24.f, PIXEL_Z) }; LLRect rect; - UNSCOPED_INFO(named(reverse, "its box is on screen")); + UNSCOPED_INFO("its box is on screen"); REQUIRE(Outline::scissorRect(pixelProjection(), extents, W, H, Outline::lineReach(RADIUS), rect)); pixelIds({ hoverDraw(pixels(6, 22, 6, 24), ID_GLOW) }); const std::vector whole = edgePass(glowView(RADIUS), nullptr, false, nullptr, true); const std::vector scissored = edgePass(glowView(RADIUS), &rect, false, &rect, true); - UNSCOPED_INFO(named(reverse, "its glow is drawn")); + UNSCOPED_INFO("its glow is drawn"); REQUIRE(lit(whole) > 100); - UNSCOPED_INFO(named(reverse, "and lies in its box grown by its reach")); + UNSCOPED_INFO("and lies in its box grown by its reach"); REQUIRE(whole == scissored); } } @@ -3136,8 +3130,7 @@ namespace const F32 blend = Outline::legacyAlphaCutoff(false, 0, 0, true); const F32 mask = Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_MASK, 0.5f); UNSCOPED_INFO("the transparent texture is drawn whole"); - CHECK(Outline::faceAlphaCutoff(IMG_TRANSPARENT, blend) == - Outline::NO_ALPHA_TEST); + CHECK(Outline::faceAlphaCutoff(IMG_TRANSPARENT, blend) == Outline::NO_ALPHA_TEST); UNSCOPED_INFO("as a GLTF base colour too"); CHECK(Outline::faceAlphaCutoff(IMG_TRANSPARENT, mask) == Outline::NO_ALPHA_TEST); UNSCOPED_INFO("any other keeps its cut"); @@ -3147,19 +3140,19 @@ namespace for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED } }, true); for (const LLUUID& texture : { IMG_TRANSPARENT, other }) { const bool whole = texture == IMG_TRANSPARENT; - const std::string which = whole ? "the transparent texture" : "another clear texture"; + INFO((whole ? "the transparent texture" : "another clear texture")); idPass({ { quadA(), ID_A, Outline::PRIORITY_ROOT, Outline::faceAlphaCutoff(texture, blend), clearTexture() } }); const std::vector ids = read(mIdMap); - UNSCOPED_INFO(named(reverse, which + (whole ? " drawn whole" : " cut away"))); - REQUIRE(idAt(ids, 20, 32) == - (whole ? ID_A : 0U)); + UNSCOPED_INFO((whole ? "drawn whole" : "cut away")); + REQUIRE(idAt(ids, 20, 32) == (whole ? ID_A : 0U)); const std::vector px = edgePass(); - UNSCOPED_INFO(named(reverse, which + (whole ? " outlined" : " not outlined"))); + UNSCOPED_INFO((whole ? "outlined" : "not outlined")); REQUIRE((whole ? red(at(px, 8, 32)) : black(at(px, 8, 32)))); } } @@ -3171,26 +3164,27 @@ namespace { for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); Draw wire_only{ pixels(36, 50, 20, 44), ID_B }; wire_only.mParts = Outline::PART_WIREFRAME; const std::vector ids = pixelIds({ { pixels(10, 26, 20, 44), ID_A }, wire_only }); - UNSCOPED_INFO(named(reverse, "its id is in the target")); + UNSCOPED_INFO("its id is in the target"); REQUIRE(idAt(ids, 40, 32) == ID_B); - UNSCOPED_INFO(named(reverse, "drawn nowhere")); + UNSCOPED_INFO("drawn nowhere"); REQUIRE((U32)at(ids, 40, 32).b == 0U); - UNSCOPED_INFO(named(reverse, "the other drawn")); + UNSCOPED_INFO("the other drawn"); REQUIRE((U32)at(ids, 20, 32).b == 255U); palette({ { ID_A, RED }, { ID_B, GREEN } }, true); const std::vector px = edgePass(Outline::makeView(identity(), pixelProjection(), TEST_WIDTH, 1.f, true)); { - INFO(named(reverse, "the other's contour")); + INFO("the other's contour"); REQUIRE(red(at(px, 9, 32))); REQUIRE(red(at(px, 26, 32))); } { - INFO(named(reverse, "none around it")); + INFO("none around it"); REQUIRE(black(at(px, 35, 32))); REQUIRE(black(at(px, 50, 32))); REQUIRE(black(at(px, 43, 45))); @@ -3206,32 +3200,33 @@ namespace const F32 half = Outline::gltfAlphaCutoff(LLGLTFMaterial::ALPHA_MODE_MASK, 0.5f); for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED } }, true); const U32 glass = glassTexture(); idPass({ { quadA(), ID_A, Outline::PRIORITY_ROOT, blend, glass } }); std::vector ids = read(mIdMap); - UNSCOPED_INFO(named(reverse, "a blended pane of glass drawn whole")); + UNSCOPED_INFO("a blended pane of glass drawn whole"); REQUIRE(idAt(ids, 20, 32) == ID_A); std::vector px = edgePass(); - UNSCOPED_INFO(named(reverse, "and outlined")); + UNSCOPED_INFO("and outlined"); REQUIRE(red(at(px, 8, 32))); windowDepth(nullptr); px = worldWireframe({ { quadA(), ID_A, Outline::PRIORITY_ROOT, blend, glass } }); - UNSCOPED_INFO(named(reverse, "and wireframed")); + UNSCOPED_INFO("and wireframed"); REQUIRE(lit(px) > 0); idPass({ { quadA(), ID_A, Outline::PRIORITY_ROOT, half, glass } }); ids = read(mIdMap); - UNSCOPED_INFO(named(reverse, "under a cutoff of a half it is cut away")); + UNSCOPED_INFO("under a cutoff of a half it is cut away"); REQUIRE(idAt(ids, 20, 32) == 0U); px = edgePass(); - UNSCOPED_INFO(named(reverse, "and not outlined")); + UNSCOPED_INFO("and not outlined"); REQUIRE(black(at(px, 8, 32))); px = worldWireframe({ { quadA(), ID_A, Outline::PRIORITY_ROOT, half, glass } }); - UNSCOPED_INFO(named(reverse, "nor wireframed")); + UNSCOPED_INFO("nor wireframed"); REQUIRE(lit(px) == size_t(0)); } } @@ -3247,6 +3242,7 @@ namespace const LLColor4 BLUE(0.f, 0.f, 1.f, 1.f); for (bool reverse : conventions()) { + CAPTURE(reverse); setUp(reverse); palette({ { ID_A, RED }, { ID_B, RED }, { ID_GLOW, GREEN }, { ID_OTHER, BLUE } }, true); @@ -3267,15 +3263,16 @@ namespace }; for (const auto& [name, draws] : scenes) { + INFO(name); pixelIds(draws); for (S32 radius : { 1, 6, 9, 17, 33 }) { - const std::string at_radius = name + ", a reach of " + std::to_string(radius); + CAPTURE(radius); const std::vector rows = edgePass(glowView(radius), nullptr, false, nullptr, true); const std::vector full = edgePass(glowView(radius), nullptr, true, nullptr, true); - UNSCOPED_INFO(named(reverse, at_radius + ": it glows")); + UNSCOPED_INFO("it glows"); REQUIRE(lit(rows) > 0); - UNSCOPED_INFO(named(reverse, at_radius + ": as the full search draws it")); + UNSCOPED_INFO("as the full search draws it"); REQUIRE(rows == full); } } @@ -3283,13 +3280,13 @@ namespace // Column 24 is five columns from each of the first scene's objects, column 23 four from the one on the left. pixelIds(scenes[0].second); const std::vector between = edgePass(glowView(9), nullptr, false, nullptr, true); - UNSCOPED_INFO(named(reverse, "as near both along a row, the lower id's colour")); + UNSCOPED_INFO("as near both along a row, the lower id's colour"); REQUIRE(green(at(between, 24, 32))); - UNSCOPED_INFO(named(reverse, "nearer the left, its colour")); + UNSCOPED_INFO("nearer the left, its colour"); REQUIRE(blue(at(between, 23, 32))); pixelIds(scenes[4].second); const std::vector across = edgePass(glowView(9), nullptr, false, nullptr, true); - UNSCOPED_INFO(named(reverse, "as near both along a column and a row, the lower id's colour")); + UNSCOPED_INFO("as near both along a column and a row, the lower id's colour"); REQUIRE(green(at(across, 30, 30))); // Behind something in the scene over columns 0 to 20, its hidden part drawing no glow. @@ -3297,12 +3294,12 @@ namespace idPass({ hoverDraw(quadA(), ID_GLOW) }); for (S32 radius : { 6, 17 }) { - const std::string at_radius = "partly hidden, a reach of " + std::to_string(radius); + CAPTURE(radius); const std::vector rows = edgePass(glowView(radius), nullptr, false, nullptr, true); const std::vector full = edgePass(glowView(radius), nullptr, true, nullptr, true); - UNSCOPED_INFO(named(reverse, at_radius + ": it glows")); + UNSCOPED_INFO("partly hidden, it glows"); REQUIRE(lit(rows) > 0); - UNSCOPED_INFO(named(reverse, at_radius + ": as the full search draws it")); + UNSCOPED_INFO("partly hidden, as the full search draws it"); REQUIRE(rows == full); } } diff --git a/indra/newview/tests/alterrainsurfacemaps_test.cpp b/indra/newview/tests/alterrainsurfacemaps_test.cpp index 7beb304fb2..52e0cb6b1a 100644 --- a/indra/newview/tests/alterrainsurfacemaps_test.cpp +++ b/indra/newview/tests/alterrainsurfacemaps_test.cpp @@ -61,7 +61,6 @@ namespace { std::vector out; ALTerrainSurfaceMaps::fill(out, GPE, 1, [](S32 gx, S32 gy, F32* t) { t[0] = (F32)(gx * 100 + gy); }); - UNSCOPED_INFO("size"); REQUIRE(out.size() == static_cast(SIZE) * SIZE); UNSCOPED_INFO("first texel is the south-west apron corner"); CHECK(out[texel(-APRON, -APRON)] == (F32)(-APRON * 100 - APRON)); @@ -83,7 +82,6 @@ namespace { std::vector out; ALTerrainSurfaceMaps::fill(out, GPE, 2, [](S32 gx, S32 gy, F32* t) { t[0] = (F32)gx; t[1] = (F32)gy; }); - UNSCOPED_INFO("size"); REQUIRE(out.size() == static_cast(SIZE) * SIZE * 2); UNSCOPED_INFO("channel 0"); CHECK(out[texel(3, 5, 2)] == 3.f); @@ -97,7 +95,6 @@ namespace CHECK(out[texel(3, 5, 2) + 1] == 5.f); } - // Inside the region nothing moves. TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: resolve moves nothing inside the region", "[ALTerrainSurfaceMaps]") { bool has[8]; @@ -105,7 +102,6 @@ namespace S32 gx = 4, gy = GPE - 1; UNSCOPED_INFO("interior is this surface"); CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == MIDDLE); - UNSCOPED_INFO("gx unchanged"); CHECK(gx == 4); UNSCOPED_INFO("gy unchanged, the buffer row is ours"); CHECK(gy == GPE - 1); @@ -118,7 +114,6 @@ namespace bool has[8]; allSet(true, has); S32 gx = -1, gy = 3; - UNSCOPED_INFO("west"); CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == WEST); UNSCOPED_INFO("west gx"); CHECK(gx == GPE - 2); @@ -131,7 +126,6 @@ namespace CHECK(gx == GPE - 3); gx = GPE; gy = 3; - UNSCOPED_INFO("east"); CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == EAST); UNSCOPED_INFO("east gx"); CHECK(gx == 1); @@ -142,25 +136,21 @@ namespace CHECK(gx == 2); gx = 3; gy = -1; - UNSCOPED_INFO("south"); CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == SOUTH); UNSCOPED_INFO("south gy"); CHECK(gy == GPE - 2); gx = 3; gy = GPE + 1; - UNSCOPED_INFO("north"); CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == NORTH); UNSCOPED_INFO("north gy"); CHECK(gy == 2); } - // Both axes out: the diagonal neighbour when it is there. TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: both axes out resolve to the diagonal neighbour when it is there", "[ALTerrainSurfaceMaps]") { bool has[8]; allSet(true, has); S32 gx = -1, gy = -APRON; - UNSCOPED_INFO("south-west"); CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == SOUTHWEST); UNSCOPED_INFO("south-west gx"); CHECK(gx == GPE - 2); @@ -168,7 +158,6 @@ namespace CHECK(gy == GPE - 3); gx = GPE + 1; gy = GPE; - UNSCOPED_INFO("north-east"); CHECK(ALTerrainSurfaceMaps::resolve(gx, gy, GPE, has) == NORTHEAST); UNSCOPED_INFO("north-east gx"); CHECK(gx == 2); @@ -226,8 +215,8 @@ namespace { for (S32 gx = 0; gx < 6; ++gx) { + CAPTURE(gx, gy); const F32 h = ALTerrainSurfaceMaps::smoothHeight((F32)gx, (F32)gy, field, nullptr, nullptr); - UNSCOPED_INFO("value at a sample is the sample"); REQUIRE(h == field(gx, gy)); } } @@ -243,6 +232,7 @@ namespace auto cliff = [](S32 gx, S32) { return gx <= 2 ? 30.f : 0.f; }; for (F32 x = 0.f; x < 2.f; x += 0.125f) { + CAPTURE(x); F32 dzdx = 1.f, dzdy = 1.f; UNSCOPED_INFO("level up to the edge"); REQUIRE_THAT(ALTerrainSurfaceMaps::smoothHeight(x, 3.f, cliff, &dzdx, &dzdy), ll_test::WithinBits(30.f, 12)); @@ -254,6 +244,7 @@ namespace F32 previous = 30.f; for (F32 x = 2.f; x <= 3.f; x += 0.0625f) { + CAPTURE(x); const F32 h = ALTerrainSurfaceMaps::smoothHeight(x, 3.f, cliff, nullptr, nullptr); { INFO("inside the cell's range"); @@ -268,6 +259,7 @@ namespace CHECK_THAT(ALTerrainSurfaceMaps::smoothHeight(2.5f, 3.f, cliff, nullptr, nullptr), ll_test::WithinBits(15.f, 12)); for (F32 x = 3.f; x < 5.f; x += 0.125f) { + CAPTURE(x); UNSCOPED_INFO("level past the foot"); REQUIRE_THAT(ALTerrainSurfaceMaps::smoothHeight(x, 3.f, cliff, nullptr, nullptr), ll_test::WithinBits(0.f, 12)); } @@ -279,25 +271,23 @@ namespace { for (F32 x = 2.f; x <= 3.f; x += 0.25f) { + CAPTURE(x, y); const F32 h = ALTerrainSurfaceMaps::smoothHeight(x, y, corner, nullptr, nullptr); - { - INFO("plateau corner within its cell's range"); - REQUIRE(h >= 0.f); - REQUIRE(h <= 30.f); - } + INFO("plateau corner within its cell's range"); + REQUIRE(h >= 0.f); + REQUIRE(h <= 30.f); } } } - // A field symmetric in x and y gives a surface symmetric in x and y. TEST_CASE_METHOD(alterrainsurfacemaps_data, "ALTerrainSurfaceMaps: a field symmetric in x and y gives a surface symmetric in x and y", "[ALTerrainSurfaceMaps]") { auto field = [](S32 gx, S32 gy) { return (F32)(gx * gx + gy * gy) * 0.1f + (F32)((gx + gy) % 3); }; for (F32 v = 0.f; v < 4.f; v += 0.37f) { + CAPTURE(v); const F32 a = ALTerrainSurfaceMaps::smoothHeight(1.2f, v, field, nullptr, nullptr); const F32 b = ALTerrainSurfaceMaps::smoothHeight(v, 1.2f, field, nullptr, nullptr); - UNSCOPED_INFO("h(x, y) == h(y, x)"); REQUIRE_THAT(a, ll_test::WithinBits(b, 5)); } } @@ -311,15 +301,14 @@ namespace { for (F32 x = 0.6f; x < 4.f; x += 0.9f) { + CAPTURE(x, y); F32 dzdx, dzdy; ALTerrainSurfaceMaps::smoothHeight(x, y, field, &dzdx, &dzdy); const F32 fdx = (ALTerrainSurfaceMaps::smoothHeight(x + eps, y, field, nullptr, nullptr) - ALTerrainSurfaceMaps::smoothHeight(x - eps, y, field, nullptr, nullptr)) / (2.f * eps); const F32 fdy = (ALTerrainSurfaceMaps::smoothHeight(x, y + eps, field, nullptr, nullptr) - ALTerrainSurfaceMaps::smoothHeight(x, y - eps, field, nullptr, nullptr)) / (2.f * eps); - UNSCOPED_INFO("dz/dx"); REQUIRE_THAT(dzdx, ll_test::WithinBits(fdx, 8)); - UNSCOPED_INFO("dz/dy"); REQUIRE_THAT(dzdy, ll_test::WithinBits(fdy, 8)); } } diff --git a/indra/newview/tests/altexturetable_test.cpp b/indra/newview/tests/altexturetable_test.cpp index fc0b360bc2..88194be953 100644 --- a/indra/newview/tests/altexturetable_test.cpp +++ b/indra/newview/tests/altexturetable_test.cpp @@ -87,7 +87,7 @@ namespace for (U32 i = 1; i <= count; ++i) { Item* item = new Item(i); - UNSCOPED_INFO("fill insert"); + CAPTURE(i); REQUIRE(mTable.insert(key(i), item)); items.push_back(item); } @@ -106,23 +106,15 @@ namespace // --- membership ---------------------------------------------------------- - // An empty table answers every query without touching anything. TEST_CASE_METHOD(texturetable_data, "ALTextureTable: an empty table answers every query without touching anything", "[ALTextureTable]") { - UNSCOPED_INFO("size"); - REQUIRE(mTable.size() == (size_t)0); - UNSCOPED_INFO("empty"); - REQUIRE(mTable.empty()); - UNSCOPED_INFO("find"); - REQUIRE(mTable.find(key(1)) == nullptr); - UNSCOPED_INFO("erase"); - REQUIRE(mTable.erase(key(1)).isNull()); - UNSCOPED_INFO("window"); - REQUIRE(window(4).size() == (size_t)0); + CHECK(mTable.size() == (size_t)0); + CHECK(mTable.empty()); + CHECK(mTable.find(key(1)) == nullptr); + CHECK(mTable.erase(key(1)).isNull()); + CHECK(window(4).size() == (size_t)0); mTable.rewind(3); - UNSCOPED_INFO("cursor"); CHECK(mTable.cursor() == 0u); - UNSCOPED_INFO("consistent"); CHECK(mTable.consistent()); } @@ -133,33 +125,25 @@ namespace mTable.reserve(8); std::vector items = fill(3); - UNSCOPED_INFO("size"); REQUIRE(mTable.size() == (size_t)3); - UNSCOPED_INFO("find 2"); CHECK(mTable.find(key(2)) == items[1]); - UNSCOPED_INFO("find type"); - REQUIRE(mTable.find(key(2, 1)) == nullptr); - UNSCOPED_INFO("contains"); + UNSCOPED_INFO("the same id under another type is another key"); + CHECK(mTable.find(key(2, 1)) == nullptr); CHECK(mTable.contains(key(3))); for (S32 i = 0; i < 3; ++i) { - UNSCOPED_INFO("index"); + CAPTURE(i); REQUIRE(items[i]->getListIndex() == i); - UNSCOPED_INFO("position"); REQUIRE(mTable[i] == items[i]); - UNSCOPED_INFO("one ref"); REQUIRE(items[i]->getNumRefs() == 1); } U32 expected = 1; for (const LLPointer& item : mTable) { - UNSCOPED_INFO("iteration order"); REQUIRE(item->mId == expected++); } - UNSCOPED_INFO("live"); CHECK(Item::sLive == 3); - UNSCOPED_INFO("consistent"); CHECK(mTable.consistent()); } @@ -172,52 +156,41 @@ namespace LLPointer other = new Item(9); UNSCOPED_INFO("duplicate key refused"); CHECK_FALSE(mTable.insert(key(2), other)); - UNSCOPED_INFO("size after key refusal"); - REQUIRE(mTable.size() == (size_t)3); + CHECK(mTable.size() == (size_t)3); UNSCOPED_INFO("original kept"); CHECK(mTable.find(key(2)) == items[1]); - UNSCOPED_INFO("refused item index"); CHECK(other->getListIndex() == -1); - UNSCOPED_INFO("refused item refs"); CHECK(other->getNumRefs() == 1); - UNSCOPED_INFO("second key refused"); + UNSCOPED_INFO("an item already in a table refused under a new key"); CHECK_FALSE(mTable.insert(key(9), items[0])); - UNSCOPED_INFO("second key absent"); - REQUIRE(mTable.find(key(9)) == nullptr); - UNSCOPED_INFO("size after item refusal"); - REQUIRE(mTable.size() == (size_t)3); - UNSCOPED_INFO("consistent"); + CHECK(mTable.find(key(9)) == nullptr); + CHECK(mTable.size() == (size_t)3); CHECK(mTable.consistent()); } - // Erasing the last item needs no patching and hands the reference back. TEST_CASE_METHOD(texturetable_data, "ALTextureTable: erasing the last item needs no patching and hands the reference back", "[ALTextureTable]") { std::vector items = fill(3); { LLPointer removed = mTable.erase(key(3)); - UNSCOPED_INFO("returned item"); - CHECK(removed == items[2]); + REQUIRE(removed == items[2]); UNSCOPED_INFO("returned ref is the only one"); CHECK(removed->getNumRefs() == 1); - UNSCOPED_INFO("removed index"); CHECK(removed->getListIndex() == -1); - UNSCOPED_INFO("size"); - REQUIRE(mTable.size() == (size_t)2); - UNSCOPED_INFO("gone"); - REQUIRE(mTable.find(key(3)) == nullptr); - UNSCOPED_INFO("others untouched 0"); - CHECK(items[0]->getListIndex() == 0); - UNSCOPED_INFO("others untouched 1"); - CHECK(items[1]->getListIndex() == 1); - UNSCOPED_INFO("still live"); + CHECK(mTable.size() == (size_t)2); + CHECK(mTable.find(key(3)) == nullptr); + { + INFO("others untouched"); + CHECK(items[0]->getListIndex() == 0); + CHECK(items[1]->getListIndex() == 1); + } + UNSCOPED_INFO("still live while the returned ref is held"); CHECK(Item::sLive == 3); } UNSCOPED_INFO("destroyed with the last ref"); CHECK(Item::sLive == 2); - UNSCOPED_INFO("consistent"); CHECK(mTable.consistent()); } @@ -228,9 +201,7 @@ namespace std::vector items = fill(5); LLPointer removed = mTable.erase(key(2)); - UNSCOPED_INFO("returned item"); CHECK(removed == items[1]); - UNSCOPED_INFO("size"); REQUIRE(mTable.size() == (size_t)4); UNSCOPED_INFO("last item fills the hole"); CHECK(mTable[1] == items[4]); @@ -238,31 +209,24 @@ namespace CHECK(items[4]->getListIndex() == 1); UNSCOPED_INFO("moved item still found"); CHECK(mTable.find(key(5)) == items[4]); - UNSCOPED_INFO("erased key gone"); - REQUIRE(mTable.find(key(2)) == nullptr); - UNSCOPED_INFO("unmoved 0"); - CHECK(items[0]->getListIndex() == 0); - UNSCOPED_INFO("unmoved 2"); - CHECK(items[2]->getListIndex() == 2); - UNSCOPED_INFO("unmoved 3"); - CHECK(items[3]->getListIndex() == 3); - UNSCOPED_INFO("consistent"); + CHECK(mTable.find(key(2)) == nullptr); + { + INFO("the others unmoved"); + CHECK(items[0]->getListIndex() == 0); + CHECK(items[2]->getListIndex() == 2); + CHECK(items[3]->getListIndex() == 3); + } CHECK(mTable.consistent()); } - // An absent key erases nothing. TEST_CASE_METHOD(texturetable_data, "ALTextureTable: an absent key erases nothing", "[ALTextureTable]") { std::vector items = fill(3); - UNSCOPED_INFO("null"); - REQUIRE(mTable.erase(key(42)).isNull()); - UNSCOPED_INFO("null by type"); - REQUIRE(mTable.erase(key(2, 1)).isNull()); - UNSCOPED_INFO("size"); - REQUIRE(mTable.size() == (size_t)3); - UNSCOPED_INFO("live"); + CHECK(mTable.erase(key(42)).isNull()); + UNSCOPED_INFO("a present id under another type"); + CHECK(mTable.erase(key(2, 1)).isNull()); + CHECK(mTable.size() == (size_t)3); CHECK(Item::sLive == 3); - UNSCOPED_INFO("consistent"); CHECK(mTable.consistent()); } @@ -274,43 +238,32 @@ namespace mTable.erase(key(2)); Item* added = new Item(6); - UNSCOPED_INFO("insert"); CHECK(mTable.insert(key(6), added)); UNSCOPED_INFO("at the end"); CHECK(added->getListIndex() == 3); - UNSCOPED_INFO("size"); - REQUIRE(mTable.size() == (size_t)4); - UNSCOPED_INFO("find"); + CHECK(mTable.size() == (size_t)4); CHECK(mTable.find(key(6)) == added); - UNSCOPED_INFO("consistent"); CHECK(mTable.consistent()); } // --- the round-robin window ---------------------------------------------- - // Consecutive windows continue from the cursor and wrap. TEST_CASE_METHOD(texturetable_data, "ALTextureTable: consecutive windows continue from the cursor and wrap", "[ALTextureTable]") { fill(5); - UNSCOPED_INFO("first"); CHECK(window(2) == ids({ 1, 2 })); - UNSCOPED_INFO("second"); CHECK(window(2) == ids({ 3, 4 })); UNSCOPED_INFO("wraps"); CHECK(window(2) == ids({ 5, 1 })); - UNSCOPED_INFO("cursor"); CHECK(mTable.cursor() == 1u); } - // A window larger than the table visits every item once. TEST_CASE_METHOD(texturetable_data, "ALTextureTable: a window larger than the table visits every item once", "[ALTextureTable]") { fill(5); std::vector seen; U32 visited = mTable.visitWindow(10, [&](Item* item) { seen.push_back(item->mId); }); - UNSCOPED_INFO("visited"); CHECK(visited == 5u); - UNSCOPED_INFO("each once"); CHECK(seen == ids({ 1, 2, 3, 4, 5 })); UNSCOPED_INFO("cursor back at start"); CHECK(mTable.cursor() == 0u); @@ -322,19 +275,15 @@ namespace { fill(5); window(4); - UNSCOPED_INFO("cursor"); CHECK(mTable.cursor() == 4u); mTable.erase(key(1)); mTable.erase(key(2)); - UNSCOPED_INFO("size"); - REQUIRE(mTable.size() == (size_t)3); - UNSCOPED_INFO("consistent"); + CHECK(mTable.size() == (size_t)3); CHECK(mTable.consistent()); UNSCOPED_INFO("restarts"); CHECK(window(1) == ids({ 5 })); - UNSCOPED_INFO("cursor after restart"); CHECK(mTable.cursor() == 1u); } @@ -345,7 +294,6 @@ namespace fill(5); window(4); mTable.rewind(2); - UNSCOPED_INFO("cursor"); CHECK(mTable.cursor() == 2u); UNSCOPED_INFO("revisits"); CHECK(window(1) == ids({ 3 })); @@ -363,33 +311,29 @@ namespace TEST_CASE_METHOD(texturetable_data, "ALTextureTable: after an erase between windows the moved item still comes around", "[ALTextureTable]") { fill(6); - UNSCOPED_INFO("first"); CHECK(window(3) == ids({ 1, 2, 3 })); mTable.erase(key(2)); - UNSCOPED_INFO("consistent"); CHECK(mTable.consistent()); std::vector second = window(3); - UNSCOPED_INFO("second"); CHECK(second == ids({ 4, 5, 1 })); for (U32 id : second) { - UNSCOPED_INFO("member"); + CAPTURE(id); REQUIRE(mTable.find(key(id)) != nullptr); } UNSCOPED_INFO("moved item comes around"); CHECK(window(3) == ids({ 6, 3, 4 })); } - // Visiting hands out raw pointers and takes no references. TEST_CASE_METHOD(texturetable_data, "ALTextureTable: visiting hands out raw pointers and takes no references", "[ALTextureTable]") { std::vector items = fill(3); window(3); for (Item* item : items) { - UNSCOPED_INFO("refs after visit"); + CAPTURE(item->mId); REQUIRE(item->getNumRefs() == 1); } } @@ -405,26 +349,19 @@ namespace window(2); mTable.clear(); - UNSCOPED_INFO("size"); - REQUIRE(mTable.size() == (size_t)0); - UNSCOPED_INFO("cursor"); + CHECK(mTable.size() == (size_t)0); CHECK(mTable.cursor() == 0u); - UNSCOPED_INFO("kept index"); CHECK(kept->getListIndex() == -1); - UNSCOPED_INFO("kept refs"); CHECK(kept->getNumRefs() == 1); UNSCOPED_INFO("others destroyed"); CHECK(Item::sLive == 1); - UNSCOPED_INFO("consistent"); CHECK(mTable.consistent()); UNSCOPED_INFO("reinsert after clear"); CHECK(mTable.insert(key(2), kept)); - UNSCOPED_INFO("reinserted index"); CHECK(kept->getListIndex() == 0); } - // Destroying the table releases its references. TEST_CASE_METHOD(texturetable_data, "ALTextureTable: destroying the table releases its references", "[ALTextureTable]") { { @@ -433,10 +370,8 @@ namespace { local.insert(key(i), new Item(i)); } - UNSCOPED_INFO("live"); CHECK(Item::sLive == 3); } - UNSCOPED_INFO("released"); CHECK(Item::sLive == 0); } @@ -453,24 +388,23 @@ namespace CHECK(mTable.consistent()); for (U32 i = 1; i <= count; i += 997) { - UNSCOPED_INFO("found after growth"); + CAPTURE(i); REQUIRE(mTable.find(key(i)) == items[i - 1]); } // erase every third item, then look for all of them for (U32 i = 3; i <= count; i += 3) { - UNSCOPED_INFO("erase"); + CAPTURE(i); REQUIRE(mTable.erase(key(i)).notNull()); } - UNSCOPED_INFO("size after erases"); - REQUIRE(mTable.size() == (size_t)(count - count / 3)); + CHECK(mTable.size() == (size_t)(count - count / 3)); UNSCOPED_INFO("consistent after erases"); CHECK(mTable.consistent()); for (U32 i = 1; i <= count; ++i) { Item* found = mTable.find(key(i)); - UNSCOPED_INFO("erased gone, kept found"); + CAPTURE(i); REQUIRE(((i % 3 == 0) ? found == nullptr : found == items[i - 1])); } @@ -478,12 +412,10 @@ namespace reserved.reserve(count); for (U32 i = 1; i <= 100; ++i) { - UNSCOPED_INFO("reserved insert"); + CAPTURE(i); REQUIRE(reserved.insert(key(i), new Item(i))); } - UNSCOPED_INFO("reserved size"); - REQUIRE(reserved.size() == (size_t)100); - UNSCOPED_INFO("reserved consistent"); + CHECK(reserved.size() == (size_t)100); CHECK(reserved.consistent()); } @@ -498,7 +430,6 @@ namespace U32 made = 0; Item* hit = mTable.findOrInsert(key(2), [&]() { ++made; return new Item(99); }); - UNSCOPED_INFO("hit returns existing"); CHECK(hit == items[1]); UNSCOPED_INFO("maker not called on hit"); CHECK(made == 0u); @@ -513,29 +444,24 @@ namespace CHECK(made == 1u); UNSCOPED_INFO("one ref from the table"); CHECK(fresh->getNumRefs() == 1); - UNSCOPED_INFO("position"); CHECK(fresh->getListIndex() == 2); - UNSCOPED_INFO("found afterwards"); CHECK(mTable.find(key(3)) == fresh); - UNSCOPED_INFO("size"); - REQUIRE(mTable.size() == (size_t)3); + CHECK(mTable.size() == (size_t)3); Item* none = mTable.findOrInsert(key(4), [&]() -> Item* { ++made; return nullptr; }); UNSCOPED_INFO("null maker yields null"); - REQUIRE(none == nullptr); + CHECK(none == nullptr); UNSCOPED_INFO("null maker leaves no key"); CHECK_FALSE(mTable.contains(key(4))); - UNSCOPED_INFO("size after null maker"); - REQUIRE(mTable.size() == (size_t)3); + CHECK(mTable.size() == (size_t)3); LLPointer other = new Item(5); mTable.insert(key(5), other); Item* dup = mTable.findOrInsert(key(6), [&]() { return other.get(); }); UNSCOPED_INFO("item already in a table refused"); - REQUIRE(dup == nullptr); + CHECK(dup == nullptr); UNSCOPED_INFO("refused key absent"); CHECK_FALSE(mTable.contains(key(6))); - UNSCOPED_INFO("consistent"); CHECK(mTable.consistent()); } } diff --git a/indra/newview/tests/alwhitebalancesolver_test.cpp b/indra/newview/tests/alwhitebalancesolver_test.cpp index 6805b61688..7422ad4d66 100644 --- a/indra/newview/tests/alwhitebalancesolver_test.cpp +++ b/indra/newview/tests/alwhitebalancesolver_test.cpp @@ -42,11 +42,8 @@ namespace TEST_CASE_METHOD(wb_data, "ALWhiteBalanceSolver: neutral in gives a gain of one", "[ALWhiteBalanceSolver]") { const LLVector3 g = ALWhiteBalanceSolver::gain(0.f, 0.f); - UNSCOPED_INFO("neutral red"); CHECK_THAT(g.mV[VX], ll_test::WithinBits(1.f, 6)); - UNSCOPED_INFO("neutral green"); CHECK_THAT(g.mV[VY], ll_test::WithinBits(1.f, 6)); - UNSCOPED_INFO("neutral blue"); CHECK_THAT(g.mV[VZ], ll_test::WithinBits(1.f, 6)); } @@ -59,7 +56,7 @@ namespace for (S32 j = -2; j <= 2; ++j) { const LLVector3 g = ALWhiteBalanceSolver::gain(i * 1000.f, j * 0.5f); - UNSCOPED_INFO("green stays pinned"); + CAPTURE(i, j); REQUIRE_THAT(g.mV[VY], ll_test::WithinBits(1.f, 6)); } } @@ -89,10 +86,12 @@ namespace { const F32 cct = i * 1200.f; const F32 duv = j * 0.25f; + CAPTURE(cct, duv); // Out of gamut is out of scope: down there the blue gain is // negative, so every candidate looks alike to the solver and - // no inverse exists to test. Test <9> covers that region. + // no inverse exists to test. The out-of-gamut case below + // covers that region. if (!ALWhiteBalanceSolver::isUsable(cct, duv)) { continue; @@ -151,7 +150,6 @@ namespace TEST_CASE_METHOD(wb_data, "ALWhiteBalanceSolver: neutralisingGain pins green and scales red and blue to meet it", "[ALWhiteBalanceSolver]") { const LLVector3 g = ALWhiteBalanceSolver::neutralisingGain(LLColor3(0.4f, 0.5f, 0.8f)); - UNSCOPED_INFO("green pinned"); CHECK_THAT(g.mV[VY], ll_test::WithinBits(1.f, 6)); UNSCOPED_INFO("red is lifted to meet green"); CHECK_THAT(g.mV[VX], ll_test::WithinBits(1.25f, 5)); @@ -180,6 +178,7 @@ namespace for (S32 i = -3; i <= 3; ++i) { const F32 cct = i * 1500.f; + CAPTURE(cct); // A grey surface seen through the inverse of the correction: this // is what the scene buffer holds when the light is that colour. @@ -207,9 +206,7 @@ namespace { const ALWhiteBalanceSolver::Result got = ALWhiteBalanceSolver::solveForColor(LLColor3(0.5f, 0.5f, 0.5f)); - UNSCOPED_INFO("cct stays put"); CHECK(std::fabs(got.mCCTOffset) < 1.f); - UNSCOPED_INFO("duv stays put"); CHECK(std::fabs(got.mDuv) < 1e-3f); UNSCOPED_INFO("exactly reachable"); CHECK(got.mResidual < 1e-4f); diff --git a/indra/newview/tests/cppfeatures_test.cpp b/indra/newview/tests/cppfeatures_test.cpp index c14963dd6a..a256a6dfb7 100644 --- a/indra/newview/tests/cppfeatures_test.cpp +++ b/indra/newview/tests/cppfeatures_test.cpp @@ -59,14 +59,12 @@ TEST_CASE("LLCPPFeatures: auto deduces an element and an iterator type", "[LLCPP // auto element auto& aval = numbers[1]; - UNSCOPED_INFO("auto element"); CHECK(aval==6); // auto iterator (non-const) auto it = numbers.rbegin(); *it += 1; S32 val = *it; - UNSCOPED_INFO("auto iterator"); CHECK(val==10); } @@ -89,7 +87,6 @@ TEST_CASE("LLCPPFeatures: range for walks a container or a C array", "[LLCPPFeat auto& n = *it; n *= 2; } - UNSCOPED_INFO("iterator for vector"); CHECK(numbers[2]==18); // Range for with container @@ -102,7 +99,6 @@ TEST_CASE("LLCPPFeatures: range for walks a container or a C array", "[LLCPPFeat { n *= 2; } - UNSCOPED_INFO("range for vector"); CHECK(numbersb[2]==18); // Range for over a C-style array. @@ -115,7 +111,6 @@ TEST_CASE("LLCPPFeatures: range for walks a container or a C array", "[LLCPPFeat { sum += v; } - UNSCOPED_INFO("for C-array"); CHECK(sum==31); } @@ -152,7 +147,6 @@ class Bar: public Foo TEST_CASE("LLCPPFeatures: an override specifier marks a virtual override", "[LLCPPFeatures]") { Bar b; - UNSCOPED_INFO("override"); CHECK(b.is_happy()); } @@ -186,7 +180,6 @@ class Bicycle: public WheeledVehicle TEST_CASE("LLCPPFeatures: a class derives from one with a final override", "[LLCPPFeatures]") { Bicycle bi; - UNSCOPED_INFO("final"); CHECK(bi.has_wheels()); } @@ -245,11 +238,8 @@ TEST_CASE("LLCPPFeatures: a defaulted copy constructor copies the members", "[LL DefaultCopyOK d; // OK DefaultCopyOK d2(d); // OK DefaultCopyOK d3 = d; // OK - UNSCOPED_INFO("default copy d"); CHECK(d.val()==123); - UNSCOPED_INFO("default copy d2"); CHECK(d.val()==d2.val()); - UNSCOPED_INFO("default copy d3"); CHECK(d.val()==d3.val()); } @@ -287,13 +277,10 @@ class InitInlineWithConstructor TEST_CASE("LLCPPFeatures: inline member initializers give defaults a constructor overrides", "[LLCPPFeatures]") { InitInline ii; - UNSCOPED_INFO("init member inline 1"); CHECK(ii.mFoo==10); InitInlineWithConstructor iici; - UNSCOPED_INFO("init member inline 2"); CHECK(iici.mFoo==10); - UNSCOPED_INFO("init member inline 3"); CHECK(iici.mBar==25); } @@ -321,12 +308,10 @@ constexpr S32 ce_factorial(S32 n) TEST_CASE("LLCPPFeatures: constexpr functions compute values", "[LLCPPFeatures]") { S32 val = compute2(); - UNSCOPED_INFO("constexpr 1"); CHECK(val==2); // Compile-time factorial. You used to need complex templates to do something this useless. S32 fac5 = ce_factorial(5); - UNSCOPED_INFO("constexpr 2"); CHECK(fac5==120); } @@ -361,7 +346,6 @@ using stringmap = std::map; TEST_CASE("LLCPPFeatures: a template type alias names a map type", "[LLCPPFeatures]") { stringmap name_counts{ {"alice", 3}, {"bob", 2} }; - UNSCOPED_INFO("type alias"); CHECK(name_counts["bob"]==2); } diff --git a/indra/newview/tests/llagentaccess_test.cpp b/indra/newview/tests/llagentaccess_test.cpp index 29e1ea374c..4fd2c2ca93 100644 --- a/indra/newview/tests/llagentaccess_test.cpp +++ b/indra/newview/tests/llagentaccess_test.cpp @@ -44,31 +44,22 @@ namespace cgr.setU32("PreferredMaturity", SIM_ACCESS_PG); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 prefersPG"); CHECK(aa.prefersPG()); - UNSCOPED_INFO("1 prefersMature"); CHECK_FALSE(aa.prefersMature()); - UNSCOPED_INFO("1 prefersAdult"); CHECK_FALSE(aa.prefersAdult()); #endif // HACKED_GODLIKE_VIEWER cgr.setU32("PreferredMaturity", SIM_ACCESS_MATURE); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("2 prefersPG"); CHECK_FALSE(aa.prefersPG()); - UNSCOPED_INFO("2 prefersMature"); CHECK(aa.prefersMature()); - UNSCOPED_INFO("2 prefersAdult"); CHECK_FALSE(aa.prefersAdult()); #endif // HACKED_GODLIKE_VIEWER cgr.setU32("PreferredMaturity", SIM_ACCESS_ADULT); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("3 prefersPG"); CHECK_FALSE(aa.prefersPG()); - UNSCOPED_INFO("3 prefersMature"); CHECK(aa.prefersMature()); - UNSCOPED_INFO("3 prefersAdult"); CHECK(aa.prefersAdult()); #endif // HACKED_GODLIKE_VIEWER } @@ -81,56 +72,40 @@ namespace // make sure default is PG #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 isTeen"); CHECK(aa.isTeen()); - UNSCOPED_INFO("1 isMature"); CHECK_FALSE(aa.isMature()); - UNSCOPED_INFO("1 isAdult"); CHECK_FALSE(aa.isAdult()); #endif // HACKED_GODLIKE_VIEWER // check the conversion routine #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 conversion"); CHECK(SIM_ACCESS_PG == aa.convertTextToMaturity('P')); - UNSCOPED_INFO("2 conversion"); CHECK(SIM_ACCESS_MATURE == aa.convertTextToMaturity('M')); - UNSCOPED_INFO("3 conversion"); CHECK(SIM_ACCESS_ADULT == aa.convertTextToMaturity('A')); - UNSCOPED_INFO("4 conversion"); CHECK(SIM_ACCESS_MIN == aa.convertTextToMaturity('Q')); #endif // HACKED_GODLIKE_VIEWER // now try the other method of setting it - PG aa.setMaturity('P'); - UNSCOPED_INFO("2 isTeen"); CHECK(aa.isTeen()); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("2 isMature"); CHECK_FALSE(aa.isMature()); - UNSCOPED_INFO("2 isAdult"); CHECK_FALSE(aa.isAdult()); #endif // HACKED_GODLIKE_VIEWER // Mature aa.setMaturity('M'); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("3 isTeen"); CHECK_FALSE(aa.isTeen()); - UNSCOPED_INFO("3 isMature"); CHECK(aa.isMature()); - UNSCOPED_INFO("3 isAdult"); CHECK_FALSE(aa.isAdult()); #endif // HACKED_GODLIKE_VIEWER // Adult aa.setMaturity('A'); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("4 isTeen"); CHECK_FALSE(aa.isTeen()); - UNSCOPED_INFO("4 isMature"); CHECK(aa.isMature()); - UNSCOPED_INFO("4 isAdult"); CHECK(aa.isAdult()); #endif // HACKED_GODLIKE_VIEWER @@ -163,21 +138,19 @@ namespace #endif // HACKED_GODLIKE_VIEWER aa.setAdminOverride(true); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("admin true"); CHECK(aa.getAdminOverride()); - UNSCOPED_INFO("overrides 1"); + UNSCOPED_INFO("the admin override alone"); CHECK(aa.isGodlike()); #endif // HACKED_GODLIKE_VIEWER aa.setGodLevel(GOD_FULL); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("overrides 2"); + UNSCOPED_INFO("the admin override and full god level"); CHECK(aa.isGodlike()); #endif // HACKED_GODLIKE_VIEWER aa.setAdminOverride(false); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("admin false"); CHECK_FALSE(aa.getAdminOverride()); - UNSCOPED_INFO("overrides 3"); + UNSCOPED_INFO("full god level alone"); CHECK(aa.isGodlike()); #endif // HACKED_GODLIKE_VIEWER } @@ -189,85 +162,85 @@ namespace LLAgentAccess aa(cgr); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 pg to start"); - CHECK(aa.wantsPGOnly()); - UNSCOPED_INFO("2 pg to start"); - CHECK_FALSE(aa.canAccessMature()); - UNSCOPED_INFO("3 pg to start"); - CHECK_FALSE(aa.canAccessAdult()); + { + INFO("pg to start"); + CHECK(aa.wantsPGOnly()); + CHECK_FALSE(aa.canAccessMature()); + CHECK_FALSE(aa.canAccessAdult()); + } #endif // HACKED_GODLIKE_VIEWER aa.setGodLevel(GOD_FULL); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 full god"); - CHECK_FALSE(aa.wantsPGOnly()); - UNSCOPED_INFO("2 full god"); - CHECK(aa.canAccessMature()); - UNSCOPED_INFO("3 full god"); - CHECK(aa.canAccessAdult()); + { + INFO("full god"); + CHECK_FALSE(aa.wantsPGOnly()); + CHECK(aa.canAccessMature()); + CHECK(aa.canAccessAdult()); + } #endif // HACKED_GODLIKE_VIEWER aa.setGodLevel(GOD_NOT); aa.setAdminOverride(true); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 admin mode"); - CHECK_FALSE(aa.wantsPGOnly()); - UNSCOPED_INFO("2 admin mode"); - CHECK(aa.canAccessMature()); - UNSCOPED_INFO("3 admin mode"); - CHECK(aa.canAccessAdult()); + { + INFO("admin mode"); + CHECK_FALSE(aa.wantsPGOnly()); + CHECK(aa.canAccessMature()); + CHECK(aa.canAccessAdult()); + } #endif // HACKED_GODLIKE_VIEWER aa.setAdminOverride(false); aa.setMaturity('M'); // preferred is still pg by default #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 mature pref pg"); - CHECK(aa.wantsPGOnly()); - UNSCOPED_INFO("2 mature pref pg"); - CHECK_FALSE(aa.canAccessMature()); - UNSCOPED_INFO("3 mature pref pg"); - CHECK_FALSE(aa.canAccessAdult()); + { + INFO("mature pref pg"); + CHECK(aa.wantsPGOnly()); + CHECK_FALSE(aa.canAccessMature()); + CHECK_FALSE(aa.canAccessAdult()); + } #endif // HACKED_GODLIKE_VIEWER cgr.setU32("PreferredMaturity", SIM_ACCESS_MATURE); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 mature"); - CHECK_FALSE(aa.wantsPGOnly()); - UNSCOPED_INFO("2 mature"); - CHECK(aa.canAccessMature()); - UNSCOPED_INFO("3 mature"); - CHECK_FALSE(aa.canAccessAdult()); + { + INFO("mature"); + CHECK_FALSE(aa.wantsPGOnly()); + CHECK(aa.canAccessMature()); + CHECK_FALSE(aa.canAccessAdult()); + } #endif // HACKED_GODLIKE_VIEWER cgr.setU32("PreferredMaturity", SIM_ACCESS_PG); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 mature pref pg"); - CHECK(aa.wantsPGOnly()); - UNSCOPED_INFO("2 mature pref pg"); - CHECK_FALSE(aa.canAccessMature()); - UNSCOPED_INFO("3 mature pref pg"); - CHECK_FALSE(aa.canAccessAdult()); + { + INFO("mature pref pg"); + CHECK(aa.wantsPGOnly()); + CHECK_FALSE(aa.canAccessMature()); + CHECK_FALSE(aa.canAccessAdult()); + } #endif // HACKED_GODLIKE_VIEWER aa.setMaturity('A'); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 adult pref pg"); - CHECK(aa.wantsPGOnly()); - UNSCOPED_INFO("2 adult pref pg"); - CHECK_FALSE(aa.canAccessMature()); - UNSCOPED_INFO("3 adult pref pg"); - CHECK_FALSE(aa.canAccessAdult()); + { + INFO("adult pref pg"); + CHECK(aa.wantsPGOnly()); + CHECK_FALSE(aa.canAccessMature()); + CHECK_FALSE(aa.canAccessAdult()); + } #endif // HACKED_GODLIKE_VIEWER cgr.setU32("PreferredMaturity", SIM_ACCESS_ADULT); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 adult"); - CHECK_FALSE(aa.wantsPGOnly()); - UNSCOPED_INFO("2 adult"); - CHECK(aa.canAccessMature()); - UNSCOPED_INFO("3 adult"); - CHECK(aa.canAccessAdult()); + { + INFO("adult"); + CHECK_FALSE(aa.wantsPGOnly()); + CHECK(aa.canAccessMature()); + CHECK(aa.canAccessAdult()); + } #endif // HACKED_GODLIKE_VIEWER // make sure that even if pref is high, if access is low we block access @@ -275,12 +248,12 @@ namespace cgr.setU32("PreferredMaturity", SIM_ACCESS_ADULT); aa.setMaturity('P'); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 pref adult, actual pg"); - CHECK(aa.wantsPGOnly()); - UNSCOPED_INFO("2 pref adult, actual pg"); - CHECK_FALSE(aa.canAccessMature()); - UNSCOPED_INFO("3 pref adult, actual pg"); - CHECK_FALSE(aa.canAccessAdult()); + { + INFO("pref adult, actual pg"); + CHECK(aa.wantsPGOnly()); + CHECK_FALSE(aa.canAccessMature()); + CHECK_FALSE(aa.canAccessAdult()); + } #endif // HACKED_GODLIKE_VIEWER } @@ -294,13 +267,11 @@ namespace cgr.setU32("PreferredMaturity", SIM_ACCESS_ADULT); aa.setMaturity('M'); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 preferred maturity pegged to M when maturity is M"); CHECK(cgr.getU32("PreferredMaturity") == SIM_ACCESS_MATURE); #endif // HACKED_GODLIKE_VIEWER aa.setMaturity('P'); #ifndef HACKED_GODLIKE_VIEWER - UNSCOPED_INFO("1 preferred maturity pegged to P when maturity is P"); CHECK(cgr.getU32("PreferredMaturity") == SIM_ACCESS_PG); #endif // HACKED_GODLIKE_VIEWER } diff --git a/indra/newview/tests/lldateutil_test.cpp b/indra/newview/tests/lldateutil_test.cpp index d2a84acca7..2ac2da00ae 100644 --- a/indra/newview/tests/lldateutil_test.cpp +++ b/indra/newview/tests/lldateutil_test.cpp @@ -111,61 +111,46 @@ namespace TEST_CASE_METHOD(dateutil, "LLDateUtil: an age of a year or more reads in years and whole months", "[LLDateUtil]") { - UNSCOPED_INFO("years + months"); CHECK(LLDateUtil::ageFromDate("10/30/2007", mNow) == "2 years 2 months old"); - UNSCOPED_INFO("years"); CHECK(LLDateUtil::ageFromDate("12/31/2007", mNow) == "2 years old"); - UNSCOPED_INFO("years"); CHECK(LLDateUtil::ageFromDate("1/1/2008", mNow) == "1 year 11 months old"); - UNSCOPED_INFO("single year + one month"); CHECK(LLDateUtil::ageFromDate("11/30/2008", mNow) == "1 year 1 month old"); - UNSCOPED_INFO("single year + a bit"); CHECK(LLDateUtil::ageFromDate("12/12/2008", mNow) == "1 year old"); - UNSCOPED_INFO("single year"); CHECK(LLDateUtil::ageFromDate("12/31/2008", mNow) == "1 year old"); } TEST_CASE_METHOD(dateutil, "LLDateUtil: an age of a month to a year reads in whole months", "[LLDateUtil]") { - UNSCOPED_INFO("months"); CHECK(LLDateUtil::ageFromDate("10/30/2009", mNow) == "2 months old"); - UNSCOPED_INFO("months 2"); CHECK(LLDateUtil::ageFromDate("10/31/2009", mNow) == "2 months old"); - UNSCOPED_INFO("single month"); CHECK(LLDateUtil::ageFromDate("11/30/2009", mNow) == "1 month old"); } TEST_CASE_METHOD(dateutil, "LLDateUtil: an age under a month reads in whole weeks", "[LLDateUtil]") { - UNSCOPED_INFO("4 weeks"); CHECK(LLDateUtil::ageFromDate("12/1/2009", mNow) == "4 weeks old"); - UNSCOPED_INFO("weeks"); CHECK(LLDateUtil::ageFromDate("12/17/2009", mNow) == "2 weeks old"); - UNSCOPED_INFO("single week"); CHECK(LLDateUtil::ageFromDate("12/24/2009", mNow) == "1 week old"); } TEST_CASE_METHOD(dateutil, "LLDateUtil: an age under a week reads in days or as joined today", "[LLDateUtil]") { - UNSCOPED_INFO("days"); CHECK(LLDateUtil::ageFromDate("12/29/2009", mNow) == "2 days old"); - UNSCOPED_INFO("single day"); CHECK(LLDateUtil::ageFromDate("12/30/2009", mNow) == "1 day old"); - UNSCOPED_INFO("today"); CHECK(LLDateUtil::ageFromDate("12/31/2009", mNow) == "Joined today"); } @@ -173,7 +158,6 @@ namespace TEST_CASE_METHOD(dateutil, "LLDateUtil: an age that spans the new year still reads in weeks", "[LLDateUtil]") { LLDate now(std::string("2010-01-04T12:00:00Z")); - UNSCOPED_INFO("days"); CHECK(LLDateUtil::ageFromDate("12/13/2009", now) == "3 weeks old"); } diff --git a/indra/newview/tests/llhttpretrypolicy_test.cpp b/indra/newview/tests/llhttpretrypolicy_test.cpp index 9dc5b26cfc..2ed768cb56 100644 --- a/indra/newview/tests/llhttpretrypolicy_test.cpp +++ b/indra/newview/tests/llhttpretrypolicy_test.cpp @@ -39,12 +39,10 @@ TEST_CASE("retry_policy: a policy of zero retries never retries", "[retry_policy F32 wait_seconds; // No retry until we've failed a try. - UNSCOPED_INFO("never retry 0"); - REQUIRE_FALSE(never_retry.shouldRetry(wait_seconds)); + CHECK_FALSE(never_retry.shouldRetry(wait_seconds)); // 0 retries max. never_retry.onFailure(500,headers); - UNSCOPED_INFO("never retry 1"); CHECK_FALSE(never_retry.shouldRetry(wait_seconds)); } @@ -56,14 +54,12 @@ TEST_CASE("retry_policy: a 404 is retried only when 4xx retries are enabled", "[ // Normally only retry on server error (5xx) LLAdaptiveRetryPolicy noRetry404(1.0,2.0,3.0,10); noRetry404.onFailure(404,headers); - UNSCOPED_INFO("no retry on 404"); - REQUIRE_FALSE(noRetry404.shouldRetry(wait_seconds)); + CHECK_FALSE(noRetry404.shouldRetry(wait_seconds)); // Can retry on 4xx errors if enabled by flag. bool do_retry_4xx = true; LLAdaptiveRetryPolicy doRetry404(1.0,2.0,3.0,10,do_retry_4xx); doRetry404.onFailure(404,headers); - UNSCOPED_INFO("do retry on 404"); CHECK(doRetry404.shouldRetry(wait_seconds)); } @@ -77,78 +73,61 @@ TEST_CASE("retry_policy: waits double to a cap and retries stop at the limit unt U32 frac_bits = 6; // No retry until we've failed a try. - UNSCOPED_INFO("basic_retry 0"); - REQUIRE_FALSE(basic_retry.shouldRetry(wait_seconds)); + CHECK_FALSE(basic_retry.shouldRetry(wait_seconds)); // Starting wait 1.0 basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - UNSCOPED_INFO("basic_retry 1"); CHECK(should_retry); - UNSCOPED_INFO("basic_retry 1"); CHECK_THAT(wait_seconds, ll_test::WithinBits(1.0F, frac_bits)); // Double wait to 2.0 basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - UNSCOPED_INFO("basic_retry 2"); CHECK(should_retry); - UNSCOPED_INFO("basic_retry 2"); CHECK_THAT(wait_seconds, ll_test::WithinBits(2.0F, frac_bits)); // Hit max wait of 3.0 (4.0 clamped to max 3) basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - UNSCOPED_INFO("basic_retry 3"); CHECK(should_retry); - UNSCOPED_INFO("basic_retry 3"); CHECK_THAT(wait_seconds, ll_test::WithinBits(3.0F, frac_bits)); // At max wait, should stay at 3.0 basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - UNSCOPED_INFO("basic_retry 4"); CHECK(should_retry); - UNSCOPED_INFO("basic_retry 4"); CHECK_THAT(wait_seconds, ll_test::WithinBits(3.0F, frac_bits)); // Max retries, should fail now. basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - UNSCOPED_INFO("basic_retry 5"); CHECK_FALSE(should_retry); // Max retries, should fail now. basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - UNSCOPED_INFO("basic_retry 5"); CHECK_FALSE(should_retry); // After a success, should reset to the starting state. basic_retry.onSuccess(); // No retry until we've failed a try. - UNSCOPED_INFO("basic_retry 6"); CHECK_FALSE(basic_retry.shouldRetry(wait_seconds)); // Starting wait 1.0 basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - UNSCOPED_INFO("basic_retry 7"); CHECK(should_retry); - UNSCOPED_INFO("basic_retry 7"); CHECK_THAT(wait_seconds, ll_test::WithinBits(1.0F, frac_bits)); // Double wait to 2.0 basic_retry.onFailure(500,headers); should_retry = basic_retry.shouldRetry(wait_seconds); - UNSCOPED_INFO("basic_retry 8"); CHECK(should_retry); - UNSCOPED_INFO("basic_retry 8"); CHECK_THAT(wait_seconds, ll_test::WithinBits(2.0F, frac_bits)); } -// Retries should stop as soon as a non-5xx error is received. TEST_CASE("retry_policy: retries stop for good at the first non-5xx error", "[retry_policy]") { // Should retry after 1.0, 2.0, 3.0, 3.0 seconds. @@ -161,29 +140,23 @@ TEST_CASE("retry_policy: retries stop for good at the first non-5xx error", "[re // Starting wait 1.0 killer404.onFailure(500,headers); should_retry = killer404.shouldRetry(wait_seconds); - UNSCOPED_INFO("killer404 1"); CHECK(should_retry); - UNSCOPED_INFO("killer404 1"); CHECK_THAT(wait_seconds, ll_test::WithinBits(1.0F, frac_bits)); // Double wait to 2.0 killer404.onFailure(500,headers); should_retry = killer404.shouldRetry(wait_seconds); - UNSCOPED_INFO("killer404 2"); CHECK(should_retry); - UNSCOPED_INFO("killer404 2"); CHECK_THAT(wait_seconds, ll_test::WithinBits(2.0F, frac_bits)); // Should fail on non-5xx killer404.onFailure(404,headers); should_retry = killer404.shouldRetry(wait_seconds); - UNSCOPED_INFO("killer404 3"); CHECK_FALSE(should_retry); // After a non-5xx, should keep failing. killer404.onFailure(500,headers); should_retry = killer404.shouldRetry(wait_seconds); - UNSCOPED_INFO("killer404 4"); CHECK_FALSE(should_retry); } @@ -204,51 +177,38 @@ TEST_CASE("retry_policy: a retry-after header overrides the wait but not its pro policy.onFailure(500,headers_without_retry); should_retry = policy.shouldRetry(wait_seconds); - UNSCOPED_INFO("retry header 1"); CHECK(should_retry); - UNSCOPED_INFO("retry header 1"); CHECK_THAT(wait_seconds, ll_test::WithinBits(1.0F, frac_bits)); policy.onFailure(500,headers_without_retry); should_retry = policy.shouldRetry(wait_seconds); - UNSCOPED_INFO("retry header 2"); CHECK(should_retry); - UNSCOPED_INFO("retry header 2"); CHECK_THAT(wait_seconds, ll_test::WithinBits(2.0F, frac_bits)); policy.onFailure(500,headers_with_retry); should_retry = policy.shouldRetry(wait_seconds); - UNSCOPED_INFO("retry header 3"); CHECK(should_retry); // 4.0 overrides by header -> 666.0 - UNSCOPED_INFO("retry header 3"); CHECK_THAT(wait_seconds, ll_test::WithinBits(666.0F, frac_bits)); policy.onFailure(500,headers_with_retry); should_retry = policy.shouldRetry(wait_seconds); - UNSCOPED_INFO("retry header 4"); CHECK(should_retry); // 8.0 overrides by header -> 666.0 - UNSCOPED_INFO("retry header 4"); CHECK_THAT(wait_seconds, ll_test::WithinBits(666.0F, frac_bits)); policy.onFailure(500,headers_without_retry); should_retry = policy.shouldRetry(wait_seconds); - UNSCOPED_INFO("retry header 5"); CHECK(should_retry); - UNSCOPED_INFO("retry header 5"); CHECK_THAT(wait_seconds, ll_test::WithinBits(16.0F, frac_bits)); policy.onFailure(500,headers_without_retry); should_retry = policy.shouldRetry(wait_seconds); - UNSCOPED_INFO("retry header 6"); CHECK(should_retry); - UNSCOPED_INFO("retry header 6"); CHECK_THAT(wait_seconds, ll_test::WithinBits(25.0F, frac_bits)); policy.onFailure(500,headers_with_retry); should_retry = policy.shouldRetry(wait_seconds); - UNSCOPED_INFO("retry header 7"); CHECK_FALSE(should_retry); } @@ -262,17 +222,13 @@ TEST_CASE("retry_policy: getSecondsUntilRetryAfter parses seconds and an HTTP da std::string str1("0"); seconds_to_wait = F32_MAX; success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str1, seconds_to_wait); - UNSCOPED_INFO("parse 1"); CHECK(success); - UNSCOPED_INFO("parse 1"); CHECK(seconds_to_wait == 0.0); std::string str2("999.9"); seconds_to_wait = F32_MAX; success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str2, seconds_to_wait); - UNSCOPED_INFO("parse 2"); CHECK(success); - UNSCOPED_INFO("parse 2"); CHECK_THAT(seconds_to_wait, ll_test::WithinBits(999.9F, 8)); time_t nowseconds; @@ -281,13 +237,10 @@ TEST_CASE("retry_policy: getSecondsUntilRetryAfter parses seconds and an HTTP da seconds_to_wait = F32_MAX; success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str3, seconds_to_wait); std::cerr << " str3 [" << str3 << "]" << std::endl; - UNSCOPED_INFO("parse 3"); CHECK(success); - UNSCOPED_INFO("parse 3"); CHECK_THAT(seconds_to_wait, Catch::Matchers::WithinAbs(44.0F, 2.0F)); } -// Test retry-after field in both llmessage and CoreHttp headers. TEST_CASE("retry_policy: retry-after is honoured in both llmessage and CoreHttp headers", "[retry_policy]") { std::cerr << "7 starts" << std::endl; @@ -300,15 +253,12 @@ TEST_CASE("retry_policy: retry-after is honoured in both llmessage and CoreHttp bool should_retry; // No retry until we've failed a try. - UNSCOPED_INFO("header 0"); - REQUIRE_FALSE(policy.shouldRetry(seconds_to_wait)); + CHECK_FALSE(policy.shouldRetry(seconds_to_wait)); // no retry header, use default. policy.onFailure(500,LLSD()); should_retry = policy.shouldRetry(seconds_to_wait); - UNSCOPED_INFO("header 1"); CHECK(should_retry); - UNSCOPED_INFO("header 1"); CHECK_THAT(seconds_to_wait, ll_test::WithinBits(17.0F, 6)); // retry header should override, give delay of 0 @@ -316,9 +266,7 @@ TEST_CASE("retry_policy: retry-after is honoured in both llmessage and CoreHttp sd_headers[HTTP_IN_HEADER_RETRY_AFTER] = date_string; policy.onFailure(503,sd_headers); should_retry = policy.shouldRetry(seconds_to_wait); - UNSCOPED_INFO("header 2"); CHECK(should_retry); - UNSCOPED_INFO("header 2"); CHECK_THAT(seconds_to_wait, Catch::Matchers::WithinAbs(7.0F, 2.0F)); LLCore::HttpResponse *response; @@ -331,9 +279,7 @@ TEST_CASE("retry_policy: retry-after is honoured in both llmessage and CoreHttp headers->append(HTTP_IN_HEADER_RETRY_AFTER, std::string("600")); policy.onFailure(response); should_retry = policy.shouldRetry(seconds_to_wait); - UNSCOPED_INFO("header 3"); CHECK(should_retry); - UNSCOPED_INFO("header 3"); CHECK_THAT(seconds_to_wait, ll_test::WithinBits(600.0F, 6)); response->release(); @@ -347,24 +293,19 @@ TEST_CASE("retry_policy: retry-after is honoured in both llmessage and CoreHttp headers->append(HTTP_IN_HEADER_RETRY_AFTER,date_string); policy.onFailure(response); should_retry = policy.shouldRetry(seconds_to_wait); - UNSCOPED_INFO("header 4"); CHECK(should_retry); - UNSCOPED_INFO("header 4"); CHECK_THAT(seconds_to_wait, Catch::Matchers::WithinAbs(77.0F, 2.0F)); response->release(); // Timeout should be clamped at max. policy.onFailure(500,LLSD()); should_retry = policy.shouldRetry(seconds_to_wait); - UNSCOPED_INFO("header 5"); CHECK(should_retry); - UNSCOPED_INFO("header 5"); CHECK_THAT(seconds_to_wait, ll_test::WithinBits(644.0F, 6)); // No more retries. policy.onFailure(500,LLSD()); should_retry = policy.shouldRetry(seconds_to_wait); - UNSCOPED_INFO("header 6"); CHECK_FALSE(should_retry); } diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 273fcb0152..4c02155661 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -412,15 +412,12 @@ namespace testPump().post(response); - UNSCOPED_INFO("Success response"); CHECK(logininstance->authSuccess()); - UNSCOPED_INFO("Test Response Data"); CHECK(logininstance->getResponse().asString() == "test_data"); logininstance->disconnect(); - UNSCOPED_INFO("Called Login Module Disconnect"); - CHECK(gDisconnectCalled == true); + CHECK(gDisconnectCalled); response.clear(); response["state"] = "offline"; @@ -443,12 +440,11 @@ namespace logininstance->connect(test_uri, agentCredential); // connect should call LLLogin::connect to init gLoginURI and gLoginCreds. - UNSCOPED_INFO("Default connect uri"); CHECK(gLoginURI == "testing-uri"); UNSCOPED_INFO("Default for agree to tos"); - CHECK(gLoginCreds["params"]["agree_to_tos"].asBoolean() == false); + CHECK_FALSE(gLoginCreds["params"]["agree_to_tos"].asBoolean()); UNSCOPED_INFO("Default for read critical"); - CHECK(gLoginCreds["params"]["read_critical"].asBoolean() == false); + CHECK_FALSE(gLoginCreds["params"]["read_critical"].asBoolean()); // TOS failure response. LLSD response; @@ -472,7 +468,7 @@ namespace testPump().post(response); // Fail for tos again. gTOSReplyPump->post(true); // Accept tos, should reconnect w/ agree_to_tos. UNSCOPED_INFO("Accepted agree to tos"); - CHECK(gLoginCreds["params"]["agree_to_tos"].asBoolean() == true); + CHECK(gLoginCreds["params"]["agree_to_tos"].asBoolean()); { INFO("Incomplete login status"); REQUIRE_FALSE(logininstance->authFailure()); @@ -483,12 +479,12 @@ namespace // The new request should have reset agree to tos to default. response["data"]["reason"] = "key"; // bad creds. testPump().post(response); - UNSCOPED_INFO("TOS auth failure"); + UNSCOPED_INFO("Bad credentials, failed auth"); CHECK(logininstance->authFailure()); logininstance->connect(test_uri, agentCredential); UNSCOPED_INFO("Reset to default for agree to tos"); - CHECK(gLoginCreds["params"]["agree_to_tos"].asBoolean() == false); + CHECK_FALSE(gLoginCreds["params"]["agree_to_tos"].asBoolean()); // Critical Message failure response. logininstance->connect(test_uri, agentCredential); @@ -501,7 +497,7 @@ namespace REQUIRE(gTOSReplyPump != 0); gTOSReplyPump->post(true); UNSCOPED_INFO("Accepted read critical message"); - CHECK(gLoginCreds["params"]["read_critical"].asBoolean() == true); + CHECK(gLoginCreds["params"]["read_critical"].asBoolean()); { INFO("Incomplete login status"); REQUIRE_FALSE(logininstance->authFailure()); @@ -511,10 +507,10 @@ namespace // Fail then attempt new connection response["data"]["reason"] = "key"; // bad creds. testPump().post(response); - UNSCOPED_INFO("TOS auth failure"); + UNSCOPED_INFO("Bad credentials, failed auth"); CHECK(logininstance->authFailure()); logininstance->connect(test_uri, agentCredential); - UNSCOPED_INFO("Default for agree to tos"); - CHECK(gLoginCreds["params"]["read_critical"].asBoolean() == false); + UNSCOPED_INFO("Reset to default for read critical"); + CHECK_FALSE(gLoginCreds["params"]["read_critical"].asBoolean()); } } diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index 6c12cb68c1..76bdad4bca 100644 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -88,6 +88,7 @@ namespace CHECK(observer->mProcessed); } + // CHOP-220: a dangling observer pointer. TEST_CASE_METHOD(RemoteParcelRequestData, "LLRemoteParcelRequest: a reply after its observer is deleted does not crash", "[LLRemoteParcelRequest]") { LLRemoteParcelInfoObserver * observer = new TestObserver(); diff --git a/indra/newview/tests/llsecapi_test.cpp b/indra/newview/tests/llsecapi_test.cpp index 44e1f448fd..2697db68ee 100644 --- a/indra/newview/tests/llsecapi_test.cpp +++ b/indra/newview/tests/llsecapi_test.cpp @@ -98,32 +98,25 @@ namespace // --------------------------------------------------------------------------------------- // Test functions // --------------------------------------------------------------------------------------- - // registration TEST_CASE_METHOD(secapiTest, "LLSecAPI: getSecHandler finds registered handlers by name and no others", "[LLSecAPI]") { // retrieve an unknown handler - UNSCOPED_INFO("'Unknown' handler should be NULL"); REQUIRE(getSecHandler("unknown") == nullptr); LLPointer test1_handler = new LLSecAPIBasicHandler(); registerSecHandler("sectest1", test1_handler); - UNSCOPED_INFO("'Unknown' handler should be NULL"); REQUIRE(getSecHandler("unknown") == nullptr); LLPointer retrieved_test1_handler = getSecHandler("sectest1"); - UNSCOPED_INFO("Retrieved sectest1 handler should be the same"); CHECK(retrieved_test1_handler == test1_handler); // insert a second handler LLPointer test2_handler = new LLSecAPIBasicHandler(); registerSecHandler("sectest2", test2_handler); - UNSCOPED_INFO("'Unknown' handler should be NULL"); REQUIRE(getSecHandler("unknown") == nullptr); retrieved_test1_handler = getSecHandler("sectest1"); - UNSCOPED_INFO("Retrieved sectest1 handler should be the same"); CHECK(retrieved_test1_handler == test1_handler); LLPointer retrieved_test2_handler = getSecHandler("sectest2"); - UNSCOPED_INFO("Retrieved sectest1 handler should be the same"); CHECK(retrieved_test2_handler == test2_handler); } diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp index 819eaba5cb..34bba3d616 100644 --- a/indra/newview/tests/llsechandler_basic_test.cpp +++ b/indra/newview/tests/llsechandler_basic_test.cpp @@ -53,15 +53,18 @@ #include "../llmachineid.h" #include -#define ensure_throws(str, exc_type, cert, func, ...) \ +#define require_throws_with_cert(str, exc_type, cert, func, ...) \ try \ { \ -func(__VA_ARGS__); FAIL(("throws, " str)); \ +func(__VA_ARGS__); \ +FAIL("no exception: " str); \ } \ catch(exc_type& except) \ { \ LLSD cert_data; \ -cert->getLLSD(cert_data); UNSCOPED_INFO(("Exception cert is incorrect for " str)); REQUIRE((valueCompareLLSD(except.getCertData(), cert_data))); \ +cert->getLLSD(cert_data); \ +UNSCOPED_INFO("Exception cert is incorrect for " str); \ +REQUIRE(valueCompareLLSD(except.getCertData(), cert_data)); \ } extern bool _cert_hostname_wildcard_match(const std::string& hostname, const std::string& wildcard_string); @@ -704,7 +707,6 @@ namespace // --------------------------------------------------------------------------------------- // Test functions // --------------------------------------------------------------------------------------- - // test cert data retrieval TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: a certificate is made from PEM without throwing", "[LLSecHandler]") { try @@ -733,48 +735,30 @@ namespace //std::ostringstream llsd_value; //llsd_value << LLSDOStreamer(llsd_cert) << std::endl; LL_DEBUGS() << "test 1 cert " << llsd_cert << LL_ENDL; - UNSCOPED_INFO("Issuer Name/commonName"); CHECK((std::string)llsd_cert["issuer_name"]["commonName"] == "Integration Test Intermediate CA"); - UNSCOPED_INFO("Issuer Name/countryName"); CHECK((std::string)llsd_cert["issuer_name"]["countryName"] == "US"); - UNSCOPED_INFO("Issuer Name/state"); CHECK((std::string)llsd_cert["issuer_name"]["stateOrProvinceName"] == "California"); - UNSCOPED_INFO("Issuer Name/org name"); CHECK((std::string)llsd_cert["issuer_name"]["organizationName"] == "Linden Lab"); - UNSCOPED_INFO("Issuer Name/org unit"); CHECK((std::string)llsd_cert["issuer_name"]["organizationalUnitName"] == "Second Life Engineering"); - UNSCOPED_INFO("Issuer name string"); CHECK((std::string)llsd_cert["issuer_name_string"] == "emailAddress=noreply@lindenlab.com,CN=Integration Test Intermediate CA,OU=Second Life Engineering,O=Linden Lab,L=San Francisco,ST=California,C=US"); - UNSCOPED_INFO("subject Name/commonName"); CHECK((std::string)llsd_cert["subject_name"]["commonName"] == "Integration Test Server Cert"); - UNSCOPED_INFO("subject Name/countryName"); CHECK((std::string)llsd_cert["subject_name"]["countryName"] == "US"); - UNSCOPED_INFO("subject Name/state"); CHECK((std::string)llsd_cert["subject_name"]["stateOrProvinceName"] == "California"); - UNSCOPED_INFO("subject Name/localityName"); CHECK((std::string)llsd_cert["subject_name"]["localityName"] == "San Francisco"); - UNSCOPED_INFO("subject Name/org name"); CHECK((std::string)llsd_cert["subject_name"]["organizationName"] == "Linden Lab"); - UNSCOPED_INFO("subjectName/org unit"); CHECK((std::string)llsd_cert["subject_name"]["organizationalUnitName"] == "Second Life Engineering"); - UNSCOPED_INFO("subject name string"); CHECK((std::string)llsd_cert["subject_name_string"] == "emailAddress=noreply@lindenlab.com,CN=Integration Test Server Cert,OU=Second Life Engineering,O=Linden Lab,L=San Francisco,ST=California,C=US"); - UNSCOPED_INFO("serial number"); CHECK((std::string)llsd_cert["serial_number"] == "9E8D3413E79BF931"); - UNSCOPED_INFO("valid from"); CHECK((std::string)llsd_cert["valid_from"] == "2024-07-23T11:46:39Z"); - UNSCOPED_INFO("valid to"); CHECK((std::string)llsd_cert["valid_to"] == "2034-07-21T11:46:39Z"); LLSD expectedKeyUsage = LLSD::emptyArray(); expectedKeyUsage.append(LLSD((std::string)"digitalSignature")); expectedKeyUsage.append(LLSD((std::string)"keyEncipherment")); - UNSCOPED_INFO("key usage"); CHECK(valueCompareLLSD(llsd_cert["keyUsage"], expectedKeyUsage)); - UNSCOPED_INFO("basic constraints"); CHECK(llsd_cert["basicConstraints"]["CA"].asInteger() == 0); UNSCOPED_INFO("x509 is equal"); @@ -782,7 +766,6 @@ namespace } - // test protected data TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: protected data is kept by type and id and survives a reload", "[LLSecHandler]") { std::string protected_data = "sUSh3wj77NG9oAMyt3XIhaej3KLZhLZWFZvI6rIGmwUUOmmelrRg0NI9rkOj8ZDpTPxpwToaBT5u" @@ -821,11 +804,8 @@ namespace LLSD data = handler->getProtectedData("test_data_type", "test_data_id"); - UNSCOPED_INFO("retrieve existing data1"); CHECK((std::string)data["data1"] == "test_data_1"); - UNSCOPED_INFO("retrieve existing data2"); CHECK((std::string)data["data2"] == "test_data_2"); - UNSCOPED_INFO("retrieve existing data3"); CHECK((std::string)data["data3"]["elem1"] == "test element1"); // data storage @@ -840,30 +820,21 @@ namespace data = handler->getProtectedData("test_data_type", "test_data_id"); // verify no overwrite of existing data - UNSCOPED_INFO("verify no overwrite 1"); CHECK((std::string)data["data1"] == "test_data_1"); - UNSCOPED_INFO("verify no overwrite 2"); CHECK((std::string)data["data2"] == "test_data_2"); - UNSCOPED_INFO("verify no overwrite 3"); CHECK((std::string)data["data3"]["elem1"] == "test element1"); // verify written data is good data = handler->getProtectedData("test_data_type", "test_data_id1"); - UNSCOPED_INFO("verify stored data1"); CHECK((std::string)data["store_data1"] == "test_store_data1"); - UNSCOPED_INFO("verify stored data2"); CHECK((int)data["store_data2"] == 27); - UNSCOPED_INFO("verify stored data3"); CHECK((std::string)data["store_data3"]["subelem1"] == "test_subelem1"); // verify overwrite works handler->setProtectedData("test_data_type", "test_data_id", store_data); data = handler->getProtectedData("test_data_type", "test_data_id"); - UNSCOPED_INFO("verify overwrite stored data1"); CHECK((std::string)data["store_data1"] == "test_store_data1"); - UNSCOPED_INFO("verify overwrite stored data2"); CHECK((int)data["store_data2"] == 27); - UNSCOPED_INFO("verify overwrite stored data3"); CHECK((std::string)data["store_data3"]["subelem1"] == "test_subelem1"); // verify other datatype doesn't conflict @@ -874,17 +845,13 @@ namespace handler->setProtectedData("test_data_type1", "test_data_id", store_data); data = handler->getProtectedData("test_data_type1", "test_data_id"); - UNSCOPED_INFO("verify datatype stored data3"); CHECK((std::string)data["store_data3"] == "test_store_data3"); - UNSCOPED_INFO("verify datatype stored data4"); CHECK((int)data["store_data4"] == 28); - UNSCOPED_INFO("verify datatype stored data5"); CHECK((std::string)data["store_data5"]["subelem2"] == "test_subelem2"); // test data not found data = handler->getProtectedData("test_data_type1", "test_data_not_found"); - UNSCOPED_INFO("not found"); REQUIRE(data.isUndefined()); // cause a 'write' by using 'LLPointer' to delete then instantiate a handler @@ -893,11 +860,8 @@ namespace handler->init(); data = handler->getProtectedData("test_data_type1", "test_data_id"); - UNSCOPED_INFO("verify datatype stored data3a"); CHECK((std::string)data["store_data3"] == "test_store_data3"); - UNSCOPED_INFO("verify datatype stored data4a"); CHECK((int)data["store_data4"] == 28); - UNSCOPED_INFO("verify datatype stored data5a"); CHECK((std::string)data["store_data5"]["subelem2"] == "test_subelem2"); // rewrite the initial file to verify reloads @@ -910,25 +874,21 @@ namespace handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat"); handler->init(); data = handler->getProtectedData("test_data_type1", "test_data_id"); - UNSCOPED_INFO("not found"); REQUIRE(data.isUndefined()); handler->deleteProtectedData("test_data_type", "test_data_id"); - UNSCOPED_INFO("Deleted data not found"); REQUIRE(handler->getProtectedData("test_data_type", "test_data_id").isUndefined()); LLFile::remove("sechandler_settings.tmp"); handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat"); handler->init(); data = handler->getProtectedData("test_data_type1", "test_data_id"); - UNSCOPED_INFO("not found"); REQUIRE(data.isUndefined()); handler = NULL; CHECK(LLFile::isfile("sechandler_settings.tmp")); } - // test credenitals TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: credentials save and load and delete and fall back to legacy logins", "[LLSecHandler]") { LLPointer handler = new LLSecAPIBasicHandler("sechandler_settings.tmp", "test_password.dat"); @@ -950,7 +910,7 @@ namespace UNSCOPED_INFO("basic credential creation: authenticator"); CHECK_THAT(my_authenticator, ll_test::LLSDEquals(my_cred->getAuthenticator())); UNSCOPED_INFO("basic credential creation: grid"); - CHECK("my_grid" == my_cred->getGrid()); + CHECK(my_cred->getGrid() == "my_grid"); // test setting/overwriting of credential components my_id["first_name"] = "firstname"; @@ -964,19 +924,18 @@ namespace UNSCOPED_INFO("set credential data: authenticator"); CHECK_THAT(my_authenticator, ll_test::LLSDEquals(my_cred->getAuthenticator())); UNSCOPED_INFO("set credential data: grid"); - CHECK("my_grid" == my_cred->getGrid()); + CHECK(my_cred->getGrid() == "my_grid"); // test loading of a credential, that hasn't been saved, without // any legacy saved credential data LLPointer my_new_cred = handler->loadCredential("my_grid2"); - UNSCOPED_INFO("unknown credential load test"); - REQUIRE(my_new_cred->getIdentifier().isMap()); - UNSCOPED_INFO("unknown credential load test"); - REQUIRE_FALSE(my_new_cred->getIdentifier().has("type")); - UNSCOPED_INFO("unknown credential load test"); - REQUIRE(my_new_cred->getAuthenticator().isMap()); - UNSCOPED_INFO("unknown credential load test"); - REQUIRE_FALSE(my_new_cred->getAuthenticator().has("type")); + { + INFO("a credential never saved loads empty"); + REQUIRE(my_new_cred->getIdentifier().isMap()); + REQUIRE_FALSE(my_new_cred->getIdentifier().has("type")); + REQUIRE(my_new_cred->getAuthenticator().isMap()); + REQUIRE_FALSE(my_new_cred->getAuthenticator().has("type")); + } // test saving of a credential handler->saveCredential(my_cred, true); @@ -987,28 +946,27 @@ namespace UNSCOPED_INFO("load a known credential: authenticator"); CHECK_THAT(my_authenticator, ll_test::LLSDEquals(my_new_cred->getAuthenticator())); UNSCOPED_INFO("load a known credential: grid"); - CHECK("my_grid" == my_cred->getGrid()); + CHECK(my_cred->getGrid() == "my_grid"); // test deletion of a credential handler->deleteCredential(my_new_cred); UNSCOPED_INFO("delete credential: identifier"); REQUIRE(my_new_cred->getIdentifier().isUndefined()); - UNSCOPED_INFO("delete credentialt: authenticator"); + UNSCOPED_INFO("delete credential: authenticator"); REQUIRE(my_new_cred->getIdentifier().isUndefined()); UNSCOPED_INFO("delete credential: grid"); - CHECK("my_grid" == my_cred->getGrid()); + CHECK(my_cred->getGrid() == "my_grid"); // load unknown cred my_new_cred = handler->loadCredential("my_grid"); - UNSCOPED_INFO("deleted credential load test"); - REQUIRE(my_new_cred->getIdentifier().isMap()); - UNSCOPED_INFO("deleted credential load test"); - REQUIRE_FALSE(my_new_cred->getIdentifier().has("type")); - UNSCOPED_INFO("deleted credential load test"); - REQUIRE(my_new_cred->getAuthenticator().isMap()); - UNSCOPED_INFO("deleted credential load test"); - REQUIRE_FALSE(my_new_cred->getAuthenticator().has("type")); + { + INFO("a deleted credential loads empty"); + REQUIRE(my_new_cred->getIdentifier().isMap()); + REQUIRE_FALSE(my_new_cred->getIdentifier().has("type")); + REQUIRE(my_new_cred->getAuthenticator().isMap()); + REQUIRE_FALSE(my_new_cred->getAuthenticator().has("type")); + } // test loading of an unknown credential with legacy saved username, but without // saved password @@ -1063,13 +1021,13 @@ namespace CHECK((const std::string)my_new_cred->getIdentifier()["last_name"] == "mylastname"); LLSD legacy_authenticator = my_new_cred->getAuthenticator(); - UNSCOPED_INFO("legacy credential with password: type"); + UNSCOPED_INFO("legacy credential with password: authenticator type"); CHECK((std::string)legacy_authenticator["type"] == "hash"); UNSCOPED_INFO("legacy credential with password: algorithm"); CHECK((std::string)legacy_authenticator["algorithm"] == "md5"); - UNSCOPED_INFO("legacy credential with password: algorithm"); + UNSCOPED_INFO("legacy credential with password: secret"); CHECK((std::string)legacy_authenticator["secret"] == "01234567890123456789012345678901"); @@ -1084,19 +1042,15 @@ namespace REQUIRE(my_new_cred->getAuthenticator().isUndefined()); } - // test cert vector TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: a certificate vector adds once and iterates and inserts and finds", "[LLSecHandler]") { // validate create from empty vector LLPointer test_vector = new LLBasicCertificateVector(); - UNSCOPED_INFO("when loading with nothing, we should result in no certs in vector"); REQUIRE(test_vector->size() == 0); test_vector->add(new LLBasicCertificate(mPemTestCert, &mValidationDate)); - UNSCOPED_INFO("one element in vector"); REQUIRE(test_vector->size() == 1); test_vector->add(new LLBasicCertificate(mPemChildCert, &mValidationDate)); - UNSCOPED_INFO("two elements in vector after add"); REQUIRE(test_vector->size() == 2); // add duplicate; should be a no-op (and log at DEBUG level) @@ -1121,36 +1075,25 @@ namespace LLBasicCertificateVector::iterator current_cert = test_vector->begin(); LLBasicCertificateVector::iterator copy_current_cert = current_cert; // operator++(int) - UNSCOPED_INFO("validate iterator++ element in vector is expected cert"); CHECK(*current_cert++ == (*test_vector)[0]); - UNSCOPED_INFO("validate 2nd iterator++ element in vector is expected cert"); CHECK(*current_cert++ == (*test_vector)[1]); - UNSCOPED_INFO("validate end iterator++"); REQUIRE(current_cert == test_vector->end()); // copy - UNSCOPED_INFO("validate copy iterator element in vector is expected cert"); CHECK(*copy_current_cert == (*test_vector)[0]); // operator--(int) current_cert--; - UNSCOPED_INFO("validate iterator-- element in vector is expected cert"); CHECK(*current_cert-- == (*test_vector)[1]); - UNSCOPED_INFO("validate iterator-- element in vector is expected cert"); CHECK(*current_cert == (*test_vector)[0]); - UNSCOPED_INFO("begin iterator is equal"); CHECK(current_cert == test_vector->begin()); // operator++ - UNSCOPED_INFO("validate ++iterator element in vector is expected cert"); CHECK(*++current_cert == (*test_vector)[1]); - UNSCOPED_INFO("end of cert vector after ++iterator"); REQUIRE(++current_cert == test_vector->end()); // operator-- - UNSCOPED_INFO("validate --iterator element in vector is expected cert"); CHECK(*--current_cert == (*test_vector)[1]); - UNSCOPED_INFO("validate 2nd --iterator element in vector is expected cert"); CHECK(*--current_cert == (*test_vector)[0]); test_vector->erase(test_vector->begin()); @@ -1178,7 +1121,6 @@ namespace LLSD find_info = LLSD::emptyMap(); find_info["subjectKeyIdentifier"] = "7b:1a:f9:2b:c4:b2:f6:ae:d6:f2:8e:b1:73:fb:dd:11:ca:db:f8:87"; LLBasicCertificateVector::iterator found_cert = test_vector->find(find_info); - UNSCOPED_INFO("found some cert"); REQUIRE(found_cert != test_vector->end()); X509* found_x509 = (*found_cert).get()->getOpenSSLX509(); UNSCOPED_INFO("child cert was found"); @@ -1187,24 +1129,20 @@ namespace find_info["subjectKeyIdentifier"] = "00:00:00:00"; // bogus current_cert =test_vector->find(find_info); - UNSCOPED_INFO("didn't find cert"); REQUIRE(current_cert == test_vector->end()); } - // test cert store TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: a certificate store loads from and saves to its file", "[LLSecHandler]") { // validate load with nothing LLFile::remove("mycertstore.pem"); LLPointer test_store = new LLBasicCertificateStore("mycertstore.pem"); - UNSCOPED_INFO("when loading with nothing, we should result in no certs in store"); REQUIRE(test_store->size() == 0); // validate load with empty file test_store->save(); test_store = NULL; test_store = new LLBasicCertificateStore("mycertstore.pem"); - UNSCOPED_INFO("when loading with nothing, we should result in no certs in store"); REQUIRE(test_store->size() == 0); test_store=NULL; @@ -1214,7 +1152,6 @@ namespace certstorefile.close(); // validate loaded certs test_store = new LLBasicCertificateStore("mycertstore.pem"); - UNSCOPED_INFO("two elements in store"); REQUIRE(test_store->size() == 2); // operator[] @@ -1247,15 +1184,12 @@ namespace CHECK_FALSE(X509_cmp(test_cert, mX509TestCert)); X509_free(test_cert); current_cert++; - UNSCOPED_INFO("end of cert store"); REQUIRE(current_cert == test_store->end()); } - // cert name wildcard matching TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: hostnames match certificate names with wildcards and end periods", "[LLSecHandler]") { - UNSCOPED_INFO("simple name match"); CHECK(_cert_hostname_wildcard_match("foo", "foo")); UNSCOPED_INFO("simple name match, with end period"); @@ -1297,7 +1231,6 @@ namespace UNSCOPED_INFO("simple name match, with dual embedded wildcard"); CHECK(_cert_hostname_wildcard_match("foobar", "f*o*ar")); - UNSCOPED_INFO("simple name mismatch"); CHECK_FALSE(_cert_hostname_wildcard_match("bar", "foo")); UNSCOPED_INFO("simple name mismatch, with end period"); @@ -1339,28 +1272,21 @@ namespace UNSCOPED_INFO("match end period2"); CHECK(_cert_hostname_wildcard_match("foo.bar.com", "*.b*r.com.")); - UNSCOPED_INFO("wildcard mismatch"); CHECK_FALSE(_cert_hostname_wildcard_match("bar.com", "*.bar.com")); - UNSCOPED_INFO("wildcard match"); CHECK(_cert_hostname_wildcard_match("foo.bar.com", "*.bar.com")); - UNSCOPED_INFO("wildcard match"); CHECK(_cert_hostname_wildcard_match("foo.foo.bar.com", "*.bar.com")); - UNSCOPED_INFO("wildcard match"); CHECK(_cert_hostname_wildcard_match("foo.foo.bar.com", "*.*.com")); - UNSCOPED_INFO("wildcard mismatch"); CHECK_FALSE(_cert_hostname_wildcard_match("foo.foo.bar.com", "*.foo.com")); } - // test cert chain TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: a certificate chain follows issuers and drops unrelated certs", "[LLSecHandler]") { // validate create from empty chain LLPointer test_chain = new LLBasicCertificateChain(NULL); - UNSCOPED_INFO("when loading with nothing, we should result in no certs in chain"); REQUIRE(test_chain->size() == 0); // Single cert in the chain. @@ -1369,7 +1295,6 @@ namespace X509_STORE_CTX_set0_untrusted(test_store, sk_X509_new_null()); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - UNSCOPED_INFO("two elements in store [1]"); REQUIRE(test_chain->size() == 1); X509* test_cert = (*test_chain)[0]->getOpenSSLX509(); UNSCOPED_INFO("validate first element in store is expected cert"); @@ -1384,7 +1309,6 @@ namespace sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509IntermediateCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - UNSCOPED_INFO("two elements in store [2]"); REQUIRE(test_chain->size() == 2); test_cert = (*test_chain)[0]->getOpenSSLX509(); UNSCOPED_INFO("validate first element in store is expected cert"); @@ -1403,7 +1327,6 @@ namespace sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509TestCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - UNSCOPED_INFO("two elements in store [3]"); REQUIRE(test_chain->size() == 1); test_cert = (*test_chain)[0]->getOpenSSLX509(); UNSCOPED_INFO("validate first element in store is expected cert"); @@ -1418,7 +1341,6 @@ namespace sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509TestCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - UNSCOPED_INFO("two elements in store [4]"); REQUIRE(test_chain->size() == 2); test_cert = (*test_chain)[0]->getOpenSSLX509(); UNSCOPED_INFO("validate first element in store is expected cert"); @@ -1437,7 +1359,6 @@ namespace sk_X509_push(X509_STORE_CTX_get0_untrusted(test_store), mX509RootCert); test_chain = new LLBasicCertificateChain(test_store); X509_STORE_CTX_free(test_store); - UNSCOPED_INFO("three elements in store"); REQUIRE(test_chain->size() == 3); test_cert = (*test_chain)[0]->getOpenSSLX509(); UNSCOPED_INFO("validate first element in store is expected cert"); @@ -1449,12 +1370,11 @@ namespace X509_free(test_cert); test_cert = (*test_chain)[2]->getOpenSSLX509(); - UNSCOPED_INFO("validate second element in store is expected cert"); + UNSCOPED_INFO("validate third element in store is expected cert"); CHECK_FALSE(X509_cmp(test_cert, mX509RootCert)); X509_free(test_cert); } - // test cert validation TEST_CASE_METHOD(sechandler_basic_test, "LLSecHandler: validation needs a trusted CA and a valid date and SSL key usage", "[LLSecHandler]") { // start with a trusted store with our known root cert @@ -1489,13 +1409,13 @@ namespace // Validate with child cert but no parent, and no parent in CA store test_store = new LLBasicCertificateStore("mycertstore.pem"); - ensure_throws("no CA, with only a child cert", - LLCertValidationTrustException, - (*test_chain)[0], - test_store->validate, - VALIDATION_POLICY_TRUSTED, - test_chain, - validation_params); + require_throws_with_cert("no CA, with only a child cert", + LLCertValidationTrustException, + (*test_chain)[0], + test_store->validate, + VALIDATION_POLICY_TRUSTED, + test_chain, + validation_params); // validate without the trust flag. @@ -1505,13 +1425,13 @@ namespace test_store = new LLBasicCertificateStore("mycertstore.pem"); // append the intermediate cert test_chain->add(new LLBasicCertificate(mX509IntermediateCert, &mValidationDate)); - ensure_throws("no CA, with child and intermediate certs", - LLCertValidationTrustException, - (*test_chain)[1], - test_store->validate, - VALIDATION_POLICY_TRUSTED | VALIDATION_POLICY_TRUSTED, - test_chain, - validation_params); + require_throws_with_cert("no CA, with child and intermediate certs", + LLCertValidationTrustException, + (*test_chain)[1], + test_store->validate, + VALIDATION_POLICY_TRUSTED | VALIDATION_POLICY_TRUSTED, + test_chain, + validation_params); // validate without the trust flag test_store->validate(0, test_chain, validation_params); @@ -1529,24 +1449,24 @@ namespace validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_FROM].asDate().secondsSinceEpoch() - 1.0); // test not yet valid - ensure_throws("Child cert not yet valid" , - LLCertValidationExpirationException, - (*test_chain)[0], - test_store->validate, - VALIDATION_POLICY_TIME | VALIDATION_POLICY_TRUSTED, - test_chain, - validation_params); + require_throws_with_cert("Child cert not yet valid" , + LLCertValidationExpirationException, + (*test_chain)[0], + test_store->validate, + VALIDATION_POLICY_TIME | VALIDATION_POLICY_TRUSTED, + test_chain, + validation_params); validation_params = LLSD::emptyMap(); validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_TO].asDate().secondsSinceEpoch() + 1.0); // test cert expired - ensure_throws("Child cert expired", - LLCertValidationExpirationException, - (*test_chain)[0], - test_store->validate, - VALIDATION_POLICY_TIME | VALIDATION_POLICY_TRUSTED, - test_chain, - validation_params); + require_throws_with_cert("Child cert expired", + LLCertValidationExpirationException, + (*test_chain)[0], + test_store->validate, + VALIDATION_POLICY_TIME | VALIDATION_POLICY_TRUSTED, + test_chain, + validation_params); // test SSL KU // validate basic trust for a chain containing child and intermediate. @@ -1560,13 +1480,13 @@ namespace test_chain->add(new LLBasicCertificate(mX509TestCert, &mValidationDate)); test_store = new LLBasicCertificateStore("mycertstore.pem"); - ensure_throws("Cert doesn't have ku", - LLCertKeyUsageValidationException, - (*test_chain)[0], - test_store->validate, - VALIDATION_POLICY_SSL_KU | VALIDATION_POLICY_TRUSTED, - test_chain, - validation_params); + require_throws_with_cert("Cert doesn't have ku", + LLCertKeyUsageValidationException, + (*test_chain)[0], + test_store->validate, + VALIDATION_POLICY_SSL_KU | VALIDATION_POLICY_TRUSTED, + test_chain, + validation_params); test_store->validate(0, test_chain, validation_params); } diff --git a/indra/newview/tests/llslurl_test.cpp b/indra/newview/tests/llslurl_test.cpp index 83b04b89e2..e53340a1fc 100644 --- a/indra/newview/tests/llslurl_test.cpp +++ b/indra/newview/tests/llslurl_test.cpp @@ -195,7 +195,6 @@ namespace // --------------------------------------------------------------------------------------- // Test functions // --------------------------------------------------------------------------------------- - // construction from slurl string TEST_CASE_METHOD(slurlTest, "LLSlurl: construction from each form of SLURL string", "[LLSlurl]") { llofstream gridfile(TEST_FILENAME); @@ -211,165 +210,163 @@ namespace CHECK((int)slurl.getType() == LLSLURL::LAST_LOCATION); slurl = LLSLURL("https://slurl.com/secondlife/myregion"); - UNSCOPED_INFO("slurl.com slurl, region only - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("slurl.com slurl, region only"); - CHECK(slurl.getSLURLString() == - "https://maps.secondlife.com/secondlife/myregion/128/128/0"); + { + INFO("slurl.com slurl, region only"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://maps.secondlife.com/secondlife/myregion/128/128/0"); + } slurl = LLSLURL("https://maps.secondlife.com/secondlife/myregion/1/2/3"); - UNSCOPED_INFO("maps.secondlife.com slurl, region + coords - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("maps.secondlife.com slurl, region + coords"); - CHECK(slurl.getSLURLString() == - "https://maps.secondlife.com/secondlife/myregion/1/2/3"); + { + INFO("maps.secondlife.com slurl, region + coords"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://maps.secondlife.com/secondlife/myregion/1/2/3"); + } slurl = LLSLURL("secondlife://"); - UNSCOPED_INFO("secondlife: slurl, empty - type"); + UNSCOPED_INFO("secondlife: slurl, empty"); CHECK(slurl.getType() == LLSLURL::EMPTY); slurl = LLSLURL("secondlife:///"); - UNSCOPED_INFO("secondlife: slurl, root - type"); + UNSCOPED_INFO("secondlife: slurl, root"); CHECK(slurl.getType() == LLSLURL::EMPTY); slurl = LLSLURL("secondlife://myregion"); - UNSCOPED_INFO("secondlife: slurl, region only - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("secondlife: slurl, region only"); - CHECK(slurl.getSLURLString() == - "https://maps.secondlife.com/secondlife/myregion/128/128/0"); + { + INFO("secondlife: slurl, region only"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://maps.secondlife.com/secondlife/myregion/128/128/0"); + } slurl = LLSLURL("secondlife://myregion/1/2/3"); - UNSCOPED_INFO("secondlife: slurl, region + coords - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("secondlife slurl, region + coords"); - CHECK(slurl.getSLURLString() == - "https://maps.secondlife.com/secondlife/myregion/1/2/3"); + { + INFO("secondlife: slurl, region + coords"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://maps.secondlife.com/secondlife/myregion/1/2/3"); + } slurl = LLSLURL("/myregion"); - UNSCOPED_INFO("/region slurl, region- type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("/region slurl, region "); - CHECK(slurl.getSLURLString() == - "https://maps.secondlife.com/secondlife/myregion/128/128/0"); + { + INFO("/region slurl, region only"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://maps.secondlife.com/secondlife/myregion/128/128/0"); + } slurl = LLSLURL("/myregion/1/2/3"); - UNSCOPED_INFO("/: slurl, region + coords - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("/ slurl, region + coords"); - CHECK(slurl.getSLURLString() == - "https://maps.secondlife.com/secondlife/myregion/1/2/3"); + { + INFO("/region slurl, region + coords"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://maps.secondlife.com/secondlife/myregion/1/2/3"); + } slurl = LLSLURL("my region/1/2/3"); - UNSCOPED_INFO(" slurl, region + coords - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO(" slurl, region + coords"); - CHECK(slurl.getSLURLString() == - "https://maps.secondlife.com/secondlife/my%20region/1/2/3"); + { + INFO("bare slurl, region with a space + coords"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://maps.secondlife.com/secondlife/my%20region/1/2/3"); + } LLGridManager::getInstance()->setGridChoice("my.grid.com"); slurl = LLSLURL("https://my.grid.com/region/my%20region/1/2/3"); - UNSCOPED_INFO("grid slurl, region + coords - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("grid slurl, region + coords"); - CHECK(slurl.getSLURLString() == - "https://my.grid.com/region/my%20region/1/2/3"); + { + INFO("grid slurl, region + coords"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://my.grid.com/region/my%20region/1/2/3"); + } slurl = LLSLURL("https://my.grid.com/region/my region"); - UNSCOPED_INFO("grid slurl, region + coords - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("grid slurl, region + coords"); - CHECK(slurl.getSLURLString() == - "https://my.grid.com/region/my%20region/128/128/0"); + { + INFO("grid slurl, region only with an unescaped space"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://my.grid.com/region/my%20region/128/128/0"); + } LLGridManager::getInstance()->setGridChoice("foo.bar.com"); slurl = LLSLURL("/myregion/1/2/3"); - UNSCOPED_INFO("/: slurl, region + coords - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("/ slurl, region + coords"); - CHECK(slurl.getSLURLString() == - "https://foo.bar.com/region/myregion/1/2/3"); + { + INFO("/region slurl on foo.bar.com, region + coords"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://foo.bar.com/region/myregion/1/2/3"); + } slurl = LLSLURL("myregion/1/2/3"); - UNSCOPED_INFO(": slurl, region + coords - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO(" slurl, region + coords"); - CHECK(slurl.getSLURLString() == - "https://foo.bar.com/region/myregion/1/2/3"); + { + INFO("bare slurl on foo.bar.com, region + coords"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://foo.bar.com/region/myregion/1/2/3"); + } slurl = LLSLURL(LLSLURL::SIM_LOCATION_HOME); - UNSCOPED_INFO("home"); CHECK(slurl.getType() == LLSLURL::HOME_LOCATION); slurl = LLSLURL(LLSLURL::SIM_LOCATION_LAST); - UNSCOPED_INFO("last"); CHECK(slurl.getType() == LLSLURL::LAST_LOCATION); slurl = LLSLURL("secondlife:///app/foo/bar?12345"); - UNSCOPED_INFO("app"); - CHECK(slurl.getType() == LLSLURL::APP); - UNSCOPED_INFO("appcmd"); - CHECK(slurl.getAppCmd() == "foo"); - UNSCOPED_INFO("apppath"); - REQUIRE(slurl.getAppPath().size() == 1); - UNSCOPED_INFO("apppath2"); - CHECK(slurl.getAppPath()[0].asString() == "bar"); - UNSCOPED_INFO("appquery"); - CHECK(slurl.getAppQuery() == "12345"); - UNSCOPED_INFO("grid1"); - CHECK(slurl.getGrid() == "FooBar"); + { + INFO("app slurl naming no grid"); + CHECK(slurl.getType() == LLSLURL::APP); + CHECK(slurl.getAppCmd() == "foo"); + REQUIRE(slurl.getAppPath().size() == 1); + CHECK(slurl.getAppPath()[0].asString() == "bar"); + CHECK(slurl.getAppQuery() == "12345"); + CHECK(slurl.getGrid() == "FooBar"); + } slurl = LLSLURL("secondlife://Aditi/app/foo/bar?12345"); - UNSCOPED_INFO("app"); - CHECK(slurl.getType() == LLSLURL::APP); - UNSCOPED_INFO("appcmd"); - CHECK(slurl.getAppCmd() == "foo"); - UNSCOPED_INFO("apppath"); - REQUIRE(slurl.getAppPath().size() == 1); - UNSCOPED_INFO("apppath2"); - CHECK(slurl.getAppPath()[0].asString() == "bar"); - UNSCOPED_INFO("appquery"); - CHECK(slurl.getAppQuery() == "12345"); - UNSCOPED_INFO("grid2"); - CHECK(slurl.getGrid() == "Aditi"); + { + INFO("app slurl naming Aditi"); + CHECK(slurl.getType() == LLSLURL::APP); + CHECK(slurl.getAppCmd() == "foo"); + REQUIRE(slurl.getAppPath().size() == 1); + CHECK(slurl.getAppPath()[0].asString() == "bar"); + CHECK(slurl.getAppQuery() == "12345"); + CHECK(slurl.getGrid() == "Aditi"); + } LLGridManager::getInstance()->setGridChoice("foo.bar.com"); slurl = LLSLURL("secondlife:///secondlife/myregion/1/2/3"); - UNSCOPED_INFO("/: slurl, region + coords - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("location"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("region"); - CHECK("myregion" == slurl.getRegion()); - UNSCOPED_INFO("grid3"); - CHECK(slurl.getGrid() == "util.agni.lindenlab.com"); + { + INFO("secondlife:///secondlife/ slurl naming no grid"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK("myregion" == slurl.getRegion()); + CHECK(slurl.getGrid() == "util.agni.lindenlab.com"); + } slurl = LLSLURL("secondlife://Aditi/secondlife/myregion/1/2/3"); - UNSCOPED_INFO("/: slurl, region + coords - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("location"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("region"); - CHECK("myregion" == slurl.getRegion()); - UNSCOPED_INFO("grid4"); - CHECK(slurl.getGrid() == "Aditi"); + { + INFO("secondlife://Aditi/secondlife/ slurl"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK("myregion" == slurl.getRegion()); + CHECK(slurl.getGrid() == "Aditi"); + } LLGridManager::getInstance()->setGridChoice("my.grid.com"); slurl = LLSLURL("https://my.grid.com/app/foo/bar?12345"); - UNSCOPED_INFO("app"); - CHECK(slurl.getType() == LLSLURL::APP); - UNSCOPED_INFO("appcmd"); - CHECK(slurl.getAppCmd() == "foo"); - UNSCOPED_INFO("apppath"); - REQUIRE(slurl.getAppPath().size() == 1); - UNSCOPED_INFO("apppath2"); - CHECK(slurl.getAppPath()[0].asString() == "bar"); - UNSCOPED_INFO("appquery"); - CHECK(slurl.getAppQuery() == "12345"); + { + INFO("app slurl on my.grid.com"); + CHECK(slurl.getType() == LLSLURL::APP); + CHECK(slurl.getAppCmd() == "foo"); + REQUIRE(slurl.getAppPath().size() == 1); + CHECK(slurl.getAppPath()[0].asString() == "bar"); + CHECK(slurl.getAppQuery() == "12345"); + } } - // construction from grid/region/vector combos TEST_CASE_METHOD(slurlTest, "LLSlurl: construction from grid/region/vector combos", "[LLSlurl]") { llofstream gridfile(TEST_FILENAME); @@ -379,37 +376,41 @@ namespace LLGridManager::getInstance()->initialize(TEST_FILENAME); LLSLURL slurl = LLSLURL("my.grid.com", "my region"); - UNSCOPED_INFO("grid/region - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO("grid/region"); - CHECK(slurl.getSLURLString() == - "https://my.grid.com/region/my%20region/128/128/0"); + { + INFO("grid/region"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://my.grid.com/region/my%20region/128/128/0"); + } slurl = LLSLURL("my.grid.com", "my region", LLVector3(1,2,3)); - UNSCOPED_INFO("grid/region/vector - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO(" grid/region/vector"); - CHECK(slurl.getSLURLString() == - "https://my.grid.com/region/my%20region/1/2/3"); + { + INFO("grid/region/vector"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://my.grid.com/region/my%20region/1/2/3"); + } LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com"); slurl = LLSLURL("my region", LLVector3(1,2,3)); - UNSCOPED_INFO("default grid/region/vector - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO(" default grid/region/vector"); - CHECK(slurl.getSLURLString() == - "https://maps.secondlife.com/secondlife/my%20region/1/2/3"); + { + INFO("region/vector on the agni grid"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://maps.secondlife.com/secondlife/my%20region/1/2/3"); + } LLGridManager::getInstance()->setGridChoice("MyGrid"); slurl = LLSLURL("my region", LLVector3(1,2,3)); - UNSCOPED_INFO("default grid/region/vector - type"); - CHECK(slurl.getType() == LLSLURL::LOCATION); - UNSCOPED_INFO(" default grid/region/vector"); - CHECK(slurl.getSLURLString() == - "https://my.grid.com/region/my%20region/1/2/3"); + { + INFO("region/vector on the grid chosen by its login id"); + CHECK(slurl.getType() == LLSLURL::LOCATION); + CHECK(slurl.getSLURLString() == + "https://my.grid.com/region/my%20region/1/2/3"); + } } - // Accessors + TEST_CASE_METHOD(slurlTest, "LLSlurl: the accessors give the login and location strings and the parts", "[LLSlurl]") { llofstream gridfile(TEST_FILENAME); @@ -420,15 +421,10 @@ namespace LLGridManager::getInstance()->setGridChoice("my.grid.com"); LLSLURL slurl = LLSLURL("https://my.grid.com/region/my%20region/1/2/3"); - UNSCOPED_INFO("login string"); CHECK(slurl.getLoginString() == "uri:my region&1&2&3"); - UNSCOPED_INFO("location string"); CHECK(slurl.getLocationString() == "my region/1/2/3"); - UNSCOPED_INFO("grid"); CHECK(slurl.getGrid() == "my.grid.com"); - UNSCOPED_INFO("region"); CHECK(slurl.getRegion() == "my region"); - UNSCOPED_INFO("position"); CHECK(slurl.getPosition() == LLVector3(1, 2, 3)); } diff --git a/indra/newview/tests/lltextureinfo_test.cpp b/indra/newview/tests/lltextureinfo_test.cpp index 747ff2125c..3bbc085b68 100644 --- a/indra/newview/tests/lltextureinfo_test.cpp +++ b/indra/newview/tests/lltextureinfo_test.cpp @@ -115,27 +115,22 @@ namespace // Test the LLTextureInfo // --------------------------------------------------------------------------------------- - - // Test instantiation TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: an LLTextureInfo is made with logging on", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); - UNSCOPED_INFO("have we crashed?"); CHECK(true); } - // Check lltextureinfo does not contain UUIDs we haven't added TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: has() is false for a UUID never added", "[LLTectureInfo]") { LLTextureInfo tex_info; tex_info.setLogging(true); LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1"); - REQUIRE_FALSE(tex_info.has(nonExistant)); + CHECK_FALSE(tex_info.has(nonExistant)); } - // Check we can add a request time for a texture TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: a request start time set is read back", "[LLTectureInfo]") { LLTextureInfo tex_info; @@ -147,7 +142,6 @@ namespace CHECK(tex_info.getRequestStartTime(id) == 200); } - // Check time for non-existant texture TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: an unknown texture's request start time is 0", "[LLTectureInfo]") { LLTextureInfo tex_info; @@ -157,7 +151,6 @@ namespace CHECK(tex_info.getRequestStartTime(nonExistant) == 0); } - // Check download complete time for non existant texture TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: an unknown texture's request complete time is 0", "[LLTectureInfo]") { LLTextureInfo tex_info; @@ -167,7 +160,6 @@ namespace CHECK(tex_info.getRequestCompleteTime(nonExistant) == 0); } - // requested size is passed in correctly TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: a request size set is read back", "[LLTectureInfo]") { LLTextureInfo tex_info; @@ -179,7 +171,6 @@ namespace CHECK(tex_info.getRequestSize(id) == 600); } - // transport type is recorded correctly (http) TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: an HTTP request type is recorded", "[LLTectureInfo]") { LLTextureInfo tex_info; @@ -191,7 +182,6 @@ namespace CHECK(tex_info.getRequestType(id) == LLTextureInfoDetails::REQUEST_TYPE_HTTP); } - // transport type is recorded correctly (udp) TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: a UDP request type is recorded", "[LLTectureInfo]") { LLTextureInfo tex_info; @@ -203,7 +193,6 @@ namespace CHECK(tex_info.getRequestType(id) == LLTextureInfoDetails::REQUEST_TYPE_UDP); } - // request offset is recorded correctly TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: a request offset set is read back", "[LLTectureInfo]") { LLTextureInfo tex_info; @@ -215,7 +204,6 @@ namespace CHECK(tex_info.getRequestOffset(id) == 1234); } - // ask for averages gives us correct figure TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: getAverages gives the bit rate and bytes and transport", "[LLTectureInfo]") { SKIP("Test skipped due to use of LLTrace stats failing in test"); @@ -250,15 +238,11 @@ namespace S32 totalBytes = requestSizeOne + requestSizeTwo; LLSD results = tex_info.getAverages(); - UNSCOPED_INFO("is average bits per second correct"); CHECK(results["bits_per_second"].asInteger() == averageBitRate); - UNSCOPED_INFO("is total bytes is correct"); CHECK(results["bytes_downloaded"].asInteger() == totalBytes); - UNSCOPED_INFO("is transport correct"); CHECK(results["transport"].asString() == std::string("HTTP")); } - // make sure averages cleared when reset is called TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: resetTextureStatistics clears the averages", "[LLTectureInfo]") { LLTextureInfo tex_info; @@ -276,15 +260,11 @@ namespace tex_info.getAverages(); tex_info.resetTextureStatistics(); LLSD results = tex_info.getAverages(); - UNSCOPED_INFO("is average bits per second correct"); CHECK(results["bits_per_second"].asInteger() == 0); - UNSCOPED_INFO("is total bytes is correct"); CHECK(results["bytes_downloaded"].asInteger() == 0); - UNSCOPED_INFO("is transport correct"); CHECK(results["transport"].asString() == std::string("NONE")); } - // make sure map item removed when expired TEST_CASE_METHOD(textureinfo_test, "LLTectureInfo: a request's map entry goes once it completes", "[LLTectureInfo]") { LLTextureInfo tex_info; @@ -298,12 +278,10 @@ namespace tex_info.setRequestSize(id1, requestSizeOne); tex_info.setRequestType(id1, LLTextureInfoDetails::REQUEST_TYPE_HTTP); - UNSCOPED_INFO("map item created"); CHECK(tex_info.getTextureInfoMapSize() == 1); tex_info.setRequestCompleteTimeAndLog(id1, requestEndTimeOne); - UNSCOPED_INFO("map item removed when consumed"); CHECK(tex_info.getTextureInfoMapSize() == 0); } } diff --git a/indra/newview/tests/llversioninfo_test.cpp b/indra/newview/tests/llversioninfo_test.cpp index c7d80869b4..6bbbe6e0d7 100644 --- a/indra/newview/tests/llversioninfo_test.cpp +++ b/indra/newview/tests/llversioninfo_test.cpp @@ -81,30 +81,14 @@ namespace { std::cout << "What we parsed from CMake: " << LL_VIEWER_VERSION_BUILD << std::endl; std::cout << "What we get from llversioninfo: " << LLVersionInfo::instance().getBuild() << std::endl; - UNSCOPED_INFO("Major version"); - CHECK(LLVersionInfo::instance().getMajor() == - LL_VIEWER_VERSION_MAJOR); - UNSCOPED_INFO("Minor version"); - CHECK(LLVersionInfo::instance().getMinor() == - LL_VIEWER_VERSION_MINOR); - UNSCOPED_INFO("Patch version"); - CHECK(LLVersionInfo::instance().getPatch() == - LL_VIEWER_VERSION_PATCH); - UNSCOPED_INFO("Build version"); - CHECK(LLVersionInfo::instance().getBuild() == - LL_VIEWER_VERSION_BUILD); - UNSCOPED_INFO("Channel version"); - CHECK(LLVersionInfo::instance().getChannel() == - ll_viewer_channel); - UNSCOPED_INFO("Version String"); - CHECK(LLVersionInfo::instance().getVersion() == - mVersion); - UNSCOPED_INFO("Short Version String"); - CHECK(LLVersionInfo::instance().getShortVersion() == - mShortVersion); - UNSCOPED_INFO("Version and channel String"); - CHECK(LLVersionInfo::instance().getChannelAndVersion() == - mVersionAndChannel); + CHECK(LLVersionInfo::instance().getMajor() == LL_VIEWER_VERSION_MAJOR); + CHECK(LLVersionInfo::instance().getMinor() == LL_VIEWER_VERSION_MINOR); + CHECK(LLVersionInfo::instance().getPatch() == LL_VIEWER_VERSION_PATCH); + CHECK(LLVersionInfo::instance().getBuild() == LL_VIEWER_VERSION_BUILD); + CHECK(LLVersionInfo::instance().getChannel() == ll_viewer_channel); + CHECK(LLVersionInfo::instance().getVersion() == mVersion); + CHECK(LLVersionInfo::instance().getShortVersion() == mShortVersion); + CHECK(LLVersionInfo::instance().getChannelAndVersion() == mVersionAndChannel); // The channel is the process's: put back however this ends. struct ChannelBack @@ -113,12 +97,8 @@ namespace ~ChannelBack() { LLVersionInfo::instance().resetChannel(was); } } channel_back; LLVersionInfo::instance().resetChannel(mResetChannel); - UNSCOPED_INFO("Reset channel version"); - CHECK(LLVersionInfo::instance().getChannel() == - mResetChannel); + CHECK(LLVersionInfo::instance().getChannel() == mResetChannel); - UNSCOPED_INFO("Reset Version and channel String"); - CHECK(LLVersionInfo::instance().getChannelAndVersion() == - mResetVersionAndChannel); + CHECK(LLVersionInfo::instance().getChannelAndVersion() == mResetVersionAndChannel); } } diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index 8331445466..2c1354b94a 100644 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -285,12 +285,10 @@ namespace LLTrace::ThreadRecorder mThreadRecorder; }; - // Testing free functions without global stats allocated TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: the free functions run without global stats allocated", "[tst_viewerassetstats_test]") { // Check that helpers aren't bothered by missing global stats - UNSCOPED_INFO("Global gViewerAssetStats should be NULL"); - REQUIRE((NULL == gViewerAssetStats)); + CHECK(gViewerAssetStats == nullptr); LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE, false, false); @@ -299,16 +297,14 @@ namespace LLViewerAssetStatsFF::record_response(LLViewerAssetType::AT_GESTURE, false, false, (U64Microseconds)12300000ULL); } - // Create a non-global instance and check the structure TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: a non-global instance's LLSD has every key", "[tst_viewerassetstats_test]") { - UNSCOPED_INFO("Global gViewerAssetStats should be NULL"); - REQUIRE((NULL == gViewerAssetStats)); + CHECK(gViewerAssetStats == nullptr); LLViewerAssetStats * it = new LLViewerAssetStats(); - UNSCOPED_INFO("Global gViewerAssetStats should still be NULL"); - REQUIRE((NULL == gViewerAssetStats)); + UNSCOPED_INFO("making an instance does not make it the global"); + CHECK(gViewerAssetStats == nullptr); LLSD sd_full = it->asLLSD(false); @@ -320,9 +316,7 @@ namespace // Once the region is set, we will get a response even with no data collection it->setRegion(region1_handle); sd_full = it->asLLSD(false); - UNSCOPED_INFO("Correct single-key LLSD map root"); CHECK(is_double_key_map(sd_full, "duration", "regions")); - UNSCOPED_INFO("Correct single-slot LLSD array regions"); CHECK(is_single_slot_array(sd_full["regions"], region1_handle)); LLSD sd = sd_full["regions"][0]; @@ -332,8 +326,7 @@ namespace // Check the structure of the LLSD for (int i = 0; i < LL_ARRAY_SIZE(all_keys); ++i) { - std::string line = llformat("Has '%s' key", all_keys[i]); - UNSCOPED_INFO(line); + CAPTURE(all_keys[i]); REQUIRE(sd.has(all_keys[i])); } @@ -341,8 +334,7 @@ namespace { for (int j = 0; j < LL_ARRAY_SIZE(sub_keys); ++j) { - std::string line = llformat("Key '%s' has '%s' key", resp_keys[i], sub_keys[j]); - UNSCOPED_INFO(line); + CAPTURE(resp_keys[i], sub_keys[j]); REQUIRE(sd[resp_keys[i]].has(sub_keys[j])); } } @@ -351,36 +343,29 @@ namespace { for (int j = 0; j < LL_ARRAY_SIZE(mmm_sub_keys); ++j) { - std::string line = llformat("Key '%s' has '%s' key", mmm_resp_keys[i], mmm_sub_keys[j]); - UNSCOPED_INFO(line); + CAPTURE(mmm_resp_keys[i], mmm_sub_keys[j]); REQUIRE(sd[mmm_resp_keys[i]].has(mmm_sub_keys[j])); } } } - // Create a non-global instance and check some content TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: a new non-global instance's counts start at zero", "[tst_viewerassetstats_test]") { LLViewerAssetStats * it = new LLViewerAssetStats(); it->setRegion(region1_handle); LLSD sd = it->asLLSD(false); - UNSCOPED_INFO("Correct single-key LLSD map root"); CHECK(is_double_key_map(sd, "regions", "duration")); - UNSCOPED_INFO("Correct single-slot LLSD array regions"); CHECK(is_single_slot_array(sd["regions"], region1_handle)); sd = sd[0]; delete it; // Check a few points on the tree for content - UNSCOPED_INFO("sd[get_texture_temp_http][dequeued] is 0"); CHECK(sd["get_texture_temp_http"]["dequeued"].asInteger() == 0); - UNSCOPED_INFO("sd[get_sound_udp][resp_min] is 0"); CHECK(sd["get_sound_udp"]["resp_min"].asReal() == 0.0); } - // Create a global instance and verify free functions do something useful TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: the free functions record into a global instance and reset clears it", "[tst_viewerassetstats_test]") { gViewerAssetStats = new LLViewerAssetStats(); @@ -393,22 +378,15 @@ namespace LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_BODYPART, false, false); LLSD sd = gViewerAssetStats->asLLSD(false); - UNSCOPED_INFO("Correct single-key LLSD map root"); CHECK(is_double_key_map(sd, "regions", "duration")); - UNSCOPED_INFO("Correct single-slot LLSD array regions"); CHECK(is_single_slot_array(sd["regions"], region1_handle)); sd = sd["regions"][0]; // Check a few points on the tree for content - UNSCOPED_INFO("sd[get_texture_non_temp_udp][enqueued] is 1"); CHECK(sd["get_texture_non_temp_udp"]["enqueued"].asInteger() == 1); - UNSCOPED_INFO("sd[get_texture_temp_udp][enqueued] is 0"); CHECK(sd["get_texture_temp_udp"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd[get_texture_non_temp_http][enqueued] is 0"); CHECK(sd["get_texture_non_temp_http"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd[get_texture_temp_http][enqueued] is 0"); CHECK(sd["get_texture_temp_http"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd[get_gesture_udp][dequeued] is 0"); CHECK(sd["get_gesture_udp"]["dequeued"].asInteger() == 0); // Reset and check zeros... @@ -419,13 +397,10 @@ namespace delete gViewerAssetStats; gViewerAssetStats = NULL; - UNSCOPED_INFO("sd[get_texture_non_temp_udp][enqueued] is reset"); CHECK(sd["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd[get_gesture_udp][dequeued] is reset"); CHECK(sd["get_gesture_udp"]["dequeued"].asInteger() == 0); } - // Check multiple region collection TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: stats are collected per region across two regions", "[tst_viewerassetstats_test]") { gViewerAssetStats = new LLViewerAssetStats(); @@ -449,9 +424,7 @@ namespace // std::cout << sd << std::endl; - UNSCOPED_INFO("Correct double-key LLSD map root"); CHECK(is_double_key_map(sd, "duration", "regions")); - UNSCOPED_INFO("Correct double-slot LLSD array regions"); CHECK(is_double_slot_array(sd["regions"], region1_handle, region2_handle)); LLSD sd1 = get_region(sd, region1_handle); LLSD sd2 = get_region(sd, region2_handle); @@ -461,45 +434,32 @@ namespace REQUIRE(sd2.isMap()); // Check a few points on the tree for content - UNSCOPED_INFO("sd1[get_texture_non_temp_udp][enqueued] is 1"); CHECK(sd1["get_texture_non_temp_udp"]["enqueued"].asInteger() == 1); - UNSCOPED_INFO("sd1[get_texture_temp_udp][enqueued] is 0"); CHECK(sd1["get_texture_temp_udp"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd1[get_texture_non_temp_http][enqueued] is 0"); CHECK(sd1["get_texture_non_temp_http"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd1[get_texture_temp_http][enqueued] is 0"); CHECK(sd1["get_texture_temp_http"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd1[get_gesture_udp][dequeued] is 0"); CHECK(sd1["get_gesture_udp"]["dequeued"].asInteger() == 0); // Check a few points on the tree for content - UNSCOPED_INFO("sd2[get_gesture_udp][enqueued] is 4"); CHECK(sd2["get_gesture_udp"]["enqueued"].asInteger() == 4); - UNSCOPED_INFO("sd2[get_gesture_udp][dequeued] is 0"); CHECK(sd2["get_gesture_udp"]["dequeued"].asInteger() == 0); - UNSCOPED_INFO("sd2[get_texture_non_temp_udp][enqueued] is 0"); CHECK(sd2["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); // Reset and check zeros... // Reset leaves current region in place gViewerAssetStats->reset(); sd = gViewerAssetStats->asLLSD(false); - UNSCOPED_INFO("Correct single-key LLSD map root"); CHECK(is_double_key_map(sd, "regions", "duration")); - UNSCOPED_INFO("Correct single-slot LLSD array regions (p2)"); CHECK(is_single_slot_array(sd["regions"], region2_handle)); sd2 = sd["regions"][0]; delete gViewerAssetStats; gViewerAssetStats = NULL; - UNSCOPED_INFO("sd2[get_texture_non_temp_udp][enqueued] is reset"); CHECK(sd2["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd2[get_gesture_udp][enqueued] is reset"); CHECK(sd2["get_gesture_udp"]["enqueued"].asInteger() == 0); } - // Check multiple region collection jumping back-and-forth between regions TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: stats per region add up across moves back and forth between regions", "[tst_viewerassetstats_test]") { gViewerAssetStats = new LLViewerAssetStats(); @@ -536,9 +496,7 @@ namespace LLSD sd = gViewerAssetStats->asLLSD(false); - UNSCOPED_INFO("Correct double-key LLSD map root"); CHECK(is_double_key_map(sd, "duration", "regions")); - UNSCOPED_INFO("Correct double-slot LLSD array regions"); CHECK(is_double_slot_array(sd["regions"], region1_handle, region2_handle)); LLSD sd1 = get_region(sd, region1_handle); LLSD sd2 = get_region(sd, region2_handle); @@ -548,32 +506,22 @@ namespace REQUIRE(sd2.isMap()); // Check a few points on the tree for content - UNSCOPED_INFO("sd1[get_texture_non_temp_udp][enqueued] is 1"); CHECK(sd1["get_texture_non_temp_udp"]["enqueued"].asInteger() == 1); - UNSCOPED_INFO("sd1[get_texture_temp_udp][enqueued] is 0"); CHECK(sd1["get_texture_temp_udp"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd1[get_texture_non_temp_http][enqueued] is 0"); CHECK(sd1["get_texture_non_temp_http"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd1[get_texture_temp_http][enqueued] is 1"); CHECK(sd1["get_texture_temp_http"]["enqueued"].asInteger() == 1); - UNSCOPED_INFO("sd1[get_gesture_udp][dequeued] is 0"); CHECK(sd1["get_gesture_udp"]["dequeued"].asInteger() == 0); // Check a few points on the tree for content - UNSCOPED_INFO("sd2[get_gesture_udp][enqueued] is 8"); CHECK(sd2["get_gesture_udp"]["enqueued"].asInteger() == 8); - UNSCOPED_INFO("sd2[get_gesture_udp][dequeued] is 0"); CHECK(sd2["get_gesture_udp"]["dequeued"].asInteger() == 0); - UNSCOPED_INFO("sd2[get_texture_non_temp_udp][enqueued] is 0"); CHECK(sd2["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); // Reset and check zeros... // Reset leaves current region in place gViewerAssetStats->reset(); sd = gViewerAssetStats->asLLSD(false); - UNSCOPED_INFO("Correct single-key LLSD map root"); CHECK(is_double_key_map(sd, "duration", "regions")); - UNSCOPED_INFO("Correct single-slot LLSD array regions (p2)"); CHECK(is_single_slot_array(sd["regions"], region2_handle)); sd2 = get_region(sd, region2_handle); UNSCOPED_INFO("Region2 is present in results"); @@ -582,13 +530,10 @@ namespace delete gViewerAssetStats; gViewerAssetStats = NULL; - UNSCOPED_INFO("sd2[get_texture_non_temp_udp][enqueued] is reset"); CHECK(sd2["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd2[get_gesture_udp][enqueued] is reset"); CHECK(sd2["get_gesture_udp"]["enqueued"].asInteger() == 0); } - // Non-texture assets ignore transport and persistence flags TEST_CASE_METHOD(tst_viewerassetstats_index, "tst_viewerassetstats_test: non-texture assets ignore the transport and persistence flags", "[tst_viewerassetstats_test]") { gViewerAssetStats = new LLViewerAssetStats(); @@ -618,38 +563,26 @@ namespace LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_LSL_BYTECODE, true, true); LLSD sd = gViewerAssetStats->asLLSD(false); - UNSCOPED_INFO("Correct single-key LLSD map root"); CHECK(is_double_key_map(sd, "regions", "duration")); - UNSCOPED_INFO("Correct single-slot LLSD array regions"); CHECK(is_single_slot_array(sd["regions"], region1_handle)); sd = get_region(sd, region1_handle); UNSCOPED_INFO("Region1 is present in results"); REQUIRE(sd.isMap()); // Check a few points on the tree for content - UNSCOPED_INFO("sd[get_gesture_udp][enqueued] is 0"); CHECK(sd["get_gesture_udp"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd[get_gesture_udp][dequeued] is 0"); CHECK(sd["get_gesture_udp"]["dequeued"].asInteger() == 0); - UNSCOPED_INFO("sd[get_wearable_http][enqueued] is 2"); CHECK(sd["get_wearable_http"]["enqueued"].asInteger() == 2); - UNSCOPED_INFO("sd[get_wearable_http][dequeued] is 2"); CHECK(sd["get_wearable_http"]["dequeued"].asInteger() == 2); - UNSCOPED_INFO("sd[get_wearable_udp][enqueued] is 2"); CHECK(sd["get_wearable_udp"]["enqueued"].asInteger() == 2); - UNSCOPED_INFO("sd[get_wearable_udp][dequeued] is 2"); CHECK(sd["get_wearable_udp"]["dequeued"].asInteger() == 2); - UNSCOPED_INFO("sd[get_other_http][enqueued] is 2"); CHECK(sd["get_other_http"]["enqueued"].asInteger() == 2); - UNSCOPED_INFO("sd[get_other_http][dequeued] is 0"); CHECK(sd["get_other_http"]["dequeued"].asInteger() == 0); - UNSCOPED_INFO("sd[get_other_udp][enqueued] is 2"); CHECK(sd["get_other_udp"]["enqueued"].asInteger() == 2); - UNSCOPED_INFO("sd[get_other_udp][dequeued] is 0"); CHECK(sd["get_other_udp"]["dequeued"].asInteger() == 0); // Reset and check zeros... @@ -662,9 +595,7 @@ namespace delete gViewerAssetStats; gViewerAssetStats = NULL; - UNSCOPED_INFO("sd[get_texture_non_temp_udp][enqueued] is reset"); CHECK(sd["get_texture_non_temp_udp"]["enqueued"].asInteger() == 0); - UNSCOPED_INFO("sd[get_gesture_udp][dequeued] is reset"); CHECK(sd["get_gesture_udp"]["dequeued"].asInteger() == 0); } } diff --git a/indra/newview/tests/llviewercontrollistener_test.cpp b/indra/newview/tests/llviewercontrollistener_test.cpp index 04bf97b560..43af275f4a 100644 --- a/indra/newview/tests/llviewercontrollistener_test.cpp +++ b/indra/newview/tests/llviewercontrollistener_test.cpp @@ -31,9 +31,8 @@ *****************************************************************************/ namespace { - void ensure_contains(const std::string& msg, const std::string& substr) + void require_contains(const std::string& msg, const std::string& substr) { - UNSCOPED_INFO("Exception does not contain " + substr); REQUIRE_THAT(msg, Catch::Matchers::ContainsSubstring(substr)); } @@ -59,32 +58,32 @@ namespace { std::string threw{ catch_what( [](){ LL::CommonControl::get("Nonexistent", "Variable"); }) }; - ensure_contains(threw, "group"); - ensure_contains(threw, "Nonexistent"); + require_contains(threw, "group"); + require_contains(threw, "Nonexistent"); } TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::get of an unknown variable names the key", "[llviewercontrollistener]") { std::string threw{ catch_what( [](){ LL::CommonControl::get("FakeGlobal", "Nonexistent"); }) }; - ensure_contains(threw, "key"); - ensure_contains(threw, "Nonexistent"); + require_contains(threw, "key"); + require_contains(threw, "Nonexistent"); } TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::toggle of a string variable says it is non-boolean", "[llviewercontrollistener]") { std::string threw{ catch_what( [](){ LL::CommonControl::toggle("FakeGlobal", "strvar"); }) }; - ensure_contains(threw, "non-boolean"); - ensure_contains(threw, "strvar"); + require_contains(threw, "non-boolean"); + require_contains(threw, "strvar"); } TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::get_vars of an unknown group names the group", "[llviewercontrollistener]") { std::string threw{ catch_what( [](){ LL::CommonControl::get_vars("Nonexistent"); }) }; - ensure_contains(threw, "group"); - ensure_contains(threw, "Nonexistent"); + require_contains(threw, "group"); + require_contains(threw, "Nonexistent"); } TEST_CASE_METHOD(llviewercontrollistener_data, "llviewercontrollistener: CommonControl::get returns each variable's value", "[llviewercontrollistener]") @@ -125,14 +124,11 @@ namespace // been made -- HeadlessUI's, another test's gSavedSettings. So the // fixture's is there once, and one more group made adds its name. const std::vector groups{ LL::CommonControl::get_groups() }; - UNSCOPED_INFO("FakeGlobal"); CHECK(std::count(groups.begin(), groups.end(), "FakeGlobal") == std::ptrdiff_t(1)); { LLControlGroup another{ "FakeAnother" }; const std::vector more{ LL::CommonControl::get_groups() }; - UNSCOPED_INFO("one more"); REQUIRE(more.size() == groups.size() + 1); - UNSCOPED_INFO("FakeAnother"); CHECK(std::count(more.begin(), more.end(), "FakeAnother") == std::ptrdiff_t(1)); } UNSCOPED_INFO("one fewer once it goes"); diff --git a/indra/newview/tests/llviewernetwork_test.cpp b/indra/newview/tests/llviewernetwork_test.cpp index 85ce97a07d..db2a97725f 100644 --- a/indra/newview/tests/llviewernetwork_test.cpp +++ b/indra/newview/tests/llviewernetwork_test.cpp @@ -201,67 +201,48 @@ namespace manager->initialize(TEST_FILENAME); // validate that some of the defaults are available. std::map known_grids = manager->getKnownGrids(); - UNSCOPED_INFO("Known grids is a string-string map of size 2"); REQUIRE(known_grids.size() == 2); - UNSCOPED_INFO("Agni has the right name and label"); CHECK(known_grids[std::string("util.agni.lindenlab.com")] == std::string("Second Life Main Grid (Agni)")); - UNSCOPED_INFO("Aditi has the right name and label"); CHECK(known_grids[std::string("util.aditi.lindenlab.com")] == std::string("Second Life Beta Test Grid (Aditi)")); - UNSCOPED_INFO("name for agni"); CHECK(LLGridManager::getInstance()->getGrid("util.agni.lindenlab.com") == std::string("util.agni.lindenlab.com")); - UNSCOPED_INFO("id for agni"); CHECK(std::string("Agni") == LLGridManager::getInstance()->getGridId("util.agni.lindenlab.com")); UNSCOPED_INFO("update url base for Agni"); CHECK(std::string("https://update.secondlife.com/update") == LLGridManager::getInstance()->getUpdateServiceURL()); - UNSCOPED_INFO("label for agni"); CHECK(LLGridManager::getInstance()->getGridLabel("util.agni.lindenlab.com") == std::string("Second Life Main Grid (Agni)")); std::vector login_uris; LLGridManager::getInstance()->getLoginURIs(std::string("util.agni.lindenlab.com"), login_uris); - UNSCOPED_INFO("Number of login uris for agni"); REQUIRE(1 == login_uris.size()); - UNSCOPED_INFO("Agni login uri"); CHECK(login_uris[0] == std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi")); - UNSCOPED_INFO("Agni helper uri"); CHECK(LLGridManager::getInstance()->getHelperURI("util.agni.lindenlab.com") == std::string("https://secondlife.com/helpers/")); - UNSCOPED_INFO("Agni login page"); CHECK(LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com") == std::string("https://viewer-splash-v2.secondlife.com/")); - UNSCOPED_INFO("Agni is a system grid"); CHECK(LLGridManager::getInstance()->isSystemGrid("util.agni.lindenlab.com")); - UNSCOPED_INFO("name for aditi"); CHECK(LLGridManager::getInstance()->getGrid("util.aditi.lindenlab.com") == std::string("util.aditi.lindenlab.com")); - UNSCOPED_INFO("id for aditi"); CHECK(LLGridManager::getInstance()->getGridId("util.aditi.lindenlab.com") == std::string("Aditi")); - UNSCOPED_INFO("label for aditi"); CHECK(LLGridManager::getInstance()->getGridLabel("util.aditi.lindenlab.com") == std::string("Second Life Beta Test Grid (Aditi)")); LLGridManager::getInstance()->getLoginURIs(std::string("util.aditi.lindenlab.com"), login_uris); - UNSCOPED_INFO("Number of login uris for aditi"); REQUIRE(1 == login_uris.size()); - UNSCOPED_INFO("Aditi login uri"); CHECK(login_uris[0] == std::string("https://login.aditi.lindenlab.com/cgi-bin/login.cgi")); - UNSCOPED_INFO("Aditi helper uri"); CHECK(LLGridManager::getInstance()->getHelperURI("util.aditi.lindenlab.com") == std::string("https://secondlife.aditi.lindenlab.com/helpers/")); - UNSCOPED_INFO("Aditi login page"); CHECK(LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com") == std::string("https://viewer-splash-v2.secondlife.com/")); - UNSCOPED_INFO("Aditi is a system grid"); CHECK(LLGridManager::getInstance()->isSystemGrid("util.aditi.lindenlab.com")); } @@ -275,124 +256,89 @@ namespace LLGridManager::getInstance()->initialize(TEST_FILENAME); std::map known_grids = LLGridManager::getInstance()->getKnownGrids(); UNSCOPED_INFO("adding a grid via a grid file increases known grid size"); - REQUIRE(4 == - known_grids.size()); + REQUIRE(4 == known_grids.size()); // Verify that Agni and Aditi were not overwritten - UNSCOPED_INFO("Agni has the right name and label"); CHECK(known_grids[std::string("util.agni.lindenlab.com")] == std::string("Second Life Main Grid (Agni)")); - UNSCOPED_INFO("Aditi has the right name and label"); CHECK(known_grids[std::string("util.aditi.lindenlab.com")] == std::string("Second Life Beta Test Grid (Aditi)")); - UNSCOPED_INFO("name for agni"); CHECK(LLGridManager::getInstance()->getGrid("util.agni.lindenlab.com") == std::string("util.agni.lindenlab.com")); - UNSCOPED_INFO("id for agni"); CHECK(LLGridManager::getInstance()->getGridId("util.agni.lindenlab.com") == std::string("Agni")); UNSCOPED_INFO("update url base for Agni"); CHECK(std::string("https://update.secondlife.com/update") == LLGridManager::getInstance()->getUpdateServiceURL()); - UNSCOPED_INFO("label for agni"); CHECK(LLGridManager::getInstance()->getGridLabel("util.agni.lindenlab.com") == std::string("Second Life Main Grid (Agni)")); std::vector login_uris; LLGridManager::getInstance()->getLoginURIs(std::string("util.agni.lindenlab.com"), login_uris); - UNSCOPED_INFO("Number of login uris for agni"); REQUIRE(1 == login_uris.size()); - UNSCOPED_INFO("Agni login uri"); CHECK(login_uris[0] == std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi")); - UNSCOPED_INFO("Agni helper uri"); CHECK(LLGridManager::getInstance()->getHelperURI("util.agni.lindenlab.com") == std::string("https://secondlife.com/helpers/")); - UNSCOPED_INFO("Agni login page"); CHECK(LLGridManager::getInstance()->getLoginPage("util.agni.lindenlab.com") == std::string("https://viewer-splash-v2.secondlife.com/")); - UNSCOPED_INFO("Agni is a system grid"); CHECK(LLGridManager::getInstance()->isSystemGrid("util.agni.lindenlab.com")); - UNSCOPED_INFO("name for aditi"); CHECK(LLGridManager::getInstance()->getGrid("util.aditi.lindenlab.com") == std::string("util.aditi.lindenlab.com")); - UNSCOPED_INFO("id for aditi"); CHECK(LLGridManager::getInstance()->getGridId("util.aditi.lindenlab.com") == std::string("Aditi")); - UNSCOPED_INFO("label for aditi"); CHECK(LLGridManager::getInstance()->getGridLabel("util.aditi.lindenlab.com") == std::string("Second Life Beta Test Grid (Aditi)")); LLGridManager::getInstance()->getLoginURIs(std::string("util.aditi.lindenlab.com"), login_uris); - UNSCOPED_INFO("Number of login uris for aditi"); REQUIRE(1 == login_uris.size()); - UNSCOPED_INFO("Aditi login uri"); CHECK(login_uris[0] == std::string("https://login.aditi.lindenlab.com/cgi-bin/login.cgi")); - UNSCOPED_INFO("Aditi helper uri"); CHECK(LLGridManager::getInstance()->getHelperURI("util.aditi.lindenlab.com") == std::string("https://secondlife.aditi.lindenlab.com/helpers/")); - UNSCOPED_INFO("Aditi login page"); CHECK(LLGridManager::getInstance()->getLoginPage("util.aditi.lindenlab.com") == std::string("https://viewer-splash-v2.secondlife.com/")); - UNSCOPED_INFO("Aditi is a system grid"); CHECK(LLGridManager::getInstance()->isSystemGrid("util.aditi.lindenlab.com")); // Check the additional grid from the file UNSCOPED_INFO("alternative grid is in name<->label map"); CHECK(known_grids["altgrid.long.name"] == std::string("Alternative Grid")); - UNSCOPED_INFO("alternative grid name is set"); CHECK(LLGridManager::getInstance()->getGrid("altgrid.long.name") == std::string("altgrid.long.name")); - UNSCOPED_INFO("alternative grid id"); CHECK(LLGridManager::getInstance()->getGridId("altgrid.long.name") == std::string("AltGrid")); - UNSCOPED_INFO("alternative grid label"); CHECK(LLGridManager::getInstance()->getGridLabel("altgrid.long.name") == std::string("Alternative Grid")); std::vector alt_login_uris; LLGridManager::getInstance()->getLoginURIs(std::string("altgrid.long.name"), alt_login_uris); - UNSCOPED_INFO("Number of login uris for altgrid"); REQUIRE(2 == alt_login_uris.size()); - UNSCOPED_INFO("alternative grid first login uri"); CHECK(alt_login_uris[0] == std::string("altgrid/myloginuri1")); - UNSCOPED_INFO("alternative grid second login uri"); CHECK(alt_login_uris[1] == std::string("altgrid/myloginuri2")); - UNSCOPED_INFO("alternative grid helper uri"); CHECK(LLGridManager::getInstance()->getHelperURI("altgrid.long.name") == std::string("https://helper1/helpers/")); - UNSCOPED_INFO("alternative grid login page"); CHECK(LLGridManager::getInstance()->getLoginPage("altgrid.long.name") == std::string("altgrid/loginpage")); - UNSCOPED_INFO("alternative grid is NOT a system grid"); CHECK_FALSE(LLGridManager::getInstance()->isSystemGrid("altgrid.long.name")); UNSCOPED_INFO("minimal grid is in name<->label map"); CHECK(known_grids["minimal.long.name"] == std::string("minimal.long.name")); - UNSCOPED_INFO("minimal grid name is set"); CHECK(LLGridManager::getInstance()->getGrid("minimal.long.name") == std::string("minimal.long.name")); - UNSCOPED_INFO("minimal grid id"); CHECK(LLGridManager::getInstance()->getGridId("minimal.long.name") == std::string("minimal.long.name")); - UNSCOPED_INFO("minimal grid label"); CHECK(LLGridManager::getInstance()->getGridLabel("minimal.long.name") == std::string("minimal.long.name")); LLGridManager::getInstance()->getLoginURIs(std::string("minimal.long.name"), alt_login_uris); - UNSCOPED_INFO("Number of login uris for altgrid"); REQUIRE(1 == alt_login_uris.size()); - UNSCOPED_INFO("minimal grid login uri"); CHECK(alt_login_uris[0] == std::string("https://minimal.long.name/cgi-bin/login.cgi")); - UNSCOPED_INFO("minimal grid helper uri"); CHECK(LLGridManager::getInstance()->getHelperURI("minimal.long.name") == std::string("https://minimal.long.name/helpers/")); - UNSCOPED_INFO("minimal grid login page"); CHECK(LLGridManager::getInstance()->getLoginPage("minimal.long.name") == std::string("https://minimal.long.name/app/login/")); @@ -410,39 +356,30 @@ namespace LLGridManager::getInstance()->initialize(TEST_FILENAME); LLGridManager::getInstance()->setGridChoice("util.agni.lindenlab.com"); - UNSCOPED_INFO("getGridLabel"); CHECK(LLGridManager::getInstance()->getGridLabel() == std::string("Second Life Main Grid (Agni)")); - UNSCOPED_INFO("getGridId"); CHECK(LLGridManager::getInstance()->getGridId() == std::string("Agni")); - UNSCOPED_INFO("getGrid"); CHECK(LLGridManager::getInstance()->getGrid() == std::string("util.agni.lindenlab.com")); - UNSCOPED_INFO("getHelperURI"); CHECK(LLGridManager::getInstance()->getHelperURI() == std::string("https://secondlife.com/helpers/")); - UNSCOPED_INFO("getLoginPage"); CHECK(LLGridManager::getInstance()->getLoginPage() == std::string("https://viewer-splash-v2.secondlife.com/")); UNSCOPED_INFO("update url base for Agni"); CHECK(std::string("https://update.secondlife.com/update") == LLGridManager::getInstance()->getUpdateServiceURL()); - UNSCOPED_INFO("Is Agni a production grid"); + UNSCOPED_INFO("Agni is a production grid"); CHECK(LLGridManager::getInstance()->isInProductionGrid()); std::vector uris; LLGridManager::getInstance()->getLoginURIs(uris); - UNSCOPED_INFO("getLoginURIs size"); REQUIRE(1 == uris.size()); - UNSCOPED_INFO("getLoginURIs"); CHECK(uris[0] == std::string("https://login.agni.lindenlab.com/cgi-bin/login.cgi")); LLGridManager::getInstance()->setGridChoice("altgrid.long.name"); - UNSCOPED_INFO("getGridLabel"); CHECK(LLGridManager::getInstance()->getGridLabel() == std::string("Alternative Grid")); - UNSCOPED_INFO("getGridId"); CHECK(LLGridManager::getInstance()->getGridId() == std::string("AltGrid")); UNSCOPED_INFO("alternative grid is not a system grid"); diff --git a/indra/newview/tests/llvocache_test.cpp b/indra/newview/tests/llvocache_test.cpp index dffaff231b..d1c4fb8856 100644 --- a/indra/newview/tests/llvocache_test.cpp +++ b/indra/newview/tests/llvocache_test.cpp @@ -145,11 +145,9 @@ namespace return entries; } - static void ensureSameEntry(const LLVOCacheEntry& expected, const LLVOCacheEntry& actual) + static void requireSameEntry(const LLVOCacheEntry& expected, const LLVOCacheEntry& actual) { - UNSCOPED_INFO("crc"); REQUIRE(actual.getCRC() == expected.getCRC()); - UNSCOPED_INFO("hit count"); REQUIRE(actual.getHitCount() == expected.getHitCount()); const LLDataPackerBinaryBuffer* a = expected.getDP(); const LLDataPackerBinaryBuffer* b = actual.getDP(); @@ -158,7 +156,6 @@ namespace REQUIRE(a); REQUIRE(b); } - UNSCOPED_INFO("body size"); REQUIRE(b->getBufferSize() == a->getBufferSize()); UNSCOPED_INFO("body bytes"); REQUIRE(memcmp(a->getBuffer(), b->getBuffer(), (size_t)a->getBufferSize()) == 0); @@ -190,7 +187,7 @@ namespace return data; } - static LLGLTFOverrideCacheEntry makeOverride(U32 local_id, U64 handle, int sides) + static LLGLTFOverrideCacheEntry requireOverride(U32 local_id, U64 handle, int sides) { LLGLTFOverrideCacheEntry entry; UNSCOPED_INFO("override parses"); @@ -265,22 +262,18 @@ namespace LLVOCache::instance().initCache(LL_PATH_CACHE, CACHE_NUMBER_OF_REGIONS, CACHE_VERSION); } - static void ensureSameOverride(const LLGLTFOverrideCacheEntry& expected, const LLGLTFOverrideCacheEntry& actual) + static void requireSameOverride(const LLGLTFOverrideCacheEntry& expected, const LLGLTFOverrideCacheEntry& actual) { - UNSCOPED_INFO("object id"); REQUIRE(actual.mObjectId == expected.mObjectId); - UNSCOPED_INFO("local id"); REQUIRE(actual.mLocalId == expected.mLocalId); - UNSCOPED_INFO("region handle"); REQUIRE(actual.mRegionHandle == expected.mRegionHandle); - UNSCOPED_INFO("side count"); REQUIRE(actual.mSides.size() == expected.mSides.size()); for (const auto& [side, llsd] : expected.mSides) { + CAPTURE(side); auto found = actual.mSides.find(side); UNSCOPED_INFO("side present"); REQUIRE(found != actual.mSides.end()); - UNSCOPED_INFO("side llsd"); REQUIRE(llsd_equals(found->second, llsd)); } } @@ -297,18 +290,13 @@ namespace LLSD data = makeOverrideLLSD(42, handle, object_id, 3); LLGLTFOverrideCacheEntry entry; - UNSCOPED_INFO("fromLLSD"); REQUIRE(entry.fromLLSD(data)); - UNSCOPED_INFO("object id"); CHECK(entry.mObjectId == object_id); - UNSCOPED_INFO("local id"); CHECK(entry.mLocalId == 42u); - UNSCOPED_INFO("region handle"); CHECK(entry.mRegionHandle == handle); - UNSCOPED_INFO("sides"); REQUIRE(entry.mSides.size() == (size_t)3); UNSCOPED_INFO("materials not built by loading"); - REQUIRE(entry.mGLTFMaterial.empty()); + CHECK(entry.mGLTFMaterial.empty()); // toLLSD walks a hash map, so compare per side rather than as arrays. LLSD back = entry.toLLSD(); @@ -325,6 +313,7 @@ namespace for (size_t i = 0; i < back["sides"].size(); ++i) { S32 side = back["sides"][i].asInteger(); + CAPTURE(side); UNSCOPED_INFO("side llsd survives"); REQUIRE(llsd_equals(back["gltf_llsd"][i], data["gltf_llsd"][side])); } @@ -334,6 +323,7 @@ namespace REQUIRE(entry.mGLTFMaterial.size() == entry.mSides.size()); for (const auto& [side, llsd] : entry.mSides) { + CAPTURE(side); UNSCOPED_INFO("material for side"); REQUIRE(entry.mGLTFMaterial.find(side) != entry.mGLTFMaterial.end()); UNSCOPED_INFO("material built"); @@ -348,7 +338,7 @@ namespace LLSD headless = data; headless.erase("region_handle_x"); UNSCOPED_INFO("no region handle is rejected"); - REQUIRE_FALSE(rejected.fromLLSD(headless)); + CHECK_FALSE(rejected.fromLLSD(headless)); headless = data; headless.erase("local_id"); UNSCOPED_INFO("no local id is rejected"); @@ -372,17 +362,18 @@ namespace REQUIRE(read.size() == written.size()); for (const auto& [local_id, entry] : written) { + CAPTURE(local_id); auto found = read.find(local_id); UNSCOPED_INFO("entry present"); REQUIRE(found != read.end()); - ensureSameEntry(*entry, *found->second); + requireSameEntry(*entry, *found->second); } LLVOCacheEntry::vocache_entry_map_t other; UNSCOPED_INFO("another region's id is refused"); - REQUIRE_FALSE(LLVOCache::instance().readFromCache(handle, LLUUID::generateNewID(), other)); + CHECK_FALSE(LLVOCache::instance().readFromCache(handle, LLUUID::generateNewID(), other)); UNSCOPED_INFO("nothing loaded for it"); - REQUIRE(other.empty()); + CHECK(other.empty()); } TEST_CASE_METHOD(vocacheTest, "LLVOCache: a save with removal enabled counts only what it wrote", "[LLVOCache]") @@ -426,9 +417,9 @@ namespace LLVOCacheEntry::vocache_entry_map_t read; UNSCOPED_INFO("truncated file fails the read"); - REQUIRE_FALSE(LLVOCache::instance().readFromCache(handle, id, read)); + CHECK_FALSE(LLVOCache::instance().readFromCache(handle, id, read)); UNSCOPED_INFO("fewer entries than written"); - REQUIRE(read.size() < written.size()); + CHECK(read.size() < written.size()); } TEST_CASE_METHOD(vocacheTest, "LLVOCache: the header survives a restart", "[LLVOCache]") @@ -446,7 +437,7 @@ namespace UNSCOPED_INFO("region known after restart"); REQUIRE(LLVOCache::instance().readFromCache(handle, id, read)); UNSCOPED_INFO("entries after restart"); - REQUIRE(read.size() == written.size()); + CHECK(read.size() == written.size()); } TEST_CASE_METHOD(vocacheTest, "LLVOCache: the override cache round-trips and drops overrides with no object", "[LLVOCache]") @@ -459,10 +450,10 @@ namespace LLVOCacheEntry::vocache_gltf_overrides_map_t written; for (U32 local_id = 1; local_id <= 20; local_id += 3) { - written[local_id] = makeOverride(local_id, handle, 1 + (int)(local_id % 4)); + written[local_id] = requireOverride(local_id, handle, 1 + (int)(local_id % 4)); } // An override for an object the primary cache does not hold is dropped on load. - written[999] = makeOverride(999, handle, 2); + written[999] = requireOverride(999, handle, 2); LLVOCache::instance().writeGenericExtrasToCache(handle, id, written, true, false); UNSCOPED_INFO("extras file written"); @@ -472,12 +463,13 @@ namespace UNSCOPED_INFO("read succeeds"); REQUIRE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, read, objects)); UNSCOPED_INFO("all overrides with an object came back"); - REQUIRE(read.size() == written.size() - 1); + CHECK(read.size() == written.size() - 1); UNSCOPED_INFO("orphan override dropped"); - REQUIRE(read.find(999) == read.end()); + CHECK(read.find(999) == read.end()); for (const auto& [local_id, entry] : read) { - ensureSameOverride(written.at(local_id), entry); + CAPTURE(local_id); + requireSameOverride(written.at(local_id), entry); UNSCOPED_INFO("materials not built by loading"); REQUIRE(entry.mGLTFMaterial.empty()); } @@ -485,9 +477,9 @@ namespace LLVOCacheEntry::vocache_gltf_overrides_map_t none; LLVOCacheEntry::vocache_entry_map_t no_objects; UNSCOPED_INFO("empty primary cache is not a failure"); - REQUIRE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, none, no_objects)); + CHECK(LLVOCache::instance().readGenericExtrasFromCache(handle, id, none, no_objects)); UNSCOPED_INFO("and loads nothing"); - REQUIRE(none.empty()); + CHECK(none.empty()); } TEST_CASE_METHOD(vocacheTest, "LLVOCache: a corrupt override record is skipped and a truncated file refused", "[LLVOCache]") @@ -500,7 +492,7 @@ namespace LLVOCacheEntry::vocache_gltf_overrides_map_t written; for (U32 local_id = 1; local_id <= 10; ++local_id) { - written[local_id] = makeOverride(local_id, handle, 2); + written[local_id] = requireOverride(local_id, handle, 2); } LLVOCache::instance().writeGenericExtrasToCache(handle, id, written, true, false); @@ -541,10 +533,11 @@ namespace UNSCOPED_INFO("corrupt record does not fail the file"); REQUIRE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, read, objects)); UNSCOPED_INFO("one record skipped"); - REQUIRE(read.size() == written.size() - 1); + CHECK(read.size() == written.size() - 1); for (const auto& [local_id, entry] : read) { - ensureSameOverride(written.at(local_id), entry); + CAPTURE(local_id); + requireSameOverride(written.at(local_id), entry); } // Cut the last record short. @@ -563,9 +556,9 @@ namespace } LLVOCacheEntry::vocache_gltf_overrides_map_t old; UNSCOPED_INFO("old version is refused"); - REQUIRE_FALSE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, old, objects)); + CHECK_FALSE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, old, objects)); UNSCOPED_INFO("old version loads nothing"); - REQUIRE(old.empty()); + CHECK(old.empty()); } TEST_CASE_METHOD(vocacheTest, "LLVOCache: memoryAdjustFactor bounds follow RAM and stay under the heap cap", "[LLVOCache]") @@ -608,6 +601,7 @@ namespace for (F32 allocated : { 0.f, 2000.f, 2500.f, 3000.f, 4000.f }) { const F32 f = factor(allocated, 0.f, no_cap, 3000.f, 2048.f); + CAPTURE(allocated); { INFO("inverted settings still give a factor in [0, 1]"); REQUIRE(f >= 0.f); @@ -651,9 +645,9 @@ namespace UNSCOPED_INFO("a file with one bad record is still a cache"); REQUIRE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, overrides, objects)); UNSCOPED_INFO("the shallow record loaded, the deep one did not"); - REQUIRE(overrides.size() == 1u); + CHECK(overrides.size() == 1u); UNSCOPED_INFO("it is the shallow one"); - REQUIRE(overrides.find(1) != overrides.end()); + CHECK(overrides.find(1) != overrides.end()); // up to the budget, unreadable records are skipped; past it the file is refused std::vector garbage(16, std::string("\xff\xfe\xfd\xfc", 4)); @@ -663,7 +657,7 @@ namespace UNSCOPED_INFO("sixteen unreadable records are within the budget"); CHECK(LLVOCache::instance().readGenericExtrasFromCache(handle, id, overrides, objects)); UNSCOPED_INFO("and the good record after them loaded"); - REQUIRE(overrides.size() == 1u); + CHECK(overrides.size() == 1u); garbage.insert(garbage.begin(), std::string("\xff\xfe\xfd\xfc", 4)); writeExtrasFile(handle, id, garbage); @@ -678,15 +672,15 @@ namespace UNSCOPED_INFO("the record still parses"); REQUIRE(entry.fromLLSD(faces)); UNSCOPED_INFO("only the face in range is kept"); - REQUIRE(entry.mSides.size() == 1u); + CHECK(entry.mSides.size() == 1u); UNSCOPED_INFO("and it is face 0"); - REQUIRE(entry.mSides.find(0) != entry.mSides.end()); + CHECK(entry.mSides.find(0) != entry.mSides.end()); faces["sides"][1] = -1; LLGLTFOverrideCacheEntry negative; UNSCOPED_INFO("a negative face parses"); REQUIRE(negative.fromLLSD(faces)); UNSCOPED_INFO("and is dropped too"); - REQUIRE(negative.mSides.size() == 1u); + CHECK(negative.mSides.size() == 1u); } TEST_CASE_METHOD(vocacheTest, "LLVOCache: header slots survive a removal followed by a crash", "[LLVOCache]") @@ -714,7 +708,7 @@ namespace CHECK(LLVOCache::instance().getCacheEntries() == 3u); LLVOCacheEntry::vocache_entry_map_t read; UNSCOPED_INFO("the first region is still there"); - REQUIRE(LLVOCache::instance().readFromCache(first, id, read)); + CHECK(LLVOCache::instance().readFromCache(first, id, read)); read.clear(); UNSCOPED_INFO("the third region was not overwritten"); CHECK(LLVOCache::instance().readFromCache(third, id, read)); @@ -731,8 +725,8 @@ namespace LLVOCache::instance().writeToCache(handle, id, objects, true, false); LLVOCacheEntry::vocache_gltf_overrides_map_t overrides; - overrides[1] = makeOverride(1, handle, 2); - overrides[2] = makeOverride(2, handle, 3); + overrides[1] = requireOverride(1, handle, 2); + overrides[2] = requireOverride(2, handle, 3); LLVOCache::instance().writeGenericExtrasToCache(handle, id, overrides, true, false); // a save with nothing dirty leaves the file as it was, whatever it is handed @@ -744,8 +738,8 @@ namespace REQUIRE(LLVOCache::instance().readGenericExtrasFromCache(handle, id, read, objects)); UNSCOPED_INFO("and still holds both overrides"); REQUIRE(read.size() == 2u); - ensureSameOverride(overrides[1], read[1]); - ensureSameOverride(overrides[2], read[2]); + requireSameOverride(overrides[1], read[1]); + requireSameOverride(overrides[2], read[2]); } TEST_CASE_METHOD(vocacheTest, "LLVOCache: staysInMemory keeps entries seen lately or inside the rear sphere", "[LLVOCache]") @@ -864,6 +858,7 @@ namespace for (F32 rear_far : rear_radii) { const F32 radius = evict(rear_far); + CAPTURE(rear_far); UNSCOPED_INFO("the eviction radius clears the load radius"); REQUIRE(radius >= rear_far * 1.25f); UNSCOPED_INFO("and never reaches inside SceneLoadMinRadius"); @@ -889,6 +884,7 @@ namespace // it has been out of sight. Turning around cannot cross both at once. for (F32 rear_far : rear_radii) { + CAPTURE(rear_far); LLVOCacheEntry::VisibilityFacts facts; facts.mCurrentFrame = 5000; facts.mEntryVisibleFrame = 0; diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp index 49905cf720..76a04d4e8f 100644 --- a/indra/newview/tests/llworldmap_test.cpp +++ b/indra/newview/tests/llworldmap_test.cpp @@ -174,33 +174,26 @@ namespace { // Test 1 : setCount() / getCount() mItem->setCount(10); - UNSCOPED_INFO("LLItemInfo::setCount() test failed"); CHECK(mItem->getCount() == 10); // Test 2 : setTooltip() / getToolTip() std::string tooltip = TOOLTIP_TEST; mItem->setTooltip(tooltip); - UNSCOPED_INFO("LLItemInfo::setTooltip() test failed"); CHECK(mItem->getToolTip() == TOOLTIP_TEST); // Test 3 : setElevation() / getGlobalPosition() mItem->setElevation(Z_WORLD_TEST); LLVector3d pos = mItem->getGlobalPosition(); LLVector3d ref(X_WORLD_TEST, Y_WORLD_TEST, Z_WORLD_TEST); - UNSCOPED_INFO("LLItemInfo::getGlobalPosition() test failed"); CHECK(pos == ref); // Test 4 : getName() std::string name = mItem->getName(); - UNSCOPED_INFO("LLItemInfo::getName() test failed"); CHECK(name == ITEM_NAME_TEST); // Test 5 : isName() - UNSCOPED_INFO("LLItemInfo::isName() test failed"); CHECK(mItem->isName(name)); // Test 6 : getUUID() LLUUID id; - UNSCOPED_INFO("LLItemInfo::getUUID() test failed"); CHECK(mItem->getUUID() == id); // Test 7 : getRegionHandle() U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST); - UNSCOPED_INFO("LLItemInfo::getRegionHandle() test failed"); CHECK(mItem->getRegionHandle() == handle); } // --------------------------------------------------------------------------------------- @@ -212,56 +205,48 @@ namespace // Test 1 : setName() / getName() std::string name = SIM_NAME_TEST; mSim->setName(name); - UNSCOPED_INFO("LLSimInfo::setName() test failed"); CHECK(mSim->getName() == SIM_NAME_TEST); // Test 2 : isName() - UNSCOPED_INFO("LLSimInfo::isName() test failed"); CHECK(mSim->isName(name)); // Test 3 : getGlobalPos() LLVector3 local; LLVector3d ref(X_WORLD_TEST, Y_WORLD_TEST, 0.0f); LLVector3d pos = mSim->getGlobalPos(local); - UNSCOPED_INFO("LLSimInfo::getGlobalPos() test failed"); CHECK(pos == ref); // Test 4 : getGlobalOrigin() pos = mSim->getGlobalOrigin(); - UNSCOPED_INFO("LLSimInfo::getGlobalOrigin() test failed"); CHECK(pos == ref); // Test 5 : clearImage() try { mSim->clearImage(); } catch (...) { - FAIL("LLSimInfo::clearImage() test failed"); + FAIL("LLSimInfo::clearImage() threw"); } // Test 6 : dropImagePriority() try { mSim->dropImagePriority(); } catch (...) { - FAIL("LLSimInfo::dropImagePriority() test failed"); + FAIL("LLSimInfo::dropImagePriority() threw"); } // Test 7 : updateAgentCount() try { mSim->updateAgentCount(0.0f); } catch (...) { - FAIL("LLSimInfo::updateAgentCount() test failed"); + FAIL("LLSimInfo::updateAgentCount() threw"); } // Test 8 : getAgentCount() S32 agents = mSim->getAgentCount(); - UNSCOPED_INFO("LLSimInfo::getAgentCount() test failed"); CHECK(agents == 0); // Test 9 : setLandForSaleImage() / getLandForSaleImage() LLUUID id; mSim->setLandForSaleImage(id); LLPointer image = mSim->getLandForSaleImage(); - UNSCOPED_INFO("LLSimInfo::getLandForSaleImage() test failed"); REQUIRE(image.isNull()); // Test 10 : isPG() mSim->setAccess(SIM_ACCESS_PG); - UNSCOPED_INFO("LLSimInfo::isPG() test failed"); CHECK(mSim->isPG()); // Test 11 : isDown() mSim->setAccess(SIM_ACCESS_DOWN); - UNSCOPED_INFO("LLSimInfo::isDown() test failed"); CHECK(mSim->isDown()); // Test 12 : Access strings can't be accessed from unit test... //ensure("LLSimInfo::getAccessString() test failed", mSim->getAccessString() == "Offline"); @@ -276,28 +261,28 @@ namespace try { mSim->clearItems(); } catch (...) { - FAIL("LLSimInfo::clearItems() at init test failed"); + FAIL("LLSimInfo::clearItems() threw at init"); } // Test 15 : Verify that all the lists are empty LLSimInfo::item_info_list_t list; list = mSim->getTeleHub(); - UNSCOPED_INFO("LLSimInfo::getTeleHub() empty at init test failed"); + UNSCOPED_INFO("telehubs"); REQUIRE(list.empty()); list = mSim->getInfoHub(); - UNSCOPED_INFO("LLSimInfo::getInfoHub() empty at init test failed"); + UNSCOPED_INFO("infohubs"); REQUIRE(list.empty()); list = mSim->getPGEvent(); - UNSCOPED_INFO("LLSimInfo::getPGEvent() empty at init test failed"); + UNSCOPED_INFO("PG events"); REQUIRE(list.empty()); list = mSim->getMatureEvent(); - UNSCOPED_INFO("LLSimInfo::getMatureEvent() empty at init test failed"); + UNSCOPED_INFO("mature events"); REQUIRE(list.empty()); list = mSim->getLandForSale(); - UNSCOPED_INFO("LLSimInfo::getLandForSale() empty at init test failed"); + UNSCOPED_INFO("land for sale"); REQUIRE(list.empty()); list = mSim->getAgentLocation(); - UNSCOPED_INFO("LLSimInfo::getAgentLocation() empty at init test failed"); + UNSCOPED_INFO("agent locations"); REQUIRE(list.empty()); // Create an item to be inserted @@ -314,49 +299,49 @@ namespace // Test 16 : Verify that the lists contain 1 item each list = mSim->getTeleHub(); - UNSCOPED_INFO("LLSimInfo::insertTeleHub() test failed"); + UNSCOPED_INFO("telehubs"); REQUIRE(list.size() == 1); list = mSim->getInfoHub(); - UNSCOPED_INFO("LLSimInfo::insertInfoHub() test failed"); + UNSCOPED_INFO("infohubs"); REQUIRE(list.size() == 1); list = mSim->getPGEvent(); - UNSCOPED_INFO("LLSimInfo::insertPGEvent() test failed"); + UNSCOPED_INFO("PG events"); REQUIRE(list.size() == 1); list = mSim->getMatureEvent(); - UNSCOPED_INFO("LLSimInfo::insertMatureEvent() test failed"); + UNSCOPED_INFO("mature events"); REQUIRE(list.size() == 1); list = mSim->getLandForSale(); - UNSCOPED_INFO("LLSimInfo::insertLandForSale() test failed"); + UNSCOPED_INFO("land for sale"); REQUIRE(list.size() == 1); list = mSim->getAgentLocation(); - UNSCOPED_INFO("LLSimInfo::insertAgentLocation() test failed"); + UNSCOPED_INFO("agent locations"); REQUIRE(list.size() == 1); // Test 17 : clearItems() try { mSim->clearItems(); } catch (...) { - FAIL("LLSimInfo::clearItems() at end test failed"); + FAIL("LLSimInfo::clearItems() threw at end"); } // Test 18 : Verify that all the lists are empty again... *except* agent which is persisted!! (on purpose) list = mSim->getTeleHub(); - UNSCOPED_INFO("LLSimInfo::getTeleHub() empty after clear test failed"); + UNSCOPED_INFO("telehubs"); REQUIRE(list.empty()); list = mSim->getInfoHub(); - UNSCOPED_INFO("LLSimInfo::getInfoHub() empty after clear test failed"); + UNSCOPED_INFO("infohubs"); REQUIRE(list.empty()); list = mSim->getPGEvent(); - UNSCOPED_INFO("LLSimInfo::getPGEvent() empty after clear test failed"); + UNSCOPED_INFO("PG events"); REQUIRE(list.empty()); list = mSim->getMatureEvent(); - UNSCOPED_INFO("LLSimInfo::getMatureEvent() empty after clear test failed"); + UNSCOPED_INFO("mature events"); REQUIRE(list.empty()); list = mSim->getLandForSale(); - UNSCOPED_INFO("LLSimInfo::getLandForSale() empty after clear test failed"); + UNSCOPED_INFO("land for sale"); REQUIRE(list.empty()); list = mSim->getAgentLocation(); - UNSCOPED_INFO("LLSimInfo::getAgentLocation() empty after clear test failed"); + UNSCOPED_INFO("agent locations, which clearItems() keeps"); REQUIRE(list.size() == 1); } @@ -370,45 +355,44 @@ namespace try { mWorld->reset(); } catch (...) { - FAIL("LLWorldMap::reset() at init test failed"); + FAIL("LLWorldMap::reset() threw at init"); } // Test 2 : clearImageRefs() try { mWorld->clearImageRefs(); } catch (...) { - FAIL("LLWorldMap::clearImageRefs() test failed"); + FAIL("LLWorldMap::clearImageRefs() threw"); } // Test 3 : dropImagePriorities() try { mWorld->dropImagePriorities(); } catch (...) { - FAIL("LLWorldMap::dropImagePriorities() test failed"); + FAIL("LLWorldMap::dropImagePriorities() threw"); } // Test 4 : reloadItems() try { mWorld->reloadItems(true); } catch (...) { - FAIL("LLWorldMap::reloadItems() test failed"); + FAIL("LLWorldMap::reloadItems() threw"); } // Test 5 : updateRegions() try { mWorld->updateRegions(1000, 1000, 1004, 1004); } catch (...) { - FAIL("LLWorldMap::updateRegions() test failed"); + FAIL("LLWorldMap::updateRegions() threw"); } // Test 6 : equalizeBoostLevels() try { mWorld->equalizeBoostLevels(); } catch (...) { - FAIL("LLWorldMap::equalizeBoostLevels() test failed"); + FAIL("LLWorldMap::equalizeBoostLevels() threw"); } // Test 7 : getObjectsTile() try { LLPointer image = mWorld->getObjectsTile((U32)(X_WORLD_TEST/REGION_WIDTH_METERS), (U32)(Y_WORLD_TEST/REGION_WIDTH_METERS), 1); - UNSCOPED_INFO("LLWorldMap::getObjectsTile() failed"); - REQUIRE(image.isNull()); + CHECK(image.isNull()); } catch (...) { - FAIL("LLWorldMap::getObjectsTile() test failed with exception"); + FAIL("LLWorldMap::getObjectsTile() threw"); } } // Test management of LLSimInfo lists @@ -418,13 +402,12 @@ namespace try { mWorld->reset(); } catch (...) { - FAIL("LLWorldMap::reset() at init test failed"); + FAIL("LLWorldMap::reset() threw at init"); } // Test 9 : Verify that all the region list is empty LLWorldMap::sim_info_map_t list; list = mWorld->getRegionMap(); - UNSCOPED_INFO("LLWorldMap::getRegionMap() empty at init test failed"); REQUIRE(list.empty()); // Test 10 : Insert a region @@ -439,7 +422,7 @@ namespace REGION_FLAGS_SANDBOX); list = mWorld->getRegionMap(); { - INFO("LLWorldMap::insertRegion() failed"); + INFO("insertRegion()"); CHECK(success); REQUIRE(list.size() == 1); } @@ -454,7 +437,7 @@ namespace 0, 0); list = mWorld->getRegionMap(); { - INFO("LLWorldMap::insertItem() in existing region failed"); + INFO("insertItem() in the same region"); CHECK(success); REQUIRE(list.size() == 1); } @@ -468,7 +451,7 @@ namespace 0, 0); list = mWorld->getRegionMap(); { - INFO("LLWorldMap::insertItem() in unexisting region failed"); + INFO("insertItem() in another region"); CHECK(success); REQUIRE(list.size() == 2); } @@ -479,7 +462,7 @@ namespace 0.0f); LLSimInfo* sim; sim = mWorld->simInfoFromPosGlobal(pos1); - UNSCOPED_INFO("LLWorldMap::simInfoFromPosGlobal() test on existing region failed"); + UNSCOPED_INFO("simInfoFromPosGlobal() in a region"); REQUIRE(sim != NULL); // Test 14 : simInfoFromPosGlobal() outside region @@ -487,18 +470,18 @@ namespace Y_WORLD_TEST + REGION_WIDTH_METERS*4 + REGION_WIDTH_METERS/2, 0.0f); sim = mWorld->simInfoFromPosGlobal(pos2); - UNSCOPED_INFO("LLWorldMap::simInfoFromPosGlobal() test outside region failed"); + UNSCOPED_INFO("simInfoFromPosGlobal() outside any region"); REQUIRE(sim == NULL); // Test 15 : simInfoFromName() sim = mWorld->simInfoFromName(name_sim); - UNSCOPED_INFO("LLWorldMap::simInfoFromName() test on existing region failed"); + UNSCOPED_INFO("simInfoFromName()"); REQUIRE(sim != NULL); // Test 16 : simInfoFromHandle() U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST); sim = mWorld->simInfoFromHandle(handle); - UNSCOPED_INFO("LLWorldMap::simInfoFromHandle() test on existing region failed"); + UNSCOPED_INFO("simInfoFromHandle()"); REQUIRE(sim != NULL); // Test 17 : simNameFromPosGlobal() @@ -507,7 +490,7 @@ namespace 0.0f); success = mWorld->simNameFromPosGlobal(pos3, name_sim); { - INFO("LLWorldMap::simNameFromPosGlobal() test on existing region failed"); + INFO("simNameFromPosGlobal() in a region"); CHECK(success); CHECK(name_sim == SIM_NAME_TEST); } @@ -516,12 +499,11 @@ namespace try { mWorld->reset(); } catch (...) { - FAIL("LLWorldMap::reset() at end test failed"); + FAIL("LLWorldMap::reset() threw at end"); } // Test 19 : Verify that all the region list is empty list = mWorld->getRegionMap(); - UNSCOPED_INFO("LLWorldMap::getRegionMap() empty at end test failed"); REQUIRE(list.empty()); } // Test tracking @@ -532,60 +514,46 @@ namespace // Test 20 : no tracking mWorld->cancelTracking(); - UNSCOPED_INFO("LLWorldMap::cancelTracking() at begin test failed"); CHECK_FALSE(mWorld->isTracking()); // Test 21 : set tracking mWorld->setTracking(pos); - { - INFO("LLWorldMap::setTracking() failed"); - REQUIRE(mWorld->isTracking()); - CHECK_FALSE(mWorld->isTrackingValidLocation()); - } + REQUIRE(mWorld->isTracking()); + CHECK_FALSE(mWorld->isTrackingValidLocation()); // Test 22 : set click and commit flags mWorld->setTrackingDoubleClick(); - UNSCOPED_INFO("LLWorldMap::setTrackingDoubleClick() failed"); CHECK(mWorld->isTrackingDoubleClick()); mWorld->setTrackingCommit(); - UNSCOPED_INFO("LLWorldMap::setTrackingCommit() failed"); CHECK(mWorld->isTrackingCommit()); // Test 23 : in rectangle test bool inRect = mWorld->isTrackingInRectangle( X_WORLD_TEST, Y_WORLD_TEST, X_WORLD_TEST + REGION_WIDTH_METERS, Y_WORLD_TEST + REGION_WIDTH_METERS); - UNSCOPED_INFO("LLWorldMap::isTrackingInRectangle() in rectangle failed"); + UNSCOPED_INFO("inside the rectangle"); CHECK(inRect); inRect = mWorld->isTrackingInRectangle( X_WORLD_TEST + REGION_WIDTH_METERS, Y_WORLD_TEST + REGION_WIDTH_METERS, X_WORLD_TEST + 2 * REGION_WIDTH_METERS, Y_WORLD_TEST + 2 * REGION_WIDTH_METERS); - UNSCOPED_INFO("LLWorldMap::isTrackingInRectangle() outside rectangle failed"); + UNSCOPED_INFO("outside the rectangle"); CHECK_FALSE(inRect); // Test 24 : set tracking to valid and invalid mWorld->setTrackingValid(); - { - INFO("LLWorldMap::setTrackingValid() failed"); - REQUIRE(mWorld->isTrackingValidLocation()); - CHECK_FALSE(mWorld->isTrackingInvalidLocation()); - } + REQUIRE(mWorld->isTrackingValidLocation()); + CHECK_FALSE(mWorld->isTrackingInvalidLocation()); mWorld->setTrackingInvalid(); - { - INFO("LLWorldMap::setTrackingInvalid() failed"); - REQUIRE_FALSE(mWorld->isTrackingValidLocation()); - CHECK(mWorld->isTrackingInvalidLocation()); - } + REQUIRE_FALSE(mWorld->isTrackingValidLocation()); + CHECK(mWorld->isTrackingInvalidLocation()); // Test 25 : getTrackedPositionGlobal() LLVector3d res = mWorld->getTrackedPositionGlobal(); - UNSCOPED_INFO("LLWorldMap::getTrackedPositionGlobal() failed"); CHECK(res == pos); // Test 26 : reset tracking mWorld->cancelTracking(); - UNSCOPED_INFO("LLWorldMap::cancelTracking() at end test failed"); CHECK_FALSE(mWorld->isTracking()); } // Test updateRegions() request grouping, size limits, and bounds @@ -595,20 +563,16 @@ namespace mWorld->reset(); gMapBlockRequests.clear(); mWorld->updateRegions(0, 0, 3, 3); - UNSCOPED_INFO("updateRegions 1x1 block: expected 1 request"); + UNSCOPED_INFO("1x1 block: one request"); REQUIRE(gMapBlockRequests.size() == 1); { + INFO("1x1 block"); const MapBlockRequest& req = gMapBlockRequests[0]; - UNSCOPED_INFO("updateRegions 1x1 block: min_x"); CHECK(req.min_x == 0); - UNSCOPED_INFO("updateRegions 1x1 block: min_y"); CHECK(req.min_y == 0); - UNSCOPED_INFO("updateRegions 1x1 block: max_x"); CHECK(req.max_x == 3); - UNSCOPED_INFO("updateRegions 1x1 block: max_y"); CHECK(req.max_y == 3); S32 regions = (req.max_x - req.min_x + 1) * (req.max_y - req.min_y + 1); - UNSCOPED_INFO("updateRegions 1x1 block: must not exceed 64 regions"); CHECK(regions <= 64); } @@ -616,20 +580,16 @@ namespace mWorld->reset(); gMapBlockRequests.clear(); mWorld->updateRegions(0, 0, 7, 7); - UNSCOPED_INFO("updateRegions 2x2 blocks: expected 1 request"); + UNSCOPED_INFO("2x2 blocks: one request"); REQUIRE(gMapBlockRequests.size() == 1); { + INFO("2x2 blocks"); const MapBlockRequest& req = gMapBlockRequests[0]; - UNSCOPED_INFO("updateRegions 2x2 blocks: min_x"); CHECK(req.min_x == 0); - UNSCOPED_INFO("updateRegions 2x2 blocks: min_y"); CHECK(req.min_y == 0); - UNSCOPED_INFO("updateRegions 2x2 blocks: max_x"); CHECK(req.max_x == 7); - UNSCOPED_INFO("updateRegions 2x2 blocks: max_y"); CHECK(req.max_y == 7); S32 regions = (req.max_x - req.min_x + 1) * (req.max_y - req.min_y + 1); - UNSCOPED_INFO("updateRegions 2x2 blocks: must not exceed 64 regions"); CHECK(regions <= 64); } @@ -638,36 +598,26 @@ namespace mWorld->reset(); gMapBlockRequests.clear(); mWorld->updateRegions(0, 0, 15, 15); - UNSCOPED_INFO("updateRegions 4x4 blocks: expected 4 requests"); + UNSCOPED_INFO("4x4 blocks: split into four strips"); REQUIRE(gMapBlockRequests.size() == 4); for (size_t i = 0; i < gMapBlockRequests.size(); ++i) { + CAPTURE(i); const MapBlockRequest& req = gMapBlockRequests[i]; S32 regions = (req.max_x - req.min_x + 1) * (req.max_y - req.min_y + 1); - UNSCOPED_INFO("updateRegions 4x4 blocks: each request must not exceed 64 regions"); REQUIRE(regions <= 64); // Requests must stay within the requested area (0..15) - UNSCOPED_INFO("updateRegions 4x4 blocks: max_x in bounds"); REQUIRE(req.max_x <= 15); - UNSCOPED_INFO("updateRegions 4x4 blocks: max_y in bounds"); REQUIRE(req.max_y <= 15); } // Each request covers one horizontal strip of 4 blocks (rows 0..3, 4..7, 8..11, 12..15) - UNSCOPED_INFO("updateRegions 4x4 blocks: request[0] min_y"); CHECK(gMapBlockRequests[0].min_y == 0); - UNSCOPED_INFO("updateRegions 4x4 blocks: request[0] max_y"); CHECK(gMapBlockRequests[0].max_y == 3); - UNSCOPED_INFO("updateRegions 4x4 blocks: request[1] min_y"); CHECK(gMapBlockRequests[1].min_y == 4); - UNSCOPED_INFO("updateRegions 4x4 blocks: request[1] max_y"); CHECK(gMapBlockRequests[1].max_y == 7); - UNSCOPED_INFO("updateRegions 4x4 blocks: request[2] min_y"); CHECK(gMapBlockRequests[2].min_y == 8); - UNSCOPED_INFO("updateRegions 4x4 blocks: request[2] max_y"); CHECK(gMapBlockRequests[2].max_y == 11); - UNSCOPED_INFO("updateRegions 4x4 blocks: request[3] min_y"); CHECK(gMapBlockRequests[3].min_y == 12); - UNSCOPED_INFO("updateRegions 4x4 blocks: request[3] max_y"); CHECK(gMapBlockRequests[3].max_y == 15); } } diff --git a/indra/newview/tests/llworldmipmap_test.cpp b/indra/newview/tests/llworldmipmap_test.cpp index f5690c30ba..e3cc6f2237 100644 --- a/indra/newview/tests/llworldmipmap_test.cpp +++ b/indra/newview/tests/llworldmipmap_test.cpp @@ -89,44 +89,31 @@ namespace // * Remember that you cannot test private methods with tut // --------------------------------------------------------------------------------------- // Test static methods - // Test 1 : scaleToLevel() TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: scaleToLevel is MAP_LEVELS at zero and 1 from a tile's size up", "[LLWorldMipmap]") { S32 level = mMap->scaleToLevel(0.0); - UNSCOPED_INFO("scaleToLevel() test 1 failed"); CHECK(level == LLWorldMipmap::MAP_LEVELS); level = mMap->scaleToLevel((F32)LLWorldMipmap::MAP_TILE_SIZE); - UNSCOPED_INFO("scaleToLevel() test 2 failed"); CHECK(level == 1); level = mMap->scaleToLevel(10.f * LLWorldMipmap::MAP_TILE_SIZE); - UNSCOPED_INFO("scaleToLevel() test 3 failed"); CHECK(level == 1); } - // Test 2 : globalToMipmap() TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: globalToMipmap gives a position's region grid cell", "[LLWorldMipmap]") { U32 grid_x, grid_y; mMap->globalToMipmap(1000.f*REGION_WIDTH_METERS, 1000.f*REGION_WIDTH_METERS, 1, &grid_x, &grid_y); - { - INFO("globalToMipmap() test 1 failed"); - CHECK(grid_x == 1000); - CHECK(grid_y == 1000); - } + CHECK(grid_x == 1000); + CHECK(grid_y == 1000); mMap->globalToMipmap(0.0, 0.0, LLWorldMipmap::MAP_LEVELS, &grid_x, &grid_y); - { - INFO("globalToMipmap() test 2 failed"); - CHECK(grid_x == 0); - CHECK(grid_y == 0); - } + CHECK(grid_x == 0); + CHECK(grid_y == 0); } - // Test 3 : getObjectsTile() TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: getObjectsTile (not yet tested)", "[LLWorldMipmap]") { // Depends on some inline methods in LLViewerImage... Thinking about how to make this work // LLPointer img = mMap->getObjectsTile(0, 0, 1); // ensure("getObjectsTile() test failed", img.isNull()); } - // Test 4 : equalizeBoostLevels() TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: equalizeBoostLevels does not throw", "[LLWorldMipmap]") { try @@ -135,10 +122,9 @@ namespace } catch (...) { - FAIL("equalizeBoostLevels() test failed"); + FAIL("equalizeBoostLevels() threw"); } } - // Test 5 : dropBoostLevels() TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: dropBoostLevels does not throw", "[LLWorldMipmap]") { try @@ -147,10 +133,9 @@ namespace } catch (...) { - FAIL("dropBoostLevels() test failed"); + FAIL("dropBoostLevels() threw"); } } - // Test 6 : reset() TEST_CASE_METHOD(worldmipmap_test, "LLWorldMipmap: reset does not throw", "[LLWorldMipmap]") { try @@ -159,7 +144,7 @@ namespace } catch (...) { - FAIL("reset() test failed"); + FAIL("reset() threw"); } } } diff --git a/indra/newview/tests/lutcube_test.cpp b/indra/newview/tests/lutcube_test.cpp index c468387c31..ee8d42590a 100644 --- a/indra/newview/tests/lutcube_test.cpp +++ b/indra/newview/tests/lutcube_test.cpp @@ -70,8 +70,8 @@ namespace return (int)cube.colorCube[(size_t)index * 4 + channel]; } - // constexpr, not const: ensure_equals takes its arguments by reference, - // which would odr-use a plain static const and want a definition. + // constexpr, not const: an assertion that took its operands by + // reference would odr-use a plain static const and want a definition. static constexpr int FULL = 65535; static constexpr int MID = 32768; }; @@ -81,9 +81,7 @@ namespace TEST_CASE_METHOD(lutcube_data, "LutCube: an identity cube parses with red varying fastest", "[LutCube]") { const LutCube cube = parse(identity(2)); - UNSCOPED_INFO("size"); REQUIRE(cube.size == 2); - UNSCOPED_INFO("entry count"); REQUIRE((int)cube.colorCube.size() == 2 * 2 * 2 * 4); UNSCOPED_INFO("black R"); @@ -114,7 +112,6 @@ namespace TEST_CASE_METHOD(lutcube_data, "LutCube: quantisation rounds rather than truncates", "[LutCube]") { const LutCube cube = parse(identity(3)); - UNSCOPED_INFO("size"); REQUIRE(cube.size == 3); // Entry 1 is x = 1 of 2, i.e. exactly mid grey on red alone. UNSCOPED_INFO("mid rounds up"); @@ -137,14 +134,13 @@ namespace } const LutCube cube = parse(text.str()); - UNSCOPED_INFO("size"); REQUIRE(cube.size == 2); - UNSCOPED_INFO("domain centre is mid grey"); - CHECK(at(cube, 0, 0) == MID); - UNSCOPED_INFO("domain centre is mid grey"); - CHECK(at(cube, 0, 1) == MID); - UNSCOPED_INFO("domain centre is mid grey"); - CHECK(at(cube, 0, 2) == MID); + { + INFO("domain centre is mid grey"); + CHECK(at(cube, 0, 0) == MID); + CHECK(at(cube, 0, 1) == MID); + CHECK(at(cube, 0, 2) == MID); + } } // The one that shows up as an artefact rather than a failure. "clampTripel" @@ -203,9 +199,9 @@ namespace { const LutCube cube = parse("0.0 0.0 0.0\n1.0 1.0 1.0\n"); UNSCOPED_INFO("data before LUT_3D_SIZE is rejected"); - REQUIRE(cube.colorCube.empty()); + CHECK(cube.colorCube.empty()); UNSCOPED_INFO("and leaves no size"); - REQUIRE(cube.size == 0); + CHECK(cube.size == 0); } // A short file used to be kept. The allocation is prefilled with full @@ -218,7 +214,7 @@ namespace const LutCube cube = parse(text); UNSCOPED_INFO("an incomplete cube is rejected"); - REQUIRE(cube.colorCube.empty()); + CHECK(cube.colorCube.empty()); } // stof/stoi throw, and nothing used to catch them, so a corrupt file threw @@ -227,7 +223,7 @@ namespace { const LutCube bad_size = parse("LUT_3D_SIZE banana\n"); UNSCOPED_INFO("a non-numeric size is rejected"); - REQUIRE(bad_size.colorCube.empty()); + CHECK(bad_size.colorCube.empty()); std::ostringstream text; text << "LUT_3D_SIZE 2\n"; @@ -235,18 +231,18 @@ namespace text << "0.5 what 0.5\n"; const LutCube bad_row = parse(text.str()); UNSCOPED_INFO("a malformed row is rejected"); - REQUIRE(bad_row.colorCube.empty()); + CHECK(bad_row.colorCube.empty()); } // An absurd size should be refused before it is allocated, not after. TEST_CASE_METHOD(lutcube_data, "LutCube: a huge or degenerate or negative size is refused", "[LutCube]") { UNSCOPED_INFO("a huge size is rejected"); - REQUIRE(parse("LUT_3D_SIZE 100000\n").colorCube.empty()); + CHECK(parse("LUT_3D_SIZE 100000\n").colorCube.empty()); UNSCOPED_INFO("a degenerate size is rejected"); - REQUIRE(parse("LUT_3D_SIZE 1\n").colorCube.empty()); + CHECK(parse("LUT_3D_SIZE 1\n").colorCube.empty()); UNSCOPED_INFO("a negative size is rejected"); - REQUIRE(parse("LUT_3D_SIZE -4\n").colorCube.empty()); + CHECK(parse("LUT_3D_SIZE -4\n").colorCube.empty()); } // Values separated by runs of spaces or by tabs, and a file with CRLF line @@ -291,7 +287,7 @@ namespace { text << "0.0 0.0 0.0\n"; } - UNSCOPED_INFO(std::string("a ") + value + " value is rejected"); + CAPTURE(value); REQUIRE(parse(text.str()).colorCube.empty()); } @@ -305,6 +301,6 @@ namespace domain << "0.0 0.0 0.0\n"; } UNSCOPED_INFO("a non-finite domain is rejected"); - REQUIRE(parse(domain.str()).colorCube.empty()); + CHECK(parse(domain.str()).colorCube.empty()); } } diff --git a/indra/newview/tests/noise_test.cpp b/indra/newview/tests/noise_test.cpp index fe09b2144a..a5e6359ebf 100644 --- a/indra/newview/tests/noise_test.cpp +++ b/indra/newview/tests/noise_test.cpp @@ -21,7 +21,7 @@ #include -namespace tut +namespace { // Every expected value below was read off the tables as MSVC's CRT built them from // srand(42) / rand(), which is what every Windows viewer has textured terrain from. A @@ -44,7 +44,7 @@ namespace tut ALNoiseRand rand(42); for (int i = 0; i < 65536; ++i) { - UNSCOPED_INFO("draw agrees with the CRT"); + CAPTURE(i); REQUIRE(rand.next() == ::rand()); } #else @@ -62,7 +62,7 @@ namespace tut ALNoiseRand rand(42); for (int i = 0; i < 16; ++i) { - UNSCOPED_INFO("draw"); + CAPTURE(i); REQUIRE(rand.next() == expected[i]); } } @@ -76,7 +76,7 @@ namespace tut }; for (int i = 0; i < 32; ++i) { - UNSCOPED_INFO("p head"); + CAPTURE(i); REQUIRE(p[i] == head[i]); } long long sum = 0; @@ -84,7 +84,6 @@ namespace tut { sum += (long long)p[i] * (i + 1); } - UNSCOPED_INFO("p weighted sum"); CHECK(sum == 4318278LL); UNSCOPED_INFO("p wraps at 256"); CHECK(p[257] == 117); @@ -102,7 +101,7 @@ namespace tut }; for (int i = 0; i < 8; ++i) { - UNSCOPED_INFO("g1 head"); + CAPTURE(i); REQUIRE(g1[i] == g1_head[i]); } @@ -114,9 +113,8 @@ namespace tut }; for (int i = 0; i < 4; ++i) { - UNSCOPED_INFO("g2 head x"); + CAPTURE(i); REQUIRE_THAT(g2[i][0], ll_test::WithinBits(g2_head[i][0], 20)); - UNSCOPED_INFO("g2 head y"); REQUIRE_THAT(g2[i][1], ll_test::WithinBits(g2_head[i][1], 20)); } @@ -128,11 +126,9 @@ namespace tut }; for (int i = 0; i < 4; ++i) { - UNSCOPED_INFO("g3 head x"); + CAPTURE(i); REQUIRE_THAT(g3[i][0], ll_test::WithinBits(g3_head[i][0], 20)); - UNSCOPED_INFO("g3 head y"); REQUIRE_THAT(g3[i][1], ll_test::WithinBits(g3_head[i][1], 20)); - UNSCOPED_INFO("g3 head z"); REQUIRE_THAT(g3[i][2], ll_test::WithinBits(g3_head[i][2], 20)); } } From 9ab6509981c85af70f95d0ce73453dad3a64343d Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 14 Oct 2026 02:32:20 -0400 Subject: [PATCH 4/4] newview's tests start with the UI up, and the state guard watches what the viewer keeps newview_tests takes llui's and llrender's checks, as llui's binaries do: the headless UI and the colour table made before the first case, what a frame clears cleared after each, and the UI's and the fonts' state watched. newview_gl_tests takes llrender's and llcommon's. newview_test_checks, a listener of newview_tests' own: - before the first case, makes the queue a case chooses to stand in for the main loop's, kept for the run, since work handed back to it for a case gone must find it; - gives the state guard, after every case, the queue ALMainLoop answers, the settings groups alive, Script Studio's recovery store, save history and viewer, and llcommon's checks: the live thread pools and work queues, and LLError's default level. It does not take llcommon's listener, which makes the event pumps afresh after every case: the viewer's own event APIs, LLViewerControlListener among them, listen on the pumps from before main, as they do for the viewer's whole run, and llviewercontrollistener's cases found none after the first. The eleven Linden-era binaries take none of these: each runs alone, and lllogininstance's second case relies on pumps its first made. I broke a case each way, and each check named it. Two threads that live for the process are no change a case made: - the recovery stores' writer is made by newview_test::useRecoveryWriter(), which each fixture that makes a store calls before it does, and is stopped by the harness's teardown. Made at run start, its thread started beside the UI being built, and one start in some hundreds found the heap corrupt, so it starts in a case, as it did when each file had a process of its own; - alscriptlookup's threaded case accepts the disk walks' thread, which its first walk makes, as the process's from then on. newview_tests, newview_gl_tests and the eleven, each run whole, pass 10 random orders and 20 repeats with no guard report. Co-Authored-By: Claude Opus 5.5 --- indra/newview/CMakeLists.txt | 20 +++ indra/newview/tests/alrecoverykeeper_test.cpp | 2 + indra/newview/tests/alscriptlookup_test.cpp | 5 + indra/newview/tests/alscriptstudio_fixture.h | 2 + .../tests/alscriptstudiorecovery_test.cpp | 4 + indra/newview/tests/newview_test_checks.cpp | 114 ++++++++++++++++++ indra/newview/tests/newview_test_fakes.h | 26 ++++ 7 files changed, 173 insertions(+) create mode 100644 indra/newview/tests/newview_test_checks.cpp diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index a80d3dff3f..11b4268f0b 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2482,6 +2482,22 @@ if(AL_BUILD_TESTS) target_compile_definitions(newview_test_llvocache PRIVATE "LL_TEST=llvocache" "LL_TEST_llvocache") target_link_libraries(newview_test_llvocache PRIVATE al::flags llui ${test_libs}) set_target_properties(newview_test_llvocache PROPERTIES FOLDER "Tests/${test_project}") + # What the viewer's tests share a process with, made before the first case + # and watched after each: the queue standing in for the main loop's, the + # recovery writer's thread, the settings groups, Script Studio's recovery, + # history and viewer, and llcommon's checks but for its event pumps made + # afresh for each case, which the viewer's own event APIs listen on from + # before main. llui's and llrender's checks make the UI and watch it. + add_library(newview_test_checks OBJECT tests/newview_test_checks.cpp) + target_include_directories( + newview_test_checks + PRIVATE ${newview_includes} ${INDRA_SOURCE_DIR}/llmath + ) + target_link_libraries( + newview_test_checks + PRIVATE al::flags al_test_support llui alscript ${test_libs} + ) + set_target_properties(newview_test_checks PROPERTIES FOLDER "Tests/${test_project}") # A viewer texture's boost level, which the world map's tests reach. add_library(newview_test_viewertexture OBJECT tests/llviewertexture_stub.cpp) target_include_directories( @@ -2652,6 +2668,9 @@ if(AL_BUILD_TESTS) newview_test_settings newview_studio_test_stubs newview_test_llvocache + newview_test_checks + llui_test_checks + llrender_test_checks DEFINES "LLUI_TEST_APP_DIR=\"${INDRA_SOURCE_DIR}/newview\"" "AL_LSL_DEFINITIONS_DIR=\"${LSL_DEFINITIONS_DIR}\"" @@ -2665,6 +2684,7 @@ if(AL_BUILD_TESTS) PROJECT ${test_project} SOURCES tests/alhuddepth_gl_test.cpp tests/alselectionoutline_gl_test.cpp LIBRARIES llrender + SUPPORT llrender_test_checks llcommon_test_checks INCLUDES ${INDRA_SOURCE_DIR}/llprimitive DEFINES "AL_TEST_SHADER_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/app_settings/shaders\"" GL diff --git a/indra/newview/tests/alrecoverykeeper_test.cpp b/indra/newview/tests/alrecoverykeeper_test.cpp index 1d2c07ff97..c08fe7f254 100644 --- a/indra/newview/tests/alrecoverykeeper_test.cpp +++ b/indra/newview/tests/alrecoverykeeper_test.cpp @@ -30,6 +30,7 @@ #include "fsyspath.h" #include "llfile.h" +#include "newview_test_fakes.h" #include @@ -53,6 +54,7 @@ namespace { folder = fsyspath(std::filesystem::temp_directory_path() / fsyspath("alrecoverykeeper_" + LLUUID::generateNewID().asString())).string(); std::filesystem::create_directories(fsyspath(folder)); + newview_test::useRecoveryWriter(); store = std::make_unique(folder, "this-session"); ALRecovery::useStore(store.get()); } diff --git a/indra/newview/tests/alscriptlookup_test.cpp b/indra/newview/tests/alscriptlookup_test.cpp index c54cd34908..446e97c222 100644 --- a/indra/newview/tests/alscriptlookup_test.cpp +++ b/indra/newview/tests/alscriptlookup_test.cpp @@ -31,6 +31,7 @@ #include "../alscriptlookup.h" #include "alincludeidentity.h" #include "almainloop.h" +#include "alteststateguard.h" #include "llfile.h" #include "workqueue.h" @@ -1405,6 +1406,10 @@ namespace const std::string LIB = "disk:/s/lib.luau"; unit->start(doc, ALEditorCommand::FindReferences, refsOf("twice"), true, LIB, span(1, 11, 5), { place("", 1, 10) }, doc.editor->document().version()); + // The thread the walks run on, made with the first of them, is the + // process's from here, as the viewer's is until it quits. + ll_test::StateGuard::accept("the live thread pools"); + ll_test::StateGuard::accept("the live work queues"); UNSCOPED_INFO("nothing read here"); CHECK(studio.expands.empty()); { diff --git a/indra/newview/tests/alscriptstudio_fixture.h b/indra/newview/tests/alscriptstudio_fixture.h index bf3a330679..f3d2190e2f 100644 --- a/indra/newview/tests/alscriptstudio_fixture.h +++ b/indra/newview/tests/alscriptstudio_fixture.h @@ -57,6 +57,7 @@ #include "../../llui/tests/alheadlessui_fixture.h" #include "alscriptstudio_stubs.h" +#include "newview_test_fakes.h" #include #include @@ -461,6 +462,7 @@ namespace al_studio_test unit(services, given ? *given : tabs, *this) { std::filesystem::create_directories(fsyspath(folder)); + newview_test::useRecoveryWriter(); store = std::make_unique(folder, "this-session"); ALRecovery::useStore(store.get()); } diff --git a/indra/newview/tests/alscriptstudiorecovery_test.cpp b/indra/newview/tests/alscriptstudiorecovery_test.cpp index a40420d655..93f723e8dc 100644 --- a/indra/newview/tests/alscriptstudiorecovery_test.cpp +++ b/indra/newview/tests/alscriptstudiorecovery_test.cpp @@ -115,6 +115,10 @@ namespace std::string folder; std::unique_ptr store; + // Every store a case makes, the fixture's or its own, writes on the + // process's writer. + alscriptstudiorecovery_data() { newview_test::useRecoveryWriter(); } + ~alscriptstudiorecovery_data() { ALRecovery::useStore(nullptr); diff --git a/indra/newview/tests/newview_test_checks.cpp b/indra/newview/tests/newview_test_checks.cpp new file mode 100644 index 0000000000..bac831dbc3 --- /dev/null +++ b/indra/newview/tests/newview_test_checks.cpp @@ -0,0 +1,114 @@ +/** + * @file newview_test_checks.cpp + * @brief What the viewer's tests share a process with: made before the first + * case, and watched after each. + * + * $LicenseInfo:firstyear=2026&license=viewerlgpl$ + * Alchemy Viewer Source Code + * Copyright (C) 2026, Rye + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "../alrecovery.h" +#include "../alscriptstudioviewer.h" + +#include "almainloop.h" +#include "alsavehistory.h" +#include "llcontrol.h" +#include "llerrorcontrol.h" +#include "threadpool.h" +#include "workqueue.h" + +#include "alteststateguard.h" +#include "newview_test_fakes.h" + +#include +#include + +#include +#include +#include + +namespace +{ + // A pointer as text: which object, or none. Only ever printed, never + // followed, since what it points at may be gone. + std::string which(const void* p) + { + return p ? llformat("%p", p) : std::string("none"); + } + + // The names a tracked class's live instances go by, sorted. + template + std::string liveNames() + { + std::vector names; + for (const std::string& name : typename TRACKED::key_snapshot()) + { + names.push_back(name); + } + std::sort(names.begin(), names.end()); + std::string text; + for (const std::string& name : names) + { + text += (text.empty() ? "" : ", ") + name; + } + return text; + } + + class NewviewChecks : public Catch::EventListenerBase + { + public: + using Catch::EventListenerBase::EventListenerBase; + + void testRunStarting(Catch::TestRunInfo const&) override + { + // The queue a case chooses to stand in for the main loop's, made + // before the first case and kept for the run: work handed back to + // it for a case gone finds it still there. Under a name of its + // own, so being made chooses nothing. + newview_test::mainLoop(); + + // llcommon's checks, without its event pumps made afresh for each + // case: the viewer's own event APIs, LLViewerControlListener's + // among them, listen on the pumps from before main, as they do for + // the viewer's whole run. A case that starts worker threads stops + // them before it ends; one that turns logging up or down puts it + // back. + ll_test::StateGuard::add("the live thread pools", liveNames); + ll_test::StateGuard::add("the live work queues", liveNames); + ll_test::StateGuard::add("LLError's default level", + [] { return std::to_string(LLError::getDefaultLevel()); }); + // A case that chooses a main loop lets go of the choice: every + // case after it would hand its work back to it. + ll_test::StateGuard::add("the main loop's queue", [] { return which(ALMainLoop::queue().get()); }); + // A case that makes a settings group of its own lets it go: one + // left would answer for that name in every case after it. + ll_test::StateGuard::add("the settings groups", liveNames); + // Script Studio's recovery, its save history and its viewer are + // each one for the process: a case that uses one of its own puts + // the one before back. + ll_test::StateGuard::add("the recovery store", [] { return which(ALRecovery::store()); }); + ll_test::StateGuard::add("the save history", [] { return which(ALRecovery::history().get()); }); + ll_test::StateGuard::add("Script Studio's viewer", [] { return which(&ALScriptStudioViewer::get()); }); + } + }; +} + +CATCH_REGISTER_LISTENER(NewviewChecks) diff --git a/indra/newview/tests/newview_test_fakes.h b/indra/newview/tests/newview_test_fakes.h index 8a6a268813..2e2e03ae3d 100644 --- a/indra/newview/tests/newview_test_fakes.h +++ b/indra/newview/tests/newview_test_fakes.h @@ -25,6 +25,12 @@ #ifndef AL_NEWVIEW_TEST_FAKES_H #define AL_NEWVIEW_TEST_FAKES_H +#if AL_TEST_CATCH2 +#include "alrecoverystore.h" +#include "alteststateguard.h" +#include "altestteardown.h" +#endif + namespace LL { class WorkQueue; @@ -39,6 +45,26 @@ namespace newview_test // for a test gone finds nobody. Not under the main loop's name, so that // its being made chooses nothing for the tests after. LL::WorkQueue& mainLoop(); + +#if AL_TEST_CATCH2 + // The thread Script Studio's recovery stores write on, ALRecoveryWriter's, + // the process's, which the viewer stops in its cleanup: made by the first + // fixture that makes a store, before it does, as the store would have + // made it when each file had a process of its own, and stopped by the + // harness's teardown, so that it then runs is no change a case made. + inline void useRecoveryWriter() + { + static const bool made = [] + { + ALRecoveryWriter::getInstance(); + ll_test::Teardown::add([] { ALRecoveryWriter::deleteSingleton(); }); + ll_test::StateGuard::accept("the live thread pools"); + ll_test::StateGuard::accept("the live work queues"); + return true; + }(); + (void)made; + } +#endif } #endif // AL_NEWVIEW_TEST_FAKES_H