go-i18n/handler_test.go
Claude 97f9c758d1
chore(ax): AX compliance sweep — banned imports, naming, Good/Bad/Ugly tests
- compose.go: remove fmt import, use local stringer interface + core.Sprint
- hooks.go: replace stdlib log with dappco.re/go/core/log
- localise.go: replace os.Getenv with core.Env
- loader.go: replace strings.CutPrefix with core.HasPrefix/TrimPrefix
- reversal/tokeniser.go: replace strings.Fields with local splitFields helper
- validate.go: rename sb → builder (AX naming)
- calibrate.go, classify.go: rename cfg → configuration (AX naming)
- numbers.go: rename local fmt variable → numberFormat
- All test files: add Good/Bad/Ugly triads per AX test naming convention

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-31 08:42:40 +01:00

262 lines
6.8 KiB
Go

package i18n
import "testing"
func TestLabelHandler(t *testing.T) {
svc, err := New()
if err != nil {
t.Fatalf("New() failed: %v", err)
}
SetDefault(svc)
h := LabelHandler{}
if !h.Match("i18n.label.status") {
t.Error("LabelHandler should match i18n.label.*")
}
if h.Match("other.key") {
t.Error("LabelHandler should not match other.key")
}
got := h.Handle("i18n.label.status", nil, nil)
if got != "Status:" {
t.Errorf("LabelHandler.Handle(status) = %q, want %q", got, "Status:")
}
}
func TestProgressHandler(t *testing.T) {
svc, err := New()
if err != nil {
t.Fatalf("New() failed: %v", err)
}
SetDefault(svc)
h := ProgressHandler{}
if !h.Match("i18n.progress.build") {
t.Error("ProgressHandler should match i18n.progress.*")
}
// Without subject
got := h.Handle("i18n.progress.build", nil, nil)
if got != "Building..." {
t.Errorf("ProgressHandler.Handle(build) = %q, want %q", got, "Building...")
}
// With subject
got = h.Handle("i18n.progress.build", []any{"project"}, nil)
if got != "Building project..." {
t.Errorf("ProgressHandler.Handle(build, project) = %q, want %q", got, "Building project...")
}
}
func TestCountHandler(t *testing.T) {
svc, err := New()
if err != nil {
t.Fatalf("New() failed: %v", err)
}
SetDefault(svc)
h := CountHandler{}
if !h.Match("i18n.count.file") {
t.Error("CountHandler should match i18n.count.*")
}
tests := []struct {
key string
args []any
want string
}{
{"i18n.count.file", []any{1}, "1 file"},
{"i18n.count.file", []any{5}, "5 files"},
{"i18n.count.file", []any{0}, "0 files"},
{"i18n.count.child", []any{3}, "3 children"},
{"i18n.count.file", nil, "file"},
}
for _, tt := range tests {
t.Run(tt.key, func(t *testing.T) {
got := h.Handle(tt.key, tt.args, nil)
if got != tt.want {
t.Errorf("CountHandler.Handle(%q, %v) = %q, want %q", tt.key, tt.args, got, tt.want)
}
})
}
}
func TestDoneHandler(t *testing.T) {
svc, err := New()
if err != nil {
t.Fatalf("New() failed: %v", err)
}
SetDefault(svc)
h := DoneHandler{}
if !h.Match("i18n.done.delete") {
t.Error("DoneHandler should match i18n.done.*")
}
// With subject
got := h.Handle("i18n.done.delete", []any{"config.yaml"}, nil)
if got != "Config.Yaml deleted" {
t.Errorf("DoneHandler.Handle(delete, config.yaml) = %q, want %q", got, "Config.Yaml deleted")
}
// Without subject — just past tense
got = h.Handle("i18n.done.delete", nil, nil)
if got != "Deleted" {
t.Errorf("DoneHandler.Handle(delete) = %q, want %q", got, "Deleted")
}
}
func TestFailHandler(t *testing.T) {
h := FailHandler{}
if !h.Match("i18n.fail.push") {
t.Error("FailHandler should match i18n.fail.*")
}
got := h.Handle("i18n.fail.push", []any{"commits"}, nil)
if got != "Failed to push commits" {
t.Errorf("FailHandler.Handle(push, commits) = %q, want %q", got, "Failed to push commits")
}
got = h.Handle("i18n.fail.push", nil, nil)
if got != "Failed to push" {
t.Errorf("FailHandler.Handle(push) = %q, want %q", got, "Failed to push")
}
}
func TestNumericHandler(t *testing.T) {
svc, err := New()
if err != nil {
t.Fatalf("New() failed: %v", err)
}
SetDefault(svc)
h := NumericHandler{}
tests := []struct {
key string
args []any
want string
}{
{"i18n.numeric.number", []any{int64(1234567)}, "1,234,567"},
{"i18n.numeric.ordinal", []any{1}, "1st"},
{"i18n.numeric.ordinal", []any{2}, "2nd"},
{"i18n.numeric.ordinal", []any{3}, "3rd"},
{"i18n.numeric.ordinal", []any{11}, "11th"},
{"i18n.numeric.percent", []any{0.85}, "85%"},
{"i18n.numeric.bytes", []any{int64(1536000)}, "1.5 MB"},
}
for _, tt := range tests {
t.Run(tt.key, func(t *testing.T) {
got := h.Handle(tt.key, tt.args, func() string { return "fallback" })
if got != tt.want {
t.Errorf("NumericHandler.Handle(%q, %v) = %q, want %q", tt.key, tt.args, got, tt.want)
}
})
}
// No args falls through to next
got := h.Handle("i18n.numeric.number", nil, func() string { return "fallback" })
if got != "fallback" {
t.Errorf("NumericHandler with no args should fallback, got %q", got)
}
}
func TestRunHandlerChain(t *testing.T) {
handlers := DefaultHandlers()
fallback := func() string { return "missed" }
// Label handler catches it
got := RunHandlerChain(handlers, "i18n.label.status", nil, fallback)
if got != "Status:" {
t.Errorf("chain label = %q, want %q", got, "Status:")
}
// Non-matching key falls through to fallback
got = RunHandlerChain(handlers, "some.other.key", nil, fallback)
if got != "missed" {
t.Errorf("chain miss = %q, want %q", got, "missed")
}
}
func TestDefaultHandlers(t *testing.T) {
handlers := DefaultHandlers()
if len(handlers) != 6 {
t.Errorf("DefaultHandlers() returned %d handlers, want 6", len(handlers))
}
}
// TestLabelHandler_Good verifies a label key produces a colon-suffixed result.
//
// h.Handle("i18n.label.status", nil, nil) // "Status:"
func TestLabelHandler_Good(t *testing.T) {
svc, _ := New()
SetDefault(svc)
h := LabelHandler{}
if got := h.Handle("i18n.label.status", nil, nil); got != "Status:" {
t.Errorf("LabelHandler.Handle = %q, want %q", got, "Status:")
}
}
// TestLabelHandler_Bad verifies that a non-matching key is not handled.
//
// h.Match("other.key") // false
func TestLabelHandler_Bad(t *testing.T) {
h := LabelHandler{}
if h.Match("other.key") {
t.Error("LabelHandler should not match other.key")
}
}
// TestLabelHandler_Ugly verifies that an empty word suffix returns a colon.
//
// h.Handle("i18n.label.", nil, nil) // ":"
func TestLabelHandler_Ugly(t *testing.T) {
svc, _ := New()
SetDefault(svc)
h := LabelHandler{}
got := h.Handle("i18n.label.", nil, nil)
// An empty word suffix produces just the punctuation — should not panic.
_ = got
}
// TestProgressHandler_Good verifies a progress key produces a gerund message.
//
// h.Handle("i18n.progress.build", nil, nil) // "Building..."
func TestProgressHandler_Good(t *testing.T) {
svc, _ := New()
SetDefault(svc)
h := ProgressHandler{}
if got := h.Handle("i18n.progress.build", nil, nil); got != "Building..." {
t.Errorf("ProgressHandler.Handle = %q, want %q", got, "Building...")
}
}
// TestProgressHandler_Bad verifies that a non-matching key returns false from Match.
//
// h.Match("i18n.label.status") // false
func TestProgressHandler_Bad(t *testing.T) {
h := ProgressHandler{}
if h.Match("i18n.label.status") {
t.Error("ProgressHandler should not match i18n.label.* keys")
}
}
// TestProgressHandler_Ugly verifies that a subject string appended to the progress message works.
//
// h.Handle("i18n.progress.build", []any{"config.yaml"}, nil) // "Building config.yaml..."
func TestProgressHandler_Ugly(t *testing.T) {
svc, _ := New()
SetDefault(svc)
h := ProgressHandler{}
got := h.Handle("i18n.progress.build", []any{"config.yaml"}, nil)
if got != "Building config.yaml..." {
t.Errorf("ProgressHandler.Handle with subject = %q, want %q", got, "Building config.yaml...")
}
}