1
// Copyright 2014 Canonical Ltd.
2
// Licensed under the LGPLv3, see LICENCE file for details.
13
jc "github.com/juju/testing/checkers"
14
gc "gopkg.in/check.v1"
16
"github.com/juju/errors"
19
type functionSuite struct {
22
var _ = gc.Suite(&functionSuite{})
24
func (*functionSuite) TestNew(c *gc.C) {
25
err := errors.New("testing") //err newTest
26
c.Assert(err.Error(), gc.Equals, "testing")
27
c.Assert(errors.Cause(err), gc.Equals, err)
28
c.Assert(errors.Details(err), jc.Contains, tagToLocation["newTest"].String())
31
func (*functionSuite) TestErrorf(c *gc.C) {
32
err := errors.Errorf("testing %d", 42) //err errorfTest
33
c.Assert(err.Error(), gc.Equals, "testing 42")
34
c.Assert(errors.Cause(err), gc.Equals, err)
35
c.Assert(errors.Details(err), jc.Contains, tagToLocation["errorfTest"].String())
38
func (*functionSuite) TestTrace(c *gc.C) {
39
first := errors.New("first")
40
err := errors.Trace(first) //err traceTest
41
c.Assert(err.Error(), gc.Equals, "first")
42
c.Assert(errors.Cause(err), gc.Equals, first)
43
c.Assert(errors.Details(err), jc.Contains, tagToLocation["traceTest"].String())
45
c.Assert(errors.Trace(nil), gc.IsNil)
48
func (*functionSuite) TestAnnotate(c *gc.C) {
49
first := errors.New("first")
50
err := errors.Annotate(first, "annotation") //err annotateTest
51
c.Assert(err.Error(), gc.Equals, "annotation: first")
52
c.Assert(errors.Cause(err), gc.Equals, first)
53
c.Assert(errors.Details(err), jc.Contains, tagToLocation["annotateTest"].String())
55
c.Assert(errors.Annotate(nil, "annotate"), gc.IsNil)
58
func (*functionSuite) TestAnnotatef(c *gc.C) {
59
first := errors.New("first")
60
err := errors.Annotatef(first, "annotation %d", 2) //err annotatefTest
61
c.Assert(err.Error(), gc.Equals, "annotation 2: first")
62
c.Assert(errors.Cause(err), gc.Equals, first)
63
c.Assert(errors.Details(err), jc.Contains, tagToLocation["annotatefTest"].String())
65
c.Assert(errors.Annotatef(nil, "annotate"), gc.IsNil)
68
func (*functionSuite) TestDeferredAnnotatef(c *gc.C) {
69
// NOTE: this test fails with gccgo
70
if runtime.Compiler == "gccgo" {
71
c.Skip("gccgo can't determine the location")
73
first := errors.New("first")
74
test := func() (err error) {
75
defer errors.DeferredAnnotatef(&err, "deferred %s", "annotate")
77
} //err deferredAnnotate
79
c.Assert(err.Error(), gc.Equals, "deferred annotate: first")
80
c.Assert(errors.Cause(err), gc.Equals, first)
81
c.Assert(errors.Details(err), jc.Contains, tagToLocation["deferredAnnotate"].String())
84
errors.DeferredAnnotatef(&err, "deferred %s", "annotate")
85
c.Assert(err, gc.IsNil)
88
func (*functionSuite) TestWrap(c *gc.C) {
89
first := errors.New("first") //err wrapFirst
90
detailed := errors.New("detailed")
91
err := errors.Wrap(first, detailed) //err wrapTest
92
c.Assert(err.Error(), gc.Equals, "detailed")
93
c.Assert(errors.Cause(err), gc.Equals, detailed)
94
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapFirst"].String())
95
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapTest"].String())
98
func (*functionSuite) TestWrapOfNil(c *gc.C) {
99
detailed := errors.New("detailed")
100
err := errors.Wrap(nil, detailed) //err nilWrapTest
101
c.Assert(err.Error(), gc.Equals, "detailed")
102
c.Assert(errors.Cause(err), gc.Equals, detailed)
103
c.Assert(errors.Details(err), jc.Contains, tagToLocation["nilWrapTest"].String())
106
func (*functionSuite) TestWrapf(c *gc.C) {
107
first := errors.New("first") //err wrapfFirst
108
detailed := errors.New("detailed")
109
err := errors.Wrapf(first, detailed, "value %d", 42) //err wrapfTest
110
c.Assert(err.Error(), gc.Equals, "value 42: detailed")
111
c.Assert(errors.Cause(err), gc.Equals, detailed)
112
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapfFirst"].String())
113
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapfTest"].String())
116
func (*functionSuite) TestWrapfOfNil(c *gc.C) {
117
detailed := errors.New("detailed")
118
err := errors.Wrapf(nil, detailed, "value %d", 42) //err nilWrapfTest
119
c.Assert(err.Error(), gc.Equals, "value 42: detailed")
120
c.Assert(errors.Cause(err), gc.Equals, detailed)
121
c.Assert(errors.Details(err), jc.Contains, tagToLocation["nilWrapfTest"].String())
124
func (*functionSuite) TestMask(c *gc.C) {
125
first := errors.New("first")
126
err := errors.Mask(first) //err maskTest
127
c.Assert(err.Error(), gc.Equals, "first")
128
c.Assert(errors.Cause(err), gc.Equals, err)
129
c.Assert(errors.Details(err), jc.Contains, tagToLocation["maskTest"].String())
131
c.Assert(errors.Mask(nil), gc.IsNil)
134
func (*functionSuite) TestMaskf(c *gc.C) {
135
first := errors.New("first")
136
err := errors.Maskf(first, "masked %d", 42) //err maskfTest
137
c.Assert(err.Error(), gc.Equals, "masked 42: first")
138
c.Assert(errors.Cause(err), gc.Equals, err)
139
c.Assert(errors.Details(err), jc.Contains, tagToLocation["maskfTest"].String())
141
c.Assert(errors.Maskf(nil, "mask"), gc.IsNil)
144
func (*functionSuite) TestCause(c *gc.C) {
145
c.Assert(errors.Cause(nil), gc.IsNil)
146
c.Assert(errors.Cause(someErr), gc.Equals, someErr)
148
fmtErr := fmt.Errorf("simple")
149
c.Assert(errors.Cause(fmtErr), gc.Equals, fmtErr)
151
err := errors.Wrap(someErr, fmtErr)
152
c.Assert(errors.Cause(err), gc.Equals, fmtErr)
154
err = errors.Annotate(err, "annotated")
155
c.Assert(errors.Cause(err), gc.Equals, fmtErr)
157
err = errors.Maskf(err, "maksed")
158
c.Assert(errors.Cause(err), gc.Equals, err)
160
// Look for a file that we know isn't there.
162
_, err = os.Stat(filepath.Join(dir, "not-there"))
163
c.Assert(os.IsNotExist(err), jc.IsTrue)
165
err = errors.Annotatef(err, "wrap it")
166
// Now the error itself isn't a 'IsNotExist'.
167
c.Assert(os.IsNotExist(err), jc.IsFalse)
168
// However if we use the Check method, it is.
169
c.Assert(os.IsNotExist(errors.Cause(err)), jc.IsTrue)
172
func (s *functionSuite) TestDetails(c *gc.C) {
173
if runtime.Compiler == "gccgo" {
174
c.Skip("gccgo can't determine the location")
176
c.Assert(errors.Details(nil), gc.Equals, "[]")
178
otherErr := fmt.Errorf("other")
179
checkDetails(c, otherErr, "[{other}]")
181
err0 := newEmbed("foo") //err TestStack#0
182
checkDetails(c, err0, "[{$TestStack#0$: foo}]")
184
err1 := errors.Annotate(err0, "bar") //err TestStack#1
185
checkDetails(c, err1, "[{$TestStack#1$: bar} {$TestStack#0$: foo}]")
187
err2 := errors.Trace(err1) //err TestStack#2
188
checkDetails(c, err2, "[{$TestStack#2$: } {$TestStack#1$: bar} {$TestStack#0$: foo}]")
191
type tracer interface {
192
StackTrace() []string
195
func (*functionSuite) TestErrorStack(c *gc.C) {
196
for i, test := range []struct {
198
generator func() error
204
generator: func() error {
208
message: "raw error",
209
generator: func() error {
210
return fmt.Errorf("raw")
214
message: "single error stack",
215
generator: func() error {
216
return errors.New("first error") //err single
218
expected: "$single$: first error",
221
message: "annotated error",
222
generator: func() error {
223
err := errors.New("first error") //err annotated-0
224
return errors.Annotate(err, "annotation") //err annotated-1
227
"$annotated-0$: first error\n" +
228
"$annotated-1$: annotation",
231
message: "wrapped error",
232
generator: func() error {
233
err := errors.New("first error") //err wrapped-0
234
return errors.Wrap(err, newError("detailed error")) //err wrapped-1
237
"$wrapped-0$: first error\n" +
238
"$wrapped-1$: detailed error",
241
message: "annotated wrapped error",
242
generator: func() error {
243
err := errors.Errorf("first error") //err ann-wrap-0
244
err = errors.Wrap(err, fmt.Errorf("detailed error")) //err ann-wrap-1
245
return errors.Annotatef(err, "annotated") //err ann-wrap-2
248
"$ann-wrap-0$: first error\n" +
249
"$ann-wrap-1$: detailed error\n" +
250
"$ann-wrap-2$: annotated",
253
message: "traced, and annotated",
254
generator: func() error {
255
err := errors.New("first error") //err stack-0
256
err = errors.Trace(err) //err stack-1
257
err = errors.Annotate(err, "some context") //err stack-2
258
err = errors.Trace(err) //err stack-3
259
err = errors.Annotate(err, "more context") //err stack-4
260
return errors.Trace(err) //err stack-5
263
"$stack-0$: first error\n" +
265
"$stack-2$: some context\n" +
267
"$stack-4$: more context\n" +
271
message: "uncomparable, wrapped with a value error",
272
generator: func() error {
273
err := newNonComparableError("first error") //err mixed-0
274
err = errors.Trace(err) //err mixed-1
275
err = errors.Wrap(err, newError("value error")) //err mixed-2
276
err = errors.Maskf(err, "masked") //err mixed-3
277
err = errors.Annotate(err, "more context") //err mixed-4
278
return errors.Trace(err) //err mixed-5
283
"$mixed-2$: value error\n" +
284
"$mixed-3$: masked\n" +
285
"$mixed-4$: more context\n" +
290
c.Logf("%v: %s", i, test.message)
291
err := test.generator()
292
expected := replaceLocations(test.expected)
293
stack := errors.ErrorStack(err)
294
ok := c.Check(stack, gc.Equals, expected)
298
tracer, ok := err.(tracer)
299
c.Check(ok, gc.Equals, test.tracer)
301
stackTrace := tracer.StackTrace()
302
c.Check(stackTrace, gc.DeepEquals, strings.Split(stack, "\n"))