cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm
leaflet
readability
golang
1package utils
2
3import (
4 "bytes"
5 "os"
6 "strings"
7 "testing"
8
9 "github.com/charmbracelet/log"
10)
11
12func TestNewLogger(t *testing.T) {
13 t.Run("creates logger with info level", func(t *testing.T) {
14 logger := NewLogger("info", "text")
15 if logger == nil {
16 t.Fatal("Logger should not be nil")
17 }
18
19 if logger.GetLevel() != log.InfoLevel {
20 t.Errorf("Expected InfoLevel, got %v", logger.GetLevel())
21 }
22 })
23
24 t.Run("creates logger with debug level", func(t *testing.T) {
25 logger := NewLogger("debug", "text")
26 if logger.GetLevel() != log.DebugLevel {
27 t.Errorf("Expected DebugLevel, got %v", logger.GetLevel())
28 }
29 })
30
31 t.Run("creates logger with warn level", func(t *testing.T) {
32 logger := NewLogger("warn", "text")
33 if logger.GetLevel() != log.WarnLevel {
34 t.Errorf("Expected WarnLevel, got %v", logger.GetLevel())
35 }
36 })
37
38 t.Run("creates logger with warning level alias", func(t *testing.T) {
39 logger := NewLogger("warning", "text")
40 if logger.GetLevel() != log.WarnLevel {
41 t.Errorf("Expected WarnLevel, got %v", logger.GetLevel())
42 }
43 })
44
45 t.Run("creates logger with error level", func(t *testing.T) {
46 logger := NewLogger("error", "text")
47 if logger.GetLevel() != log.ErrorLevel {
48 t.Errorf("Expected ErrorLevel, got %v", logger.GetLevel())
49 }
50 })
51
52 t.Run("defaults to info level for invalid level", func(t *testing.T) {
53 logger := NewLogger("invalid", "text")
54 if logger.GetLevel() != log.InfoLevel {
55 t.Errorf("Expected InfoLevel for invalid input, got %v", logger.GetLevel())
56 }
57 })
58
59 t.Run("handles case insensitive levels", func(t *testing.T) {
60 logger := NewLogger("DEBUG", "text")
61 if logger.GetLevel() != log.DebugLevel {
62 t.Errorf("Expected DebugLevel for uppercase input, got %v", logger.GetLevel())
63 }
64 })
65
66 t.Run("creates logger with json format", func(t *testing.T) {
67 var buf bytes.Buffer
68 logger := NewLogger("info", "json")
69 logger.SetOutput(&buf)
70
71 logger.Info("test message")
72 output := buf.String()
73
74 if !strings.Contains(output, "{") || !strings.Contains(output, "}") {
75 t.Error("Expected JSON formatted output")
76 }
77 })
78
79 t.Run("creates logger with text format", func(t *testing.T) {
80 var buf bytes.Buffer
81 logger := NewLogger("info", "text")
82 logger.SetOutput(&buf)
83
84 logger.Info("test message")
85 output := buf.String()
86
87 if strings.Contains(output, "{") && strings.Contains(output, "}") {
88 t.Error("Expected text formatted output, not JSON")
89 }
90 })
91
92 t.Run("text format includes timestamp", func(t *testing.T) {
93 var buf bytes.Buffer
94 logger := NewLogger("info", "text")
95 logger.SetOutput(&buf)
96
97 logger.Info("test message")
98 output := buf.String()
99
100 if !strings.Contains(output, ":") {
101 t.Error("Expected timestamp in text format output")
102 }
103 })
104}
105
106func TestGetLogger(t *testing.T) {
107 t.Run("returns global logger when set", func(t *testing.T) {
108 originalLogger := Logger
109 defer func() { Logger = originalLogger }()
110
111 testLogger := NewLogger("debug", "json")
112 Logger = testLogger
113
114 retrieved := GetLogger()
115 if retrieved != testLogger {
116 t.Error("GetLogger should return the global logger")
117 }
118 })
119
120 t.Run("creates default logger when global is nil", func(t *testing.T) {
121 originalLogger := Logger
122 defer func() { Logger = originalLogger }()
123
124 Logger = nil
125
126 retrieved := GetLogger()
127 if retrieved == nil {
128 t.Fatal("GetLogger should create a default logger")
129 }
130
131 if retrieved.GetLevel() != log.InfoLevel {
132 t.Error("Default logger should have InfoLevel")
133 }
134
135 if Logger != retrieved {
136 t.Error("Global logger should be set after GetLogger call")
137 }
138 })
139
140 t.Run("subsequent calls return same logger", func(t *testing.T) {
141 originalLogger := Logger
142 defer func() { Logger = originalLogger }()
143
144 Logger = nil
145
146 logger1 := GetLogger()
147 logger2 := GetLogger()
148
149 if logger1 != logger2 {
150 t.Error("Subsequent GetLogger calls should return the same instance")
151 }
152 })
153}
154
155func TestLoggerIntegration(t *testing.T) {
156 t.Run("logger writes to stderr by default", func(t *testing.T) {
157 oldStderr := os.Stderr
158 r, w, _ := os.Pipe()
159 os.Stderr = w
160
161 logger := NewLogger("info", "text")
162 logger.Info("test message")
163
164 w.Close()
165 os.Stderr = oldStderr
166
167 var buf bytes.Buffer
168 buf.ReadFrom(r)
169 output := buf.String()
170
171 if !strings.Contains(output, "test message") {
172 t.Error("Logger should write to stderr by default")
173 }
174 })
175
176 t.Run("logger respects level filtering", func(t *testing.T) {
177 var buf bytes.Buffer
178 logger := NewLogger("error", "text")
179 logger.SetOutput(&buf)
180
181 logger.Debug("debug message")
182 logger.Info("info message")
183 logger.Warn("warn message")
184 logger.Error("error message")
185
186 output := buf.String()
187
188 if strings.Contains(output, "debug message") {
189 t.Error("Debug message should be filtered out at error level")
190 }
191 if strings.Contains(output, "info message") {
192 t.Error("Info message should be filtered out at error level")
193 }
194 if strings.Contains(output, "warn message") {
195 t.Error("Warn message should be filtered out at error level")
196 }
197 if !strings.Contains(output, "error message") {
198 t.Error("Error message should be included at error level")
199 }
200 })
201
202 t.Run("global logger persists between function calls", func(t *testing.T) {
203 originalLogger := Logger
204 defer func() { Logger = originalLogger }()
205
206 Logger = NewLogger("debug", "json")
207
208 retrieved := GetLogger()
209
210 if retrieved.GetLevel() != log.DebugLevel {
211 t.Error("Global logger settings should persist")
212 }
213 })
214}