package log import ( "log/slog" "os" "testing" ) func TestInit(t *testing.T) { // Save original stdout oldLogger := logger defer func() { logger = oldLogger }() Init() if logger == nil { t.Error("logger should not be nil after Init") } } func TestInitWithLevel(t *testing.T) { // Test different levels levels := []string{"DEBUG", "INFO", "WARN", "ERROR", "unknown"} for _, level := range levels { InitWithLevel(level) if logger == nil { t.Errorf("logger should not be nil for level %s", level) } } } func TestParseLevel(t *testing.T) { tests := []struct { input string expected slog.Level }{ {"DEBUG", slog.LevelDebug}, {"debug", slog.LevelDebug}, {"INFO", slog.LevelInfo}, {"info", slog.LevelInfo}, {"WARN", slog.LevelWarn}, {"WARNING", slog.LevelWarn}, {"ERROR", slog.LevelError}, {"error", slog.LevelError}, {"unknown", slog.LevelInfo}, {"", slog.LevelInfo}, } for _, test := range tests { result := parseLevel(test.input) if result != test.expected { t.Errorf("parseLevel(%q) = %v, want %v", test.input, result, test.expected) } } } func TestIsSensitive(t *testing.T) { sensitive := []string{ "token", "password", "secret", "api_key", "access_token", "PRIVATE_KEY", } for _, field := range sensitive { if !IsSensitive(field) { t.Errorf("IsSensitive(%q) should be true", field) } } notSensitive := []string{ "name", "email", "user_id", } for _, field := range notSensitive { if IsSensitive(field) { t.Errorf("IsSensitive(%q) should be false", field) } } } func TestSanitizeAttrs(t *testing.T) { // Test that sensitive fields are redacted tests := []struct { key string value string expected string }{ {"password", "secret123", "[REDACTED]"}, {"api_token", "abc123", "[REDACTED]"}, {"secret_key", "xyz789", "[REDACTED]"}, {"name", "test", "test"}, } for _, test := range tests { attr := slog.String(test.key, test.value) result := sanitizeAttrs(nil, attr) if result.Value.String() != test.expected { t.Errorf("sanitizeAttrs(%q) = %q, want %q", test.key, result.Value.String(), test.expected) } } } func TestLoggingMethods(t *testing.T) { // Just verify methods don't panic Init() Info("test info message", "key", "value") Debug("test debug message", "key", "value") Warn("test warn message", "key", "value") Error("test error message", "key", "value") } func TestLogger(t *testing.T) { Init() l := Logger() if l == nil { t.Error("Logger() should not return nil") } } func TestRequestLogger(t *testing.T) { Init() l := RequestLogger("GET", "/api/hosts", "127.0.0.1") if l == nil { t.Error("RequestLogger should not return nil") } } func TestInitWithConfig(t *testing.T) { // Test with stdout output cfg := DefaultConfig() cfg.Output = "stdout" cfg.Level = "DEBUG" InitWithConfig(cfg) if logger == nil { t.Error("logger should not be nil after InitWithConfig") } } func TestInitWithConfigFileOutput(t *testing.T) { // Test with file output (no rotation) tmpFile := t.TempDir() + "/test.log" cfg := DefaultConfig() cfg.Output = tmpFile cfg.Rotation = false InitWithConfig(cfg) Info("test message for file") // Verify file was created if _, err := os.Stat(tmpFile); os.IsNotExist(err) { t.Errorf("log file %s should exist", tmpFile) } } func TestDefaultConfig(t *testing.T) { cfg := DefaultConfig() if cfg.Level != "INFO" { t.Errorf("default Level = %s, want INFO", cfg.Level) } if cfg.Output != "stdout" { t.Errorf("default Output = %s, want stdout", cfg.Output) } if cfg.MaxSize != 100 { t.Errorf("default MaxSize = %d, want 100", cfg.MaxSize) } if cfg.MaxBackups != 3 { t.Errorf("default MaxBackups = %d, want 3", cfg.MaxBackups) } if cfg.MaxAge != 7 { t.Errorf("default MaxAge = %d, want 7", cfg.MaxAge) } if !cfg.Compress { t.Error("default Compress should be true") } }