github.com/boyter/gocodewalker@v1.3.2/go-gitignore/gitignore_test.go (about)

     1  // SPDX-License-Identifier: MIT
     2  
     3  package gitignore_test
     4  
     5  import (
     6  	"github.com/boyter/gocodewalker/go-gitignore"
     7  	"testing"
     8  
     9  	"os"
    10  	"path/filepath"
    11  )
    12  
    13  type gitignoretest struct {
    14  	errors   []gitignore.Error
    15  	error    func(gitignore.Error) bool
    16  	cache    gitignore.Cache
    17  	cached   bool
    18  	instance func(string) (gitignore.GitIgnore, error)
    19  } // gitignoretest{}
    20  
    21  func TestNewFromFile(t *testing.T) {
    22  	_test := &gitignoretest{}
    23  	_test.instance = func(file string) (gitignore.GitIgnore, error) {
    24  		return gitignore.NewFromFile(file)
    25  	}
    26  
    27  	// perform the gitignore test
    28  	withfile(t, _test, _GITIGNORE)
    29  } // TestNewFromFile()
    30  
    31  func TestNewFromWhitespaceFile(t *testing.T) {
    32  	_test := &gitignoretest{}
    33  	_test.instance = func(file string) (gitignore.GitIgnore, error) {
    34  		return gitignore.NewFromFile(file)
    35  	}
    36  
    37  	// perform the gitignore test
    38  	withfile(t, _test, _GITIGNORE_WHITESPACE)
    39  } // TestNewFromWhitespaceFile()
    40  
    41  func TestNewFromEmptyFile(t *testing.T) {
    42  	_test := &gitignoretest{}
    43  	_test.instance = func(file string) (gitignore.GitIgnore, error) {
    44  		return gitignore.NewFromFile(file)
    45  	}
    46  
    47  	// perform the gitignore test
    48  	withfile(t, _test, "")
    49  } // TestNewFromEmptyFile()
    50  
    51  func TestNewWithErrors(t *testing.T) {
    52  	_test := &gitignoretest{}
    53  	_test.error = func(e gitignore.Error) bool {
    54  		_test.errors = append(_test.errors, e)
    55  		return true
    56  	}
    57  	_test.instance = func(file string) (gitignore.GitIgnore, error) {
    58  		// reset the error slice
    59  		_test.errors = make([]gitignore.Error, 0)
    60  
    61  		// attempt to create the GitIgnore instance
    62  		_ignore := gitignore.NewWithErrors(file, _test.error)
    63  
    64  		// if we encountered errors, and the first error has a zero position
    65  		// then it represents a file access error
    66  		//		- extract the error and return it
    67  		//		- remove it from the list of errors
    68  		var _err error
    69  		if len(_test.errors) > 0 {
    70  			if _test.errors[0].Position().Zero() {
    71  				_err = _test.errors[0].Underlying()
    72  				_test.errors = _test.errors[1:]
    73  			}
    74  		}
    75  
    76  		// return the GitIgnore instance
    77  		return _ignore, _err
    78  	}
    79  
    80  	// perform the gitignore test
    81  	withfile(t, _test, _GITIGNORE)
    82  
    83  	_test.error = nil
    84  	withfile(t, _test, _GITIGNORE)
    85  } // TestNewWithErrors()
    86  
    87  func TestNewWithCache(t *testing.T) {
    88  	// perform the gitignore test with a custom cache
    89  	_test := &gitignoretest{}
    90  	_test.cached = true
    91  	_test.cache = gitignore.NewCache()
    92  	_test.instance = func(file string) (gitignore.GitIgnore, error) {
    93  		// reset the error slice
    94  		_test.errors = make([]gitignore.Error, 0)
    95  
    96  		// attempt to create the GitIgnore instance
    97  		_ignore := gitignore.NewWithCache(file, _test.cache, _test.error)
    98  
    99  		// if we encountered errors, and the first error has a zero position
   100  		// then it represents a file access error
   101  		//		- extract the error and return it
   102  		//		- remove it from the list of errors
   103  		var _err error
   104  		if len(_test.errors) > 0 {
   105  			if _test.errors[0].Position().Zero() {
   106  				_err = _test.errors[0].Underlying()
   107  				_test.errors = _test.errors[1:]
   108  			}
   109  		}
   110  
   111  		// return the GitIgnore instance
   112  		return _ignore, _err
   113  	}
   114  
   115  	// perform the gitignore test
   116  	withfile(t, _test, _GITIGNORE)
   117  
   118  	// repeat the tests while accumulating errors
   119  	_test.error = func(e gitignore.Error) bool {
   120  		_test.errors = append(_test.errors, e)
   121  		return true
   122  	}
   123  	withfile(t, _test, _GITIGNORE)
   124  
   125  	// create a temporary .gitignore
   126  	_file, _err := file(_GITIGNORE)
   127  	if _err != nil {
   128  		t.Fatalf("unable to create temporary .gitignore: %s", _err.Error())
   129  	}
   130  	defer os.Remove(_file.Name())
   131  
   132  	// attempt to load the .gitignore file
   133  	_ignore, _err := _test.instance(_file.Name())
   134  	if _err != nil {
   135  		t.Fatalf("unable to open temporary .gitignore: %s", _err.Error())
   136  	}
   137  
   138  	// remove the .gitignore and try again
   139  	os.Remove(_file.Name())
   140  
   141  	// ensure the retrieved GitIgnore matches the stored instance
   142  	_new, _err := _test.instance(_file.Name())
   143  	if _err != nil {
   144  		t.Fatalf(
   145  			"unexpected error retrieving cached .gitignore: %s", _err.Error(),
   146  		)
   147  	} else if _new != _ignore {
   148  		t.Fatalf(
   149  			"gitignore.NewWithCache() mismatch; expected %v, got %v",
   150  			_ignore, _new,
   151  		)
   152  	}
   153  } // TestNewWithCache()
   154  
   155  func TestNew(t *testing.T) {
   156  	// create a temporary .gitignore
   157  	_file, _err := file(_GITIGNORE)
   158  	if _err != nil {
   159  		t.Fatalf("unable to create temporary .gitignore: %s", _err.Error())
   160  	}
   161  	defer os.Remove(_file.Name())
   162  
   163  	// ensure we can run NewGitIgnore()
   164  	//		- ensure we encounter the expected errors
   165  	_position := []gitignore.Position{}
   166  	_error := func(e gitignore.Error) bool {
   167  		_position = append(_position, e.Position())
   168  		return true
   169  	}
   170  
   171  	_dir := filepath.Dir(_file.Name())
   172  	_ignore := gitignore.New(_file, _dir, _error)
   173  
   174  	// ensure we have a non-nil GitIgnore instance
   175  	if _ignore == nil {
   176  		t.Error("expected non-nil GitIgnore instance; nil found")
   177  	}
   178  
   179  	// ensure the base of the ignore is the directory of the temporary file
   180  	if _ignore.Base() != _dir {
   181  		t.Errorf(
   182  			"gitignore.Base() mismatch; expected %q, got %q",
   183  			_dir, _ignore.Base(),
   184  		)
   185  	}
   186  
   187  	// ensure we encountered the right number of errors
   188  	if len(_position) != _GITBADPATTERNS {
   189  		t.Errorf(
   190  			"parse error mismatch; expected %d errors, got %d",
   191  			_GITBADPATTERNS, len(_position),
   192  		)
   193  	} else {
   194  		// ensure the error positions are correct
   195  		for _i := 0; _i < _GITBADPATTERNS; _i++ {
   196  			_got := _position[_i]
   197  			_expected := _GITBADPOSITION[_i]
   198  
   199  			// ensure the positions are correct
   200  			if !coincident(_got, _expected) {
   201  				t.Errorf("bad pattern position mismatch; expected %q, got %q",
   202  					pos(_expected), pos(_got),
   203  				)
   204  			}
   205  		}
   206  	}
   207  } // TestNew()
   208  
   209  func withfile(t *testing.T, test *gitignoretest, content string) {
   210  	// create a temporary .gitignore
   211  	_file, _err := file(content)
   212  	if _err != nil {
   213  		t.Fatalf("unable to create temporary .gitignore: %s", _err.Error())
   214  	}
   215  	defer os.Remove(_file.Name())
   216  
   217  	// attempt to retrieve the GitIgnore instance
   218  	_ignore, _err := test.instance(_file.Name())
   219  	if _err != nil {
   220  		t.Fatalf("unable to open temporary .gitignore: %s", _err.Error())
   221  	}
   222  
   223  	// ensure we have a non-nil GitIgnore instance
   224  	if _ignore == nil {
   225  		t.Error("expected non-nil GitIgnore instance; nil found")
   226  	}
   227  
   228  	// ensure the base of the ignore is the directory of the temporary file
   229  	_dir := filepath.Dir(_file.Name())
   230  	if _ignore.Base() != _dir {
   231  		t.Errorf(
   232  			"gitignore.Base() mismatch; expected %q, got %q",
   233  			_dir, _ignore.Base(),
   234  		)
   235  	}
   236  
   237  	// ensure we encountered the right number of errors
   238  	//		- only do this if we are configured to record bad patterns
   239  	if test.error != nil {
   240  		if len(test.errors) != _GITBADPATTERNS {
   241  			t.Errorf(
   242  				"parse error mismatch; expected %d errors, got %d",
   243  				_GITBADPATTERNS, len(test.errors),
   244  			)
   245  		} else {
   246  			// ensure the error positions are correct
   247  			for _i := 0; _i < _GITBADPATTERNS; _i++ {
   248  				_got := test.errors[_i].Position()
   249  				_expected := _GITBADPOSITION[_i]
   250  
   251  				// augment the expected position with the test file name
   252  				_expected.File = _file.Name()
   253  
   254  				// ensure the positions are correct
   255  				if !coincident(_got, _expected) {
   256  					t.Errorf(
   257  						"bad pattern position mismatch; expected %q, got %q",
   258  						pos(_expected), pos(_got),
   259  					)
   260  				}
   261  			}
   262  		}
   263  	}
   264  
   265  	// test NewFromFile() behaves as expected if the .gitgnore file does
   266  	// not exist
   267  	_err = os.Remove(_file.Name())
   268  	if _err != nil {
   269  		t.Fatalf(
   270  			"unable to remove temporary .gitignore %s: %s",
   271  			_file.Name(), _err.Error(),
   272  		)
   273  	}
   274  	_ignore, _err = test.instance(_file.Name())
   275  	if _err == nil {
   276  		// if we are using a cache in this test, then no error is acceptable
   277  		// as long as a GitIgnore instance is retrieved
   278  		if test.cached {
   279  			if _ignore == nil {
   280  				t.Fatal("expected non-nil GitIgnore, nil found")
   281  			}
   282  		} else if test.error != nil {
   283  			t.Fatalf(
   284  				"expected error loading deleted file %s; none found",
   285  				_file.Name(),
   286  			)
   287  		}
   288  	} else if !os.IsNotExist(_err) {
   289  		t.Fatalf(
   290  			"unexpected error attempting to load non-existant .gitignore: %s",
   291  			_err.Error(),
   292  		)
   293  	} else if _ignore != nil {
   294  		t.Fatalf("expected nil GitIgnore, got %v", _ignore)
   295  	}
   296  
   297  	// test NewFromFile() behaves as expected if absolute path of the
   298  	// .gitignore cannot be determined
   299  	_map := map[string]string{gitignore.File: content}
   300  	_dir, _err = dir(_map)
   301  	if _err != nil {
   302  		t.Fatalf("unable to create temporary directory: %s", _err.Error())
   303  	}
   304  	defer os.RemoveAll(_dir)
   305  
   306  	// change into the temporary directory
   307  	_cwd, _err := os.Getwd()
   308  	if _err != nil {
   309  		t.Fatalf("unable to retrieve working directory: %s", _err.Error())
   310  	}
   311  	_err = os.Chdir(_dir)
   312  	if _err != nil {
   313  		t.Fatalf("unable to chdir into temporary directory: %s", _err.Error())
   314  	}
   315  	defer func(dir string) { _ = os.Chdir(dir) }(_cwd)
   316  
   317  	// remove permission from the temporary directory
   318  	_err = os.Chmod(_dir, 0)
   319  	if _err != nil {
   320  		t.Fatalf(
   321  			"unable to remove temporary directory permissions: %s: %s",
   322  			_dir, _err.Error(),
   323  		)
   324  	}
   325  
   326  	// attempt to load the .gitignore using a relative path
   327  	_ignore, _err = test.instance(gitignore.File)
   328  	if test.error != nil && _err == nil {
   329  		_git := filepath.Join(_dir, gitignore.File)
   330  		t.Fatalf(
   331  			"%s: expected error for inaccessible .gitignore; none found",
   332  			_git,
   333  		)
   334  	} else if _ignore != nil {
   335  		t.Fatalf("expected nil GitIgnore, got %v", _ignore)
   336  	}
   337  } // withfile()