github.com/cockroachdb/errors@v1.11.1/errutil/as_test.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. See the License for the specific language governing 13 // permissions and limitations under the License. 14 15 package errutil_test 16 17 import ( 18 goErr "errors" 19 "fmt" 20 "testing" 21 22 "github.com/cockroachdb/errors" 23 "github.com/cockroachdb/errors/testutils" 24 ) 25 26 func TestAs(t *testing.T) { 27 tt := testutils.T{t} 28 29 refErr := &myType{msg: "woo"} 30 31 // Check we can fish the leaf back. 32 var mySlot *myType 33 tt.Check(errors.As(refErr, &mySlot)) 34 tt.Check(errors.Is(mySlot, refErr)) 35 36 // Check we can fish it even if behind something else. 37 // Note: this would fail with xerrors.As() because 38 // Wrap() uses github.com/pkg/errors which implements 39 // Cause() but not Unwrap(). 40 // This may change with https://github.com/pkg/errors/pull/206. 41 wErr := errors.Wrap(refErr, "hidden") 42 mySlot = nil 43 tt.Check(errors.As(wErr, &mySlot)) 44 tt.Check(errors.Is(mySlot, refErr)) 45 46 // Check we can fish the wrapper back. 47 refwErr := &myWrapper{cause: errors.New("world"), msg: "hello"} 48 var mywSlot *myWrapper 49 tt.Check(errors.As(refwErr, &mywSlot)) 50 tt.Check(errors.Is(mywSlot, refwErr)) 51 52 // Check that it works even if behind something else. 53 wwErr := errors.Wrap(refwErr, "hidden") 54 mywSlot = nil 55 tt.Check(errors.As(wwErr, &mywSlot)) 56 tt.Check(errors.Is(mywSlot, refwErr)) 57 58 // Check that it works even if hidden in wrapError 59 multiWrapErr := fmt.Errorf("test %w test", errors.Wrap(refwErr, "hidden")) 60 mywSlot = nil 61 tt.Check(errors.As(multiWrapErr, &mywSlot)) 62 tt.Check(errors.Is(mywSlot, refwErr)) 63 64 // Check that it works even if hidden in multi-cause wrapErrors 65 multiWrapErr = fmt.Errorf("error: %w and %w", errors.Wrap(refwErr, "hidden"), errors.New("world")) 66 mywSlot = nil 67 tt.Check(errors.As(multiWrapErr, &mywSlot)) 68 tt.Check(errors.Is(mywSlot, refwErr)) 69 70 // Check that it works even if hidden in custom multi-error 71 multiWrapErr = &myMultiWrapper{ 72 causes: []error{errors.Wrap(refwErr, "hidden"), errors.New("world")}, 73 msg: "errors", 74 } 75 mywSlot = nil 76 tt.Check(errors.As(multiWrapErr, &mywSlot)) 77 tt.Check(errors.Is(mywSlot, refwErr)) 78 79 // Check that it works even if hidden in a multi-level multi-cause chain 80 multiWrapErr = fmt.Errorf("error: %w and %w", 81 &myMultiWrapper{ 82 causes: []error{errors.New("ignoreme"), errors.New("also ignore")}, 83 msg: "red herring", 84 }, &myMultiWrapper{ 85 causes: []error{errors.Wrap(refwErr, "hidden"), errors.New("world")}, 86 msg: "errors", 87 }) 88 mywSlot = nil 89 tt.Check(errors.As(multiWrapErr, &mywSlot)) 90 tt.Check(errors.Is(mywSlot, refwErr)) 91 } 92 93 type myType struct{ msg string } 94 95 func (m *myType) Error() string { return m.msg } 96 97 type myWrapper struct { 98 cause error 99 msg string 100 } 101 102 func (m *myWrapper) Error() string { return fmt.Sprintf("%s: %v", m.msg, m.cause) } 103 104 type myMultiWrapper struct { 105 causes []error 106 msg string 107 } 108 109 func (m *myMultiWrapper) Error() string { return fmt.Sprintf("%s: %v", m.msg, goErr.Join(m.causes...)) } 110 111 func (m *myMultiWrapper) Unwrap() []error { 112 return m.causes 113 }