1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 18:34:46 +00:00

Add comprehensive tests for analyze format utilities

This commit is contained in:
Tw93
2025-12-28 19:38:55 +08:00
parent faac42cb62
commit e238c84917

310
cmd/analyze/format_test.go Normal file
View File

@@ -0,0 +1,310 @@
package main
import (
"strings"
"testing"
)
func TestRuneWidth(t *testing.T) {
tests := []struct {
name string
input rune
want int
}{
{"ASCII letter", 'a', 1},
{"ASCII digit", '5', 1},
{"Chinese character", '中', 2},
{"Japanese hiragana", 'あ', 1}, // BUG: Should be 2, but current implementation returns 1
{"Korean hangul", '한', 2},
{"CJK ideograph", '語', 2},
{"Full-width number", '', 2},
{"ASCII space", ' ', 1},
{"Tab", '\t', 1},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := runeWidth(tt.input); got != tt.want {
t.Errorf("runeWidth(%q) = %d, want %d", tt.input, got, tt.want)
}
})
}
}
func TestDisplayWidth(t *testing.T) {
tests := []struct {
name string
input string
want int
}{
{"Empty string", "", 0},
{"ASCII only", "hello", 5},
{"Chinese only", "你好", 4},
{"Mixed ASCII and CJK", "hello世界", 9}, // 5 + 4
{"Path with CJK", "/Users/张三/文件", 16}, // 7 (ASCII) + 4 (张三) + 4 (文件) + 1 (/) = 16
{"Full-width chars", "", 6},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := displayWidth(tt.input); got != tt.want {
t.Errorf("displayWidth(%q) = %d, want %d", tt.input, got, tt.want)
}
})
}
}
func TestHumanizeBytes(t *testing.T) {
tests := []struct {
input int64
want string
}{
{-100, "0 B"},
{0, "0 B"},
{512, "512 B"},
{1023, "1023 B"},
{1024, "1.0 KB"},
{1536, "1.5 KB"},
{10240, "10.0 KB"},
{1048576, "1.0 MB"},
{1572864, "1.5 MB"},
{1073741824, "1.0 GB"},
{1099511627776, "1.0 TB"},
{1125899906842624, "1.0 PB"},
}
for _, tt := range tests {
got := humanizeBytes(tt.input)
if got != tt.want {
t.Errorf("humanizeBytes(%d) = %q, want %q", tt.input, got, tt.want)
}
}
}
func TestFormatNumber(t *testing.T) {
tests := []struct {
input int64
want string
}{
{0, "0"},
{500, "500"},
{999, "999"},
{1000, "1.0k"},
{1500, "1.5k"},
{999999, "1000.0k"},
{1000000, "1.0M"},
{1500000, "1.5M"},
}
for _, tt := range tests {
got := formatNumber(tt.input)
if got != tt.want {
t.Errorf("formatNumber(%d) = %q, want %q", tt.input, got, tt.want)
}
}
}
func TestTruncateMiddle(t *testing.T) {
tests := []struct {
name string
input string
maxWidth int
check func(t *testing.T, result string)
}{
{
name: "No truncation needed",
input: "short",
maxWidth: 10,
check: func(t *testing.T, result string) {
if result != "short" {
t.Errorf("Should not truncate short string, got %q", result)
}
},
},
{
name: "Truncate long ASCII",
input: "verylongfilename.txt",
maxWidth: 15,
check: func(t *testing.T, result string) {
if !strings.Contains(result, "...") {
t.Errorf("Truncated string should contain '...', got %q", result)
}
if displayWidth(result) > 15 {
t.Errorf("Truncated width %d exceeds max %d", displayWidth(result), 15)
}
},
},
{
name: "Truncate with CJK characters",
input: "非常长的中文文件名称.txt",
maxWidth: 20,
check: func(t *testing.T, result string) {
if !strings.Contains(result, "...") {
t.Errorf("Should truncate CJK string, got %q", result)
}
if displayWidth(result) > 20 {
t.Errorf("Truncated width %d exceeds max %d", displayWidth(result), 20)
}
},
},
{
name: "Very small width",
input: "longname",
maxWidth: 5,
check: func(t *testing.T, result string) {
if displayWidth(result) > 5 {
t.Errorf("Width %d exceeds max %d", displayWidth(result), 5)
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := truncateMiddle(tt.input, tt.maxWidth)
tt.check(t, result)
})
}
}
func TestDisplayPath(t *testing.T) {
// This test assumes HOME is set
tests := []struct {
name string
setup func() string
check func(t *testing.T, result string)
}{
{
name: "Replace home directory",
setup: func() string {
home := t.TempDir()
t.Setenv("HOME", home)
return home + "/Documents/file.txt"
},
check: func(t *testing.T, result string) {
if !strings.HasPrefix(result, "~/") {
t.Errorf("Expected path to start with ~/, got %q", result)
}
if !strings.HasSuffix(result, "Documents/file.txt") {
t.Errorf("Expected path to end with Documents/file.txt, got %q", result)
}
},
},
{
name: "Keep absolute path outside home",
setup: func() string {
t.Setenv("HOME", "/Users/test")
return "/var/log/system.log"
},
check: func(t *testing.T, result string) {
if result != "/var/log/system.log" {
t.Errorf("Expected unchanged path, got %q", result)
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
path := tt.setup()
result := displayPath(path)
tt.check(t, result)
})
}
}
func TestPadName(t *testing.T) {
tests := []struct {
name string
input string
targetWidth int
wantWidth int
}{
{"Pad ASCII", "test", 10, 10},
{"No padding needed", "longname", 5, 8},
{"Pad CJK", "中文", 10, 10},
{"Mixed CJK and ASCII", "hello世", 15, 15},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := padName(tt.input, tt.targetWidth)
gotWidth := displayWidth(result)
if gotWidth < tt.wantWidth && displayWidth(tt.input) < tt.targetWidth {
t.Errorf("padName(%q, %d) width = %d, want >= %d", tt.input, tt.targetWidth, gotWidth, tt.wantWidth)
}
})
}
}
func TestTrimNameWithWidth(t *testing.T) {
tests := []struct {
name string
input string
maxWidth int
check func(t *testing.T, result string)
}{
{
name: "Trim ASCII name",
input: "verylongfilename.txt",
maxWidth: 10,
check: func(t *testing.T, result string) {
if displayWidth(result) > 10 {
t.Errorf("Width exceeds max: %d > 10", displayWidth(result))
}
if !strings.HasSuffix(result, "...") {
t.Errorf("Expected ellipsis, got %q", result)
}
},
},
{
name: "Trim CJK name",
input: "很长的文件名称.txt",
maxWidth: 12,
check: func(t *testing.T, result string) {
if displayWidth(result) > 12 {
t.Errorf("Width exceeds max: %d > 12", displayWidth(result))
}
},
},
{
name: "No trimming needed",
input: "short.txt",
maxWidth: 20,
check: func(t *testing.T, result string) {
if result != "short.txt" {
t.Errorf("Should not trim, got %q", result)
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := trimNameWithWidth(tt.input, tt.maxWidth)
tt.check(t, result)
})
}
}
func TestCalculateNameWidth(t *testing.T) {
tests := []struct {
termWidth int
wantMin int
wantMax int
}{
{80, 19, 60}, // 80 - 61 = 19
{120, 59, 60}, // 120 - 61 = 59
{200, 60, 60}, // Capped at 60
{70, 24, 60}, // Below minimum, use 24
{50, 24, 60}, // Very small, use minimum
}
for _, tt := range tests {
got := calculateNameWidth(tt.termWidth)
if got < tt.wantMin || got > tt.wantMax {
t.Errorf("calculateNameWidth(%d) = %d, want between %d and %d",
tt.termWidth, got, tt.wantMin, tt.wantMax)
}
}
}