cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm
leaflet
readability
golang
1package shared
2
3import (
4 "bytes"
5 "errors"
6 "io"
7 "testing"
8)
9
10func TestCompoundWriter(t *testing.T) {
11 t.Run("New", func(t *testing.T) {
12 t.Run("creates writer with primary and secondary", func(t *testing.T) {
13 var primary bytes.Buffer
14 var secondary bytes.Buffer
15
16 cw := New(&primary, &secondary)
17
18 if cw == nil {
19 t.Fatal("Expected CompoundWriter to be created")
20 }
21 if cw.primary == nil {
22 t.Error("Expected primary writer to be set")
23 }
24 if cw.secondary == nil {
25 t.Error("Expected secondary writer to be set")
26 }
27 })
28 })
29
30 t.Run("Write", func(t *testing.T) {
31 t.Run("writes to both primary and secondary", func(t *testing.T) {
32 var primary bytes.Buffer
33 var secondary bytes.Buffer
34
35 cw := New(&primary, &secondary)
36
37 testData := []byte("test message")
38 n, err := cw.Write(testData)
39
40 if err != nil {
41 t.Errorf("Expected no error, got %v", err)
42 }
43 if n != len(testData) {
44 t.Errorf("Expected to write %d bytes, got %d", len(testData), n)
45 }
46
47 if primary.String() != "test message" {
48 t.Errorf("Expected primary to contain 'test message', got '%s'", primary.String())
49 }
50 if secondary.String() != "test message" {
51 t.Errorf("Expected secondary to contain 'test message', got '%s'", secondary.String())
52 }
53 })
54
55 t.Run("writes multiple times to both sinks", func(t *testing.T) {
56 var primary bytes.Buffer
57 var secondary bytes.Buffer
58
59 cw := New(&primary, &secondary)
60
61 messages := []string{"first", "second", "third"}
62 for _, msg := range messages {
63 _, err := cw.Write([]byte(msg))
64 if err != nil {
65 t.Errorf("Expected no error writing '%s', got %v", msg, err)
66 }
67 }
68
69 expected := "firstsecondthird"
70 if primary.String() != expected {
71 t.Errorf("Expected primary to contain '%s', got '%s'", expected, primary.String())
72 }
73 if secondary.String() != expected {
74 t.Errorf("Expected secondary to contain '%s', got '%s'", expected, secondary.String())
75 }
76 })
77
78 t.Run("returns error from primary writer", func(t *testing.T) {
79 var secondary bytes.Buffer
80 expectedErr := errors.New("primary write failed")
81 primary := &errorWriter{err: expectedErr}
82
83 cw := New(primary, &secondary)
84
85 _, err := cw.Write([]byte("test"))
86
87 if err == nil {
88 t.Error("Expected error from primary writer")
89 }
90 if !errors.Is(err, expectedErr) {
91 t.Errorf("Expected error '%v', got '%v'", expectedErr, err)
92 }
93 })
94
95 t.Run("returns error from secondary writer", func(t *testing.T) {
96 var primary bytes.Buffer
97 expectedErr := errors.New("secondary write failed")
98 secondary := &errorWriter{err: expectedErr}
99
100 cw := New(&primary, secondary)
101
102 _, err := cw.Write([]byte("test"))
103
104 if err == nil {
105 t.Error("Expected error from secondary writer")
106 }
107 if !errors.Is(err, expectedErr) {
108 t.Errorf("Expected error '%v', got '%v'", expectedErr, err)
109 }
110 })
111
112 t.Run("writes to primary even if secondary fails", func(t *testing.T) {
113 var primary bytes.Buffer
114 expectedErr := errors.New("secondary write failed")
115 secondary := &errorWriter{err: expectedErr}
116
117 cw := New(&primary, secondary)
118
119 testData := []byte("test message")
120 _, _ = cw.Write(testData)
121
122 if primary.String() != "test message" {
123 t.Errorf("Expected primary to contain 'test message' even with secondary error, got '%s'", primary.String())
124 }
125 })
126
127 t.Run("handles empty write", func(t *testing.T) {
128 var primary bytes.Buffer
129 var secondary bytes.Buffer
130
131 cw := New(&primary, &secondary)
132
133 n, err := cw.Write([]byte{})
134
135 if err != nil {
136 t.Errorf("Expected no error on empty write, got %v", err)
137 }
138 if n != 0 {
139 t.Errorf("Expected to write 0 bytes, got %d", n)
140 }
141 })
142
143 t.Run("handles large write", func(t *testing.T) {
144 var primary bytes.Buffer
145 var secondary bytes.Buffer
146
147 cw := New(&primary, &secondary)
148
149 largeData := make([]byte, 1024*1024) // 1MB
150 for i := range largeData {
151 largeData[i] = byte(i % 256)
152 }
153
154 n, err := cw.Write(largeData)
155
156 if err != nil {
157 t.Errorf("Expected no error on large write, got %v", err)
158 }
159 if n != len(largeData) {
160 t.Errorf("Expected to write %d bytes, got %d", len(largeData), n)
161 }
162
163 if !bytes.Equal(primary.Bytes(), largeData) {
164 t.Error("Primary writer didn't receive correct data")
165 }
166 if !bytes.Equal(secondary.Bytes(), largeData) {
167 t.Error("Secondary writer didn't receive correct data")
168 }
169 })
170 })
171
172 t.Run("WithStdErr", func(t *testing.T) {
173 t.Run("creates writer with stderr as primary", func(t *testing.T) {
174 var buf bytes.Buffer
175 closer := &nopCloser{Writer: &buf}
176
177 cw := LogWithStdErr(closer)
178
179 if cw == nil {
180 t.Fatal("Expected CompoundWriter to be created")
181 }
182
183 testData := []byte("test")
184 _, err := cw.Write(testData)
185 if err != nil {
186 t.Errorf("Expected no error, got %v", err)
187 }
188
189 if buf.String() != "test" {
190 t.Errorf("Expected secondary to contain 'test', got '%s'", buf.String())
191 }
192 })
193 })
194
195 t.Run("WithStdOut", func(t *testing.T) {
196 t.Run("creates writer with stdout as primary", func(t *testing.T) {
197 var buf bytes.Buffer
198 closer := &nopCloser{Writer: &buf}
199
200 cw := LogWithStdOut(closer)
201
202 if cw == nil {
203 t.Fatal("Expected CompoundWriter to be created")
204 }
205
206 testData := []byte("test")
207 _, err := cw.Write(testData)
208 if err != nil {
209 t.Errorf("Expected no error, got %v", err)
210 }
211
212 if buf.String() != "test" {
213 t.Errorf("Expected secondary to contain 'test', got '%s'", buf.String())
214 }
215 })
216 })
217}
218
219func TestConfigError(t *testing.T) {
220 t.Run("wraps error with message", func(t *testing.T) {
221 originalErr := errors.New("original error")
222 configErr := ConfigError("test message", originalErr)
223
224 if configErr == nil {
225 t.Fatal("Expected error to be returned")
226 }
227
228 errMsg := configErr.Error()
229 if errMsg != "configuration error\ntest message: original error" {
230 t.Errorf("Expected specific error format, got '%s'", errMsg)
231 }
232 })
233
234 t.Run("is detectable with IsConfigError", func(t *testing.T) {
235 originalErr := errors.New("original error")
236 configErr := ConfigError("test message", originalErr)
237
238 if !IsConfigError(configErr) {
239 t.Error("Expected IsConfigError to return true")
240 }
241 })
242
243 t.Run("wraps original error", func(t *testing.T) {
244 originalErr := errors.New("original error")
245 configErr := ConfigError("test message", originalErr)
246
247 if !errors.Is(configErr, originalErr) {
248 t.Error("Expected config error to wrap original error")
249 }
250 })
251}
252
253func TestIsConfigError(t *testing.T) {
254 t.Run("returns true for config error", func(t *testing.T) {
255 configErr := ConfigError("test", errors.New("inner"))
256
257 if !IsConfigError(configErr) {
258 t.Error("Expected IsConfigError to return true for config error")
259 }
260 })
261
262 t.Run("returns false for non-config error", func(t *testing.T) {
263 regularErr := errors.New("regular error")
264
265 if IsConfigError(regularErr) {
266 t.Error("Expected IsConfigError to return false for regular error")
267 }
268 })
269
270 t.Run("returns false for nil error", func(t *testing.T) {
271 if IsConfigError(nil) {
272 t.Error("Expected IsConfigError to return false for nil error")
273 }
274 })
275}
276
277type errorWriter struct {
278 err error
279}
280
281func (w *errorWriter) Write(p []byte) (int, error) {
282 return 0, w.err
283}
284
285type nopCloser struct {
286 io.Writer
287}
288
289func (nc *nopCloser) Close() error {
290 return nil
291}