github.com/haraldrudell/parl@v0.4.176/punix/errno_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 punix
     7  
     8  import (
     9  	"errors"
    10  	"fmt"
    11  	"math"
    12  	"os"
    13  	"reflect"
    14  	"strconv"
    15  	"strings"
    16  	"testing"
    17  
    18  	"github.com/haraldrudell/parl/perrors"
    19  	"golang.org/x/sys/unix"
    20  )
    21  
    22  func TestIsENOENT(t *testing.T) {
    23  	err := perrors.Errorf("err: %w", unix.ENOENT)
    24  	if !IsENOENT(err) {
    25  		t.Error("IsENOENT returned false")
    26  	}
    27  
    28  	err = perrors.New("error")
    29  	if IsENOENT(err) {
    30  		t.Error("IsENOENT returned true")
    31  	}
    32  }
    33  
    34  func TestErrnoValues(t *testing.T) {
    35  
    36  	// this test will only run from the command-line like:
    37  	// go test -v -run '^TestErrnoValues$' ./punix
    38  
    39  	// skip test if go test -v flag was not provided
    40  	hasVFlag := false
    41  	verboseFlag := "-test.v=true"
    42  	for _, s := range os.Args {
    43  		if hasVFlag = s == verboseFlag; hasVFlag {
    44  			break
    45  		}
    46  	}
    47  	if !hasVFlag {
    48  		t.Skip()
    49  	}
    50  
    51  	// /var/folders/sq/0x1_9fyn1bv907s7ypfryt1c0000gn/T/go-build2538455228/b001/punix.test,
    52  	// -test.testlogfile=/var/folders/sq/0x1_9fyn1bv907s7ypfryt1c0000gn/T/go-build2538455228/b001/testlog.txt,
    53  	// -test.paniconexit0,
    54  	// -test.timeout=10m0s,
    55  	// -test.v=true,
    56  	// -test.run=/TestErrnoValues$
    57  	//t.Logf("%#v", os.Args)
    58  
    59  	var errno unix.Errno
    60  	var _ error = errno
    61  	var _ error = &errno
    62  	var errnop = &errno
    63  	_ = errnop
    64  
    65  	// two-level indirection interface matching does not work
    66  	// cannot use &errnop (value of type **unix.Errno) as *error value in variable declaration:
    67  	// **unix.Errno does not implement *error (type *error is pointer to interface, not interface)
    68  	//var _ *error = &errnop
    69  
    70  	// invalid operation: cannot compare errno == nil
    71  	// (mismatched types unix.Errno and untyped nil)
    72  	//t.Logf("errno == nil: %t", errno == nil)
    73  
    74  	// errno is compared to int, not nil
    75  	// errno == 0 → true
    76  	t.Logf("errno == 0 → %t", errno == 0)
    77  
    78  	// to print properly, errno need to be cast to int
    79  	// printing errno: %s: state not recoverable %q: "state not recoverable" %v: state not recoverable
    80  	// printing int(errno): %d: 104 0x%x: 0x68
    81  	errno = unix.ENOTRECOVERABLE
    82  	t.Logf("printing errno: %%s: %s %%q: %[1]q %%v: %[1]v", errno)
    83  	t.Logf("printing int(errno): %%d: %d 0x%%x: 0x%[1]x", int(errno))
    84  
    85  	var e unix.Errno
    86  	if e == 0 {
    87  		t.Logf("if errno != 0 {…")
    88  	}
    89  
    90  	// %T: unix.Errno %#v: 0x68
    91  	t.Logf("%%T: %T %%#v: %#[1]v", errno)
    92  
    93  	t.Fail() // causes prints to be output
    94  }
    95  
    96  func TestErrno(t *testing.T) {
    97  	var errno unix.Errno
    98  
    99  	// test nil
   100  	errno = Errno(nil)
   101  	if errno != 0 {
   102  		t.Errorf("punix.Errno returned non-zero")
   103  	}
   104  
   105  	// test non-unix.Errno
   106  	errno = Errno(perrors.New("error"))
   107  	if errno != 0 {
   108  		t.Errorf("punix.Errno returned non-zero")
   109  	}
   110  
   111  	err := fmt.Errorf("err: %w", unix.ENOENT)
   112  
   113  	var sList []string
   114  	for e := err; e != nil; e = errors.Unwrap(e) {
   115  		sList = append(sList, reflect.TypeOf(e).String())
   116  	}
   117  	t.Logf("err types: %s", strings.Join(sList, "\x20"))
   118  	t.Logf("unix.ENOENT type: %s", reflect.TypeOf(unix.ENOENT).String())
   119  
   120  	// test non-unix.Errno
   121  	errno = Errno(err)
   122  	if errno == 0 {
   123  		t.Errorf("punix.Errno returned zero")
   124  	}
   125  	if errno != unix.ENOENT {
   126  		t.Errorf("punix.Errno returned wrong value: %#v", errno)
   127  	}
   128  
   129  }
   130  
   131  func TestErrnoValue(t *testing.T) {
   132  	var epermInt = 1
   133  	var epermString = "operation not permitted"
   134  	var epermName = "EPERM"
   135  
   136  	var isError bool
   137  	var errnoValue int
   138  	var actual string
   139  
   140  	isError = unix.EPERM != 0
   141  	if !isError {
   142  		t.Error("isError false")
   143  	}
   144  	errnoValue = int(unix.EPERM)
   145  	if errnoValue != epermInt {
   146  		t.Errorf("errnoValue %d exp %d", errnoValue, epermInt)
   147  	}
   148  	actual = fmt.Sprintf("%d", unix.EPERM)
   149  	if actual != strconv.Itoa(epermInt) {
   150  		t.Errorf("%%d: %q exp %q", actual, strconv.Itoa(epermInt))
   151  	}
   152  	actual = fmt.Sprintf("%v", unix.EPERM)
   153  	if actual != epermString {
   154  		t.Errorf("%%v: %q exp %q", actual, epermString)
   155  	}
   156  	actual = unix.ErrnoName(unix.EPERM)
   157  	if actual != epermName {
   158  		t.Errorf("ErrnoName: %q exp %q", actual, epermName)
   159  	}
   160  }
   161  
   162  func TestErrorNumberString(t *testing.T) {
   163  	type args struct {
   164  		label string
   165  		err   error
   166  	}
   167  	tests := []struct {
   168  		name                   string
   169  		args                   args
   170  		wantErrnoNumericString string
   171  	}{
   172  		{"no error", args{"abc", nil}, ""},
   173  		{"EPERM", args{"errno", unix.EPERM}, "errno: EPERM 1 0x1"},
   174  		{"-1", args{"", unix.Errno(math.MaxUint)}, "-1 -0x1"},
   175  	}
   176  	for _, tt := range tests {
   177  		t.Run(tt.name, func(t *testing.T) {
   178  			if gotErrnoNumericString := ErrnoString(tt.args.label, tt.args.err); gotErrnoNumericString != tt.wantErrnoNumericString {
   179  				t.Errorf("ErrorNumberString() = %v, want %v", gotErrnoNumericString, tt.wantErrnoNumericString)
   180  			}
   181  		})
   182  	}
   183  }