Print the byte unit once in the summary line (closes #17)
check / check (push) Successful in 2m13s

formatBytes already ends in a unit, so the summary line read "9 B
bytes" or "1.0 KiB bytes". The format string in Stats.Print no longer
adds the word "bytes".

Print now takes the io.Writer to print to; its callers pass os.Stderr,
and the new test passes a buffer to read the line for one small and
one large byte count.

Model: opus-5-5
This commit was merged in pull request #20.
This commit is contained in:
2026-10-06 08:27:08 +02:00
parent c4b50e2b55
commit 9e55fd7113
3 changed files with 33 additions and 6 deletions
+2
View File
@@ -25,6 +25,8 @@ today), `.dockerignore`, `.gitea/workflows/check.yml` and
# Completed Steps # Completed Steps
* 2026-10-06: the summary line after `sum`, `check` and `clear` prints
the byte unit once (`1.5 KiB`, not `1.5 KiB bytes`)
* 2026-10-06: a path that `--exclude` or `--exclude-dotfiles` excludes * 2026-10-06: a path that `--exclude` or `--exclude-dotfiles` excludes
is skipped even when it cannot be read, so an excluded directory is skipped even when it cannot be read, so an excluded directory
that cannot be listed no longer fails the run that cannot be listed no longer fails the run
+6 -6
View File
@@ -71,13 +71,13 @@ func (s *Stats) Duration() time.Duration {
return time.Since(s.StartTime) return time.Since(s.StartTime)
} }
func (s *Stats) Print(opts *options, operation string) { func (s *Stats) Print(w io.Writer, opts *options, operation string) {
if opts.quiet { if opts.quiet {
return return
} }
fmt.Fprintf(os.Stderr, _, _ = fmt.Fprintf(w,
"\n%s complete: %d files processed, %d skipped, %d failed, %s bytes in %s\n", "\n%s complete: %d files processed, %d skipped, %d failed, %s in %s\n",
operation, operation,
s.FilesProcessed, s.FilesProcessed,
s.FilesSkipped, s.FilesSkipped,
@@ -227,7 +227,7 @@ func runOverPaths(
} }
finishBar(bar) finishBar(bar)
stats.Print(opts, op) stats.Print(os.Stderr, opts, op)
return nil return nil
} }
@@ -481,7 +481,7 @@ func runCheck(opts *options, args []string, cont bool) error {
if perr != nil { if perr != nil {
if !cont { if !cont {
finishBar(bar) finishBar(bar)
stats.Print(opts, "check") stats.Print(os.Stderr, opts, "check")
return perr return perr
} }
@@ -491,7 +491,7 @@ func runCheck(opts *options, args []string, cont bool) error {
} }
finishBar(bar) finishBar(bar)
stats.Print(opts, "check") stats.Print(os.Stderr, opts, "check")
return finalErr return finalErr
} }
+25
View File
@@ -1,6 +1,7 @@
package main package main
import ( import (
"bytes"
"errors" "errors"
"os" "os"
"path/filepath" "path/filepath"
@@ -376,3 +377,27 @@ func TestCheckContinuePastUnreadable(t *testing.T) {
t.Fatalf("expected verification error from runCheck, got %v", err) t.Fatalf("expected verification error from runCheck, got %v", err)
} }
} }
func TestSummaryPrintsByteUnitOnce(t *testing.T) {
t.Parallel()
tests := []struct {
bytesProcessed int64
want string
}{
{9, ", 9 B in "},
{1536, ", 1.5 KiB in "},
}
for _, tt := range tests {
var out bytes.Buffer
stats := newTestStats()
stats.BytesProcessed = tt.bytesProcessed
stats.Print(&out, &options{}, "check")
if !strings.Contains(out.String(), tt.want) {
t.Errorf("summary %q does not contain %q", out.String(), tt.want)
}
}
}