github.com/ianlewis/go-gitignore@v0.1.1-0.20231110021210-4a0f15cbd56f/match_test.go (about)

     1  // Copyright 2016 Denormal Limited
     2  // Copyright 2023 Google LLC
     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  package gitignore_test
    17  
    18  import (
    19  	"os"
    20  	"path/filepath"
    21  	"testing"
    22  
    23  	"github.com/ianlewis/go-gitignore"
    24  )
    25  
    26  func TestMatch(t *testing.T) {
    27  	// we need to populate a directory with the match test files
    28  	//		- this is to permit GitIgnore.Match() to correctly resolve
    29  	//		  absolute path names
    30  	_dir, _ignore := directory(t)
    31  	defer os.RemoveAll(_dir)
    32  
    33  	// perform the path matching
    34  	//		- first we test absolute paths
    35  	_cb := func(path string, isdir bool) gitignore.Match {
    36  		_path := filepath.Join(_dir, path)
    37  		return _ignore.Match(_path)
    38  	}
    39  	for _, _test := range _GITMATCHES {
    40  		do(t, _cb, _test)
    41  	}
    42  
    43  	// now, attempt relative path matching
    44  	//		- to do this, we need to change the working directory
    45  	_cwd, _err := os.Getwd()
    46  	if _err != nil {
    47  		t.Fatalf("unable to retrieve working directory: %s", _err.Error())
    48  	}
    49  	_err = os.Chdir(_dir)
    50  	if _err != nil {
    51  		t.Fatalf("unable to chdir into temporary directory: %s", _err.Error())
    52  	}
    53  	defer os.Chdir(_cwd)
    54  
    55  	// perform the relative path tests
    56  	_cb = func(path string, isdir bool) gitignore.Match {
    57  		return _ignore.Match(path)
    58  	}
    59  	for _, _test := range _GITMATCHES {
    60  		do(t, _cb, _test)
    61  	}
    62  
    63  	// perform absolute path tests with paths not under the same root
    64  	// directory as the GitIgnore we are testing
    65  	_new, _ := directory(t)
    66  	defer os.RemoveAll(_new)
    67  
    68  	for _, _test := range _GITMATCHES {
    69  		_path := filepath.Join(_new, _test.Local())
    70  		_match := _ignore.Match(_path)
    71  		if _match != nil {
    72  			t.Fatalf("unexpected match; expected nil, got %v", _match)
    73  		}
    74  	}
    75  
    76  	// ensure Match() behaves as expected if the absolute path cannot
    77  	// be determined
    78  	//		- we do this by choosing as our working directory a path
    79  	//		  that this process does not have permission to
    80  	_dir, _err = dir(nil)
    81  	if _err != nil {
    82  		t.Fatalf("unable to create temporary directory: %s", _err.Error())
    83  	}
    84  	defer os.RemoveAll(_dir)
    85  
    86  	_err = os.Chdir(_dir)
    87  	if _err != nil {
    88  		t.Fatalf("unable to chdir into temporary directory: %s", _err.Error())
    89  	}
    90  	defer os.Chdir(_cwd)
    91  
    92  	// remove permission from the temporary directory
    93  	_err = os.Chmod(_dir, 0)
    94  	if _err != nil {
    95  		t.Fatalf(
    96  			"unable to modify temporary directory permissions: %s: %s",
    97  			_dir, _err.Error(),
    98  		)
    99  	}
   100  
   101  	// now perform the match tests and ensure an error is returned
   102  	for _, _test := range _GITMATCHES {
   103  		_match := _ignore.Match(_test.Local())
   104  		if _match != nil {
   105  			t.Fatalf("unexpected match; expected nil, got %v", _match)
   106  		}
   107  	}
   108  } // TestMatch()
   109  
   110  func TestIgnore(t *testing.T) {
   111  	// we need to populate a directory with the match test files
   112  	//		- this is to permit GitIgnore.Ignore() to correctly resolve
   113  	//		  absolute path names
   114  	_dir, _ignore := directory(t)
   115  	defer os.RemoveAll(_dir)
   116  
   117  	// perform the path matching
   118  	//		- first we test absolute paths
   119  	for _, _test := range _GITMATCHES {
   120  		_path := filepath.Join(_dir, _test.Local())
   121  		_rtn := _ignore.Ignore(_path)
   122  		if _rtn != _test.Ignore {
   123  			t.Errorf(
   124  				"ignore mismatch for %q; expected %v, got %v",
   125  				_path, _test.Ignore, _rtn,
   126  			)
   127  		}
   128  	}
   129  
   130  	// now, attempt relative path matching
   131  	//		- to do this, we need to change the working directory
   132  	_cwd, _err := os.Getwd()
   133  	if _err != nil {
   134  		t.Fatalf("unable to retrieve working directory: %s", _err.Error())
   135  	}
   136  	_err = os.Chdir(_dir)
   137  	if _err != nil {
   138  		t.Fatalf("unable to chdir into temporary directory: %s", _err.Error())
   139  	}
   140  	defer os.Chdir(_cwd)
   141  
   142  	// perform the relative path tests
   143  	for _, _test := range _GITMATCHES {
   144  		_rtn := _ignore.Ignore(_test.Local())
   145  		if _rtn != _test.Ignore {
   146  			t.Errorf(
   147  				"ignore mismatch for %q; expected %v, got %v",
   148  				_test.Path, _test.Ignore, _rtn,
   149  			)
   150  		}
   151  	}
   152  
   153  	// perform absolute path tests with paths not under the same root
   154  	// directory as the GitIgnore we are testing
   155  	_new, _ := directory(t)
   156  	defer os.RemoveAll(_new)
   157  
   158  	for _, _test := range _GITMATCHES {
   159  		_path := filepath.Join(_new, _test.Local())
   160  		_ignore := _ignore.Ignore(_path)
   161  		if _ignore {
   162  			t.Fatalf("unexpected ignore for %q", _path)
   163  		}
   164  	}
   165  } // TestIgnore()
   166  
   167  func TestInclude(t *testing.T) {
   168  	// we need to populate a directory with the match test files
   169  	//		- this is to permit GitIgnore.Include() to correctly resolve
   170  	//		  absolute path names
   171  	_dir, _ignore := directory(t)
   172  	defer os.RemoveAll(_dir)
   173  
   174  	// perform the path matching
   175  	//		- first we test absolute paths
   176  	for _, _test := range _GITMATCHES {
   177  		_path := filepath.Join(_dir, _test.Local())
   178  		_rtn := _ignore.Include(_path)
   179  		if _rtn == _test.Ignore {
   180  			t.Errorf(
   181  				"include mismatch for %q; expected %v, got %v",
   182  				_path, !_test.Ignore, _rtn,
   183  			)
   184  		}
   185  	}
   186  
   187  	// now, attempt relative path matching
   188  	//		- to do this, we need to change the working directory
   189  	_cwd, _err := os.Getwd()
   190  	if _err != nil {
   191  		t.Fatalf("unable to retrieve working directory: %s", _err.Error())
   192  	}
   193  	_err = os.Chdir(_dir)
   194  	if _err != nil {
   195  		t.Fatalf("unable to chdir into temporary directory: %s", _err.Error())
   196  	}
   197  	defer os.Chdir(_cwd)
   198  
   199  	// perform the relative path tests
   200  	for _, _test := range _GITMATCHES {
   201  		_rtn := _ignore.Include(_test.Local())
   202  		if _rtn == _test.Ignore {
   203  			t.Errorf(
   204  				"include mismatch for %q; expected %v, got %v",
   205  				_test.Path, !_test.Ignore, _rtn,
   206  			)
   207  		}
   208  	}
   209  
   210  	// perform absolute path tests with paths not under the same root
   211  	// directory as the GitIgnore we are testing
   212  	_new, _ := directory(t)
   213  	defer os.RemoveAll(_new)
   214  
   215  	for _, _test := range _GITMATCHES {
   216  		_path := filepath.Join(_new, _test.Local())
   217  		_include := _ignore.Include(_path)
   218  		if !_include {
   219  			t.Fatalf("unexpected include for %q", _path)
   220  		}
   221  	}
   222  } // TestInclude()
   223  
   224  func TestMatchRelative(t *testing.T) {
   225  	// create a temporary .gitignore
   226  	_buffer, _err := buffer(_GITMATCH)
   227  	if _err != nil {
   228  		t.Fatalf("unable to create temporary .gitignore: %s", _err.Error())
   229  	}
   230  
   231  	// ensure we can run New()
   232  	//		- ensure we encounter no errors
   233  	_position := []gitignore.Position{}
   234  	_error := func(e gitignore.Error) bool {
   235  		_position = append(_position, e.Position())
   236  		return true
   237  	}
   238  
   239  	// ensure we have a non-nil GitIgnore instance
   240  	_ignore := gitignore.New(_buffer, _GITBASE, _error)
   241  	if _ignore == nil {
   242  		t.Error("expected non-nil GitIgnore instance; nil found")
   243  	}
   244  
   245  	// ensure we encountered the right number of errors
   246  	if len(_position) != _GITBADMATCHPATTERNS {
   247  		t.Errorf(
   248  			"match error mismatch; expected %d errors, got %d",
   249  			_GITBADMATCHPATTERNS, len(_position),
   250  		)
   251  	}
   252  
   253  	// perform the relative path matching
   254  	_cb := func(path string, isdir bool) gitignore.Match {
   255  		return _ignore.Relative(path, isdir)
   256  	}
   257  	for _, _test := range _GITMATCHES {
   258  		do(t, _cb, _test)
   259  	}
   260  } // TestMatchRelative()
   261  
   262  func do(t *testing.T, cb func(string, bool) gitignore.Match, m match) {
   263  	// attempt to match this path
   264  	_match := cb(m.Local(), m.IsDir())
   265  	if _match == nil {
   266  		// we have no match, is this expected?
   267  		//		- a test that matches will list the expected pattern
   268  		if m.Pattern != "" {
   269  			t.Errorf(
   270  				"failed match; expected match for %q by %q",
   271  				m.Path, m.Pattern,
   272  			)
   273  			return
   274  		}
   275  
   276  		// since we have no match, ensure this path is not ignored
   277  		if m.Ignore {
   278  			t.Errorf(
   279  				"failed ignore; no match for %q but expected to be ignored",
   280  				m.Path,
   281  			)
   282  		}
   283  	} else {
   284  		// we have a match, is this expected?
   285  		//		- a test that matches will list the expected pattern
   286  		if m.Pattern == "" {
   287  			t.Errorf(
   288  				"unexpected match by %q; expected no match for %q",
   289  				_match, m.Path,
   290  			)
   291  			return
   292  		} else if m.Pattern != _match.String() {
   293  			t.Errorf(
   294  				"mismatch for %q; expected match pattern %q, got %q",
   295  				m.Path, m.Pattern, _match.String(),
   296  			)
   297  			return
   298  		}
   299  
   300  		// since we have a match, are we expected to ignore this file?
   301  		if m.Ignore != _match.Ignore() {
   302  			t.Errorf(
   303  				"ignore mismatch; expected %v for %q Ignore(), "+
   304  					"got %v from pattern %q",
   305  				m.Ignore, m.Path, _match.Ignore(), _match,
   306  			)
   307  		}
   308  	}
   309  } // do()
   310  
   311  func directory(t *testing.T) (string, gitignore.GitIgnore) {
   312  	// we need to populate a directory with the match test files
   313  	//		- this is to permit GitIgnore.Match() to correctly resolve
   314  	//		  absolute path names
   315  	//		- populate the directory by passing a map of file names and their
   316  	//		  contents
   317  	//		- the content is not important, it just can't be empty
   318  	//		- use this mechanism to also populate the .gitignore file
   319  	_map := map[string]string{gitignore.File: _GITMATCH}
   320  	for _, _test := range _GITMATCHES {
   321  		_map[_test.Path] = " " // this is the file contents
   322  	}
   323  
   324  	// create the temporary directory
   325  	_dir, _err := dir(_map)
   326  	if _err != nil {
   327  		t.Fatalf("unable to create temporary .gitignore: %s", _err.Error())
   328  	}
   329  
   330  	// ensure we can run New()
   331  	//		- ensure we encounter no errors
   332  	_position := []gitignore.Position{}
   333  	_error := func(e gitignore.Error) bool {
   334  		_position = append(_position, e.Position())
   335  		return true
   336  	}
   337  
   338  	// ensure we have a non-nil GitIgnore instance
   339  	_file := filepath.Join(_dir, gitignore.File)
   340  	_ignore := gitignore.NewWithErrors(_file, _error)
   341  	if _ignore == nil {
   342  		t.Fatalf("expected non-nil GitIgnore instance; nil found")
   343  	}
   344  
   345  	// ensure we encountered the right number of errors
   346  	if len(_position) != _GITBADMATCHPATTERNS {
   347  		t.Errorf(
   348  			"match error mismatch; expected %d errors, got %d",
   349  			_GITBADMATCHPATTERNS, len(_position),
   350  		)
   351  	}
   352  
   353  	// return the directory name and the GitIgnore instance
   354  	return _dir, _ignore
   355  } // directory()