Repository navigation
Test framework, stage 3: llui's tests in Catch2 - #471
Merged
Merged
Conversation
xui_notes.xml gives each tag the one sentence the Library and the generated xui.xsd show. Thirteen of Alchemy's widgets had none: angle_dial, choice_list, code_editor, color_table_panel, corner_field, diff_bar, diff_view, find_bar, image_field, offset_pad, output_view, pane_list and text_view. Each now has one, in the file's sorted run of Alchemy's own tags. alxuischema's "every tag says what it is for" did not see them: its TUT executable linked only the parts of llui its own file reached, and a widget registers itself from its own object, so the schema it read had none of these thirteen in it. In one binary with the rest of llui's tests, as in the viewer, every widget registers, and both alxuischema cases that hold the notes to the schema failed on them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… fits Its window was 1620 wide, but its three panes are authored at 400, 744 and 500, which with the bars between them come to a stack 1664 wide: a window of 1680. The navigator and the inspector keep their widths, so the canvas got what was left, 684. The row of controls under it is laid out from the left at fixed widths and needed 748, more than even the 744 it was authored in: its last align buttons sat past its edge. The window, its header bar, its stack and its status line are now the width the panes were authored for, so the canvas opens at 744; and Reload is 54 wide, as Show and Hide beside it are, so the row is 744 too. alxuifill's "every stack fills what it is in" did not see it. Its TUT executable linked only the parts of llui its own file reached, and a widget registers from its own object, so the row was built without the canvas_zoom spinner and the canvas_backdrop menu button, 102 pixels narrower. In one binary with the rest of llui's tests, as in the viewer, the spinner is there and the case failed; with the menu button linked in as well, the row now ends at the canvas's edge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TM23, the sixth wave of stage 3: llui's 117 TUT files, 1,541 tests, become two Catch2 binaries, each file still run in a process of its own: - llui_tests, 114 files with no GL: templates tested whole in their headers, text and XUI below the view, a file of llui's each, what comparing two texts is made of, and every widget above LLView, built over one headless UI on the source tree's skins and fonts; - llui_gl_tests, the three that draw into llrender's hidden window and read the pixels back: the text view, a surface and its tab strip, and a comparison. LLUI_TEST_APP_DIR is defined for every file of each. The fakes llui asks the viewer for are a SUPPORT object of both, and the benchmarks keep linking them as they did. The files are tut2catch.py's output, with the names the idiom pass that follows chose. It marked two sites TM-CHECK, both in code this Mac does not compile, resolved by hand: alkeymap's off-Mac check that no binding is Control-Alt with a key that types (an ensure() whose message is built), and alvimkeymap's off-Mac "nothing changed" (an ensure_equals() over strings). tut_parity.py, against the TUT executables' recorded results (1,541 tests, all ok), holds plain for 115 files and under --recounted for the two hand-resolved ones, with four assertion sites reviewed as never running in a passing case: three reached only to fail, inside an if that finds a mismatch (alcodeeditor, allinetable, alsyntaxhighlighter), and one of altextview's that runs only where a wide character's drawn width does not land near half a column, as it does in this host's fonts. All 119 entries pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The idiom pass over TM23's conversion, by fifteen 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: 1,512 of 1,541 changed. Most were set_test_name sentences, and 1,102 had commas, which a Catch2 test spec reads as "or"; many ran past a hundred characters. Where a shorter name dropped a why, a comment above the case keeps it. - Messages: 10,675 to 8,350, with 134 CAPTUREs. Most of those removed restated their check; most that remain say which step, line or key a failure is at. - 35 asserting helpers are named require_*: require_key, require_typed, require_url, require_same_layout, require_lexed and the like. A label before a CHECK that calls one is a scoped INFO around it: the helper's own passing assertion took an unscoped one. - Messages built from what a later call fills (an error string) come after the call: its result is kept and checked, the same value. - 55 CHECKs whose subject the next lines index or follow are REQUIREs, and 1,251 REQUIREs that guarded nothing are CHECKs. - alkeymap's and alvimkeymap's namespace tut, kept only for the code the converter could not compile, is an anonymous namespace. tut_parity.py holds all 117 files under --recounted, every case's count unchanged, with the conversion's four sites 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: a findChild(), find(), getParentByType(), tabButton() or optional used unchecked, and [0], front() or back() of what nothing sized, in many widget tests (quickopen, specimenlist, studiofloater, propertygrid, tabcontainer, dockpanel, popover, jumpbar, codeeditor, textview, textlayout, undostack, snippetsession, diffmodel, alxui*); - checks that cannot fail: CHECK(true) in alvimkeymap; checks after a getChild() that makes a dummy, after the check that implies them, or over the test's own expected model (altextview_gl's wave coverage); alxuiservice's "|| true"; alpanelist's fold check before any callback is set; altextundo's forgotten-steps case, where nothing is forgotten; - checks of something other or less than they say: alsyntaxgrammars' and alsyntaxhighlighter's load messages built before the loads; altextdiff checks minimal against patience twice where histogram was meant; llemojidictionary's gender check passes by variant order; llurlentry's "multicase" inputs are lower case; comments promising checks that are not there (aldiffview_gl, alcolortablepanel, lltabcontainer, propertygrid, settingrow and others); - state a failure leaks: altextview_gl's sResolutionGeneration, never put back; signal connections over locals that a teardown signal could reach; altextsearch's two threads write one bool unsynchronised; - leftovers: stale comments (alviewtype, alxuiedit, alpanelist's comparator), and cases with no ui.ok() skip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…focus LLFocusMgr keeps the chain of the focused view and its ancestors, and on the next change of focus drops the ancestors the old focus shares with the new, then tells the rest of the old chain it lost focus. Two ways left handles to views that were gone, or no longer focused, in that chain: - removeKeyboardFocusWithoutCallback, which LLDragHandle, LLFolderViewItem, LLLayoutPanel, LLResizeHandle and the media focus call from their destructors, cleared the focus but kept the chain; - the walk down the old chain told and dropped only the views still alive, so a view that died holding focus kept its dead handle there. Handles stuck at the chain's root end match no ancestor of the new focus, so every change after was found to share none: every view above the old focus was told it lost focus it still had, as were the views above the one whose focus was taken without callbacks. A popover told so closes, as an editor that lost focus would. Focus taken without callbacks now leaves no chain, and dead handles are dropped before the chains are compared. Two new llfocusmgr cases fail without each change. In one process with the rest of llui's tests, llfocusmgr's cases left such handles, and popovers, Go to Line and the studio floater's questions failed after them in random orders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the state guard watches what llui keeps llui_test_checks, a listener in llui's test binaries: - before the first case, makes the headless UI, as the viewer has it before it builds a view (in llui_gl_tests on llrender's shared context, with the fonts' glyphs in textures), and the colour table, loaded by none; - after every case, clears what a frame of the viewer clears between one thing and the next: escapes any popover left up, lets go of the keyboard, the mouse and the top, empties the clipboard, and deletes the views that asked to die; - gives the state guard, after every case, the floater view, LLMenuGL's menu container, LLKeyboard's key names, the UI's root view, and the colour table's colours, the loaded and the user's, each with its value: not its generation, which a colour set and set back still moves. Each binary takes llrender's and llcommon's checks too. I broke a case each way, and each check named it; and a case that left focus and the clipboard full left the next case nothing of either. The headless UI and the shared GL context end with the main, after the last case, rather than at static destruction: HeadlessUI::get() hands its end to the teardown in a Catch2 binary, and puts back the process's directory object, and uiGL() is llrender's sharedHeadlessGL(). Making the UI is the state the guard compares with from then on. The plan made the UI at run start, so that no case is the one that made it; the 52 files that never ask for it pass with it there. Three tests read the skin's colours, each loading them once for its process behind a static of its own; ll_test::loadSkinColours() loads them once for the process and tells the guard, since the table's names cannot be taken back out. lluicolortable's cases each load documents of their own, whose names stay for every case after, so it is a binary of its own, lluicolortable_test, without llui's checks, as the plan allowed. llui_tests, llui_gl_tests and lluicolortable_test, each run whole, pass 10 random orders and 20 repeats with no guard report. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 of 9 tasks
Contributor
|
Important Review skippedToo many files! This PR contains 126 files, which is 26 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configuration
📒 Files selected for processing: 126
You can disable this status message by setting the
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 |
AL_TEST_CATCH2 was defined on each test binary and not on the OBJECT libraries of checks it links, so a fixture the tests share with their checks had two inline bodies in one binary. HeadlessUI::get() keeps the process's one UI in a function's static: the Catch2 body in `made`, which the harness's teardown ends, and the TUT body in `ui`. Apple's linker kept the checks' TUT body for every call, so the Catch2 one never ran; GCC and MSVC inlined each where it was called, and the run setup's UI and the cases' were two. On Linux the second failed on a settings group the first had named, and on Windows every case that asked for the UI crashed: 63 of llui_tests' files and llui_gl_tests on each CI row. The shared GL context's accessor had the same split. The harness carries the define now, as a usage requirement of al_test_support, so whatever links it is built for Catch2: the binaries and their check libraries alike. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
<binary>/stray_cases runs the binary with a filter that matches nothing, to find the cases no file's entry runs. A run starts its listeners whatever it matches, and llui_gl_tests' checks make the shared GL context before the first case, so on a host without one -- the Windows rows, which build GL tests disabled -- the stray run crashed where every file's own entry was skipped. It is disabled with them now; llrender's GL binaries, whose checks make nothing, lose a run that could only pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 14, 2026
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 sixth wave of stage 3 of the test framework's move from TUT to Catch2 (TM23): llui's tests. 117 TUT files with 1,541 tests become three Catch2 binaries. Each test file still runs in a process of its own.
llui_testsllui_gl_testslluicolortable_testTwo gaps that one binary found. Each TUT executable registered only the widgets its own file happened to link. One binary registers them all, as the viewer does.
xui_notes.xmlwas missing thirteen of Alchemy's widgets. The Library and the generatedxui.xsdshow its one-sentence notes, and these widgets had none. alxuischema's "every tag says what it is for" now sees them.The conversion:
afb2ae3, the conversion: tut2catch.py's output, with the names the idiom pass chose, given through
--names. It marked two sites for review, both in code this Mac does not compile, and resolved them by hand:b9f739b, the idiom pass, by fifteen agents:
CAPTUREs.require_*.No case and no assertion was added, removed or moved.
747e770, a production fix in Linden's
LLFocusMgr.LLDragHandle,LLFolderViewItem,LLLayoutPanel,LLResizeHandle, the media focus);283c3d0, run setup, teardown and guard checks for this wave.
Related Issues
Issue Link: none. This follows #468 (TM22).
Checklist
Additional Notes
ctest -LE manualpass, and so do all 17 pending combined runs, llui's two among them;AL_TEST_PER_CASE, 1,543 case entries, and 1,542 pass. The other, aldiffview_gl's "range bands draw in the same number of batches", needs an earlier case of its file to have drawn first. That was already true under TUT; Test framework: fix the old test bugs in llui's tests #472 fixes it.tut_parity.pyholds every file to the TUT executables' recorded results: 1,541 tests, all ok.--recountedfor the two resolved by hand.--recountedfor all 117, every case's count unchanged.🤖 Generated with Claude Code