github.com/c12o16h1/go/src@v0.0.0-20200114212001-5a151c0f00ed/errors/wrap_test.go (about)

     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  
     5  package errors_test
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"os"
    11  	"reflect"
    12  	"testing"
    13  )
    14  
    15  func TestIs(t *testing.T) {
    16  	err1 := errors.New("1")
    17  	erra := wrapped{"wrap 2", err1}
    18  	errb := wrapped{"wrap 3", erra}
    19  
    20  	err3 := errors.New("3")
    21  
    22  	poser := &poser{"either 1 or 3", func(err error) bool {
    23  		return err == err1 || err == err3
    24  	}}
    25  
    26  	testCases := []struct {
    27  		err    error
    28  		target error
    29  		match  bool
    30  	}{
    31  		{nil, nil, true},
    32  		{err1, nil, false},
    33  		{err1, err1, true},
    34  		{erra, err1, true},
    35  		{errb, err1, true},
    36  		{err1, err3, false},
    37  		{erra, err3, false},
    38  		{errb, err3, false},
    39  		{poser, err1, true},
    40  		{poser, err3, true},
    41  		{poser, erra, false},
    42  		{poser, errb, false},
    43  		{errorUncomparable{}, errorUncomparable{}, true},
    44  		{errorUncomparable{}, &errorUncomparable{}, false},
    45  		{&errorUncomparable{}, errorUncomparable{}, true},
    46  		{&errorUncomparable{}, &errorUncomparable{}, false},
    47  		{errorUncomparable{}, err1, false},
    48  		{&errorUncomparable{}, err1, false},
    49  	}
    50  	for _, tc := range testCases {
    51  		t.Run("", func(t *testing.T) {
    52  			if got := errors.Is(tc.err, tc.target); got != tc.match {
    53  				t.Errorf("Is(%v, %v) = %v, want %v", tc.err, tc.target, got, tc.match)
    54  			}
    55  		})
    56  	}
    57  }
    58  
    59  type poser struct {
    60  	msg string
    61  	f   func(error) bool
    62  }
    63  
    64  var poserPathErr = &os.PathError{Op: "poser"}
    65  
    66  func (p *poser) Error() string     { return p.msg }
    67  func (p *poser) Is(err error) bool { return p.f(err) }
    68  func (p *poser) As(err interface{}) bool {
    69  	switch x := err.(type) {
    70  	case **poser:
    71  		*x = p
    72  	case *errorT:
    73  		*x = errorT{"poser"}
    74  	case **os.PathError:
    75  		*x = poserPathErr
    76  	default:
    77  		return false
    78  	}
    79  	return true
    80  }
    81  
    82  func TestAs(t *testing.T) {
    83  	var errT errorT
    84  	var errP *os.PathError
    85  	var timeout interface{ Timeout() bool }
    86  	var p *poser
    87  	_, errF := os.Open("non-existing")
    88  	poserErr := &poser{"oh no", nil}
    89  
    90  	testCases := []struct {
    91  		err    error
    92  		target interface{}
    93  		match  bool
    94  		want   interface{} // value of target on match
    95  	}{{
    96  		nil,
    97  		&errP,
    98  		false,
    99  		nil,
   100  	}, {
   101  		wrapped{"pitied the fool", errorT{"T"}},
   102  		&errT,
   103  		true,
   104  		errorT{"T"},
   105  	}, {
   106  		errF,
   107  		&errP,
   108  		true,
   109  		errF,
   110  	}, {
   111  		errorT{},
   112  		&errP,
   113  		false,
   114  		nil,
   115  	}, {
   116  		wrapped{"wrapped", nil},
   117  		&errT,
   118  		false,
   119  		nil,
   120  	}, {
   121  		&poser{"error", nil},
   122  		&errT,
   123  		true,
   124  		errorT{"poser"},
   125  	}, {
   126  		&poser{"path", nil},
   127  		&errP,
   128  		true,
   129  		poserPathErr,
   130  	}, {
   131  		poserErr,
   132  		&p,
   133  		true,
   134  		poserErr,
   135  	}, {
   136  		errors.New("err"),
   137  		&timeout,
   138  		false,
   139  		nil,
   140  	}, {
   141  		errF,
   142  		&timeout,
   143  		true,
   144  		errF,
   145  	}, {
   146  		wrapped{"path error", errF},
   147  		&timeout,
   148  		true,
   149  		errF,
   150  	}}
   151  	for i, tc := range testCases {
   152  		name := fmt.Sprintf("%d:As(Errorf(..., %v), %v)", i, tc.err, tc.target)
   153  		// Clear the target pointer, in case it was set in a previous test.
   154  		rtarget := reflect.ValueOf(tc.target)
   155  		rtarget.Elem().Set(reflect.Zero(reflect.TypeOf(tc.target).Elem()))
   156  		t.Run(name, func(t *testing.T) {
   157  			match := errors.As(tc.err, tc.target)
   158  			if match != tc.match {
   159  				t.Fatalf("match: got %v; want %v", match, tc.match)
   160  			}
   161  			if !match {
   162  				return
   163  			}
   164  			if got := rtarget.Elem().Interface(); got != tc.want {
   165  				t.Fatalf("got %#v, want %#v", got, tc.want)
   166  			}
   167  		})
   168  	}
   169  }
   170  
   171  func TestAsValidation(t *testing.T) {
   172  	var s string
   173  	testCases := []interface{}{
   174  		nil,
   175  		(*int)(nil),
   176  		"error",
   177  		&s,
   178  	}
   179  	err := errors.New("error")
   180  	for _, tc := range testCases {
   181  		t.Run(fmt.Sprintf("%T(%v)", tc, tc), func(t *testing.T) {
   182  			defer func() {
   183  				recover()
   184  			}()
   185  			if errors.As(err, tc) {
   186  				t.Errorf("As(err, %T(%v)) = true, want false", tc, tc)
   187  				return
   188  			}
   189  			t.Errorf("As(err, %T(%v)) did not panic", tc, tc)
   190  		})
   191  	}
   192  }
   193  
   194  func TestUnwrap(t *testing.T) {
   195  	err1 := errors.New("1")
   196  	erra := wrapped{"wrap 2", err1}
   197  
   198  	testCases := []struct {
   199  		err  error
   200  		want error
   201  	}{
   202  		{nil, nil},
   203  		{wrapped{"wrapped", nil}, nil},
   204  		{err1, nil},
   205  		{erra, err1},
   206  		{wrapped{"wrap 3", erra}, erra},
   207  	}
   208  	for _, tc := range testCases {
   209  		if got := errors.Unwrap(tc.err); got != tc.want {
   210  			t.Errorf("Unwrap(%v) = %v, want %v", tc.err, got, tc.want)
   211  		}
   212  	}
   213  }
   214  
   215  type errorT struct{ s string }
   216  
   217  func (e errorT) Error() string { return fmt.Sprintf("errorT(%s)", e.s) }
   218  
   219  type wrapped struct {
   220  	msg string
   221  	err error
   222  }
   223  
   224  func (e wrapped) Error() string { return e.msg }
   225  
   226  func (e wrapped) Unwrap() error { return e.err }
   227  
   228  type errorUncomparable struct {
   229  	f []string
   230  }
   231  
   232  func (errorUncomparable) Error() string {
   233  	return "uncomparable error"
   234  }
   235  
   236  func (errorUncomparable) Is(target error) bool {
   237  	_, ok := target.(errorUncomparable)
   238  	return ok
   239  }
   240  
   241  func ExampleAs() {
   242  	if _, err := os.Open("non-existing"); err != nil {
   243  		var pathError *os.PathError
   244  		if errors.As(err, &pathError) {
   245  			fmt.Println("Failed at path:", pathError.Path)
   246  		} else {
   247  			fmt.Println(err)
   248  		}
   249  	}
   250  
   251  	// Output:
   252  	// Failed at path: non-existing
   253  }