Skip to content

Drive the editor's trees, panels and graph from tests, and fix the undo they caught (#128) - #140

Merged
matt-edmondson merged 1 commit into
mainfrom
claude/project-continuation-qgaxsq
Sep 4, 2026
Merged

Drive the editor's trees, panels and graph from tests, and fix the undo they caught (#128)#140
matt-edmondson merged 1 commit into
mainfrom
claude/project-continuation-qgaxsq

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Follow-on to #139. The harness landed with the panel and tree files still excluded from coverage, because nothing could reach them: they draw plain ImGui.Buttons, and a test had no way to name one.

Addressing widgets by name

ktsu.ImGui.Probes closes that. It is a dependency-free package whose stated purpose is that an application, a widget library and a dialog library can each mark items without depending on one another — so an application marking its own widgets is what it is for, not a test-only hack. Marking costs nothing when no probe is installed, which is every run that is not a test.

The marks are deliberately few and central:

Where Covers
One call in ButtonTree Every row of every tree — classes, members, enums, enum values, data sources, code generators
One per + New button The five add flows
One per context-menu entry Rename and delete for every kind
A probe scope per member row Keeps two rows' controls apart, the same job PushID does for ImGui itself

A test then writes App.Click("BtnUser") or App.Click("memberAge/Delete") and never states a coordinate.

37 new tests

  • Tree navigation — clicking a class, member, enum, data source or code generator row selects the right thing, and clears the other selections.
  • Adding — each + New button, the name it asks for, the element that results, and that a name already in use is refused rather than replacing what has it.
  • Context menus — rename and delete for every kind, driven by right-clicking the row and choosing the entry.
  • Member rows — reorder up and down, the ends of the list that cannot move further, delete, and that each is undoable.
  • The class graph — drawn through WidgetHarness rather than the editor, because the tab bar comes from a widget library that does not record its tabs, so there is no name to click. Drawing the view directly reaches the same code and is what the editor's tab delegate does.

The bug they found

Undoing a delete put the element back at the end of its collection, because Restore* appends. Delete a member from the middle of a class, undo, and the class comes back reordered.

That is not cosmetic. The library documents member order as "part of the schema's meaning rather than a display concern" — it is the declaration order generated code uses, it round-trips through the file, and TryMoveMember exists precisely so users can control it. An undo that silently rewrites it is an edit of its own.

Fixed for members, classes and enums by remembering the index and moving the element back to it.

Data sources and code generators have the same bug and are deliberately not fixed here. Schema exposes an ordered set for classes and enums (ClassSet, EnumSet) and nothing equivalent for those two, so the editor has nothing to reposition them with. Fixing it means adding public API to a published package, which is your call rather than mine — the obvious shape is DataSourceSet / CodeGeneratorSet mirroring the two that exist. It is recorded in the roadmap's decisions, and the test that covers those deletes says so rather than asserting the current behaviour is right.

Coverage

The exclusion is now just SchemaEditor/Program.cs, which holds only Main — the third acceptance criterion of #128, "narrowed to what genuinely cannot be executed".

File Before After
ClassGraphView.cs 3.2% 80.3%
TreeClass.cs excluded 92.6%
TreeDataSource.cs excluded 90.8%
TreeCodeGenerator.cs excluded 90.6%
ButtonTree.cs excluded 86.7%
TreeEnum.cs excluded 82.1%
SchemaEditor.Panels.cs excluded 54.5%
CodeGeneratorPanel.cs excluded 42.3%

Nothing in the editor is unmeasurable any more; what is left is a question of how much each panel is worth testing, not of whether it can be. New-code coverage measured locally at 95.6%, over the gate's 80%.

Verification

382 tests, 0 failures (299 library + 83 editor).

🤖 Generated with Claude Code

https://claude.ai/code/session_01Jc8o5zF3cmfCGjzWvQdGDE


Generated by Claude Code

The harness landed with the panel and tree files still excluded from coverage,
because nothing could reach them: they draw plain ImGui buttons, and a test had
no way to name one.

ktsu.ImGui.Probes is what closes that. It is a dependency-free package whose
stated purpose is that an application, a widget library and a dialog library can
each mark items without depending on one another, and marking costs nothing when
no probe is installed - which is every run that is not a test. So the marks here
are few and central: one in ButtonTree covers every row of every tree, one per
"+ New" button, one per context-menu entry, and a probe scope per member row so
two rows' controls stay apart the same way PushID keeps them apart for ImGui.

37 new tests then drive the editor as a user does, never stating a coordinate:

- Tree navigation: clicking a class, member, enum, data source or code generator
  row selects the right thing, and clears the other selections.
- Adding: each "+ New" button, the name it asks for, the element that results,
  and that a name already in use is refused rather than replacing what has it.
- Context menus: rename and delete for every kind, driven by right-clicking the
  row and choosing the entry.
- Member rows: reorder up and down, the ends of the list that cannot move
  further, delete, and that each is undoable.
- The class graph, drawn directly through WidgetHarness because the tab bar comes
  from a widget library that does not record its tabs, so there is no name to
  click.

Those tests found a bug. Undoing a delete put the element back at the END of its
collection, because Restore appends - so deleting a member from the middle of a
class and undoing came back with the class reordered. Order is not cosmetic here:
the library documents it as the declaration order generated code uses, it
round-trips through the file, and TryMoveMember exists so users can control it.
Fixed for members, classes and enums by remembering the index and moving the
element back to it.

Data sources and code generators have the same bug and are NOT fixed: Schema
exposes an ordered set for classes and enums (ClassSet, EnumSet) and nothing
equivalent for those two, so the editor has nothing to reposition them with.
Fixing it means adding public API to a published package, which is the owner's
call rather than mine. Recorded in the roadmap's decisions.

The coverage exclusion is now just SchemaEditor/Program.cs. ClassGraphView went
from 3% to 80%, the tree files sit between 82% and 100%, and nothing in the
editor is unmeasurable any more - what is left is a question of how much each
panel is worth testing, not of whether it can be.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc8o5zF3cmfCGjzWvQdGDE
@sonarqubecloud

sonarqubecloud Bot commented Sep 4, 2026

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit e9b71f5 into main Sep 4, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants