Add comprehensive edge case tests for status line functions

This commit is contained in:
2025-12-18 11:29:46 +01:00
parent 52d6bbaf84
commit 58aaad4c9c

View File

@ -494,3 +494,328 @@ func TestFormatOutput_WithANSI(t *testing.T) {
t.Errorf("formatOutput with ANSI = %q, expected both parts visible", stripped) t.Errorf("formatOutput with ANSI = %q, expected both parts visible", stripped)
} }
} }
// Additional edge case tests
func TestFormatContextInfo_MaxTokens(t *testing.T) {
// Test when usage equals context size
usage := &TokenUsage{
InputTokens: 200000,
CacheCreationTokens: 0,
CacheReadInputTokens: 0,
}
result := formatContextInfo(200000, usage)
expected := "200k/200k"
if result != expected {
t.Errorf("formatContextInfo(max) = %q, want %q", result, expected)
}
}
func TestFormatContextInfo_OverflowTokens(t *testing.T) {
// Test when usage exceeds context size
usage := &TokenUsage{
InputTokens: 250000,
CacheCreationTokens: 0,
CacheReadInputTokens: 0,
}
result := formatContextInfo(200000, usage)
expected := "250k/200k"
if result != expected {
t.Errorf("formatContextInfo(overflow) = %q, want %q", result, expected)
}
}
func TestFormatContextInfo_AllCacheTypes(t *testing.T) {
// Test all cache token types contributing
usage := &TokenUsage{
InputTokens: 10000,
CacheCreationTokens: 20000,
CacheReadInputTokens: 30000,
}
result := formatContextInfo(100000, usage)
expected := "60k/100k"
if result != expected {
t.Errorf("formatContextInfo(all cache) = %q, want %q", result, expected)
}
}
func TestFormatContextInfo_OnlyCacheCreation(t *testing.T) {
usage := &TokenUsage{
InputTokens: 0,
CacheCreationTokens: 5000,
CacheReadInputTokens: 0,
}
result := formatContextInfo(100000, usage)
expected := "5k/100k"
if result != expected {
t.Errorf("formatContextInfo(cache creation) = %q, want %q", result, expected)
}
}
func TestFormatContextInfo_OnlyCacheRead(t *testing.T) {
usage := &TokenUsage{
InputTokens: 0,
CacheCreationTokens: 0,
CacheReadInputTokens: 8000,
}
result := formatContextInfo(100000, usage)
expected := "8k/100k"
if result != expected {
t.Errorf("formatContextInfo(cache read) = %q, want %q", result, expected)
}
}
func TestBuildStatusLine_EmptyDir(t *testing.T) {
data := &StatusInput{}
data.Model.DisplayName = "Model"
data.Workspace.CurrentDir = ""
data.ContextWindow.ContextWindowSize = 100000
left, right := buildStatusLine(data)
// Should not panic, should produce valid output
if left == "" {
t.Error("buildStatusLine with empty dir should produce left output")
}
if right == "" {
t.Error("buildStatusLine with empty dir should produce right output")
}
}
func TestBuildStatusLine_LongModelName(t *testing.T) {
data := &StatusInput{}
data.Model.DisplayName = "Claude 3.5 Sonnet with Extended Context"
data.Workspace.CurrentDir = "/home/user/my-very-long-project-name-here"
data.ContextWindow.ContextWindowSize = 200000
data.ContextWindow.CurrentUsage = &TokenUsage{
InputTokens: 50000,
}
left, right := buildStatusLine(data)
if !contains(left, "Claude 3.5 Sonnet with Extended Context") {
t.Errorf("long model name not in left: %q", left)
}
if !contains(left, "my-very-long-project-name-here") {
t.Errorf("long dir name not in left: %q", left)
}
if !contains(right, "50k/200k") {
t.Errorf("context info not in right: %q", right)
}
}
func TestBuildStatusLine_NilUsage(t *testing.T) {
data := &StatusInput{}
data.Model.DisplayName = "Model"
data.Workspace.CurrentDir = "/test"
data.ContextWindow.ContextWindowSize = 100000
data.ContextWindow.CurrentUsage = nil
left, right := buildStatusLine(data)
if !contains(right, "0/100k") {
t.Errorf("nil usage should show 0: %q", right)
}
if left == "" {
t.Error("left should not be empty")
}
}
func TestBuildStatusLine_RootDir(t *testing.T) {
data := &StatusInput{}
data.Model.DisplayName = "Model"
data.Workspace.CurrentDir = "/"
data.ContextWindow.ContextWindowSize = 100000
left, _ := buildStatusLine(data)
// filepath.Base("/") returns "/"
if !contains(left, "/") || !contains(left, "Model") {
t.Errorf("root dir handling failed: %q", left)
}
}
func TestCalculatePadding_ExactFit(t *testing.T) {
// When content exactly fills the width
result := calculatePadding("12345", "67890", 10)
expected := 1 // max(10-5-5, 1) = max(0, 1) = 1
if result != expected {
t.Errorf("calculatePadding(exact fit) = %d, want %d", result, expected)
}
}
func TestCalculatePadding_LargeWidth(t *testing.T) {
result := calculatePadding("left", "right", 200)
expected := 200 - 4 - 5 // 191
if result != expected {
t.Errorf("calculatePadding(large) = %d, want %d", result, expected)
}
}
func TestStripANSI_256Color(t *testing.T) {
// 256-color escape sequences
input := "\033[38;5;196mred\033[0m"
result := stripANSI(input)
expected := "red"
if result != expected {
t.Errorf("stripANSI(256color) = %q, want %q", result, expected)
}
}
func TestStripANSI_TrueColor(t *testing.T) {
// 24-bit true color escape sequences
input := "\033[38;2;255;0;0mred\033[0m"
result := stripANSI(input)
expected := "red"
if result != expected {
t.Errorf("stripANSI(truecolor) = %q, want %q", result, expected)
}
}
func TestStripANSI_Multiline(t *testing.T) {
input := "\033[31mline1\033[0m\n\033[32mline2\033[0m"
result := stripANSI(input)
expected := "line1\nline2"
if result != expected {
t.Errorf("stripANSI(multiline) = %q, want %q", result, expected)
}
}
func TestReadInputFromStdin_SingleLine(t *testing.T) {
reader := bufio.NewReader(strings.NewReader("single line"))
result := readInputFromStdin(reader)
if result != "single line" {
t.Errorf("readInputFromStdin(single) = %q, want 'single line'", result)
}
}
func TestReadInputFromStdin_JSONLike(t *testing.T) {
jsonStr := `{"key": "value", "nested": {"a": 1}}`
reader := bufio.NewReader(strings.NewReader(jsonStr))
result := readInputFromStdin(reader)
if result != jsonStr {
t.Errorf("readInputFromStdin(json) = %q, want %q", result, jsonStr)
}
}
func TestParseStatusInput_AllFields(t *testing.T) {
jsonStr := `{
"model": {"display_name": "FullTest"},
"workspace": {"current_dir": "/full/path"},
"context_window": {
"context_window_size": 150000,
"current_usage": {
"input_tokens": 1000,
"cache_creation_input_tokens": 2000,
"cache_read_input_tokens": 3000
}
}
}`
data, err := parseStatusInput(jsonStr)
if err != nil {
t.Fatalf("parseStatusInput failed: %v", err)
}
if data.Model.DisplayName != "FullTest" {
t.Errorf("DisplayName = %q, want FullTest", data.Model.DisplayName)
}
if data.ContextWindow.CurrentUsage.CacheCreationTokens != 2000 {
t.Errorf("CacheCreationTokens = %d, want 2000", data.ContextWindow.CurrentUsage.CacheCreationTokens)
}
if data.ContextWindow.CurrentUsage.CacheReadInputTokens != 3000 {
t.Errorf("CacheReadInputTokens = %d, want 3000", data.ContextWindow.CurrentUsage.CacheReadInputTokens)
}
}
func TestParseStatusInput_ExtraFields(t *testing.T) {
// JSON with extra unknown fields should still parse
jsonStr := `{"model": {"display_name": "Test", "unknown": "field"}, "extra": "data"}`
data, err := parseStatusInput(jsonStr)
if err != nil {
t.Fatalf("parseStatusInput with extra fields failed: %v", err)
}
if data.Model.DisplayName != "Test" {
t.Errorf("DisplayName = %q, want Test", data.Model.DisplayName)
}
}
func TestTokenUsage_ZeroValues(t *testing.T) {
usage := &TokenUsage{
InputTokens: 0,
CacheCreationTokens: 0,
CacheReadInputTokens: 0,
}
result := formatContextInfo(100000, usage)
expected := "0k/100k"
if result != expected {
t.Errorf("formatContextInfo(zero usage) = %q, want %q", result, expected)
}
}
func TestStatuslineWidthOffset_Constant(t *testing.T) {
// Verify the constant is defined and reasonable
if statuslineWidthOffset <= 0 || statuslineWidthOffset > 20 {
t.Errorf("statuslineWidthOffset = %d, expected between 1 and 20", statuslineWidthOffset)
}
}
// Benchmark tests
func BenchmarkFormatContextInfo(b *testing.B) {
usage := &TokenUsage{
InputTokens: 50000,
CacheCreationTokens: 10000,
CacheReadInputTokens: 5000,
}
for i := 0; i < b.N; i++ {
formatContextInfo(200000, usage)
}
}
func BenchmarkStripANSI(b *testing.B) {
input := "\033[32m●\033[0m \033[35mOpus\033[0m \033[1;32m➜\033[0m \033[36mproject\033[0m"
for i := 0; i < b.N; i++ {
stripANSI(input)
}
}
func BenchmarkParseStatusInput(b *testing.B) {
jsonStr := `{"model": {"display_name": "Test"}, "workspace": {"current_dir": "/test"}, "context_window": {"context_window_size": 200000, "current_usage": {"input_tokens": 50000}}}`
for i := 0; i < b.N; i++ {
parseStatusInput(jsonStr)
}
}
func BenchmarkBuildStatusLine(b *testing.B) {
data := &StatusInput{}
data.Model.DisplayName = "Claude Opus"
data.Workspace.CurrentDir = "/home/user/project"
data.ContextWindow.ContextWindowSize = 200000
data.ContextWindow.CurrentUsage = &TokenUsage{
InputTokens: 50000,
}
for i := 0; i < b.N; i++ {
buildStatusLine(data)
}
}
func BenchmarkCalculatePadding(b *testing.B) {
for i := 0; i < b.N; i++ {
calculatePadding("left side content", "right side", 120)
}
}
func BenchmarkFormatOutput(b *testing.B) {
left := red + "left" + reset
right := green + "right" + reset
for i := 0; i < b.N; i++ {
formatOutput(left, right, 50)
}
}
func BenchmarkReadInputFromStdin(b *testing.B) {
jsonStr := `{"model": {"display_name": "Test"}, "workspace": {"current_dir": "/test"}}`
for i := 0; i < b.N; i++ {
reader := bufio.NewReader(strings.NewReader(jsonStr))
readInputFromStdin(reader)
}
}