package logger import ( "strings" "testing" ) func TestParseLogLevel(t *testing.T) { tests := []struct { input string want LogLevel }{ {"debug", DEBUG}, {"DEBUG", DEBUG}, {"info", INFO}, {"INFO", INFO}, {"warn", WARN}, {"WARN", WARN}, {"warning", WARN}, {"WARNING", WARN}, {"error", ERROR}, {"ERROR", ERROR}, {"invalid", INFO}, {"", INFO}, } for _, tt := range tests { got := ParseLogLevel(tt.input) if got != tt.want { t.Errorf("ParseLogLevel(%q) = %v, want %v", tt.input, got, tt.want) } } } func TestLogger_LevelFiltering(t *testing.T) { tests := []struct { loggerLevel string logLevel LogLevel shouldLog bool }{ {"debug", DEBUG, true}, {"debug", INFO, true}, {"info", DEBUG, false}, {"info", INFO, true}, {"warn", INFO, false}, {"warn", WARN, true}, {"error", WARN, false}, {"error", ERROR, true}, } for _, tt := range tests { l := NewWithLevel("test", tt.loggerLevel) got := l.ShouldLog(tt.logLevel) if got != tt.shouldLog { t.Errorf("level=%s ShouldLog(%v)=%v want %v", tt.loggerLevel, tt.logLevel, got, tt.shouldLog) } } } func TestLogger_WithFields(t *testing.T) { l := New("test") l2 := l.WithFields(map[string]any{"key": "value", "n": 42}) if l2 == l { t.Error("WithFields should return a new Logger") } if len(l2.fields) != 2 { t.Errorf("expected 2 fields, got %d", len(l2.fields)) } } func TestLogger_SetLevel(t *testing.T) { l := New("test") if l.minLevel != INFO { t.Errorf("default level should be INFO, got %v", l.minLevel) } l.SetLevel("debug") if l.minLevel != DEBUG { t.Errorf("level after SetLevel(debug) should be DEBUG, got %v", l.minLevel) } } func TestComponentLogger_Interface(t *testing.T) { cl := NewComponentLogger("debug") // Verify it implements the component-based interface by calling all methods cl.Debug("component", "debug msg", nil) cl.Info("component", "info msg", map[string]string{"key": "val"}) cl.Warn("component", "warn msg", nil) cl.Error("component", "error msg", map[string]string{"err": "test"}) cl.Log("component", "info", "log msg", nil) } func TestComponentLogger_LevelFiltering(t *testing.T) { cl := NewComponentLogger("warn") // At warn level, debug and info should be filtered if cl.Logger.ShouldLog(DEBUG) { t.Error("DEBUG should be filtered at warn level") } if cl.Logger.ShouldLog(INFO) { t.Error("INFO should be filtered at warn level") } if !cl.Logger.ShouldLog(WARN) { t.Error("WARN should pass at warn level") } } func TestLogger_LogLevelString(t *testing.T) { tests := []struct { level LogLevel want string }{ {DEBUG, "DEBUG"}, {INFO, "INFO"}, {WARN, "WARN"}, {ERROR, "ERROR"}, } for _, tt := range tests { if got := tt.level.String(); got != tt.want { t.Errorf("%v.String() = %q, want %q", tt.level, got, tt.want) } } } func TestLogger_EmitContainsLevel(t *testing.T) { // Use a custom logger that captures output var buf strings.Builder l := New("myservice") l.logger.SetOutput(&buf) l.SetLevel("debug") l.Info("hello from info") if !strings.Contains(buf.String(), "INFO") { t.Errorf("expected INFO in output, got: %s", buf.String()) } buf.Reset() l.Debug("hello from debug") if !strings.Contains(buf.String(), "DEBUG") { t.Errorf("expected DEBUG in output, got: %s", buf.String()) } }