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()