1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package zapcore_test
22
23 import (
24 "errors"
25 "fmt"
26 "io"
27 "testing"
28
29 "github.com/stretchr/testify/assert"
30
31 "go.uber.org/multierr"
32
33 . "go.uber.org/zap/zapcore"
34 )
35
36 type errTooManyUsers int
37
38 func (e errTooManyUsers) Error() string {
39 return fmt.Sprintf("%d too many users", int(e))
40 }
41
42 func (e errTooManyUsers) Format(s fmt.State, verb rune) {
43
44
45 if verb == 'v' && s.Flag('+') {
46 io.WriteString(s, e.Error())
47 }
48 }
49
50 type customMultierr struct{}
51
52 func (e customMultierr) Error() string {
53 return "great sadness"
54 }
55
56 func (e customMultierr) Errors() []error {
57 return []error{
58 errors.New("foo"),
59 nil,
60 multierr.Append(
61 errors.New("bar"),
62 errors.New("baz"),
63 ),
64 }
65 }
66
67 func TestErrorEncoding(t *testing.T) {
68 tests := []struct {
69 k string
70 t FieldType
71 iface interface{}
72 want map[string]interface{}
73 }{
74 {
75 k: "k",
76 iface: errTooManyUsers(2),
77 want: map[string]interface{}{
78 "k": "2 too many users",
79 },
80 },
81 {
82 k: "err",
83 iface: multierr.Combine(
84 errors.New("foo"),
85 errors.New("bar"),
86 errors.New("baz"),
87 ),
88 want: map[string]interface{}{
89 "err": "foo; bar; baz",
90 "errCauses": []interface{}{
91 map[string]interface{}{"error": "foo"},
92 map[string]interface{}{"error": "bar"},
93 map[string]interface{}{"error": "baz"},
94 },
95 },
96 },
97 {
98 k: "e",
99 iface: customMultierr{},
100 want: map[string]interface{}{
101 "e": "great sadness",
102 "eCauses": []interface{}{
103 map[string]interface{}{"error": "foo"},
104 map[string]interface{}{
105 "error": "bar; baz",
106 "errorCauses": []interface{}{
107 map[string]interface{}{"error": "bar"},
108 map[string]interface{}{"error": "baz"},
109 },
110 },
111 },
112 },
113 },
114 {
115 k: "k",
116 iface: fmt.Errorf("failed: %w", errors.New("egad")),
117 want: map[string]interface{}{
118 "k": "failed: egad",
119 },
120 },
121 {
122 k: "error",
123 iface: multierr.Combine(
124 fmt.Errorf("hello: %w",
125 multierr.Combine(errors.New("foo"), errors.New("bar")),
126 ),
127 errors.New("baz"),
128 fmt.Errorf("world: %w", errors.New("qux")),
129 ),
130 want: map[string]interface{}{
131 "error": "hello: foo; bar; baz; world: qux",
132 "errorCauses": []interface{}{
133 map[string]interface{}{
134 "error": "hello: foo; bar",
135 },
136 map[string]interface{}{"error": "baz"},
137 map[string]interface{}{"error": "world: qux"},
138 },
139 },
140 },
141 }
142
143 for _, tt := range tests {
144 if tt.t == UnknownType {
145 tt.t = ErrorType
146 }
147
148 enc := NewMapObjectEncoder()
149 f := Field{Key: tt.k, Type: tt.t, Interface: tt.iface}
150 f.AddTo(enc)
151 assert.Equal(t, tt.want, enc.Fields, "Unexpected output from field %+v.", f)
152 }
153 }
154
155 func TestRichErrorSupport(t *testing.T) {
156 f := Field{
157 Type: ErrorType,
158 Interface: fmt.Errorf("failed: %w", errors.New("egad")),
159 Key: "k",
160 }
161 enc := NewMapObjectEncoder()
162 f.AddTo(enc)
163 assert.Equal(t, "failed: egad", enc.Fields["k"], "Unexpected basic error message.")
164 }
165
166 func TestErrArrayBrokenEncoder(t *testing.T) {
167 t.Parallel()
168
169 f := Field{
170 Key: "foo",
171 Type: ErrorType,
172 Interface: multierr.Combine(
173 errors.New("foo"),
174 errors.New("bar"),
175 ),
176 }
177
178 failWith := errors.New("great sadness")
179 enc := NewMapObjectEncoder()
180 f.AddTo(brokenArrayObjectEncoder{
181 Err: failWith,
182 ObjectEncoder: enc,
183 })
184
185
186
187 assert.Equal(t, "great sadness", enc.Fields["fooError"],
188 "Unexpected error message.")
189 }
190
191
192
193 type brokenArrayObjectEncoder struct {
194 ObjectEncoder
195 ArrayEncoder
196
197 Err error
198 }
199
200 func (enc brokenArrayObjectEncoder) AddArray(key string, marshaler ArrayMarshaler) error {
201 return enc.ObjectEncoder.AddArray(key,
202 ArrayMarshalerFunc(func(ae ArrayEncoder) error {
203 enc.ArrayEncoder = ae
204 return marshaler.MarshalLogArray(enc)
205 }))
206 }
207
208 func (enc brokenArrayObjectEncoder) AppendObject(ObjectMarshaler) error {
209 return enc.Err
210 }
211
View as plain text