From f6e7bc32c315f9b3334dc01b018b91b0a76423a6 Mon Sep 17 00:00:00 2001 From: MsfPablo <129399053+MsfPablo@users.noreply.github.com> Date: Wed, 2 Sep 2026 00:27:53 +0200 Subject: [PATCH] feat(diagnose): show per-check execution time in text output formatText rendered each check's status, severity and confidence but dropped the ExecutionTime that every check already records, so users could not tell which check was slow. Append the duration, human-readable via time.Duration.String() (e.g. [1.2s], [350ms]), to each result's status line. JSON/HTML/Markdown output already carried the field. Closes #43 --- cmd/cli/commands/diagnose.go | 4 +-- cmd/cli/commands/diagnose_test.go | 41 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/cmd/cli/commands/diagnose.go b/cmd/cli/commands/diagnose.go index 9e38a94..d89120b 100644 --- a/cmd/cli/commands/diagnose.go +++ b/cmd/cli/commands/diagnose.go @@ -308,8 +308,8 @@ func formatText(report *engine.DiagnosisReport) string { } out += fmt.Sprintf("%d. %s %s\n", i+1, status, result.ID) - out += fmt.Sprintf(" Status: %s | Severity: %s | Confidence: %.0f%%\n", - result.Status, result.Severity, result.Confidence*100) + out += fmt.Sprintf(" Status: %s | Severity: %s | Confidence: %.0f%% [%s]\n", + result.Status, result.Severity, result.Confidence*100, result.ExecutionTime) out += fmt.Sprintf(" %s\n\n", result.Explanation) } diff --git a/cmd/cli/commands/diagnose_test.go b/cmd/cli/commands/diagnose_test.go index 757ceb6..fede05f 100644 --- a/cmd/cli/commands/diagnose_test.go +++ b/cmd/cli/commands/diagnose_test.go @@ -230,6 +230,47 @@ func TestFormatHTMLIncludesSummaryAndEvidence(t *testing.T) { } } +// TestFormatTextIncludesPerCheckExecutionTime guards #43: every check result +// already carries ExecutionTime, but formatText never rendered it, so users +// could not see which check was slow. The duration must appear, human-readable, +// on each result's status line. +func TestFormatTextIncludesPerCheckExecutionTime(t *testing.T) { + report := &engine.DiagnosisReport{ + ChecksExecuted: 2, + ChecksFailed: 0, + CriticalFindings: 0, + ExecutionTime: 2 * time.Second, + Results: []check.CheckResult{ + { + ID: "public_ip", + Status: check.StatusPassed, + Severity: check.SeverityInfo, + Confidence: 0.95, + Explanation: "Public IP resolved via proxy.", + ExecutionTime: 1200 * time.Millisecond, + }, + { + ID: "dns_resolve", + Status: check.StatusPassed, + Severity: check.SeverityInfo, + Confidence: 0.90, + Explanation: "DNS resolved through proxy.", + ExecutionTime: 350 * time.Millisecond, + }, + }, + } + + out := formatText(report) + + // time.Duration.String() renders these as "1.2s" and "350ms" — the + // human-readable forms the issue asks for, and they must be bracketed. + for _, want := range []string{"[1.2s]", "[350ms]", "public_ip", "dns_resolve"} { + if !strings.Contains(out, want) { + t.Fatalf("text output missing %q:\n%s", want, out) + } + } +} + func newTestRegistry() *engine.CheckRegistry { registry := engine.NewCheckRegistry() if err := checkspkg.RegisterDefaults(registry); err != nil {