To audit what each UI test actually exercises, every step now snapshots the
live window to <TestFixtureName>/<TestName>_<NN>_<ShortDescription>.png: a
booted frame (emitted automatically by TestHarness.BootAsync), one after each
state-changing action, and one before each assertion. Flip ILSPY_TESTS_VISIBLE=1
to render the filmstrip; it lands under %TEMP%/ilspy-test-captures (overridable
via ILSPY_TEST_CAPTURES).
The step number and fixture/test name are derived automatically so inserting a
breakpoint never renumbers the rest. The identity is recorded up front from the
real ITest in an ITestAction hook rather than read live: NUnit's
TestContext.CurrentContext does not flow onto async continuations, so a capture
after an await would otherwise collide under the ad-hoc context. And when
rendering is off the whole call is a true no-op -- not even a dispatcher pump --
so instrumenting a test can never perturb the navigation/tab timing it asserts
on. Full headless suite stays green.
Nearly every headless UI test opened with the same four-line prologue
(resolve the shared MainWindow, show it, cast its DataContext, wait for the
assembly list), then repeated the corelib lookup, the EnsureLazyChildren +
Children.OfType<T>().Single() drill, the registry single-by-header lookups,
and the open-an-assembly-and-wait dance. The duplication made the intent of
each test hard to see and every signature tweak a suite-wide edit.
Collapse those into TestHarness (BootAsync, OpenAssemblyAsync, GetCommand,
GetEntry) and TreeNavigation extensions (FindCoreLib, GetChild<T>, Expand<T>),
then apply them across the suite. Net ~865 lines of boilerplate removed with
no change in behaviour; the full headless suite stays green.
Replace the single text-bar above the grid with one filter input per
column, baked into each DataGridColumn's header. The page model carries
a ColumnFilters collection alongside Columns; the filter predicate ANDs
every non-empty column's case-insensitive substring match. Column
instances are built fresh per page so sibling tabs don't share filter
state, and the column name moves to Tag for cell-level lookups now that
Header is a Panel.
Assisted-by: Claude:claude-opus-4-7:Claude Code
The generic MetadataTableTreeNode<TEntry> base now overrides
CreateTab() to return a MetadataTablePageModel populated from
LoadTable() + reflected columns. Every typed CorTable / DebugTable
inherits the grid behaviour for free; the per-table text dump is gone.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Replaces the universal placeholder for Field, MethodDef, Param,
MemberRef, CustomAttribute, and Assembly with their own typed leaves.
Each carries the columns the WPF view shows (RID / Token / Offset / row
data) — the analogous tooltips and click handlers stay deferred to the
Phase-3 navigation work since Phase 1 only renders text. The remaining
25 CorTables continue to land as placeholders until the next pass.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds the generic MetadataTableTreeNode<TEntry> base — caches LoadTable's
result and runs it through MetadataTextWriter for the Phase 1 text dump.
Ports Module / TypeRef / TypeDef / AssemblyRef as the first concrete
leaves; the remaining 31 CorTables and 8 DebugTables continue to land
through the universal placeholder until subsequent commits replace
them. Also fixes MetadataTextWriter to convert enum values to their
underlying integer before applying digit-bearing format strings, since
Enum.ToString rejects "X8".
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds the synthetic "Tables" folder that lazy-loads one leaf per
non-empty CLI metadata table, sitting between the PE headers and the
heaps to match WPF tree shape. The leaves are universal placeholders for
now — typed per-table viewers (35 CorTables + 8 DebugTables) replace
them in the next commit.
Assisted-by: Claude:claude-opus-4-7:Claude Code
Adds the five PE-format leaves (DOS / COFF / Optional / DataDirectories
/ DebugDirectory) under each assembly's Metadata folder. Phase 1 renders
them as fixed-width text tables via Decompile; Phase 2 will swap to a
DataGrid tab. Introduces Entry / BitEntry / ColumnInfoAttribute and a
MetadataTextWriter helper that the heap and table nodes reuse.
Assisted-by: Claude:claude-opus-4-7:Claude Code