wrap_test.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package errors_test
  5. import (
  6. "fmt"
  7. "os"
  8. "testing"
  9. "github.com/go-faster/errors"
  10. )
  11. func TestIs(t *testing.T) {
  12. err1 := errors.New("1")
  13. erra := errors.Wrap(err1, "wrap 2")
  14. errb := errors.Wrap(erra, "wrap3")
  15. erro := errors.Opaque(err1)
  16. errco := errors.Wrap(erro, "opaque")
  17. err3 := errors.New("3")
  18. poser := &poser{"either 1 or 3", func(err error) bool {
  19. return err == err1 || err == err3
  20. }}
  21. testCases := []struct {
  22. err error
  23. target error
  24. match bool
  25. }{
  26. {nil, nil, true},
  27. {nil, err1, false},
  28. {err1, nil, false},
  29. {err1, err1, true},
  30. {erra, err1, true},
  31. {errb, err1, true},
  32. {errco, erro, true},
  33. {errco, err1, false},
  34. {erro, erro, true},
  35. {err1, err3, false},
  36. {erra, err3, false},
  37. {errb, err3, false},
  38. {poser, err1, true},
  39. {poser, err3, true},
  40. {poser, erra, false},
  41. {poser, errb, false},
  42. {poser, erro, false},
  43. {poser, errco, false},
  44. {errorUncomparable{}, errorUncomparable{}, true},
  45. {errorUncomparable{}, &errorUncomparable{}, false},
  46. {&errorUncomparable{}, errorUncomparable{}, true},
  47. {&errorUncomparable{}, &errorUncomparable{}, false},
  48. {errorUncomparable{}, err1, false},
  49. {&errorUncomparable{}, err1, false},
  50. }
  51. for _, tc := range testCases {
  52. t.Run("", func(t *testing.T) {
  53. if got := errors.Is(tc.err, tc.target); got != tc.match {
  54. t.Errorf("Is(%v, %v) = %v, want %v", tc.err, tc.target, got, tc.match)
  55. }
  56. })
  57. }
  58. }
  59. type poser struct {
  60. msg string
  61. f func(error) bool
  62. }
  63. func (p *poser) Error() string { return p.msg }
  64. func (p *poser) Is(err error) bool { return p.f(err) }
  65. func (p *poser) As(err interface{}) bool {
  66. switch x := err.(type) {
  67. case **poser:
  68. *x = p
  69. case *errorT:
  70. *x = errorT{}
  71. case **os.PathError:
  72. *x = &os.PathError{}
  73. default:
  74. return false
  75. }
  76. return true
  77. }
  78. func TestAs(t *testing.T) {
  79. var errT errorT
  80. var errP *os.PathError
  81. var timeout interface{ Timeout() bool }
  82. var p *poser
  83. _, errF := os.Open("non-existing")
  84. testCases := []struct {
  85. err error
  86. target interface{}
  87. match bool
  88. }{{
  89. nil,
  90. &errP,
  91. false,
  92. }, {
  93. errors.Wrap(errorT{}, "pittied the fool"),
  94. &errT,
  95. true,
  96. }, {
  97. errF,
  98. &errP,
  99. true,
  100. }, {
  101. errors.Opaque(errT),
  102. &errT,
  103. false,
  104. }, {
  105. errorT{},
  106. &errP,
  107. false,
  108. }, {
  109. errWrap{nil},
  110. &errT,
  111. false,
  112. }, {
  113. &poser{"error", nil},
  114. &errT,
  115. true,
  116. }, {
  117. &poser{"path", nil},
  118. &errP,
  119. true,
  120. }, {
  121. &poser{"oh no", nil},
  122. &p,
  123. true,
  124. }, {
  125. errors.New("err"),
  126. &timeout,
  127. false,
  128. }, {
  129. errF,
  130. &timeout,
  131. true,
  132. }, {
  133. errors.Wrap(errF, "path error"),
  134. &timeout,
  135. true,
  136. }}
  137. for i, tc := range testCases {
  138. name := fmt.Sprintf("%d:As(Errorf(..., %v), %v)", i, tc.err, tc.target)
  139. t.Run(name, func(t *testing.T) {
  140. match := errors.As(tc.err, tc.target)
  141. if match != tc.match {
  142. t.Fatalf("errors.As(%T, %T): got %v; want %v", tc.err, tc.target, match, tc.match)
  143. }
  144. if !match {
  145. return
  146. }
  147. if tc.target == nil {
  148. t.Fatalf("non-nil result after match")
  149. }
  150. })
  151. }
  152. }
  153. func TestAsValidation(t *testing.T) {
  154. var s string
  155. testCases := []interface{}{
  156. nil,
  157. (*int)(nil),
  158. "error",
  159. &s,
  160. }
  161. err := errors.New("error")
  162. for _, tc := range testCases {
  163. t.Run(fmt.Sprintf("%T(%v)", tc, tc), func(t *testing.T) {
  164. defer func() {
  165. recover()
  166. }()
  167. if errors.As(err, tc) {
  168. t.Errorf("As(err, %T(%v)) = true, want false", tc, tc)
  169. return
  170. }
  171. t.Errorf("As(err, %T(%v)) did not panic", tc, tc)
  172. })
  173. }
  174. }
  175. func TestUnwrap(t *testing.T) {
  176. err1 := errors.New("1")
  177. erra := errors.Wrap(err1, "wrap 2")
  178. erro := errors.Opaque(err1)
  179. testCases := []struct {
  180. err error
  181. want error
  182. }{
  183. {nil, nil},
  184. {errWrap{nil}, nil},
  185. {err1, nil},
  186. {erra, err1},
  187. {errors.Wrap(erra, "wrap 3"), erra},
  188. {erro, nil},
  189. {errors.Wrap(erro, "opaque"), erro},
  190. }
  191. for _, tc := range testCases {
  192. if got := errors.Unwrap(tc.err); got != tc.want {
  193. t.Errorf("Unwrap(%v) = %v, want %v", tc.err, got, tc.want)
  194. }
  195. }
  196. }
  197. func TestOpaque(t *testing.T) {
  198. got := fmt.Sprintf("%v", errors.Wrap(errors.Opaque(errorT{}), "foo"))
  199. want := "foo: errorT"
  200. if got != want {
  201. t.Errorf("error without Format: got %v; want %v", got, want)
  202. }
  203. got = fmt.Sprintf("%v", errors.Wrap(errors.Opaque(errorD{}), "foo"))
  204. want = "foo: errorD"
  205. if got != want {
  206. t.Errorf("error with Format: got %v; want %v", got, want)
  207. }
  208. }
  209. type errorT struct{}
  210. func (errorT) Error() string { return "errorT" }
  211. type errorD struct{}
  212. func (errorD) Error() string { return "errorD" }
  213. func (errorD) FormatError(p errors.Printer) error {
  214. p.Print("errorD")
  215. p.Detail()
  216. p.Print("detail")
  217. return nil
  218. }
  219. type errWrap struct{ error }
  220. func (errWrap) Error() string { return "wrapped" }
  221. func (errWrap) Unwrap() error { return nil }
  222. type errorUncomparable struct {
  223. _ interface{} // forbid compare
  224. }
  225. func (errorUncomparable) Error() string {
  226. return "uncomparable error"
  227. }
  228. func (errorUncomparable) Is(target error) bool {
  229. _, ok := target.(errorUncomparable)
  230. return ok
  231. }