github.com/Wrdlbrnft/go-gitignore@v0.0.0-20201129201858-74ef740b8b77/repository_test.go (about)

     1  package gitignore_test
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"testing"
     7  
     8  	"github.com/denormal/go-gitignore"
     9  )
    10  
    11  type repositorytest struct {
    12  	file      string
    13  	directory string
    14  	cache     gitignore.Cache
    15  	cached    bool
    16  	error     func(e gitignore.Error) bool
    17  	errors    []gitignore.Error
    18  	bad       int
    19  	instance  func(string) (gitignore.GitIgnore, error)
    20  	exclude   string
    21  	gitdir    string
    22  } // repostorytest{}
    23  
    24  func (r *repositorytest) create(path string, gitdir bool) (gitignore.GitIgnore, error) {
    25  	// if we have an error handler, reset the list of errors
    26  	if r.error != nil {
    27  		r.errors = make([]gitignore.Error, 0)
    28  	}
    29  
    30  	if r.file == gitignore.File || r.file == "" {
    31  		// should we create the global exclude file
    32  		r.gitdir = os.Getenv("GIT_DIR")
    33  		if gitdir {
    34  			// create a temporary file for the global exclude file
    35  			_exclude, _err := exclude(_GITEXCLUDE)
    36  			if _err != nil {
    37  				return nil, _err
    38  			}
    39  
    40  			// extract the current value of the GIT_DIR environment variable
    41  			// and set the value to be that of the temporary file
    42  			r.exclude = _exclude
    43  			_err = os.Setenv("GIT_DIR", r.exclude)
    44  			if _err != nil {
    45  				return nil, _err
    46  			}
    47  		} else {
    48  			_err := os.Unsetenv("GIT_DIR")
    49  			if _err != nil {
    50  				return nil, _err
    51  			}
    52  		}
    53  	}
    54  
    55  	// attempt to create the GitIgnore instance
    56  	_repository, _err := r.instance(path)
    57  
    58  	// if we encountered errors, and the first error has a zero position
    59  	// then it represents a file access error
    60  	//		- extract the error and return it
    61  	//		- remove it from the list of errors
    62  	if len(r.errors) > 0 {
    63  		if r.errors[0].Position().Zero() {
    64  			_err = r.errors[0].Underlying()
    65  			r.errors = r.errors[1:]
    66  		}
    67  	}
    68  
    69  	// return the GitIgnore instance
    70  	return _repository, _err
    71  } // create()
    72  
    73  func (r *repositorytest) destroy() {
    74  	// remove the temporary files and directories
    75  	for _, _path := range []string{r.directory, r.exclude} {
    76  		if _path != "" {
    77  			defer os.RemoveAll(_path)
    78  		}
    79  	}
    80  
    81  	if r.file == gitignore.File || r.file == "" {
    82  		// reset the GIT_DIR environment variable
    83  		if r.gitdir == "" {
    84  			defer os.Unsetenv("GIT_DIR")
    85  		} else {
    86  			defer os.Setenv("GIT_DIR", r.gitdir)
    87  		}
    88  	}
    89  } // destroy()
    90  
    91  type invalidtest struct {
    92  	*repositorytest
    93  	tag   string
    94  	match func() gitignore.Match
    95  } // invalidtest{}
    96  
    97  func TestRepository(t *testing.T) {
    98  	_test := &repositorytest{}
    99  	_test.bad = _GITREPOSITORYERRORS
   100  	_test.instance = func(path string) (gitignore.GitIgnore, error) {
   101  		return gitignore.NewRepository(path)
   102  	}
   103  
   104  	// perform the repository tests
   105  	repository(t, _test, _REPOSITORYMATCHES)
   106  
   107  	// remove the temporary directory used for this test
   108  	defer _test.destroy()
   109  } // TestRepository()
   110  
   111  func TestRepositoryWithFile(t *testing.T) {
   112  	_test := &repositorytest{}
   113  	_test.bad = _GITREPOSITORYERRORS
   114  	_test.file = gitignore.File + "-with-file"
   115  	_test.instance = func(path string) (gitignore.GitIgnore, error) {
   116  		return gitignore.NewRepositoryWithFile(path, _test.file)
   117  	}
   118  
   119  	// perform the repository tests
   120  	repository(t, _test, _REPOSITORYMATCHES)
   121  
   122  	// remove the temporary directory used for this test
   123  	defer _test.destroy()
   124  } // TestRepositoryWithFile()
   125  
   126  func TestRepositoryWithErrors(t *testing.T) {
   127  	_test := &repositorytest{}
   128  	_test.bad = _GITREPOSITORYERRORS
   129  	_test.file = gitignore.File + "-with-errors"
   130  	_test.error = func(e gitignore.Error) bool {
   131  		_test.errors = append(_test.errors, e)
   132  		return true
   133  	}
   134  	_test.instance = func(path string) (gitignore.GitIgnore, error) {
   135  		return gitignore.NewRepositoryWithErrors(
   136  			path, _test.file, _test.error,
   137  		), nil
   138  	}
   139  
   140  	// perform the repository tests
   141  	repository(t, _test, _REPOSITORYMATCHES)
   142  
   143  	// remove the temporary directory used for this test
   144  	defer _test.destroy()
   145  } // TestRepositoryWithErrors()
   146  
   147  func TestRepositoryWithErrorsFalse(t *testing.T) {
   148  	_test := &repositorytest{}
   149  	_test.bad = _GITREPOSITORYERRORSFALSE
   150  	_test.file = gitignore.File + "-with-errors-false"
   151  	_test.error = func(e gitignore.Error) bool {
   152  		_test.errors = append(_test.errors, e)
   153  		return false
   154  	}
   155  	_test.instance = func(path string) (gitignore.GitIgnore, error) {
   156  		return gitignore.NewRepositoryWithErrors(
   157  			path, _test.file, _test.error,
   158  		), nil
   159  	}
   160  
   161  	// perform the repository tests
   162  	repository(t, _test, _REPOSITORYMATCHESFALSE)
   163  
   164  	// remove the temporary directory used for this test
   165  	defer _test.destroy()
   166  } // TestRepositoryWithErrorsFalse()
   167  
   168  func TestRepositoryWithCache(t *testing.T) {
   169  	_test := &repositorytest{}
   170  	_test.bad = _GITREPOSITORYERRORS
   171  	_test.cache = gitignore.NewCache()
   172  	_test.cached = true
   173  	_test.instance = func(path string) (gitignore.GitIgnore, error) {
   174  		return gitignore.NewRepositoryWithCache(
   175  			path, _test.file, _test.cache, _test.error,
   176  		), nil
   177  	}
   178  
   179  	// perform the repository tests
   180  	repository(t, _test, _REPOSITORYMATCHES)
   181  
   182  	// clean up
   183  	defer _test.destroy()
   184  
   185  	// rerun the tests while accumulating errors
   186  	_test.directory = ""
   187  	_test.file = gitignore.File + "-with-cache"
   188  	_test.error = func(e gitignore.Error) bool {
   189  		_test.errors = append(_test.errors, e)
   190  		return true
   191  	}
   192  	repository(t, _test, _REPOSITORYMATCHES)
   193  
   194  	// remove the temporary directory used for this test
   195  	_err := os.RemoveAll(_test.directory)
   196  	if _err != nil {
   197  		t.Fatalf(
   198  			"unable to remove temporary directory %s: %s",
   199  			_test.directory, _err.Error(),
   200  		)
   201  	}
   202  
   203  	// recreate the temporary directory
   204  	//		- this remove & recreate gives us an empty directory for the
   205  	//		  repository test
   206  	//		- this lets us test the caching
   207  	_err = os.MkdirAll(_test.directory, _GITMASK)
   208  	if _err != nil {
   209  		t.Fatalf(
   210  			"unable to recreate temporary directory %s: %s",
   211  			_test.directory, _err.Error(),
   212  		)
   213  	}
   214  	defer _test.destroy()
   215  
   216  	// repeat the repository tests
   217  	//		- these should succeed using just the cache data
   218  	repository(t, _test, _REPOSITORYMATCHES)
   219  } // TestRepositoryWithCache()
   220  
   221  func TestInvalidRepository(t *testing.T) {
   222  	_test := &repositorytest{}
   223  	_test.instance = func(path string) (gitignore.GitIgnore, error) {
   224  		return gitignore.NewRepository(path)
   225  	}
   226  
   227  	// perform the invalid repository tests
   228  	invalid(t, _test)
   229  } // TestInvalidRepository()
   230  
   231  func TestInvalidRepositoryWithFile(t *testing.T) {
   232  	_test := &repositorytest{}
   233  	_test.file = gitignore.File + "-invalid-with-file"
   234  	_test.instance = func(path string) (gitignore.GitIgnore, error) {
   235  		return gitignore.NewRepositoryWithFile(path, _test.file)
   236  	}
   237  
   238  	// perform the invalid repository tests
   239  	invalid(t, _test)
   240  } // TestInvalidRepositoryWithFile()
   241  
   242  func TestInvalidRepositoryWithErrors(t *testing.T) {
   243  	_test := &repositorytest{}
   244  	_test.file = gitignore.File + "-invalid-with-errors"
   245  	_test.error = func(e gitignore.Error) bool {
   246  		_test.errors = append(_test.errors, e)
   247  		return true
   248  	}
   249  	_test.instance = func(path string) (gitignore.GitIgnore, error) {
   250  		return gitignore.NewRepositoryWithErrors(
   251  			path, _test.file, _test.error,
   252  		), nil
   253  	}
   254  
   255  	// perform the invalid repository tests
   256  	invalid(t, _test)
   257  } // TestInvalidRepositoryWithErrors()
   258  
   259  func TestInvalidRepositoryWithErrorsFalse(t *testing.T) {
   260  	_test := &repositorytest{}
   261  	_test.file = gitignore.File + "-invalid-with-errors-false"
   262  	_test.error = func(e gitignore.Error) bool {
   263  		_test.errors = append(_test.errors, e)
   264  		return false
   265  	}
   266  	_test.instance = func(path string) (gitignore.GitIgnore, error) {
   267  		return gitignore.NewRepositoryWithErrors(
   268  			path, _test.file, _test.error,
   269  		), nil
   270  	}
   271  
   272  	// perform the invalid repository tests
   273  	invalid(t, _test)
   274  } // TestInvalidRepositoryWithErrorsFalse()
   275  
   276  func TestInvalidRepositoryWithCache(t *testing.T) {
   277  	_test := &repositorytest{}
   278  	_test.file = gitignore.File + "-invalid-with-cache"
   279  	_test.cache = gitignore.NewCache()
   280  	_test.cached = true
   281  	_test.error = func(e gitignore.Error) bool {
   282  		_test.errors = append(_test.errors, e)
   283  		return true
   284  	}
   285  	_test.instance = func(path string) (gitignore.GitIgnore, error) {
   286  		return gitignore.NewRepositoryWithCache(
   287  			path, _test.file, _test.cache, _test.error,
   288  		), nil
   289  	}
   290  
   291  	// perform the invalid repository tests
   292  	invalid(t, _test)
   293  
   294  	// repeat the tests using a default cache
   295  	_test.cache = nil
   296  	invalid(t, _test)
   297  } // TestInvalidRepositoryWithCache()
   298  
   299  //
   300  // helper functions
   301  //
   302  
   303  func repository(t *testing.T, test *repositorytest, m []match) {
   304  	// if the test has no configured directory, then create a new
   305  	// directory with the required .gitignore files
   306  	if test.directory == "" {
   307  		// what name should we use for the .gitignore file?
   308  		//		- if none is given, use the default
   309  		_file := test.file
   310  		if _file == "" {
   311  			_file = gitignore.File
   312  		}
   313  
   314  		// create a temporary directory populated with sample .gitignore files
   315  		//		- first, augment the test data to include file names
   316  		_map := make(map[string]string)
   317  		for _k, _content := range _GITREPOSITORY {
   318  			_map[_k+"/"+_file] = _content
   319  		}
   320  		_dir, _err := dir(_map)
   321  		if _err != nil {
   322  			t.Fatalf("unable to create temporary directory: %s", _err.Error())
   323  		}
   324  		test.directory = _dir
   325  	}
   326  
   327  	// create the repository
   328  	_repository, _err := test.create(test.directory, true)
   329  	if _err != nil {
   330  		t.Fatalf("unable to create repository: %s", _err.Error())
   331  	}
   332  
   333  	// ensure we have a non-nill repository returned
   334  	if _repository == nil {
   335  		t.Error("expected non-nill GitIgnore repository instance; nil found")
   336  	}
   337  
   338  	// ensure the base of the repository is correct
   339  	if _repository.Base() != test.directory {
   340  		t.Errorf(
   341  			"repository.Base() mismatch; expected %q, got %q",
   342  			test.directory, _repository.Base(),
   343  		)
   344  	}
   345  
   346  	// we need to check each test to see if it's matching against a
   347  	// GIT_DIR/info/exclude
   348  	//		- we only do this if the target does not use .gitignore
   349  	//		  as the name of the ignore file
   350  	_prepare := func(m match) match {
   351  		if test.file == "" || test.file == gitignore.File {
   352  			return m
   353  		} else if m.Exclude {
   354  			return match{m.Path, "", false, m.Exclude}
   355  		} else {
   356  			return m
   357  		}
   358  	} // _prepare()
   359  
   360  	// perform the repository matching using absolute paths
   361  	_cb := func(path string, isdir bool) gitignore.Match {
   362  		_path := filepath.Join(_repository.Base(), path)
   363  		return _repository.Absolute(_path, isdir)
   364  	}
   365  	for _, _test := range m {
   366  		do(t, _cb, _prepare(_test))
   367  	}
   368  
   369  	// repeat the tests using relative paths
   370  	_repository, _err = test.create(test.directory, true)
   371  	if _err != nil {
   372  		t.Fatalf("unable to create repository: %s", _err.Error())
   373  	}
   374  	_cb = func(path string, isdir bool) gitignore.Match {
   375  		return _repository.Relative(path, isdir)
   376  	}
   377  	for _, _test := range m {
   378  		do(t, _cb, _prepare(_test))
   379  	}
   380  
   381  	// perform absolute path tests with paths not under the same repository
   382  	_map := make(map[string]string)
   383  	for _, _test := range m {
   384  		_map[_test.Path] = " "
   385  	}
   386  	_new, _err := dir(_map)
   387  	if _err != nil {
   388  		t.Fatalf("unable to create temporary directory: %s", _err.Error())
   389  	}
   390  	defer os.RemoveAll(_new)
   391  
   392  	// first, perform Match() tests
   393  	_repository, _err = test.create(test.directory, true)
   394  	if _err != nil {
   395  		t.Fatalf("unable to create repository: %s", _err.Error())
   396  	}
   397  	for _, _test := range m {
   398  		_path := filepath.Join(_new, _test.Local())
   399  		_match := _repository.Match(_path)
   400  		if _match != nil {
   401  			t.Fatalf("unexpected match; expected nil, got %v", _match)
   402  		}
   403  	}
   404  
   405  	// next, perform Absolute() tests
   406  	_repository, _err = test.create(test.directory, true)
   407  	if _err != nil {
   408  		t.Fatalf("unable to create repository: %s", _err.Error())
   409  	}
   410  	for _, _test := range m {
   411  		// build the absolute path
   412  		_path := filepath.Join(_new, _test.Local())
   413  
   414  		// we don't expect to match paths not under this repository
   415  		_match := _repository.Absolute(_path, _test.IsDir())
   416  		if _match != nil {
   417  			t.Fatalf("unexpected match; expected nil, got %v", _match)
   418  		}
   419  	}
   420  
   421  	// now, repeat the Match() test after having first removed the
   422  	// temporary directory
   423  	//		- we are testing correct handling of missing files
   424  	_err = os.RemoveAll(_new)
   425  	if _err != nil {
   426  		t.Fatalf(
   427  			"unable to remove temporary directory %s: %s",
   428  			_new, _err.Error(),
   429  		)
   430  	}
   431  	_repository, _err = test.create(test.directory, true)
   432  	if _err != nil {
   433  		t.Fatalf("unable to create repository: %s", _err.Error())
   434  	}
   435  	for _, _test := range m {
   436  		_path := filepath.Join(_new, _test.Local())
   437  
   438  		// if we have an error handler configured, we should be recording
   439  		// and error in this call to Match()
   440  		_before := len(test.errors)
   441  
   442  		// perform the match
   443  		_match := _repository.Match(_path)
   444  		if _match != nil {
   445  			t.Fatalf("unexpected match; expected nil, got %v", _match)
   446  		}
   447  
   448  		// were we recording errors?
   449  		if test.error != nil {
   450  			_after := len(test.errors)
   451  			if !(_after > _before) {
   452  				t.Fatalf(
   453  					"expected Match() error; none found for %s",
   454  					_path,
   455  				)
   456  			}
   457  
   458  			// ensure the most recent error is "not exists"
   459  			_latest := test.errors[_after-1]
   460  			_underlying := _latest.Underlying()
   461  			if !os.IsNotExist(_underlying) {
   462  				t.Fatalf(
   463  					"unexpected Match() error for %s; expected %q, got %q",
   464  					_path, os.ErrNotExist.Error(), _underlying.Error(),
   465  				)
   466  			}
   467  		}
   468  	}
   469  
   470  	// ensure Match() behaves as expected if the absolute path cannot
   471  	// be determined
   472  	//		- we do this by choosing as our working directory a path
   473  	//		  that this process does not have permission to
   474  	_dir, _err := dir(nil)
   475  	if _err != nil {
   476  		t.Fatalf("unable to create temporary directory: %s", _err.Error())
   477  	}
   478  	defer os.RemoveAll(_dir)
   479  
   480  	_cwd, _err := os.Getwd()
   481  	if _err != nil {
   482  		t.Fatalf("unable to retrieve working directory: %s", _err.Error())
   483  	}
   484  	_err = os.Chdir(_dir)
   485  	if _err != nil {
   486  		t.Fatalf("unable to chdir into temporary directory: %s", _err.Error())
   487  	}
   488  	defer os.Chdir(_cwd)
   489  
   490  	// remove permission from the temporary directory
   491  	_err = os.Chmod(_dir, 0)
   492  	if _err != nil {
   493  		t.Fatalf(
   494  			"unable to remove temporary directory %s: %s",
   495  			_dir, _err.Error(),
   496  		)
   497  	}
   498  
   499  	// perform the repository tests
   500  	_repository, _err = test.create(test.directory, true)
   501  	if _err != nil {
   502  		t.Fatalf("unable to create repository: %s", _err.Error())
   503  	}
   504  	for _, _test := range m {
   505  		_match := _repository.Match(_test.Local())
   506  		if _match != nil {
   507  			t.Fatalf("unexpected match; expected nil, not %v", _match)
   508  		}
   509  	}
   510  
   511  	if test.errors != nil {
   512  		// ensure the number of errors is expected
   513  		if len(test.errors) != test.bad {
   514  			t.Fatalf(
   515  				"unexpected repository errors; expected %d, got %d",
   516  				test.bad, len(test.errors),
   517  			)
   518  		} else {
   519  			// if we're here, then we intended to record errors
   520  			//		- ensure we recorded the expected errors
   521  			for _i := 0; _i < len(test.errors); _i++ {
   522  				_got := test.errors[_i]
   523  				_underlying := _got.Underlying()
   524  				if os.IsNotExist(_underlying) ||
   525  					os.IsPermission(_underlying) {
   526  					continue
   527  				} else {
   528  					t.Log(_i)
   529  					t.Fatalf("unexpected repository error: %s", _got.Error())
   530  				}
   531  			}
   532  		}
   533  	}
   534  } // repository()
   535  
   536  func invalid(t *testing.T, test *repositorytest) {
   537  	// create a temporary file to use as the repository
   538  	_file, _err := file("")
   539  	if _err != nil {
   540  		t.Fatalf("unable to create temporary file: %s", _err.Error())
   541  	}
   542  	defer os.Remove(_file.Name())
   543  
   544  	// test repository instance creation against a file
   545  	_repository, _err := test.create(_file.Name(), false)
   546  	if _err == nil {
   547  		t.Errorf(
   548  			"invalid repository error; expected %q, got nil",
   549  			gitignore.InvalidDirectoryError.Error(),
   550  		)
   551  	} else if _err != gitignore.InvalidDirectoryError {
   552  		t.Errorf(
   553  			"invalid repository mismatch; expected %q, got %q",
   554  			gitignore.InvalidDirectoryError.Error(), _err.Error(),
   555  		)
   556  	}
   557  
   558  	// ensure no repository is returned
   559  	if _repository != nil {
   560  		t.Errorf(
   561  			"invalid repository; expected nil, got %v",
   562  			_repository,
   563  		)
   564  	}
   565  
   566  	// now, remove the temporary file and repeat the tests
   567  	_err = os.Remove(_file.Name())
   568  	if _err != nil {
   569  		t.Fatalf(
   570  			"unable to remove temporary file %s: %s",
   571  			_file.Name(), _err.Error(),
   572  		)
   573  	}
   574  
   575  	// test repository instance creating against a missing file
   576  	_repository, _err = test.create(_file.Name(), false)
   577  	if _err == nil {
   578  		t.Errorf(
   579  			"invalid repository error; expected %q, got nil",
   580  			gitignore.InvalidDirectoryError.Error(),
   581  		)
   582  	} else if !os.IsNotExist(_err) {
   583  		t.Errorf(
   584  			"invalid repository mismatch; "+
   585  				"expected no such file or directory, got %q",
   586  			_err.Error(),
   587  		)
   588  	}
   589  
   590  	// ensure no repository is returned
   591  	if _repository != nil {
   592  		t.Errorf(
   593  			"invalid repository; expected nil, got %v",
   594  			_repository,
   595  		)
   596  	}
   597  
   598  	// ensure we can't create a repository instance where the absolute path
   599  	// of the repository cannot be determined
   600  	//		- we do this by choosing a working directory this process does
   601  	//		  not have access to and using a relative path
   602  	_map := map[string]string{gitignore.File: _GITIGNORE}
   603  	_dir, _err := dir(_map)
   604  	if _err != nil {
   605  		t.Fatalf("unable to create a temporary directory: %s", _err.Error())
   606  	}
   607  	defer os.RemoveAll(_dir)
   608  
   609  	// now change the working directory
   610  	_cwd, _err := os.Getwd()
   611  	if _err != nil {
   612  		t.Fatalf("unable to retrieve working directory: %s", _err.Error())
   613  	}
   614  	_err = os.Chdir(_dir)
   615  	if _err != nil {
   616  		t.Fatalf("unable to chdir into temporary directory: %s", _err.Error())
   617  	}
   618  	defer os.Chdir(_cwd)
   619  
   620  	// remove permissions from the working directory
   621  	_err = os.Chmod(_dir, 0)
   622  	if _err != nil {
   623  		t.Fatalf("unable remove temporary directory permissions: %s: %s",
   624  			_dir, _err.Error(),
   625  		)
   626  	}
   627  
   628  	// test repository instance creating against a relative path
   629  	//		- the relative path exists
   630  	_repository, _err = test.create(gitignore.File, false)
   631  	if _err == nil {
   632  		t.Errorf("expected repository error, got nil")
   633  	} else if os.IsNotExist(_err) {
   634  		t.Errorf(
   635  			"unexpected repository error; file exists, but %q returned",
   636  			_err.Error(),
   637  		)
   638  	}
   639  
   640  	// next, create a repository where we do not have read permission
   641  	// to a .gitignore file within the repository
   642  	//		- this should trigger a panic() when attempting a file match
   643  	for _, _test := range _REPOSITORYMATCHES {
   644  		_map[_test.Path] = " "
   645  	}
   646  	_dir, _err = dir(_map)
   647  	if _err != nil {
   648  		t.Fatalf("unable to create a temporary directory: %s", _err.Error())
   649  	}
   650  	defer os.RemoveAll(_dir)
   651  
   652  	_git := filepath.Join(_dir, gitignore.File)
   653  	_err = os.Chmod(_git, 0)
   654  	if _err != nil {
   655  		t.Fatalf("unable remove temporary .gitignore permissions: %s: %s",
   656  			_git, _err.Error(),
   657  		)
   658  	}
   659  
   660  	// attempt to match a path in this repository
   661  	//		- it can be anything, so we just use the .gitignore itself
   662  	//		- between each test we recreate the repository instance to
   663  	//		  remove the effect of any caching
   664  	_instance := func() gitignore.GitIgnore {
   665  		// reset the cache
   666  		if test.cached {
   667  			if test.cache != nil {
   668  				test.cache = gitignore.NewCache()
   669  			}
   670  		}
   671  
   672  		// create the new repository
   673  		_repository, _err := test.create(_dir, false)
   674  		if _err != nil {
   675  			t.Fatalf("unable to create repository: %s", _err.Error())
   676  		}
   677  
   678  		// return the repository
   679  		return _repository
   680  	}
   681  	for _, _match := range _REPOSITORYMATCHES {
   682  		_local := _match.Local()
   683  		_isdir := _match.IsDir()
   684  		_path := filepath.Join(_dir, _local)
   685  
   686  		// try Match() with an absolute path
   687  		_test := &invalidtest{repositorytest: test}
   688  		_test.tag = "Match()"
   689  		_test.match = func() gitignore.Match {
   690  			return _instance().Match(_path)
   691  		}
   692  		run(t, _test)
   693  
   694  		// try Absolute() with an absolute path
   695  		_test = &invalidtest{repositorytest: test}
   696  		_test.tag = "Absolute()"
   697  		_test.match = func() gitignore.Match {
   698  			return _instance().Absolute(_path, _isdir)
   699  		}
   700  		run(t, _test)
   701  
   702  		// try Absolute() with an absolute path
   703  		_test = &invalidtest{repositorytest: test}
   704  		_test.tag = "Relative()"
   705  		_test.match = func() gitignore.Match {
   706  			return _instance().Relative(_local, _isdir)
   707  		}
   708  		run(t, _test)
   709  	}
   710  } // invalid()
   711  
   712  func run(t *testing.T, test *invalidtest) {
   713  	// perform the match, and ensure it returns nil, nil
   714  	_match := test.match()
   715  	if _match != nil {
   716  		t.Fatalf("%s: unexpected match: %v", test.tag, _match)
   717  	} else if test.errors == nil {
   718  		return
   719  	}
   720  
   721  	// if we're here, then we intended to record errors
   722  	//		- ensure we recorded the expected errors
   723  	for _i := 0; _i < len(test.errors); _i++ {
   724  		_got := test.errors[_i]
   725  		_underlying := _got.Underlying()
   726  		if os.IsNotExist(_underlying) ||
   727  			os.IsPermission(_underlying) {
   728  			continue
   729  		} else {
   730  			t.Fatalf(
   731  				"%s: unexpected error: %q",
   732  				test.tag, _got.Error(),
   733  			)
   734  		}
   735  	}
   736  } // run()