github.com/haraldrudell/parl@v0.4.176/perrors/accessors_test.go (about)

     1  /*
     2  © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package perrors
     7  
     8  import (
     9  	"errors"
    10  	"fmt"
    11  	"os"
    12  	"syscall"
    13  	"testing"
    14  
    15  	"github.com/haraldrudell/parl/perrors/errorglue"
    16  	"golang.org/x/sys/unix"
    17  )
    18  
    19  func TestDumpChain(t *testing.T) {
    20  	errorMessage := "an error"
    21  	err := errors.New(errorMessage)
    22  	err2 := Stack(err)
    23  	expected := fmt.Sprintf("%T %T", err2, err)
    24  	actual := errorglue.DumpChain(err2)
    25  	if actual != expected {
    26  		t.Errorf("DumpChain: %q expected: %q", actual, expected)
    27  	}
    28  }
    29  
    30  func TestIsWarning(t *testing.T) {
    31  	err := errors.New("err")
    32  	w := Warning(err) // mark as warning
    33  
    34  	// outermost error is now the stack trace
    35  	// *errorglue.errorStack *errorglue.WarningType *errors.errorString
    36  	//t.Error(errorglue.DumpChain(w))
    37  
    38  	actual := IsWarning(w)
    39  	if !actual {
    40  		t.Error("IsWarning broken")
    41  	}
    42  }
    43  
    44  func TestIsType(t *testing.T) {
    45  	var test string
    46  	expected := "expected"
    47  	wrongValue := "wrongValue"
    48  
    49  	test = "1 err nil"
    50  	{
    51  		var e2 error
    52  		t.Logf("%s", test)
    53  		if IsType(nil, &e2) {
    54  			t.Errorf("%s: IsType returned true FAIL", test)
    55  		}
    56  	}
    57  
    58  	{ // value receiver error value
    59  		err := valueError{s: expected}
    60  
    61  		test = "2 value non-match"
    62  		{
    63  			err2 := pointerError{s: wrongValue}
    64  			t.Logf("%s", test)
    65  			if IsType(err, &err2) {
    66  				t.Errorf("%s: IsType returned true FAIL", test)
    67  			}
    68  		}
    69  
    70  		test = "3 value match"
    71  		{
    72  			err2 := valueError{s: wrongValue}
    73  			t.Logf("%s", test)
    74  			if !IsType(err, &err2) {
    75  				t.Errorf("%s: IsType returned false FAIL", test)
    76  			}
    77  			if err2.Error() != expected {
    78  				t.Errorf("%s: value not updated FAIL %#v exp: %q", test, err2, expected)
    79  			}
    80  		}
    81  	}
    82  
    83  	{ // value receiver error pointer
    84  		err := &valueError{s: expected}
    85  
    86  		test = "4 value pointer non-match"
    87  		{
    88  			err2 := pointerError{s: wrongValue}
    89  			t.Logf("%s", test)
    90  			if IsType(err, &err2) {
    91  				t.Errorf("%s: IsType returned true FAIL", test)
    92  			}
    93  		}
    94  
    95  		test = "5 value pointer match"
    96  		{
    97  			err2 := valueError{s: wrongValue}
    98  			t.Logf("%s", test)
    99  			if !IsType(err, &err2) {
   100  				t.Errorf("%s: IsType returned false FAIL", test)
   101  			}
   102  			if err2.Error() != expected {
   103  				t.Errorf("%s: value not updated FAIL %q exp: %q", test, err2.Error(), expected)
   104  			}
   105  		}
   106  	}
   107  
   108  	{ // pointer receiver
   109  		err := &pointerError{s: expected}
   110  
   111  		test = "6 pointer non-match"
   112  		{ // non-match
   113  			err2 := valueError{s: wrongValue}
   114  			t.Logf("%s", test)
   115  			if IsType(err, &err2) {
   116  				t.Errorf("%s: IsType returned true FAIL", test)
   117  			}
   118  		}
   119  
   120  		test = "7 pointer match"
   121  		{
   122  			err2 := pointerError{s: wrongValue}
   123  			t.Logf("%s", test)
   124  			if !IsType(err, &err2) {
   125  				t.Errorf("%s: IsType returned false FAIL", test)
   126  			}
   127  			if err2.Error() != expected {
   128  				t.Errorf("%s: value not updated FAIL %q exp: %q", test, err2.Error(), expected)
   129  			}
   130  		}
   131  	}
   132  }
   133  
   134  func TestIsTypeErrno(t *testing.T) {
   135  
   136  	// an error implementation with value receiver
   137  	var err0 error = syscall.ENOENT
   138  	var err error = fmt.Errorf("error: %w", err0)
   139  	var actual bool
   140  	var err2 syscall.Errno
   141  
   142  	actual = IsType(err, &err2)
   143  	if !actual {
   144  		t.Errorf("errno: IsType returned false FAIL")
   145  	}
   146  	if err2 != err0 {
   147  		t.Errorf("errno: IsType returned wrong value FAIL")
   148  	}
   149  }
   150  func TestIsTypeSyscall(t *testing.T) {
   151  	expected := "expected"
   152  
   153  	// an error implementation with pointer receiver
   154  	err0 := os.NewSyscallError(expected, errors.New(expected))
   155  	err := fmt.Errorf("error: %w", err0)
   156  	// pointer error implementation requires the star
   157  	var err3 *os.SyscallError
   158  	actual := IsType(err, &err3)
   159  	if !actual {
   160  		t.Errorf("syscall: IsType returned false FAIL")
   161  	}
   162  	if err3 == nil {
   163  		t.Errorf("syscall: IsType returned err3 nil FAIL")
   164  	}
   165  	if err3 != err0 {
   166  		t.Errorf("syscall: IsType returned wrong value %#v exp: %q#v FAIL", err3, err0)
   167  	}
   168  }
   169  
   170  type valueError struct{ s string }
   171  
   172  func (er valueError) Error() string { return er.s }
   173  
   174  type pointerError struct{ s string }
   175  
   176  func (er *pointerError) Error() string { return er.s }
   177  
   178  func TestIsError(t *testing.T) {
   179  
   180  	// err nil
   181  	var err error
   182  	if IsError(err) {
   183  		t.Error("error(nil): true")
   184  	}
   185  
   186  	// err non-nil
   187  	if !IsError(errors.New("x")) {
   188  		t.Error("errors.New: false")
   189  	}
   190  
   191  	// Errno 0
   192  	if IsError(unix.Errno(0)) {
   193  		t.Error("unix.Errno(0): true")
   194  	}
   195  
   196  	// Errno non-0
   197  	if !IsError(unix.EPERM) {
   198  		t.Error("unix.EPERM: false")
   199  	}
   200  
   201  	//t.Fail()
   202  }
   203  
   204  func TestErrorDataMap(t *testing.T) {
   205  	k1 := "k1"
   206  	v1 := "s1"
   207  	k2 := "k2"
   208  	v2 := "s2"
   209  	e1error := "e1"
   210  
   211  	var expectedInt int
   212  
   213  	e1 := errors.New(e1error)
   214  	e2 := errorglue.NewErrorData(e1, k1, v1)
   215  	e3 := errorglue.NewErrorData(e2, k2, v2)
   216  	strs, values := eErrorData(e3)
   217  	expectedInt = len(strs)
   218  	if expectedInt > 0 {
   219  		t.Errorf("slice has unexpected values: %d", expectedInt)
   220  	}
   221  	if len(values) != 2 || values[k1] != v1 || values[k2] != v2 {
   222  		t.Errorf("bad map: %#v expected: %#v", values, map[string]string{k1: v1, k2: v2})
   223  	}
   224  }
   225  
   226  func TestErrorDataSlice(t *testing.T) {
   227  	s1 := "s1"
   228  	s2 := "s2"
   229  	e1error := "e1"
   230  
   231  	var expectedInt int
   232  
   233  	e1 := errors.New(e1error)
   234  	e2 := errorglue.NewErrorData(e1, "", s1)
   235  	e3 := errorglue.NewErrorData(e2, "", s2)
   236  	strs, values := eErrorData(e3)
   237  	expectedInt = len(values)
   238  	if expectedInt > 0 {
   239  		t.Errorf("map has unexpected values: %d", expectedInt)
   240  	}
   241  	if len(strs) != 2 || strs[0] != s1 || strs[1] != s2 {
   242  		t.Errorf("bad slice: %#v expected: %#v", strs, []string{s1, s2})
   243  	}
   244  }
   245  
   246  func eErrorData(err error) (list []string, keyValues map[string]string) {
   247  	for err != nil {
   248  		if e, ok := err.(errorglue.ErrorHasData); ok {
   249  			key, value := e.KeyValue()
   250  			if key == "" { // for the slice
   251  				list = append([]string{value}, list...)
   252  			} else { // for the map
   253  				if keyValues == nil {
   254  					keyValues = map[string]string{key: value}
   255  				} else if _, ok := keyValues[key]; !ok {
   256  					keyValues[key] = value
   257  				}
   258  			}
   259  		}
   260  		err = errors.Unwrap(err)
   261  	}
   262  	return
   263  }