1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package zap
22
23 import (
24 "errors"
25 "fmt"
26 "testing"
27
28 "go.uber.org/zap/zapcore"
29
30 "github.com/stretchr/testify/assert"
31 "github.com/stretchr/testify/require"
32 )
33
34 func TestErrorConstructors(t *testing.T) {
35 fail := errors.New("fail")
36
37 tests := []struct {
38 name string
39 field Field
40 expect Field
41 }{
42 {"Error", Skip(), Error(nil)},
43 {"Error", Field{Key: "error", Type: zapcore.ErrorType, Interface: fail}, Error(fail)},
44 {"NamedError", Skip(), NamedError("foo", nil)},
45 {"NamedError", Field{Key: "foo", Type: zapcore.ErrorType, Interface: fail}, NamedError("foo", fail)},
46 {"Any:Error", Any("k", errors.New("v")), NamedError("k", errors.New("v"))},
47 {"Any:Errors", Any("k", []error{errors.New("v")}), Errors("k", []error{errors.New("v")})},
48 }
49
50 for _, tt := range tests {
51 if !assert.Equal(t, tt.expect, tt.field, "Unexpected output from convenience field constructor %s.", tt.name) {
52 t.Logf("type expected: %T\nGot: %T", tt.expect.Interface, tt.field.Interface)
53 }
54 assertCanBeReused(t, tt.field)
55 }
56 }
57
58 func TestErrorArrayConstructor(t *testing.T) {
59 tests := []struct {
60 desc string
61 field Field
62 expected []interface{}
63 }{
64 {"empty errors", Errors("", []error{}), []interface{}{}},
65 {
66 "errors",
67 Errors("", []error{nil, errors.New("foo"), nil, errors.New("bar")}),
68 []interface{}{map[string]interface{}{"error": "foo"}, map[string]interface{}{"error": "bar"}},
69 },
70 }
71
72 for _, tt := range tests {
73 enc := zapcore.NewMapObjectEncoder()
74 tt.field.Key = "k"
75 tt.field.AddTo(enc)
76 assert.Equal(t, tt.expected, enc.Fields["k"], "%s: unexpected map contents.", tt.desc)
77 assert.Equal(t, 1, len(enc.Fields), "%s: found extra keys in map: %v", tt.desc, enc.Fields)
78 }
79 }
80
81 func TestErrorsArraysHandleRichErrors(t *testing.T) {
82 errs := []error{fmt.Errorf("egad")}
83
84 enc := zapcore.NewMapObjectEncoder()
85 Errors("k", errs).AddTo(enc)
86 assert.Equal(t, 1, len(enc.Fields), "Expected only top-level field.")
87
88 val := enc.Fields["k"]
89 arr, ok := val.([]interface{})
90 require.True(t, ok, "Expected top-level field to be an array.")
91 require.Equal(t, 1, len(arr), "Expected only one error object in array.")
92
93 serialized := arr[0]
94 errMap, ok := serialized.(map[string]interface{})
95 require.True(t, ok, "Expected serialized error to be a map, got %T.", serialized)
96 assert.Equal(t, "egad", errMap["error"], "Unexpected standard error string.")
97 }
98
99 func TestErrArrayBrokenEncoder(t *testing.T) {
100 t.Parallel()
101
102 failWith := errors.New("great sadness")
103 err := (brokenArrayObjectEncoder{
104 Err: failWith,
105 ObjectEncoder: zapcore.NewMapObjectEncoder(),
106 }).AddArray("errors", errArray{
107 errors.New("foo"),
108 errors.New("bar"),
109 })
110 require.Error(t, err, "Expected error from broken encoder.")
111 assert.ErrorIs(t, err, failWith, "Unexpected error.")
112 }
113
114
115
116 type brokenArrayObjectEncoder struct {
117 zapcore.ObjectEncoder
118 zapcore.ArrayEncoder
119
120 Err error
121 }
122
123 func (enc brokenArrayObjectEncoder) AddArray(key string, marshaler zapcore.ArrayMarshaler) error {
124 return enc.ObjectEncoder.AddArray(key,
125 zapcore.ArrayMarshalerFunc(func(ae zapcore.ArrayEncoder) error {
126 enc.ArrayEncoder = ae
127 return marshaler.MarshalLogArray(enc)
128 }))
129 }
130
131 func (enc brokenArrayObjectEncoder) AppendObject(zapcore.ObjectMarshaler) error {
132 return enc.Err
133 }
134
View as plain text