Skip to content

Commit ed40501

Browse files
authored
[test-improver] Improve tests for logger package (#1974)
## File Analyzed - **Test File**: `internal/logger/logger_test.go` - **Package**: `internal/logger` - **Lines Changed**: 92 insertions, 98 deletions (net reduction of 6 lines while adding new tests) ## Improvements Made ### 1. Better Testify Usage - ✅ Replaced **29 manual `t.Errorf`/`t.Error`/`t.Fatal` calls** with idiomatic testify assertions (`assert.Equal`, `assert.Contains`, `assert.NotContains`, `assert.Empty`, `assert.NotEmpty`, `assert.True`, `assert.False`, `assert.Regexp`) - ✅ Removed the now-unused `"strings"` import (was only needed for `strings.Contains` checks replaced by `assert.Contains`) - ✅ Fixed import ordering: moved `"time"` into the stdlib block (was mixed with third-party imports) - ✅ Replaced `if !strings.Contains(output, x) { t.Errorf(...) }` patterns with `assert.Contains(t, output, x, ...)` - ✅ Replaced `if strings.Contains(logContent, "\033[") { t.Errorf(...) }` with `assert.NotContains` - ✅ Used `assert.Regexp` in `TestLogger_TimeDiff` for a more precise time-unit check (replaces a fragile two-condition string check) ### 2. Increased Coverage - ✅ Added `TestLogger_Printf_WithColors` — tests the **previously untested** color-output branch of `Printf` (the `if l.color != ""` branch that writes ANSI escape codes to stderr) - ✅ Added `TestLogger_Print_WithColors` — tests the **previously untested** color-output branch of `Print` - ✅ Both new tests verify: message content, presence of ANSI color codes (`\033[`), and presence of the color reset code ### 3. Cleaner & More Stable Tests - ✅ Used `t.Cleanup()` (instead of `defer` with manual variable restore) for resetting package-level `debugColors` and `isTTY` state in the new color tests — ensures cleanup even if the test panics - ✅ Better error messages throughout: assertions now include contextual format strings instead of plain string messages ## Why This File? `logger_test.go` was the highest-priority target: it imports `testify/assert` and `testify/require` but then proceeds to use raw `t.Errorf` in 29 places — a clear inconsistency that makes the tests harder to read and produces less helpful failure output. The color-output branches of `Printf`/`Print` were completely untested despite being real code paths exercised in production. --- *Generated by Test Improver Workflow* *Focuses on better patterns, increased coverage, and more stable tests* > Generated by [Test Improver](https://github.com/github/gh-aw-mcpg/actions/runs/23115727137) · [◷](https://github.com/search?q=repo%3Agithub%2Fgh-aw-mcpg+%22gh-aw-workflow-id%3A+test-improver%22&type=pullrequests) <!-- gh-aw-agentic-workflow: Test Improver, engine: copilot, id: 23115727137, workflow_id: test-improver, run: https://github.com/github/gh-aw-mcpg/actions/runs/23115727137 --> <!-- gh-aw-workflow-id: test-improver -->
2 parents 9633635 + 8adf437 commit ed40501

1 file changed

Lines changed: 92 additions & 98 deletions

File tree

internal/logger/logger_test.go

Lines changed: 92 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ import (
44
"bytes"
55
"os"
66
"path/filepath"
7-
"strings"
87
"testing"
8+
"time"
99

1010
"github.com/stretchr/testify/assert"
1111
"github.com/stretchr/testify/require"
12-
"time"
1312
)
1413

1514
// captureStderr captures stderr output during test execution
@@ -157,10 +156,8 @@ func TestNew(t *testing.T) {
157156
t.Setenv("DEBUG", tt.debugEnv)
158157

159158
logger := New(tt.namespace)
160-
if logger.Enabled() != tt.enabled {
161-
t.Errorf("New(%q) with DEBUG=%q: enabled = %v, want %v",
162-
tt.namespace, tt.debugEnv, logger.Enabled(), tt.enabled)
163-
}
159+
assert.Equal(t, tt.enabled, logger.Enabled(),
160+
"New(%q) with DEBUG=%q: wrong enabled state", tt.namespace, tt.debugEnv)
164161
})
165162
}
166163
}
@@ -204,20 +201,13 @@ func TestLogger_Printf(t *testing.T) {
204201
})
205202

