package logger import ( "bytes" "context" "log/slog" "os" "testing" "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gormlogger "gorm.io/gorm/logger" ) // ---------- multiHandler ---------- type countingHandler struct { enabled bool handled int attrs []slog.Attr group string } func (h *countingHandler) Enabled(_ context.Context, _ slog.Level) bool { return h.enabled } func (h *countingHandler) Handle(_ context.Context, _ slog.Record) error { h.handled++ return nil } func (h *countingHandler) WithAttrs(attrs []slog.Attr) slog.Handler { return &countingHandler{enabled: h.enabled, attrs: attrs} } func (h *countingHandler) WithGroup(name string) slog.Handler { return &countingHandler{enabled: h.enabled, group: name} } func TestMultiHandlerEnabledAny(t *testing.T) { a := &countingHandler{enabled: false} b := &countingHandler{enabled: true} mh := &multiHandler{handlers: []slog.Handler{a, b}} assert.True(t, mh.Enabled(context.Background(), slog.LevelInfo)) } func TestMultiHandlerEnabledNone(t *testing.T) { a := &countingHandler{enabled: false} b := &countingHandler{enabled: false} mh := &multiHandler{handlers: []slog.Handler{a, b}} assert.False(t, mh.Enabled(context.Background(), slog.LevelInfo)) } func TestMultiHandlerHandle(t *testing.T) { a := &countingHandler{enabled: true} b := &countingHandler{enabled: true} mh := &multiHandler{handlers: []slog.Handler{a, b}} var r slog.Record r = slog.NewRecord(r.Time, slog.LevelInfo, "hello", 0) require.NoError(t, mh.Handle(context.Background(), r)) assert.Equal(t, 1, a.handled) assert.Equal(t, 1, b.handled) } func TestMultiHandlerWithAttrs(t *testing.T) { a := &countingHandler{enabled: true} mh := &multiHandler{handlers: []slog.Handler{a}} attrs := []slog.Attr{slog.String("k", "v")} result := mh.WithAttrs(attrs) require.NotNil(t, result) inner, ok := result.(*multiHandler) require.True(t, ok) assert.Len(t, inner.handlers, 1) } func TestMultiHandlerWithGroup(t *testing.T) { a := &countingHandler{enabled: true} mh := &multiHandler{handlers: []slog.Handler{a}} result := mh.WithGroup("mygroup") require.NotNil(t, result) inner, ok := result.(*multiHandler) require.True(t, ok) assert.Len(t, inner.handlers, 1) } // ---------- SlogWriter ---------- func TestSlogWriterPrintf(t *testing.T) { // Redirect slog to a buffer so the Printf output can be verified. var buf bytes.Buffer h := slog.NewTextHandler(&buf, &slog.HandlerOptions{Level: slog.LevelDebug}) old := slog.Default() slog.SetDefault(slog.New(h)) defer slog.SetDefault(old) w := &SlogWriter{} assert.NotPanics(t, func() { w.Printf("hello %s %d", "world", 42) }) assert.Contains(t, buf.String(), "hello world 42") } // ---------- GormLogger ---------- func TestGormLoggerNotNil(t *testing.T) { l := GormLogger() require.NotNil(t, l) _, ok := l.(gormlogger.Interface) assert.True(t, ok) } // ---------- Init ---------- func TestLoggerInitLevelInfo(t *testing.T) { viper.Set("server.log_level", "info") viper.Set("server.service_name", "test-svc") defer viper.Reset() assert.NotPanics(t, func() { Init() }) } func TestLoggerInitLevelDebug(t *testing.T) { t.Cleanup(func() { os.Remove("app.log") }) viper.Set("server.log_level", "debug") viper.Set("server.service_name", "test-svc") defer viper.Reset() assert.NotPanics(t, func() { Init() }) } func TestLoggerInitLevelWarn(t *testing.T) { viper.Set("server.log_level", "warn") viper.Set("server.service_name", "test-svc") defer viper.Reset() assert.NotPanics(t, func() { Init() }) } func TestLoggerInitLevelError(t *testing.T) { viper.Set("server.log_level", "error") viper.Set("server.service_name", "test-svc") defer viper.Reset() assert.NotPanics(t, func() { Init() }) } func TestLoggerInitUnknownLevel(t *testing.T) { viper.Set("server.log_level", "verbose") viper.Set("server.service_name", "test-svc") defer viper.Reset() // Unknown level falls back to info — must not panic. assert.NotPanics(t, func() { Init() }) }