github.com/muesli/go-gitignore@v0.0.0-20200714020803-ff91c85188b2/gitignore_test.go (about)

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