From 38b7c19b4f7371a51773583b119c2e389d94d138 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Wed, 5 Aug 2026 03:23:39 +0100 Subject: [PATCH] fix: match report deltas by module type --- .../Helpers/SpectreResultsPrinter.cs | 13 +++-- .../Helpers/SpectreResultsPrinterTests.cs | 53 +++++++++++++++++++ 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/ModularPipelines/Helpers/SpectreResultsPrinter.cs b/src/ModularPipelines/Helpers/SpectreResultsPrinter.cs index 92bd5474020..ecd6ee642bd 100644 --- a/src/ModularPipelines/Helpers/SpectreResultsPrinter.cs +++ b/src/ModularPipelines/Helpers/SpectreResultsPrinter.cs @@ -141,11 +141,10 @@ private static Table CreateModulesTableCore(PipelineSummary pipelineSummary) table.AddColumn(new TableColumn("[bold]Status[/]").Centered()); table.AddColumn(new TableColumn("[bold]Duration[/]").RightAligned()); var reportLookup = pipelineSummary.RunReport is null - ? new Dictionary() - : pipelineSummary.Modules - .Zip(pipelineSummary.RunReport.Modules) - .GroupBy(static pair => pair.First.GetType()) - .ToDictionary(static group => group.Key, static group => group.First().Second); + ? new Dictionary(StringComparer.Ordinal) + : pipelineSummary.RunReport.Modules + .GroupBy(static report => report.ModuleTypeName, StringComparer.Ordinal) + .ToDictionary(static group => group.Key, static group => group.First(), StringComparer.Ordinal); var showDeltas = pipelineSummary.RunReport?.TotalDurationDelta.HasValue == true || reportLookup.Values.Any(static module => module.DurationDelta.HasValue); if (showDeltas) @@ -208,7 +207,7 @@ private static void AddModuleRow( Table table, object module, Dictionary timelineLookup, - IReadOnlyDictionary reportLookup, + IReadOnlyDictionary reportLookup, bool showDeltas) { var moduleName = module.GetType().Name; @@ -249,7 +248,7 @@ private static void AddModuleRow( }; if (showDeltas) { - cells.Add(reportLookup.TryGetValue(module.GetType(), out var report) + cells.Add(reportLookup.TryGetValue(ModuleTypeIdentifier.Get(module.GetType()), out var report) ? FormatDelta(report.DurationDelta) : "[dim]-[/]"); } diff --git a/test/ModularPipelines.UnitTests/Helpers/SpectreResultsPrinterTests.cs b/test/ModularPipelines.UnitTests/Helpers/SpectreResultsPrinterTests.cs index fb7c04c7a47..fe1c5dd43a2 100644 --- a/test/ModularPipelines.UnitTests/Helpers/SpectreResultsPrinterTests.cs +++ b/test/ModularPipelines.UnitTests/Helpers/SpectreResultsPrinterTests.cs @@ -19,6 +19,14 @@ protected internal override Task ExecuteAsync( CancellationToken cancellationToken) => Task.FromResult(true); } + private sealed class FirstModule : SkippedModule + { + } + + private sealed class SecondModule : SkippedModule + { + } + [Test] public async Task ModulesTable_IsCompactWithoutBlankSeparator_AndLabelsSkippedModules() { @@ -145,6 +153,51 @@ public async Task ModulesTable_ShowsTotalDeltaWithoutMatchingModuleDeltas() } } + [Test] + public async Task ModulesTable_MatchesDurationDeltasByModuleType() + { + var start = new DateTimeOffset(2026, 7, 27, 12, 0, 0, TimeSpan.Zero); + var firstModule = new FirstModule(); + var secondModule = new SecondModule(); + var summary = new PipelineSummary( + [firstModule, secondModule], + [], + TimeSpan.FromSeconds(5), + start, + start.AddSeconds(5)) with + { + RunReport = new PipelineRunReport + { + Modules = + [ + new ModuleRunReport + { + ModuleName = nameof(SecondModule), + ModuleTypeName = ModuleTypeIdentifier.Get(typeof(SecondModule)), + DurationDelta = TimeSpan.FromSeconds(2), + }, + new ModuleRunReport + { + ModuleName = nameof(FirstModule), + ModuleTypeName = ModuleTypeIdentifier.Get(typeof(FirstModule)), + DurationDelta = TimeSpan.FromSeconds(1), + }, + ], + }, + }; + + var output = RenderToString(SpectreResultsPrinter.CreateModulesTable(summary)); + var lines = output.Split(Environment.NewLine); + var firstModuleLine = lines.Single(line => line.Contains(nameof(FirstModule), StringComparison.Ordinal)); + var secondModuleLine = lines.Single(line => line.Contains(nameof(SecondModule), StringComparison.Ordinal)); + + using (Assert.Multiple()) + { + await Assert.That(firstModuleLine).Contains("+1s"); + await Assert.That(secondModuleLine).Contains("+2s"); + } + } + private static string RenderToString(IRenderable renderable) { using var writer = new StringWriter();