github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/throw/chain_test.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package throw 7 8 import ( 9 "fmt" 10 "io" 11 "runtime" 12 "strings" 13 "testing" 14 15 "github.com/stretchr/testify/require" 16 ) 17 18 type errType1 struct { 19 m string 20 } 21 22 func (errType1) Error() string { 23 return "" 24 } 25 26 type errType2 struct { 27 m func() // incomparable 28 } 29 30 func (errType2) Error() string { 31 return "" 32 } 33 34 func TestIsEqual(t *testing.T) { 35 require.Panics(t, func() { 36 var e1, e2 error = errType2{}, errType2{} 37 runtime.KeepAlive(e1 == e2) 38 }) 39 40 require.False(t, IsEqual(nil, errType1{})) 41 require.False(t, IsEqual(errType1{}, nil)) 42 43 require.True(t, IsEqual(errType1{}, errType1{})) 44 require.False(t, IsEqual(errType1{"A"}, errType1{"B"})) 45 46 require.False(t, IsEqual(errType2{}, errType2{})) 47 48 require.False(t, IsEqual(errType1{}, errType2{})) 49 require.False(t, IsEqual(errType2{}, errType1{})) 50 } 51 52 type errBuilder struct { 53 bottomErr error 54 } 55 56 func (v errBuilder) _err0() error { 57 err := WithDetails(v.bottomErr, Unsupported()) 58 return err 59 } 60 61 func (v errBuilder) _err1() error { 62 err := WithStackAndDetails(v._err0(), struct { 63 msg string 64 v0 int 65 }{"err1Txt", 1}) 66 return err 67 } 68 69 func (v errBuilder) _err2() error { 70 err := WithStack(v._err1()) 71 return err 72 } 73 74 func (v errBuilder) _err3() error { 75 panic(v._err2()) 76 } 77 78 func (v errBuilder) _err4() (err error) { 79 defer func() { 80 err = RW(recover(), err, "panicCatch", struct{ position int }{7}) 81 }() 82 return v._err3() 83 } 84 85 func newChain(bottom error) error { 86 return errBuilder{bottom}._err4() 87 } 88 89 func TestWrapPanicExt(t *testing.T) { 90 err := WrapPanicExt("test", 0) 91 st := OutermostStack(err).ShallowStackTrace() 92 s := st.StackTraceAsText() 93 methodName := "github.com/insolar/vanilla/throw.TestWrapPanicExt" 94 require.True(t, strings.HasPrefix(st.StackTraceAsText(), methodName), "missing method: %s", s) 95 } 96 97 func TestStackOf(t *testing.T) { 98 errChain := newChain(io.EOF) 99 st := DeepestStackTraceOf(errChain) 100 require.NotNil(t, st) 101 s := ErrorWithStack(errChain) 102 methodName := "github.com/insolar/vanilla/throw.TestStackOf" 103 require.Contains(t, s, methodName) 104 } 105 106 func TestWalk(t *testing.T) { 107 t.Run("bad input", func(t *testing.T) { 108 // Cannot use panics with value, because throw.stackTrace is not comparable 109 require.Panics(t, func() { 110 Walk(nil, nil) 111 }) 112 }) 113 114 t.Run("empty error chain", func(t *testing.T) { 115 require.False(t, Walk(nil, func(err error, holder StackTraceHolder) bool { 116 return true 117 })) 118 }) 119 120 t.Run("simple error", func(t *testing.T) { 121 require.True(t, Walk(fmt.Errorf("some error"), func(err error, holder StackTraceHolder) bool { 122 return true 123 })) 124 }) 125 126 t.Run("single error chain", func(t *testing.T) { 127 require.True(t, Walk(IllegalValue(), func(err error, holder StackTraceHolder) bool { 128 return true 129 })) 130 }) 131 132 t.Run("double error chain", func(t *testing.T) { 133 require.True(t, Walk(W(IllegalValue(), "one layer more", ""), func(err error, holder StackTraceHolder) bool { 134 return true 135 })) 136 }) 137 } 138 139 func TestPrintTo(t *testing.T) { 140 t.Run("nil err with stack", func(t *testing.T) { 141 b := strings.Builder{} 142 PrintTo(nil, true, &b) 143 require.Equal(t, "", b.String()) 144 }) 145 146 t.Run("nil err without stack", func(t *testing.T) { 147 b := strings.Builder{} 148 PrintTo(nil, false, &b) 149 require.Equal(t, "", b.String()) 150 }) 151 152 t.Run("simple error without stack", func(t *testing.T) { 153 b := strings.Builder{} 154 PrintTo(fmt.Errorf("simple error"), false, &b) 155 require.Equal(t, "simple error\n", b.String()) 156 }) 157 158 t.Run("simple error with stack", func(t *testing.T) { 159 b := strings.Builder{} 160 PrintTo(fmt.Errorf("simple error"), false, &b) 161 require.Equal(t, "simple error\n", b.String()) 162 }) 163 164 t.Run("stacked error without stack", func(t *testing.T) { 165 b := strings.Builder{} 166 PrintTo(IllegalValue(), false, &b) 167 require.Equal(t, "illegal value\n", b.String()) 168 }) 169 170 t.Run("stacked error with stack", func(t *testing.T) { 171 b := strings.Builder{} 172 PrintTo(IllegalValue(), true, &b) 173 _, fileName, fileLine, ok := runtime.Caller(0) 174 require.True(t, ok, "failed to get caller") 175 require.Equal(t, fmt.Sprintf("illegal value\nStack trace:\ngithub.com/insolar/vanilla/throw.TestPrintTo.func6\n\t%s:%d\n", fileName, fileLine-1), b.String()) 176 }) 177 }