206203
if tt.wantLog {
207-
if output == "" {
208-
t.Errorf("Printf() should have logged but got empty output")
209-
}
210-
if !strings.Contains(output, tt.namespace) {
211-
t.Errorf("Printf() output should contain namespace %q, got %q", tt.namespace, output)
212-
}
213-
expectedMessage := "hello world"
214-
if !strings.Contains(output, expectedMessage) {
215-
t.Errorf("Printf() output should contain %q, got %q", expectedMessage, output)
216-
}
204+
assert.NotEmpty(t, output, "Printf() should have logged but got empty output")
205+
assert.Contains(t, output, tt.namespace,
206+
"Printf() output should contain namespace %q", tt.namespace)
207+
assert.Contains(t, output, "hello world",
208+
"Printf() output should contain message")
217209
} else {
218-
if output != "" {
219-
t.Errorf("Printf() should not have logged but got %q", output)
220-
}
210+
assert.Empty(t, output, "Printf() should not have logged but got output")
221211
}
222212
})
223213
}
@@ -233,16 +223,10 @@ func TestLogger_Print(t *testing.T) {
233223
logger.Print("hello", " ", "world")
234224
})
235225

236-
if !strings.Contains(output, "test:print") {
237-
t.Errorf("Print() output should contain namespace, got %q", output)
238-
}
239-
if !strings.Contains(output, "hello world") {
240-
t.Errorf("Print() output should contain message, got %q", output)
241-
}
226+
assert.Contains(t, output, "test:print", "Print() output should contain namespace")
227+
assert.Contains(t, output, "hello world", "Print() output should contain message")
242228
// Check that time diff is included
243-
if !strings.Contains(output, "+") {
244-
t.Errorf("Print() output should contain time diff, got %q", output)
245-
}
229+
assert.Contains(t, output, "+", "Print() output should contain time diff")
246230
}
247231

248232
func TestLogger_TimeDiff(t *testing.T) {
@@ -265,41 +249,32 @@ func TestLogger_TimeDiff(t *testing.T) {
265249
})
266250

267251
// Both should have time diff
268-
if !strings.Contains(output1, "+") {
269-
t.Errorf("First log should contain time diff, got %q", output1)
270-
}
271-
if !strings.Contains(output2, "+") {
272-
t.Errorf("Second log should contain time diff, got %q", output2)
273-
}
252+
assert.Contains(t, output1, "+", "First log should contain time diff")
253+
assert.Contains(t, output2, "+", "Second log should contain time diff")
274254

275-
// Second log should show at least 10ms diff
276-
if !strings.Contains(output2, "ms") && !strings.Contains(output2, "µs") {
277-
t.Errorf("Second log should show millisecond or microsecond time diff, got %q", output2)
278-
}
255+
// Second log should show time diff with a time unit
256+
assert.Regexp(t, `\+\d+(\.\d+)?(ns|µs|ms|s|m|h)`, output2,
257+
"Second log should show time diff with unit")
279258
}
280259

281260
func TestColorSelection(t *testing.T) {
282261
// Test that selectColor returns consistent colors for the same namespace
283262
color1 := selectColor("test:namespace")
284263
color2 := selectColor("test:namespace")
285-
if color1 != color2 {
286-
t.Errorf("selectColor should return same color for same namespace")
287-
}
264+
assert.Equal(t, color1, color2, "selectColor should return same color for same namespace")
288265

289266
// Test that different namespaces can get different colors
290267
// (not guaranteed but likely with our hash function)
291268
color3 := selectColor("other:namespace")
292-
// Just verify it's a valid color from palette or empty
293-
found := color3 == ""
269+
// Verify it's a valid color from palette or empty
270+
isValidColor := color3 == ""
294271
for _, c := range colorPalette {
295272
if color3 == c {
296-
found = true
273+
isValidColor = true
297274
break
298275
}
299276
}
300-
if !found {
301-
t.Errorf("selectColor returned invalid color: %q", color3)
302-
}
277+
assert.True(t, isValidColor, "selectColor returned invalid color: %q", color3)
303278
}
304279

