...

Source file src/errors/wrap_test.go

Documentation: errors

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

View as plain text