Browse Source

Assert debug-step replay highlights are precise, not just present

The replay tests only checked DebugStepHighlight was non-null, which the
ancestor fallback satisfies unconditionally -- a regression widening every
highlight to the enclosing method would have passed. Assert instead that the
range lies in bounds, does not span the whole document, and (unless it is a
zero-length removal caret) covers non-whitespace rendered code.

Assisted-by: Claude:claude-opus-4-8:Claude Code
pull/3847/head
Siegfried Pammer 6 days ago committed by Siegfried Pammer
parent
commit
c644776a67
  1. 28
      ILSpy.Tests/Views/DebugStepsTests.cs

28
ILSpy.Tests/Views/DebugStepsTests.cs

@ -177,13 +177,13 @@ public class DebugStepsTests @@ -177,13 +177,13 @@ public class DebugStepsTests
await tab.RestartDecompileWithStepLimit(replayStep.BeginStep, isDebug: false, replayStep.BeginStep);
tab.Text.Should().NotBeNullOrWhiteSpace("C# replay before a selected AST mutation step must still emit code");
tab.DebugStepHighlight.Should().NotBeNull("C# replay before a selected AST mutation step must locate the changed node");
AssertPreciseHighlight(tab, "C# replay before a selected AST mutation step must locate the changed node");
debugStepsVm.Steps.Should().BeSameAs(collectedSteps,
"a step-limited C# replay must not replace the full step tree shown by the pane");
await tab.RestartDecompileWithStepLimit(replayStep.EndStep, isDebug: false, replayStep.BeginStep);
tab.Text.Should().NotBeNullOrWhiteSpace("C# replay after a selected AST mutation step must still emit code");
tab.DebugStepHighlight.Should().NotBeNull("C# replay after a selected AST mutation step must locate the changed node");
AssertPreciseHighlight(tab, "C# replay after a selected AST mutation step must locate the changed node");
debugStepsVm.Steps.Should().BeSameAs(collectedSteps,
"a step-limited C# replay must preserve the current full-run step tree and selection context");
@ -229,13 +229,13 @@ public class DebugStepsTests @@ -229,13 +229,13 @@ public class DebugStepsTests
await tab.RestartDecompileWithStepLimit(replayStep!.BeginStep, isDebug: false, replayStep.BeginStep);
tab.Text.Should().NotBeNullOrWhiteSpace("ILAst replay before a selected step must still emit IL");
tab.DebugStepHighlight.Should().NotBeNull("ILAst replay before a selected step must locate the changed instruction");
AssertPreciseHighlight(tab, "ILAst replay before a selected step must locate the changed instruction");
debugStepsVm.Steps.Should().BeSameAs(collectedSteps,
"a step-limited ILAst replay must not replace the full step tree shown by the pane");
await tab.RestartDecompileWithStepLimit(replayStep.EndStep, isDebug: false, replayStep.BeginStep);
tab.Text.Should().NotBeNullOrWhiteSpace("ILAst replay after a selected step must still emit IL");
tab.DebugStepHighlight.Should().NotBeNull("ILAst replay after a selected step must locate the changed instruction");
AssertPreciseHighlight(tab, "ILAst replay after a selected step must locate the changed instruction");
// The first leaf step that acts on a concrete instruction; a step whose Position is null
// (e.g. an empty transform group) has nothing to highlight and is not what a user replays.
@ -391,6 +391,26 @@ public class DebugStepsTests @@ -391,6 +391,26 @@ public class DebugStepsTests
return Task.CompletedTask;
}
// A replay highlight must land on the changed node, not merely be non-null: in bounds, not a
// flood of the whole document, and (unless it is a zero-length removal caret) on rendered code
// rather than whitespace. This is what keeps the ancestor fallback from silently widening every
// highlight to the enclosing method undetected.
static void AssertPreciseHighlight(DecompilerTabPageModel tab, string because)
{
tab.DebugStepHighlight.Should().NotBeNull(because);
var range = tab.DebugStepHighlight!.Value;
var text = tab.Text!;
(range.Start >= 0 && range.Start + range.Length <= text.Length).Should()
.BeTrue("the debug-step highlight must lie within the emitted document");
range.Length.Should().BeLessThan(text.Length,
"the highlight must mark a specific node, not flood the whole document");
if (range.Length > 0)
{
text.Substring(range.Start, range.Length).Trim().Should()
.NotBeEmpty("a non-caret highlight must cover rendered code, not just whitespace");
}
}
[AvaloniaTest]
public Task MarkNodeStart_Excludes_Leading_Indentation()
{

Loading…
Cancel
Save