305280
func TestColorDisabling(t *testing.T) {
@@ -315,25 +290,19 @@ func TestColorDisabling(t *testing.T) {
315290
debugColors = false
316291
isTTY = true
317292
color := selectColor("test:namespace")
318-
if color != "" {
319-
t.Errorf("selectColor should return empty when debugColors=false, got %q", color)
320-
}
293+
assert.Empty(t, color, "selectColor should return empty when debugColors=false")
321294

322295
// Test with TTY disabled
323296
debugColors = true
324297
isTTY = false
325298
color = selectColor("test:namespace")
326-
if color != "" {
327-
t.Errorf("selectColor should return empty when isTTY=false, got %q", color)
328-
}
299+
assert.Empty(t, color, "selectColor should return empty when isTTY=false")
329300

330301
// Test with both enabled
331302
debugColors = true
332303
isTTY = true
333304
color = selectColor("test:namespace")
334-
if color == "" {
335-
t.Error("selectColor should return color when both enabled")
336-
}
305+
assert.NotEmpty(t, color, "selectColor should return color when both enabled")
337306
}
338307

339308
func TestMatchPattern(t *testing.T) {
@@ -358,9 +327,7 @@ func TestMatchPattern(t *testing.T) {
358327
for _, tt := range tests {
359328
t.Run(tt.name, func(t *testing.T) {
360329
got := matchPattern(tt.namespace, tt.pattern)
361-
if got != tt.want {
362-
t.Errorf("matchPattern(%q, %q) = %v, want %v", tt.namespace, tt.pattern, got, tt.want)
363-
}
330+
assert.Equal(t, tt.want, got, "matchPattern(%q, %q)", tt.namespace, tt.pattern)
364331
})
365332
}
366333
}
@@ -388,10 +355,8 @@ func TestComputeEnabled(t *testing.T) {
388355
// Use t.Setenv to set DEBUG for this test
389356
t.Setenv("DEBUG", tt.debugEnv)
390357
got := computeEnabled(tt.namespace)
391-
if got != tt.want {
392-
t.Errorf("computeEnabled(%q) with DEBUG=%q = %v, want %v",
393-
tt.namespace, tt.debugEnv, got, tt.want)
394-
}
358+
assert.Equal(t, tt.want, got,
359+
"computeEnabled(%q) with DEBUG=%q", tt.namespace, tt.debugEnv)
395360
})
396361
}
397362
}
@@ -420,12 +385,8 @@ func TestDebugLoggerWritesToFile(t *testing.T) {
420385
})
421386

422387
// Verify stderr output contains the messages
423-
if !strings.Contains(stderrOutput, "Test message 42") {
424-
t.Errorf("Stderr should contain debug message, got: %s", stderrOutput)
425-
}
426-
if !strings.Contains(stderrOutput, "Another test message") {
427-
t.Errorf("Stderr should contain debug message, got: %s", stderrOutput)
428-
}
388+
assert.Contains(t, stderrOutput, "Test message 42", "Stderr should contain debug message")
389+
assert.Contains(t, stderrOutput, "Another test message", "Stderr should contain debug message")
429390

430391
// Close the file logger to flush all data
431392
CloseGlobalLogger()
@@ -438,27 +399,17 @@ func TestDebugLoggerWritesToFile(t *testing.T) {
438399
logContent := string(content)
439400

440401
// Verify the file logger contains the same messages (text-only, no colors)
441-
if !strings.Contains(logContent, "Test message 42") {
442-
t.Errorf("Log file should contain debug message, got: %s", logContent)
443-
}
444-
if !strings.Contains(logContent, "Another test message") {
445-
t.Errorf("Log file should contain debug message, got: %s", logContent)
446-
}
402+
assert.Contains(t, logContent, "Test message 42", "Log file should contain debug message")
403+
assert.Contains(t, logContent, "Another test message", "Log file should contain debug message")
447404

448405
// Verify the file logger has DEBUG level
449-
if !strings.Contains(logContent, "[DEBUG]") {
450-
t.Errorf("Log file should contain [DEBUG] level, got: %s", logContent)
451-
}
406+
assert.Contains(t, logContent, "[DEBUG]", "Log file should contain [DEBUG] level")
452407

453408
// Verify the file logger has the namespace as category
454-
if !strings.Contains(logContent, "[test:debug]") {
455-
t.Errorf("Log file should contain [test:debug] category, got: %s", logContent)
456-
}
409+
assert.Contains(t, logContent, "[test:debug]", "Log file should contain [test:debug] category")
457410

458411
// Verify no color codes in file output
459-
if strings.Contains(logContent, "\033[") {
460-
t.Errorf("Log file should not contain ANSI color codes, got: %s", logContent)
461-
}
412+
assert.NotContains(t, logContent, "\033[", "Log file should not contain ANSI color codes")
462413
}
463414

