1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package zapcore
22
23 import (
24 "testing"
25 "time"
26
27 "github.com/stretchr/testify/assert"
28 "github.com/stretchr/testify/require"
29 )
30
31 func TestMapObjectEncoderAdd(t *testing.T) {
32
33 wantTurducken := map[string]interface{}{
34 "ducks": []interface{}{
35 map[string]interface{}{"in": "chicken"},
36 map[string]interface{}{"in": "chicken"},
37 },
38 }
39
40 tests := []struct {
41 desc string
42 f func(ObjectEncoder)
43 expected interface{}
44 }{
45 {
46 desc: "AddObject",
47 f: func(e ObjectEncoder) {
48 assert.NoError(t, e.AddObject("k", loggable{true}), "Expected AddObject to succeed.")
49 },
50 expected: map[string]interface{}{"loggable": "yes"},
51 },
52 {
53 desc: "AddObject (nested)",
54 f: func(e ObjectEncoder) {
55 assert.NoError(t, e.AddObject("k", turducken{}), "Expected AddObject to succeed.")
56 },
57 expected: wantTurducken,
58 },
59 {
60 desc: "AddArray",
61 f: func(e ObjectEncoder) {
62 assert.NoError(t, e.AddArray("k", ArrayMarshalerFunc(func(arr ArrayEncoder) error {
63 arr.AppendBool(true)
64 arr.AppendBool(false)
65 arr.AppendBool(true)
66 return nil
67 })), "Expected AddArray to succeed.")
68 },
69 expected: []interface{}{true, false, true},
70 },
71 {
72 desc: "AddArray (nested)",
73 f: func(e ObjectEncoder) {
74 assert.NoError(t, e.AddArray("k", turduckens(2)), "Expected AddArray to succeed.")
75 },
76 expected: []interface{}{wantTurducken, wantTurducken},
77 },
78 {
79 desc: "AddArray (empty)",
80 f: func(e ObjectEncoder) {
81 assert.NoError(t, e.AddArray("k", turduckens(0)), "Expected AddArray to succeed.")
82 },
83 expected: []interface{}{},
84 },
85 {
86 desc: "AddBinary",
87 f: func(e ObjectEncoder) { e.AddBinary("k", []byte("foo")) },
88 expected: []byte("foo"),
89 },
90 {
91 desc: "AddByteString",
92 f: func(e ObjectEncoder) { e.AddByteString("k", []byte("foo")) },
93 expected: "foo",
94 },
95 {
96 desc: "AddBool",
97 f: func(e ObjectEncoder) { e.AddBool("k", true) },
98 expected: true,
99 },
100 {
101 desc: "AddComplex128",
102 f: func(e ObjectEncoder) { e.AddComplex128("k", 1+2i) },
103 expected: 1 + 2i,
104 },
105 {
106 desc: "AddComplex64",
107 f: func(e ObjectEncoder) { e.AddComplex64("k", 1+2i) },
108 expected: complex64(1 + 2i),
109 },
110 {
111 desc: "AddDuration",
112 f: func(e ObjectEncoder) { e.AddDuration("k", time.Millisecond) },
113 expected: time.Millisecond,
114 },
115 {
116 desc: "AddFloat64",
117 f: func(e ObjectEncoder) { e.AddFloat64("k", 3.14) },
118 expected: 3.14,
119 },
120 {
121 desc: "AddFloat32",
122 f: func(e ObjectEncoder) { e.AddFloat32("k", 3.14) },
123 expected: float32(3.14),
124 },
125 {
126 desc: "AddInt",
127 f: func(e ObjectEncoder) { e.AddInt("k", 42) },
128 expected: 42,
129 },
130 {
131 desc: "AddInt64",
132 f: func(e ObjectEncoder) { e.AddInt64("k", 42) },
133 expected: int64(42),
134 },
135 {
136 desc: "AddInt32",
137 f: func(e ObjectEncoder) { e.AddInt32("k", 42) },
138 expected: int32(42),
139 },
140 {
141 desc: "AddInt16",
142 f: func(e ObjectEncoder) { e.AddInt16("k", 42) },
143 expected: int16(42),
144 },
145 {
146 desc: "AddInt8",
147 f: func(e ObjectEncoder) { e.AddInt8("k", 42) },
148 expected: int8(42),
149 },
150 {
151 desc: "AddString",
152 f: func(e ObjectEncoder) { e.AddString("k", "v") },
153 expected: "v",
154 },
155 {
156 desc: "AddTime",
157 f: func(e ObjectEncoder) { e.AddTime("k", time.Unix(0, 100)) },
158 expected: time.Unix(0, 100),
159 },
160 {
161 desc: "AddUint",
162 f: func(e ObjectEncoder) { e.AddUint("k", 42) },
163 expected: uint(42),
164 },
165 {
166 desc: "AddUint64",
167 f: func(e ObjectEncoder) { e.AddUint64("k", 42) },
168 expected: uint64(42),
169 },
170 {
171 desc: "AddUint32",
172 f: func(e ObjectEncoder) { e.AddUint32("k", 42) },
173 expected: uint32(42),
174 },
175 {
176 desc: "AddUint16",
177 f: func(e ObjectEncoder) { e.AddUint16("k", 42) },
178 expected: uint16(42),
179 },
180 {
181 desc: "AddUint8",
182 f: func(e ObjectEncoder) { e.AddUint8("k", 42) },
183 expected: uint8(42),
184 },
185 {
186 desc: "AddUintptr",
187 f: func(e ObjectEncoder) { e.AddUintptr("k", 42) },
188 expected: uintptr(42),
189 },
190 {
191 desc: "AddReflected",
192 f: func(e ObjectEncoder) {
193 assert.NoError(t, e.AddReflected("k", map[string]interface{}{"foo": 5}), "Expected AddReflected to succeed.")
194 },
195 expected: map[string]interface{}{"foo": 5},
196 },
197 {
198 desc: "OpenNamespace",
199 f: func(e ObjectEncoder) {
200 e.OpenNamespace("k")
201 e.AddInt("foo", 1)
202 e.OpenNamespace("middle")
203 e.AddInt("foo", 2)
204 e.OpenNamespace("inner")
205 e.AddInt("foo", 3)
206 },
207 expected: map[string]interface{}{
208 "foo": 1,
209 "middle": map[string]interface{}{
210 "foo": 2,
211 "inner": map[string]interface{}{
212 "foo": 3,
213 },
214 },
215 },
216 },
217 {
218 desc: "object (no nested namespace) then string",
219 f: func(e ObjectEncoder) {
220 e.OpenNamespace("k")
221 assert.NoError(t, e.AddObject("obj", maybeNamespace{false}))
222 e.AddString("not-obj", "should-be-outside-obj")
223 },
224 expected: map[string]interface{}{
225 "obj": map[string]interface{}{
226 "obj-out": "obj-outside-namespace",
227 },
228 "not-obj": "should-be-outside-obj",
229 },
230 },
231 {
232 desc: "object (with nested namespace) then string",
233 f: func(e ObjectEncoder) {
234 e.OpenNamespace("k")
235 assert.NoError(t, e.AddObject("obj", maybeNamespace{true}))
236 e.AddString("not-obj", "should-be-outside-obj")
237 },
238 expected: map[string]interface{}{
239 "obj": map[string]interface{}{
240 "obj-out": "obj-outside-namespace",
241 "obj-namespace": map[string]interface{}{
242 "obj-in": "obj-inside-namespace",
243 },
244 },
245 "not-obj": "should-be-outside-obj",
246 },
247 },
248 }
249
250 for _, tt := range tests {
251 t.Run(tt.desc, func(t *testing.T) {
252 enc := NewMapObjectEncoder()
253 tt.f(enc)
254 assert.Equal(t, tt.expected, enc.Fields["k"], "Unexpected encoder output.")
255 })
256 }
257 }
258
259 func TestSliceArrayEncoderAppend(t *testing.T) {
260 tests := []struct {
261 desc string
262 f func(ArrayEncoder)
263 expected interface{}
264 }{
265
266
267 {"AppendBool", func(e ArrayEncoder) { e.AppendBool(true) }, true},
268 {"AppendByteString", func(e ArrayEncoder) { e.AppendByteString([]byte("foo")) }, "foo"},
269 {"AppendComplex128", func(e ArrayEncoder) { e.AppendComplex128(1 + 2i) }, 1 + 2i},
270 {"AppendComplex64", func(e ArrayEncoder) { e.AppendComplex64(1 + 2i) }, complex64(1 + 2i)},
271 {"AppendDuration", func(e ArrayEncoder) { e.AppendDuration(time.Second) }, time.Second},
272 {"AppendFloat64", func(e ArrayEncoder) { e.AppendFloat64(3.14) }, 3.14},
273 {"AppendFloat32", func(e ArrayEncoder) { e.AppendFloat32(3.14) }, float32(3.14)},
274 {"AppendInt", func(e ArrayEncoder) { e.AppendInt(42) }, 42},
275 {"AppendInt64", func(e ArrayEncoder) { e.AppendInt64(42) }, int64(42)},
276 {"AppendInt32", func(e ArrayEncoder) { e.AppendInt32(42) }, int32(42)},
277 {"AppendInt16", func(e ArrayEncoder) { e.AppendInt16(42) }, int16(42)},
278 {"AppendInt8", func(e ArrayEncoder) { e.AppendInt8(42) }, int8(42)},
279 {"AppendString", func(e ArrayEncoder) { e.AppendString("foo") }, "foo"},
280 {"AppendTime", func(e ArrayEncoder) { e.AppendTime(time.Unix(0, 100)) }, time.Unix(0, 100)},
281 {"AppendUint", func(e ArrayEncoder) { e.AppendUint(42) }, uint(42)},
282 {"AppendUint64", func(e ArrayEncoder) { e.AppendUint64(42) }, uint64(42)},
283 {"AppendUint32", func(e ArrayEncoder) { e.AppendUint32(42) }, uint32(42)},
284 {"AppendUint16", func(e ArrayEncoder) { e.AppendUint16(42) }, uint16(42)},
285 {"AppendUint8", func(e ArrayEncoder) { e.AppendUint8(42) }, uint8(42)},
286 {"AppendUintptr", func(e ArrayEncoder) { e.AppendUintptr(42) }, uintptr(42)},
287 {
288 desc: "AppendReflected",
289 f: func(e ArrayEncoder) {
290 assert.NoError(t, e.AppendReflected(map[string]interface{}{"foo": 5}))
291 },
292 expected: map[string]interface{}{"foo": 5},
293 },
294 {
295 desc: "AppendArray (arrays of arrays)",
296 f: func(e ArrayEncoder) {
297 err := e.AppendArray(ArrayMarshalerFunc(func(inner ArrayEncoder) error {
298 inner.AppendBool(true)
299 inner.AppendBool(false)
300 return nil
301 }))
302 assert.NoError(t, err)
303 },
304 expected: []interface{}{true, false},
305 },
306 {
307 desc: "object (no nested namespace) then string",
308 f: func(e ArrayEncoder) {
309 err := e.AppendArray(ArrayMarshalerFunc(func(inner ArrayEncoder) error {
310 err := inner.AppendObject(maybeNamespace{false})
311 inner.AppendString("should-be-outside-obj")
312 return err
313 }))
314 assert.NoError(t, err)
315 },
316 expected: []interface{}{
317 map[string]interface{}{
318 "obj-out": "obj-outside-namespace",
319 },
320 "should-be-outside-obj",
321 },
322 },
323 {
324 desc: "object (with nested namespace) then string",
325 f: func(e ArrayEncoder) {
326 err := e.AppendArray(ArrayMarshalerFunc(func(inner ArrayEncoder) error {
327 err := inner.AppendObject(maybeNamespace{true})
328 inner.AppendString("should-be-outside-obj")
329 return err
330 }))
331 assert.NoError(t, err)
332 },
333 expected: []interface{}{
334 map[string]interface{}{
335 "obj-out": "obj-outside-namespace",
336 "obj-namespace": map[string]interface{}{
337 "obj-in": "obj-inside-namespace",
338 },
339 },
340 "should-be-outside-obj",
341 },
342 },
343 }
344
345 for _, tt := range tests {
346 t.Run(tt.desc, func(t *testing.T) {
347 enc := NewMapObjectEncoder()
348 assert.NoError(t, enc.AddArray("k", ArrayMarshalerFunc(func(arr ArrayEncoder) error {
349 tt.f(arr)
350 tt.f(arr)
351 return nil
352 })), "Expected AddArray to succeed.")
353
354 arr, ok := enc.Fields["k"].([]interface{})
355 require.True(t, ok, "Test case %s didn't encode an array.", tt.desc)
356 assert.Equal(t, []interface{}{tt.expected, tt.expected}, arr, "Unexpected encoder output.")
357 })
358 }
359 }
360
361 func TestMapObjectEncoderReflectionFailures(t *testing.T) {
362 enc := NewMapObjectEncoder()
363 assert.Error(t, enc.AddObject("object", loggable{false}), "Expected AddObject to fail.")
364 assert.Equal(
365 t,
366 map[string]interface{}{"object": map[string]interface{}{}},
367 enc.Fields,
368 "Expected encoder to use empty values on errors.",
369 )
370 }
371
View as plain text