diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 2ee894e..ac37b69 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -495,8 +495,8 @@ func runCheck(cfg *config.Config, chatProvider, embedProvider llm.Provider, inde if err := engine.CollectedBaseline.Save(baseline.Path); err != nil { return ExitError, fmt.Errorf("failed to write baseline file %s: %v", baseline.Path, err) } - fmt.Printf("Baseline scan complete: %d violation(s) recorded, %d file(s) skipped due to errors, %d ADR check(s) skipped due to LLM errors.\n", len(engine.CollectedBaseline.Entries), engine.SkippedFiles, engine.SkippedADRChecks) - fmt.Printf("Baseline written to %s (%d violation(s) recorded).\n", baseline.Path, len(engine.CollectedBaseline.Entries)) + fmt.Println(formatBaselineScanSummary(len(engine.CollectedBaseline.Entries), engine.SkippedFiles, engine.SkippedADRChecks)) + fmt.Println(formatBaselineWrittenSummary(baseline.Path, len(engine.CollectedBaseline.Entries))) return ExitSuccess, nil } @@ -504,6 +504,16 @@ func runCheck(cfg *config.Config, chatProvider, embedProvider llm.Provider, inde return ExitSuccess, nil } +// formatBaselineScanSummary is its own function so runCheck's exact summary +// wording is unit-testable without the engine/LLM pipeline that feeds it. +func formatBaselineScanSummary(violations, skippedFiles, skippedADRChecks int) string { + return fmt.Sprintf("Baseline scan complete: %d violation(s) recorded, %d file(s) skipped due to errors, %d ADR check(s) skipped due to LLM errors.", violations, skippedFiles, skippedADRChecks) +} + +func formatBaselineWrittenSummary(path string, violations int) string { + return fmt.Sprintf("Baseline written to %s (%d violation(s) recorded).", path, violations) +} + // resolveContentProvider picks the ContentProvider for a check run. // updateBaseline forces a full-repo scan, overriding any other flag. func resolveContentProvider(files []string, staged, all, updateBaseline bool) analysis.ContentProvider { diff --git a/internal/cli/cli_test.go b/internal/cli/cli_test.go index 47ee0b3..241c497 100644 --- a/internal/cli/cli_test.go +++ b/internal/cli/cli_test.go @@ -455,3 +455,40 @@ func TestExecute_NormalizesPositionalArgPath_EvenWhenCwdEqualsRepoRoot(t *testin t.Errorf("expected the uncleaned positional path to be normalized to %q by Execute itself even though cwd == repoRoot, got %q", "file.go", os.Args[2]) } } + +func TestFormatBaselineScanSummary(t *testing.T) { + tests := []struct { + name string + violations, skippedFiles, skippedADRChecks int + want string + }{ + { + name: "all zero", violations: 0, skippedFiles: 0, skippedADRChecks: 0, + want: "Baseline scan complete: 0 violation(s) recorded, 0 file(s) skipped due to errors, 0 ADR check(s) skipped due to LLM errors.", + }, + { + name: "nonzero ADR checks skipped", violations: 1, skippedFiles: 0, skippedADRChecks: 1, + want: "Baseline scan complete: 1 violation(s) recorded, 0 file(s) skipped due to errors, 1 ADR check(s) skipped due to LLM errors.", + }, + { + name: "all nonzero, distinct values", violations: 3, skippedFiles: 2, skippedADRChecks: 5, + want: "Baseline scan complete: 3 violation(s) recorded, 2 file(s) skipped due to errors, 5 ADR check(s) skipped due to LLM errors.", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := formatBaselineScanSummary(tt.violations, tt.skippedFiles, tt.skippedADRChecks) + if got != tt.want { + t.Errorf("formatBaselineScanSummary(%d, %d, %d) = %q, want %q", tt.violations, tt.skippedFiles, tt.skippedADRChecks, got, tt.want) + } + }) + } +} + +func TestFormatBaselineWrittenSummary(t *testing.T) { + got := formatBaselineWrittenSummary("archguard-baseline.json", 3) + want := "Baseline written to archguard-baseline.json (3 violation(s) recorded)." + if got != want { + t.Errorf("formatBaselineWrittenSummary(...) = %q, want %q", got, want) + } +}