From 28030d5c11618db5b53d73aedf03acb6b565c622 Mon Sep 17 00:00:00 2001 From: Yurii Chukhlib Date: Sat, 8 Aug 2026 20:43:57 +0200 Subject: [PATCH] fix: report non-zero megabyte size for xkcd-kb unit in non-leap years The xkcd-kb size case assigned `size` only inside the leap-year branch with no else, so in a non-leap year `size` stayed 0.0 and the output read "0.000 megabytes" for any byte count, contradicting the unit's help text "1000 bytes during leap years, 1024 otherwise". Divide by a new pure helper xkcdKbDivisor(year) returning 1_000_000 (1000-based) in leap years and 1_048_576 (1024-based) otherwise, mirroring the existing pure isLeapYear(year). Adds TestCalculateSizeXkcdKb covering both year classes. I licence this contribution under the MIT licence. --- processor/formatters_cost.go | 15 ++++++++++++--- processor/formatters_test.go | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/processor/formatters_cost.go b/processor/formatters_cost.go index 8c95c90e5..f64f5fca8 100644 --- a/processor/formatters_cost.go +++ b/processor/formatters_cost.go @@ -144,9 +144,7 @@ func calculateSize(sumBytes int64, str *strings.Builder) { size = float64(sumBytes) / 1_024_000 case "xkcd-kb": str.WriteString("1000 bytes during leap years, 1024 otherwise\n") - if isLeapYear(time.Now().Year()) { - size = float64(sumBytes) / 1_000_000 - } + size = float64(sumBytes) / xkcdKbDivisor(time.Now().Year()) case "xkcd-kelly": str.WriteString("compromise between 1000 and 1024 bytes\n") size = float64(sumBytes) / (1012 * 1012) @@ -189,3 +187,14 @@ func isLeapYear(year int) bool { } return leapFlag } + +// xkcdKbDivisor returns the byte divisor the xkcd-kb unit divides total bytes +// by to obtain megabytes: 1_000_000 (1000-based) during leap years and +// 1_048_576 (1024-based) otherwise, matching the unit's help text "1000 bytes +// during leap years, 1024 otherwise". Pure in year for year-independent tests. +func xkcdKbDivisor(year int) float64 { + if isLeapYear(year) { + return 1_000_000 + } + return 1_048_576 +} diff --git a/processor/formatters_test.go b/processor/formatters_test.go index 3faa598c3..72ad7038e 100644 --- a/processor/formatters_test.go +++ b/processor/formatters_test.go @@ -3,11 +3,13 @@ package processor import ( + "fmt" "io" "os" "slices" "strings" "testing" + "time" "github.com/mattn/go-runewidth" ) @@ -42,6 +44,41 @@ func TestCalculateSize(t *testing.T) { } } +func TestCalculateSizeXkcdKb(t *testing.T) { + t.Setenv("LANG", "en_US.UTF-8") + + prevSizeUnit := SizeUnit + SizeUnit = "xkcd-kb" + t.Cleanup(func() { SizeUnit = prevSizeUnit }) + + // The divisor mirrors the case's help text "1000 bytes during leap + // years, 1024 otherwise": 1_000_000 (1000-based) in leap years and + // 1_048_576 (1024-based) otherwise. Asserting it directly keeps the + // expectation year-independent. + if got := xkcdKbDivisor(2026); got != float64(1024*1024) { + t.Errorf("xkcdKbDivisor(2026) = %v, want %d (non-leap, 1024-based)", got, 1024*1024) + } + if got := xkcdKbDivisor(2024); got != 1_000_000.0 { + t.Errorf("xkcdKbDivisor(2024) = %v, want 1000000 (leap, 1000-based)", got) + } + + var str strings.Builder + calculateSize(10_000_000, &str) + + // Regression guard: before the fix `size` was left at 0.0 in non-leap + // years, so the line read "0.000 megabytes" for any byte count. + if strings.Contains(str.String(), "0.000 megabytes") { + t.Errorf("expected a non-zero megabyte size for xkcd-kb, got:\n%s", str.String()) + } + + // The rendered value must equal bytes/divisor for the current year + // ("9.537 megabytes" in a non-leap year such as 2026). + want := fmt.Sprintf("%.3f megabytes", 10_000_000.0/xkcdKbDivisor(time.Now().Year())) + if !strings.Contains(str.String(), want) { + t.Errorf("expected output to contain %q, got:\n%s", want, str.String()) + } +} + func TestSortSummaryFilesEmpty(t *testing.T) { summary := LanguageSummary{} sortSummaryFiles(&summary)