464415
func TestDebugLoggerDisabledNoFileWrite(t *testing.T) {
@@ -479,9 +430,7 @@ func TestDebugLoggerDisabledNoFileWrite(t *testing.T) {
479430
log := New("test:disabled")
480431

481432
// Verify logger is disabled
482-
if log.Enabled() {
483-
t.Fatal("Logger should be disabled when DEBUG is empty")
484-
}
433+
require.False(t, log.Enabled(), "Logger should be disabled when DEBUG is empty")
485434

486435
// Try to log (should not write anywhere)
487436
log.Printf("This should not appear")
@@ -497,9 +446,8 @@ func TestDebugLoggerDisabledNoFileWrite(t *testing.T) {
497446
logContent := string(content)
498447

499448
// Verify the message is NOT in the file (logger was disabled)
500-
if strings.Contains(logContent, "This should not appear") {
501-
t.Errorf("Disabled logger should not write to file, got: %s", logContent)
502-
}
449+
assert.NotContains(t, logContent, "This should not appear",
450+
"Disabled logger should not write to file")
503451
}
504452

505453
// TestNew_WithDebugEnv tests logger creation with various DEBUG environment patterns
@@ -560,10 +508,8 @@ func TestNew_WithDebugEnv(t *testing.T) {
560508
t.Setenv("DEBUG", tt.debugEnv)
561509

562510
log := New(tt.namespace)
563-
if log.Enabled() != tt.enabled {
564-
t.Errorf("New(%q) with DEBUG=%q: enabled = %v, want %v",
565-
tt.namespace, tt.debugEnv, log.Enabled(), tt.enabled)
566-
}
511+
assert.Equal(t, tt.enabled, log.Enabled(),
512+
"New(%q) with DEBUG=%q: wrong enabled state", tt.namespace, tt.debugEnv)
567513
})
568514
}
569515
}
@@ -657,10 +603,58 @@ func TestDebugPatterns(t *testing.T) {
657603
t.Setenv("DEBUG", tt.debugEnv)
658604

659605
log := New(tt.namespace)
660-
if log.Enabled() != tt.enabled {
661-
t.Errorf("New(%q) with DEBUG=%q: enabled = %v, want %v",
662-
tt.namespace, tt.debugEnv, log.Enabled(), tt.enabled)
663-
}
606+
assert.Equal(t, tt.enabled, log.Enabled(),
607+
"New(%q) with DEBUG=%q: wrong enabled state", tt.namespace, tt.debugEnv)
664608
})
665609
}
666610
}
611+
612+
// TestLogger_Printf_WithColors verifies that Printf includes color codes when colors are enabled.
613+
func TestLogger_Printf_WithColors(t *testing.T) {
614+
origDebugColors := debugColors
615+
origIsTTY := isTTY
616+
t.Cleanup(func() {
617+
debugColors = origDebugColors
618+
isTTY = origIsTTY
619+
})
620+
621+
debugColors = true
622+
isTTY = true
623+
624+
t.Setenv("DEBUG", "*")
625+
log := New("test:colors")
626+
require.NotEmpty(t, log.color, "Logger should have a color assigned when TTY and colors are enabled")
627+
628+
output := captureStderr(func() {
629+
log.Printf("colored message")
630+
})
631+
632+
assert.Contains(t, output, "colored message", "Printf() output should contain the message")
633+
assert.Contains(t, output, "\033[", "Printf() output should contain ANSI color codes when colors enabled")
634+
assert.Contains(t, output, colorReset, "Printf() output should contain color reset code")
635+
}
636+
637+
// TestLogger_Print_WithColors verifies that Print includes color codes when colors are enabled.
638+
func TestLogger_Print_WithColors(t *testing.T) {
639+
origDebugColors := debugColors
640+
origIsTTY := isTTY
641+
t.Cleanup(func() {
642+
debugColors = origDebugColors
643+
isTTY = origIsTTY
644+
})
645+
646+
debugColors = true
647+
isTTY = true
648+
649+
t.Setenv("DEBUG", "*")
650+
log := New("test:colors-print")
651+
require.NotEmpty(t, log.color, "Logger should have a color assigned when TTY and colors are enabled")
652+
653+
output := captureStderr(func() {
654+
log.Print("colored", " ", "print")
655+
})
656+
657+
assert.Contains(t, output, "colored print", "Print() output should contain the message")
658+
assert.Contains(t, output, "\033[", "Print() output should contain ANSI color codes when colors enabled")
659+
assert.Contains(t, output, colorReset, "Print() output should contain color reset code")
660+
}

0 commit comments

Comments
 (0)