github.com/avfs/avfs@v0.33.1-0.20240303173310-c6ba67c33eb7/test/test_error.go (about)

     1  //
     2  //  Copyright 2023 The AVFS authors
     3  //
     4  //  Licensed under the Apache License, Version 2.0 (the "License");
     5  //  you may not use this file except in compliance with the License.
     6  //  You may obtain a copy of the License at
     7  //
     8  //  	http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  //  Unless required by applicable law or agreed to in writing, software
    11  //  distributed under the License is distributed on an "AS IS" BASIS,
    12  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  //  See the License for the specific language governing permissions and
    14  //  limitations under the License.
    15  //
    16  
    17  package test
    18  
    19  import (
    20  	"io/fs"
    21  	"os"
    22  	"reflect"
    23  	"regexp"
    24  	"runtime"
    25  	"slices"
    26  	"testing"
    27  
    28  	"github.com/avfs/avfs"
    29  )
    30  
    31  // assertError stores the current fs.PathError or the os.LinkError test data.
    32  type assertError struct {
    33  	tb             testing.TB
    34  	err            error
    35  	wantOsTypes    []avfs.OSType
    36  	wantGoVersions []string
    37  	wantOps        []string
    38  	wantPath       string
    39  	wantOld        string
    40  	wantNew        string
    41  	wantErrs       []error
    42  	IsLinkError    bool
    43  }
    44  
    45  // AssertPathError checks an error of type fs.PathError.
    46  func AssertPathError(tb testing.TB, err error) *assertError {
    47  	return &assertError{tb: tb, err: err, IsLinkError: false}
    48  }
    49  
    50  // AssertLinkError checks an error of type os.LinkError.
    51  func AssertLinkError(tb testing.TB, err error) *assertError {
    52  	return &assertError{tb: tb, err: err, IsLinkError: true}
    53  }
    54  
    55  // Test runs the test.
    56  func (ae *assertError) Test() *assertError {
    57  	tb := ae.tb
    58  	tb.Helper()
    59  
    60  	if len(ae.wantOsTypes) != 0 && !slices.Contains(ae.wantOsTypes, avfs.CurrentOSType()) {
    61  		return ae
    62  	}
    63  
    64  	if len(ae.wantGoVersions) != 0 {
    65  		re := regexp.MustCompile(`go\d+\.\d+`)
    66  		version := re.FindString(runtime.Version())
    67  
    68  		if !slices.Contains(ae.wantGoVersions, version) {
    69  			return ae
    70  		}
    71  	}
    72  
    73  	if len(ae.wantErrs) == 0 {
    74  		if ae.err != nil {
    75  			tb.Errorf("want error to be nil got %v", ae.err)
    76  		}
    77  
    78  		return ae
    79  	}
    80  
    81  	if ae.IsLinkError {
    82  		return ae.testLinkError()
    83  	}
    84  
    85  	return ae.testPathError()
    86  }
    87  
    88  func (ae *assertError) testLinkError() *assertError {
    89  	tb := ae.tb
    90  
    91  	e, ok := ae.err.(*os.LinkError)
    92  	if !ok {
    93  		tb.Errorf("want error type to be *os.LinkError, got %v : %v", reflect.TypeOf(ae.err), ae.err)
    94  
    95  		return ae
    96  	}
    97  
    98  	if len(ae.wantOps) != 0 && !slices.Contains(ae.wantOps, e.Op) {
    99  		tb.Errorf("want Op to be %s, got %s", ae.wantOps, e.Op)
   100  	}
   101  
   102  	if ae.wantOld != "" && ae.wantOld != e.Old {
   103  		tb.Errorf("want Old to be %s, got %s", ae.wantOld, e.Old)
   104  	}
   105  
   106  	if ae.wantNew != "" && ae.wantNew != e.New {
   107  		tb.Errorf("want New to be %s, got %s", ae.wantNew, e.New)
   108  	}
   109  
   110  	te := reflect.ValueOf(e.Err)
   111  	foundOk := false
   112  
   113  	for _, wantErr := range ae.wantErrs {
   114  		we := reflect.ValueOf(wantErr)
   115  		if (te.CanUint() && we.CanUint() && te.Uint() == we.Uint()) || (e.Err.Error() == wantErr.Error()) {
   116  			foundOk = true
   117  
   118  			break
   119  		}
   120  	}
   121  
   122  	if !foundOk {
   123  		tb.Errorf("want error to be %s, got %s", ae.wantErrs, e.Err.Error())
   124  	}
   125  
   126  	return ae
   127  }
   128  
   129  func (ae *assertError) testPathError() *assertError {
   130  	tb := ae.tb
   131  
   132  	e, ok := ae.err.(*fs.PathError)
   133  	if !ok {
   134  		tb.Errorf("want error type to be *fs.PathError, got %v : %v", reflect.TypeOf(ae.err), ae.err)
   135  
   136  		return ae
   137  	}
   138  
   139  	if len(ae.wantOps) != 0 && !slices.Contains(ae.wantOps, e.Op) {
   140  		tb.Errorf("want Op to be %s, got %s", ae.wantOps, e.Op)
   141  	}
   142  
   143  	if ae.wantPath != "" && ae.wantPath != e.Path {
   144  		tb.Errorf("want Path to be %s, got %s", ae.wantPath, e.Path)
   145  	}
   146  
   147  	te := reflect.ValueOf(e.Err)
   148  	foundOk := false
   149  
   150  	for _, wantErr := range ae.wantErrs {
   151  		we := reflect.ValueOf(wantErr)
   152  		if (te.CanUint() && we.CanUint() && te.Uint() == we.Uint()) || (e.Err.Error() == wantErr.Error()) {
   153  			foundOk = true
   154  
   155  			break
   156  		}
   157  	}
   158  
   159  	if !foundOk {
   160  		tb.Errorf("want error to be %s, got %s", ae.wantErrs, e.Err.Error())
   161  	}
   162  
   163  	return ae
   164  }
   165  
   166  // GoVersion sets the expected Go version.
   167  func (ae *assertError) GoVersion(goVersions ...string) *assertError {
   168  	ae.wantGoVersions = goVersions
   169  
   170  	return ae
   171  }
   172  
   173  // New sets the expected new path.
   174  func (ae *assertError) New(wantNew string) *assertError {
   175  	ae.wantNew = wantNew
   176  
   177  	return ae
   178  }
   179  
   180  // NoError set the expected error to nil.
   181  func (ae *assertError) NoError() *assertError {
   182  	ae.wantErrs = nil
   183  
   184  	return ae
   185  }
   186  
   187  // Old sets the expected old path.
   188  func (ae *assertError) Old(WantOld string) *assertError {
   189  	ae.wantOld = WantOld
   190  
   191  	return ae
   192  }
   193  
   194  // Op sets the expected Op.
   195  func (ae *assertError) Op(ops ...string) *assertError {
   196  	ae.wantOps = ops
   197  
   198  	return ae
   199  }
   200  
   201  // OpLstat sets the expected Lstat Op for the current OS.
   202  func (ae *assertError) OpLstat() *assertError {
   203  	switch avfs.CurrentOSType() {
   204  	case avfs.OsWindows:
   205  		return ae.Op("CreateFile")
   206  	default:
   207  		return ae.Op("lstat")
   208  	}
   209  }
   210  
   211  // OpStat sets the expected Stat Op for the current OS.
   212  func (ae *assertError) OpStat() *assertError {
   213  	switch avfs.CurrentOSType() {
   214  	case avfs.OsWindows:
   215  		return ae.Op("CreateFile")
   216  	default:
   217  		return ae.Op("stat")
   218  	}
   219  }
   220  
   221  // OSType sets at least one expected OSType.
   222  func (ae *assertError) OSType(ost ...avfs.OSType) *assertError {
   223  	ae.wantOsTypes = ost
   224  
   225  	return ae
   226  }
   227  
   228  // Path sets the expected path.
   229  func (ae *assertError) Path(path string) *assertError {
   230  	ae.wantPath = path
   231  
   232  	return ae
   233  }
   234  
   235  // Err sets the expected error.
   236  func (ae *assertError) Err(wantErr ...error) *assertError {
   237  	ae.wantErrs = wantErr
   238  
   239  	return ae
   240  }
   241  
   242  // ErrPermDenied sets the expected permission error for the current OS.
   243  func (ae *assertError) ErrPermDenied() *assertError {
   244  	switch avfs.CurrentOSType() {
   245  	case avfs.OsWindows:
   246  		ae.Err(avfs.ErrWinAccessDenied)
   247  	default:
   248  		ae.Err(avfs.ErrPermDenied)
   249  	}
   250  
   251  	return ae
   252  }