package logger import ( "context" "testing" "git.dcentral.systems/toolz/goplt/pkg/logger" "go.uber.org/zap" ) func TestNewZapLogger_JSONFormat(t *testing.T) { t.Parallel() log, err := NewZapLogger("info", "json") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } if log == nil { t.Fatal("NewZapLogger returned nil") } // Verify it implements the interface (compile-time check) _ = log // Test that it can log log.Info("test message") } func TestNewZapLogger_ConsoleFormat(t *testing.T) { t.Parallel() log, err := NewZapLogger("info", "console") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } if log == nil { t.Fatal("NewZapLogger returned nil") } // Test that it can log log.Info("test message") } func TestNewZapLogger_InvalidLevel(t *testing.T) { t.Parallel() log, err := NewZapLogger("invalid", "json") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } if log == nil { t.Fatal("NewZapLogger returned nil") } // Should default to info level log.Info("test message") } func TestNewZapLogger_AllLevels(t *testing.T) { t.Parallel() levels := []string{"debug", "info", "warn", "error"} for _, level := range levels { t.Run(level, func(t *testing.T) { t.Parallel() log, err := NewZapLogger(level, "json") if err != nil { t.Fatalf("NewZapLogger(%q) failed: %v", level, err) } if log == nil { t.Fatalf("NewZapLogger(%q) returned nil", level) } // Test logging at each level log.Debug("debug message") log.Info("info message") log.Warn("warn message") log.Error("error message") }) } } func TestZapLogger_With(t *testing.T) { t.Parallel() log, err := NewZapLogger("info", "json") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } childLog := log.With( logger.String("key", "value"), logger.Int("number", 42), ) if childLog == nil { t.Fatal("With returned nil") } // Verify it's a different logger instance if childLog == log { t.Error("With should return a new logger instance") } // Test that child logger can log childLog.Info("test message with fields") } func TestZapLogger_WithContext_RequestID(t *testing.T) { t.Parallel() log, err := NewZapLogger("info", "json") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } ctx := context.WithValue(context.Background(), requestIDKey, "test-request-id") contextLog := log.WithContext(ctx) if contextLog == nil { t.Fatal("WithContext returned nil") } // Test that context logger can log contextLog.Info("test message with request ID") } func TestZapLogger_WithContext_UserID(t *testing.T) { t.Parallel() log, err := NewZapLogger("info", "json") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } ctx := context.WithValue(context.Background(), userIDKey, "test-user-id") contextLog := log.WithContext(ctx) if contextLog == nil { t.Fatal("WithContext returned nil") } // Test that context logger can log contextLog.Info("test message with user ID") } func TestZapLogger_WithContext_Both(t *testing.T) { t.Parallel() log, err := NewZapLogger("info", "json") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } ctx := context.WithValue(context.Background(), requestIDKey, "test-request-id") ctx = context.WithValue(ctx, userIDKey, "test-user-id") contextLog := log.WithContext(ctx) if contextLog == nil { t.Fatal("WithContext returned nil") } // Test that context logger can log contextLog.Info("test message with both IDs") } func TestZapLogger_WithContext_EmptyContext(t *testing.T) { t.Parallel() log, err := NewZapLogger("info", "json") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } ctx := context.Background() contextLog := log.WithContext(ctx) if contextLog == nil { t.Fatal("WithContext returned nil") } // With empty context, should return the same logger if contextLog != log { t.Error("WithContext with empty context should return the same logger") } } func TestZapLogger_LoggingMethods(t *testing.T) { t.Parallel() log, err := NewZapLogger("debug", "json") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } fields := []logger.Field{ logger.String("key", "value"), logger.Int("number", 42), logger.Bool("flag", true), } // Test all logging methods log.Debug("debug message", fields...) log.Info("info message", fields...) log.Warn("warn message", fields...) log.Error("error message", fields...) } func TestConvertFields(t *testing.T) { t.Parallel() tests := []struct { name string fields []logger.Field }{ { name: "empty fields", fields: []logger.Field{}, }, { name: "valid zap fields", fields: []logger.Field{ zap.String("key", "value"), zap.Int("number", 42), }, }, { name: "mixed fields", fields: []logger.Field{ logger.String("key", "value"), zap.Int("number", 42), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() log, err := NewZapLogger("info", "json") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } // Test that convertFields works by logging log.Info("test message", tt.fields...) }) } } func TestRequestIDKey(t *testing.T) { t.Parallel() key := RequestIDKey() if key == "" { t.Error("RequestIDKey returned empty contextKey") } if key != requestIDKey { t.Errorf("RequestIDKey() = %v, want %v", key, requestIDKey) } } func TestUserIDKey(t *testing.T) { t.Parallel() key := UserIDKey() if key == "" { t.Error("UserIDKey returned empty contextKey") } if key != userIDKey { t.Errorf("UserIDKey() = %v, want %v", key, userIDKey) } } func TestZapLogger_ChainedWith(t *testing.T) { t.Parallel() log, err := NewZapLogger("info", "json") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } // Chain multiple With calls childLog := log.With( logger.String("parent", "value1"), ).With( logger.String("child", "value2"), ) if childLog == nil { t.Fatal("Chained With returned nil") } childLog.Info("test message with chained fields") } func TestZapLogger_WithContext_ChainedWith(t *testing.T) { t.Parallel() log, err := NewZapLogger("info", "json") if err != nil { t.Fatalf("NewZapLogger failed: %v", err) } ctx := context.WithValue(context.Background(), requestIDKey, "test-id") contextLog := log.WithContext(ctx).With( logger.String("additional", "field"), ) if contextLog == nil { t.Fatal("Chained WithContext and With returned nil") } contextLog.Info("test message with context and additional fields") } // Benchmark tests func BenchmarkZapLogger_Info(b *testing.B) { log, err := NewZapLogger("info", "json") if err != nil { b.Fatalf("NewZapLogger failed: %v", err) } b.ResetTimer() for i := 0; i < b.N; i++ { log.Info("benchmark message") } } func BenchmarkZapLogger_InfoWithFields(b *testing.B) { log, err := NewZapLogger("info", "json") if err != nil { b.Fatalf("NewZapLogger failed: %v", err) } fields := []logger.Field{ logger.String("key1", "value1"), logger.Int("key2", 42), logger.Bool("key3", true), } b.ResetTimer() for i := 0; i < b.N; i++ { log.Info("benchmark message", fields...) } } func BenchmarkZapLogger_WithContext(b *testing.B) { log, err := NewZapLogger("info", "json") if err != nil { b.Fatalf("NewZapLogger failed: %v", err) } ctx := context.WithValue(context.Background(), requestIDKey, "test-id") b.ResetTimer() for i := 0; i < b.N; i++ { _ = log.WithContext(ctx) } }