Repository navigation
Test framework, stage 3: the small libraries' tests in Catch2 - #449
Merged
Merged
Conversation
…r several mask_source() turned the whole inside of a string literal into underscores, newlines too where the literal was continued with a backslash. tut_parity.py counts lines in that masked text, so every assertion after such a literal got a line number too low. It then said CHECKs that had run in passing cases never ran: llmediaentry's three LLSD macros span 93 lines, and parity reported 18 of its CHECKs that way. A line splice in a literal now stays as it is, backslash and newline, as one in code does. Lines then count as in the text, and a #define whose literal goes on over lines still reads as one directive. Over the tree's 379 TUT files, only llmediaentry and llmessagetemplateparser mask differently, and tut2catch.py converts both to the same bytes and the same mapping as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A library's own guard checks will come from a listener of its own, which adds them when the run starts. Catch2 calls listeners in the order they registered, which across files is static-init order. Where the library's listener ran after the guard's, the guard's snapshot had already been taken. The new check had nothing to compare with, and the first case of every run was blamed for changing it. StateGuard::add now describes the check as it adds it, so the order of the listeners no longer matters. The harness's own tests have such a listener now, with a hidden case that changes its state. That entry names its case, and the entries that expect a clean exit pass whichever listener runs first. Without the change, four of them fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a one-file binary without a combined entry UNIT names files of the library compiled into the binary rather than linked, with the library's include directories, as al_add_test's UNIT did. It is for a test that stubs what its file calls, and so cannot link the library its stubs would duplicate: llprimitive_test, whose stubs replace LLMaterialID, LLPrimTextureList and LLMessageSystem, and llimageworker_test, whose stubs replace the image classes. Each is a binary of its own. A binary of one file had a combined entry that ran exactly what the file's entry ran, a second time. It no longer gets one. That drops test_support_tests' combined entry, and its COMBINED with it, and the combined entries of llmath's one-file ISA tier binaries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h.py TM18, the first wave of stage 3: 25 TUT files in seven libraries become eight Catch2 binaries, each file still run in a process of its own: - llxml_tests (3 files), llcharacter_tests (7), llinventory_tests (6), llfilesystem_tests (2) and llprimitive_tests (4), each linking its library; - llprimitive_test, llimageworker_test and lllogin_test alone. The first two stub what their file calls and so compile it in (UNIT). lllogin's cases make an LLApp, and clear every event pump as they end. llprimitive_tests' one tinygltf and stb implementation stays in llgltfmaterial_test.cpp. llbvhloader's paths to the shipped anim.ini and skeleton are defines of the whole of llcharacter_tests. The files are tut2catch.py's output, with the case names the idiom pass that follows chose given through --names. Two carry hand edits: - lldir_test.cpp: <set>, which lltut.h used to bring, and the twelve ensure_equals() calls in its Linux-only case, which the converter met only as text and so marked. They compare LLDirXDG::Layout's std::string fields, so each is a CHECK(a == b). - lllogin_test.cpp: one LLTestApp for the process, made by the first case and ended by the harness's teardown. An LLApp sets up LLCommon as it is made and tears it down as it ends, APR and LLTrace's master recorder included. Under TUT each test's fixture made one and ended it, and so freed APR for whatever ran after it. The state guard reported that against the first case. tut_parity.py, against the TUT binaries' recorded results (290 tests, all passing): every file holds, 23 as the converter wrote them and lldir and lllogin under --recounted. lldir's four Linux-only cases and llmaterialid's three under !SHOW_ASSERT are not compiled here, and are listed. All 38 entries pass, and so do the five combined runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The idiom pass over TM18's 25 converted files, as llmath had in stage 2: - every case named for what it checks (206 were #N, and some names taken from comments were cut off or carried commas); - messages that only restated their assertion are gone: 1,263 became 431, and 44 CAPTUREs say what string-building said before; - asserting helpers are named for what they do now (require_*), with a scoped INFO or CAPTURE in place of a message built by hand; - 113 REQUIREs that guarded nothing are CHECKs, and the 7 CHECKs that guard an index after them are REQUIREs; - lldir's Linux-only cases, which the converter met only as text, are written as the rest are, and its empty fixture and nested anonymous namespaces are gone; - lllogin loses skip macros nothing used, which still called TUT's skip. No case was added, removed or moved, and no assertion: per case, each assertion compares what it compared before, in the same order. Beyond a CHECK becoming REQUIRE or the reverse, nine changed only in form: literals moved right, string-building turned into streaming, and an UNSCOPED_INFO and REQUIRE(false) became a FAIL. tut_parity.py --recounted holds for all 25 files, and all 38 entries pass. Bugs in the tests that the pass found are left for their own change, since a conversion keeps behaviour: - lljoint: after addChild, a check repeats an earlier one, where it seems to have meant lljoint's parent; - llcharacter: a joint's parent, and a motion findMotion found, are dereferenced unchecked; - llpose: a case's comment says a joint is left out of the motion's signature, which the case never checks; - llmultigesture: the sound step's flags are never read back, and the first case checks only steps 0 and 2; - llbvhloader: results are indexed with no count checked first, and two refusals share one message; - llkeyframemotion: a U32 cursor is compared through LLSDEquals, as TUT's overload for a string message chose; - alxmllayermerge: a check on an observer nothing installed cannot fail; - llpermissions: the allowCopyBy case calls allowModifyBy, the allow*By cases pass only through the default everyone mask, and a getValue result is discarded; - llcontrol: the listener flag is a static never reset; - inventorymisc: a fromLLSD result is never checked; it and llsaleinfo each keep an empty placeholder case, and llsaleinfo builds a sale info it never uses; - llsettingssky: one result is indexed with no size check; - llgltfmaterial: the texture-transforms-only material is given texture ids, and one block sets the override material where it meant the render material; - llprimitive: createPrimitive's result is never deleted; - llimageworker: the worker's done flag is a plain bool polled without synchronisation, and written through a dangling reference after a timeout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… libraries keep for the process Each wave adds its domain's guard checks. TM18's libraries keep three things for the process that a case could leave behind for the next: - llxml: the live settings groups, by name. Two may not share one, so a group a case leaves alive is one a later case cannot make. - llcharacter: the live characters, every one of which an update walks; and the keyframe data cache, which llkeyframemotion's cases expect to find empty. Each library's checks are an OBJECT library of their own, whose listener adds them as the run starts, for every binary that links the library: llxml_tests and llcharacter_tests now, and llui's and newview's later. llinventory, llfilesystem, llprimitive and llimage keep nothing a case could leave changed; lllogin's event pumps are llcommon's, and come with its wave. Both binaries pass 10 random orders and 20 repeats with no report. With llkeyframemotion's fixture not clearing the cache, the guard names each case that left data in it; with a settings group leaked, the case that leaked it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 3 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This was referenced Oct 12, 2026
RyeMutt
added this pull request to stack #452
October 12, 2026 07:57
The optimised Windows builds compile with /fp:fast, under which MSVC may compile == without its test for an unordered result. A NaN then compares equal to any number. LLSDEquals compared reals and dates' seconds with ==, so on Windows x64 a NaN date matched LLDate(0.0), and test_support_tests failed there, as it has on develop since #446. clang and GCC keep IEEE comparisons under the flags the tree gives them, so no other row saw it. Reals and dates now go through a compare that asks about NaN apart, with std::isnan, which classifies the bits and so holds under /fp:fast. The harness's tests check a NaN real as well as a NaN date. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RyeMutt
added a commit
that referenced
this pull request
Oct 12, 2026
Two pull requests merged into develop on the same morning. #451 added a TUT test<13> to llgltfmaterial_test.cpp, which #449 had converted to Catch2, so llprimitive's tests no longer compiled anywhere: llgltfmaterial_object_t no longer exists. Its two parts are now two TEST_CASEs, as the rest of the file is written. Each finding of a tracked texture is a REQUIRE before the entry is read; the rest are CHECKs. What they check is unchanged: the override's local texture tracked beside the material's own, both found by updateTextureTracking and covered by the digest, and the override's world id winning where both track the same texture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5 of 9 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The first wave of stage 3 of the test framework's move from TUT to Catch2 (TM18, "the small libraries"). 25 TUT files with 290 tests, from seven libraries, become eight Catch2 binaries. Each test file still runs in a process of its own, as each was an executable before.
llxml_testsllcharacter_testsllinventory_testsllfilesystem_testsllprimitive_testsllprimitive_testLLMaterialID,LLPrimTextureListandLLMessageSystem, so it compiles llprimitive.cpp inllimageworker_testlllogin_testLLApp, and clear every event pump as they endCommits
32ca1c6, parity's line numbers.
mask_source()masked a line splice inside a string literal, newline and all, so tut_parity.py numbered every line after one too low. llmediaentry's LLSD macros span 93 lines, and parity said 18 CHECKs that had run never ran. Over all 379 TUT files only two mask differently with the fix, and both convert to the same bytes as before.843599a, the state guard. A check is described as it is added. A library's checks come from its own listener at the start of the run, and Catch2 calls listeners in static-init order. Before this, a check added after the guard's snapshot blamed the first case of every run. The harness's tests now include such a listener; without the fix, four of their entries fail.
04caa02,
al_add_test_binary.UNIT <file>...compiles in the library files a stubbing test needs, asal_add_test's UNIT did.combinedentry, which ran its file's cases a second time.51b9e23, the conversion. tut2catch.py's output, with the case names the idiom pass chose given through
--names. Two files carry hand edits:<set>, which lltut.h used to bring, and the twelveensure_equalscalls in its Linux-only case, which the converter met only as text.LLTestAppfor the whole process, ended by the harness's teardown. AnLLAppsets upLLCommonas it is made and tears it down as it ends, APR and LLTrace's master recorder included. Under TUT each test made one and ended it, freeing APR for whatever ran after; the state guard reported it.3bbc58d, the idiom pass, as llmath had in Test framework, stage 2: Catch2, its harness and converter, and llmath in one binary #446:
#N);CAPTUREs;require_*;No case and no assertion was added, removed or moved. Per case, each assertion compares what it compared before.
fac126b, this wave's guard checks. These are OBJECT libraries any binary linking the library can take, watching:
I broke a test for each on purpose, and each check named the case responsible.
Related Issues
Issue Link: none. This follows #446 (stage 2), on develop.
Checklist
Additional Notes
ctest -LE manualpass;LLSingleton,LLInstanceTrackerand the like) in two files of one binary.--recounted;--recounted.!SHOW_ASSERT. The Linux cases were syntax-checked against an unguarded copy oflldir_linux.h. CI's Linux rows are the first to build and run them.allowCopyBycase callsallowModifyBy;🤖 Generated with Claude Code