github.com/tilt-dev/wat@v0.0.2-0.20180626175338-9349b638e250/os/ospath/matcher_test.go (about) 1 package ospath 2 3 import ( 4 "encoding/json" 5 "strings" 6 "testing" 7 8 "github.com/windmilleng/wat/data/pathutil" 9 ) 10 11 func TestGitPattern(t *testing.T) { 12 m, _ := NewMatcherFromPattern(".git/**") 13 assertMatch(t, m, ".git") 14 assertMatch(t, m, ".git/a") 15 assertMatch(t, m, ".git/a/b") 16 assertNotMatch(t, m, "a/.git") 17 assertNotMatch(t, m, "a/.git/b") 18 assertNotMatch(t, m, "a/b/.git") 19 assertNotMatch(t, m, ".gitx") 20 assertNotMatch(t, m, "x.git") 21 assertNotMatch(t, m, "a/.gitx") 22 } 23 24 func TestGitFile(t *testing.T) { 25 m, _ := NewFileMatcher(".git") 26 assertMatch(t, m, ".git") 27 assertNotMatch(t, m, "a/.git") 28 } 29 30 func TestGitFilePattern(t *testing.T) { 31 m, _ := NewMatcherFromPattern(".git") 32 assertMatch(t, m, ".git") 33 assertNotMatch(t, m, "a/.git") 34 } 35 36 func TestFolderStar(t *testing.T) { 37 m, _ := NewMatcherFromPattern("*/x") 38 assertMatch(t, m, "a/x") 39 assertMatch(t, m, "b/x") 40 assertNotMatch(t, m, "x") 41 assertNotMatch(t, m, "a/b/x") 42 } 43 44 func TestEndStar(t *testing.T) { 45 m, _ := NewMatcherFromPattern("a/*") 46 assertMatch(t, m, "a/x") 47 assertMatch(t, m, "a/y") 48 assertNotMatch(t, m, "a") 49 assertNotMatch(t, m, "x/a") 50 assertNotMatch(t, m, "x/a/x") 51 assertNotMatch(t, m, "a/x/y") 52 } 53 54 func TestDoubleStar(t *testing.T) { 55 m, _ := NewMatcherFromPattern("**/*.go") 56 assertMatch(t, m, "x.go") 57 assertMatch(t, m, "a/x.go") 58 assertMatch(t, m, "a/b/x.go") 59 assertMatch(t, m, "a.go/x") 60 assertNotMatch(t, m, "x") 61 assertNotMatch(t, m, "x.gox") 62 } 63 64 func TestInnerDoubleStar(t *testing.T) { 65 m, _ := NewMatcherFromPattern("a/**/*.go") 66 assertMatch(t, m, "a/x.go") 67 assertMatch(t, m, "a/b/x.go") 68 assertMatch(t, m, "a/b/c/x.go") 69 assertNotMatch(t, m, "x.go") 70 } 71 72 func TestSeparatorPattern(t *testing.T) { 73 m, _ := NewMatcherFromPattern("a/b") 74 assertMatch(t, m, "a/b") 75 assertNotMatch(t, m, "a/b/c") 76 assertNotMatch(t, m, "c/a/b") 77 assertNotMatch(t, m, "a/bob") 78 } 79 80 func TestStarPattern(t *testing.T) { 81 m, _ := NewMatcherFromPattern("*.txt") 82 assertMatch(t, m, "a.txt") 83 assertMatch(t, m, "b.txt") 84 assertNotMatch(t, m, "a/txt") 85 } 86 87 func TestMultiplePattern(t *testing.T) { 88 m, _ := NewMatcherFromPatterns([]string{"a", "b"}) 89 assertMatch(t, m, "a") 90 assertMatch(t, m, "b") 91 assertNotMatch(t, m, "a/b") 92 assertNotMatch(t, m, "ab") 93 } 94 95 func TestSubdirPattern(t *testing.T) { 96 m, _ := NewMatcherFromPattern("b/**") 97 m = m.Subdir("a").(*Matcher) 98 assertMatch(t, m, "a/b") 99 assertMatch(t, m, "a/b/c") 100 assertNotMatch(t, m, "c/a/b") 101 assertNotMatch(t, m, "a/bob") 102 } 103 104 func TestChildPattern(t *testing.T) { 105 m, _ := NewMatcherFromPattern("a/b/**") 106 m = m.Child("a").(*Matcher) 107 assertMatch(t, m, "b") 108 assertMatch(t, m, "b/c") 109 assertNotMatch(t, m, "a/b") 110 assertNotMatch(t, m, "a/c") 111 } 112 113 func TestChildPatternEmpty(t *testing.T) { 114 m, _ := NewMatcherFromPattern("a/b/c") 115 m = m.Child("a/c").(*Matcher) 116 if !m.Empty() { 117 t.Errorf("Matcher %v should be empty", m) 118 } 119 } 120 121 func TestChildPatternStar(t *testing.T) { 122 m, _ := NewMatcherFromPattern("a/*/b") 123 m = m.Child("a/x").(*Matcher) 124 assertMatch(t, m, "b") 125 assertNotMatch(t, m, "b/c") 126 assertNotMatch(t, m, "a/b") 127 assertNotMatch(t, m, "a/c") 128 } 129 130 func TestChildPatternStarEmpty(t *testing.T) { 131 m, _ := NewMatcherFromPattern("a/*/b") 132 m = m.Child("c").(*Matcher) 133 assertNotMatch(t, m, "b") 134 if !m.Empty() { 135 t.Errorf("Matcher %v should be empty", m) 136 } 137 } 138 139 func TestInversion(t *testing.T) { 140 m, _ := NewMatcherFromPattern("!a/**") 141 assertMatch(t, m, "b") 142 assertMatch(t, m, "b/c") 143 assertMatch(t, m, "b/a") 144 assertMatch(t, m, "ax") 145 assertMatch(t, m, "ax/ax") 146 assertNotMatch(t, m, "a") 147 assertNotMatch(t, m, "a/b") 148 } 149 150 func TestPositivesAndNegativesInversion(t *testing.T) { 151 m, _ := NewMatcherFromPatterns([]string{"**/*.go", "!vendor/**"}) 152 assertMatch(t, m, "a.go") 153 assertMatch(t, m, "b/a.go") 154 assertNotMatch(t, m, "vendor/a.go") 155 } 156 157 func TestPositivesAndNegativesInversion2(t *testing.T) { 158 m, _ := NewMatcherFromPatterns([]string{"**/*.go", "!vendor/**", "**/*.js", "!node_modules/**"}) 159 assertMatch(t, m, "a.go") 160 assertMatch(t, m, "b/a.go") 161 assertMatch(t, m, "a.js") 162 assertMatch(t, m, "b/a.js") 163 assertNotMatch(t, m, "vendor/a.go") 164 assertNotMatch(t, m, "node_modules/b.js") 165 } 166 167 func TestInvertMatcher1(t *testing.T) { 168 m, _ := NewMatcherFromPatterns([]string{"**/*.go", "!vendor/**"}) 169 m2, err := InvertMatcher(m) 170 expected := "Inverted matcher cannot be written in normal form: [**/*.go !vendor/**]" 171 if err == nil || err.Error() != expected { 172 t.Errorf("Unexpected error: %v, %s", err, m2.ToPatterns()) 173 } 174 } 175 176 func TestInvertMatcher2(t *testing.T) { 177 m, _ := NewMatcherFromPatterns([]string{"!**/*.go", "!vendor/**"}) 178 im, err := InvertMatcher(m) 179 if err != nil { 180 t.Fatal(err) 181 } 182 assertNotMatch(t, m, "a.go") 183 assertMatch(t, im, "a.go") 184 assertNotMatch(t, m, "vendor/a.js") 185 assertMatch(t, im, "vendor/a.js") 186 assertMatch(t, m, "a.js") 187 assertNotMatch(t, im, "a.js") 188 } 189 190 func TestInvertMatcher3(t *testing.T) { 191 m, _ := NewMatcherFromPatterns([]string{"**/*.go", "vendor/**"}) 192 im, err := InvertMatcher(m) 193 if err != nil { 194 t.Fatal(err) 195 } 196 assertMatch(t, m, "a.go") 197 assertNotMatch(t, im, "a.go") 198 assertMatch(t, m, "vendor/a.js") 199 assertNotMatch(t, im, "vendor/a.js") 200 assertNotMatch(t, m, "a.js") 201 assertMatch(t, im, "a.js") 202 } 203 204 func TestSelfPattern(t *testing.T) { 205 // The empty string is a special pattern that matches the current directory 206 // but nothing below it, much like "." in Linux. 207 m, _ := NewMatcherFromPattern("") 208 assertNotEmpty(t, m) 209 assertNotAll(t, m) 210 assertMatch(t, m, "") 211 assertNotMatch(t, m, "log.txt") 212 } 213 214 func TestAllAndNotAll(t *testing.T) { 215 m, _ := NewMatcherFromPatterns([]string{"**", "!**"}) 216 assertEmpty(t, m) 217 assertNotAll(t, m) 218 assertNotMatch(t, m, "") 219 assertNotMatch(t, m, "log.txt") 220 } 221 222 func TestAllAndNotSelf(t *testing.T) { 223 m, _ := NewMatcherFromPatterns([]string{"**", "!"}) 224 assertNotEmpty(t, m) 225 assertNotAll(t, m) 226 assertNotMatch(t, m, "") 227 assertMatch(t, m, "log.txt") 228 } 229 230 func TestAllAndChildEmpty(t *testing.T) { 231 m, _ := NewMatcherFromPatterns([]string{"**", "!foo.txt"}) 232 assertNotEmpty(t, m) 233 assertNotAll(t, m) 234 assertMatch(t, m, "log.txt") 235 assertNotMatch(t, m, "foo.txt") 236 237 m = m.ChildOS("foo.txt") 238 assertNotEmpty(t, m) 239 assertNotAll(t, m) 240 assertNotMatch(t, m, "") 241 assertMatch(t, m, "log.txt") 242 assertMatch(t, m, "foo.txt") 243 } 244 245 func TestChildDoubleStar(t *testing.T) { 246 m, _ := NewMatcherFromPatterns([]string{"**/*.pb.go", "!vendor/**"}) 247 assertNotEmpty(t, m) 248 assertMatch(t, m, "a.pb.go") 249 assertMatch(t, m, "foo/bar/a.pb.go") 250 assertNotMatch(t, m, "vendor/foo/a.pb.go") 251 assertNotMatch(t, m, "a.go") 252 253 child := m.ChildOS("foo") 254 assertMatch(t, child, "a.pb.go") 255 assertMatch(t, child, "foo/bar/a.pb.go") 256 assertMatch(t, child, "vendor/foo/a.pb.go") 257 assertNotMatch(t, child, "a.go") 258 } 259 260 func TestChildDoubleStarEmpty(t *testing.T) { 261 m, _ := NewMatcherFromPatterns([]string{"!build/**"}) 262 assertNotEmpty(t, m) 263 assertNotMatch(t, m, "build/log.txt") 264 assertMatch(t, m, "log.txt") 265 266 child := m.ChildOS("build") 267 assertNotMatch(t, child, "log.go") 268 assertEmpty(t, child) 269 } 270 271 func TestDoubleChildDoubleStar(t *testing.T) { 272 m, _ := NewMatcherFromPatterns([]string{"pkg/**"}) 273 assertNotEmpty(t, m) 274 assertMatch(t, m, "pkg/a") 275 assertMatch(t, m, "pkg/a/b") 276 assertMatch(t, m, "pkg/a/b/c") 277 assertNotMatch(t, m, "log.txt") 278 assertNotAll(t, m) 279 assertNotEmpty(t, m) 280 281 child := m.ChildOS("pkg") 282 assertMatch(t, child, "a") 283 assertMatch(t, child, "a/b") 284 assertMatch(t, child, "a/b/c") 285 assertAll(t, child) 286 assertNotEmpty(t, child) 287 288 child = m.ChildOS("pkg/a") 289 assertMatch(t, child, "a") 290 assertMatch(t, child, "a/b") 291 assertMatch(t, child, "a/b/c") 292 assertAll(t, child) 293 assertNotEmpty(t, child) 294 295 child = m.ChildOS("pkg/a/b/c") 296 assertMatch(t, child, "a") 297 assertMatch(t, child, "a/b") 298 assertMatch(t, child, "a/b/c") 299 assertAll(t, child) 300 assertNotEmpty(t, child) 301 } 302 303 func TestJSON(t *testing.T) { 304 matcher, _ := NewMatcherFromPattern("*/foo.txt") 305 matcherBytes, err := json.Marshal(matcher) 306 if err != nil { 307 t.Fatal(err) 308 } 309 310 var newMatcher *Matcher 311 err = json.Unmarshal(matcherBytes, &newMatcher) 312 if err != nil { 313 t.Fatal(err) 314 } 315 316 patterns := newMatcher.ToPatterns() 317 if len(patterns) != 1 || patterns[0] != "*/foo.txt" { 318 t.Errorf("Unexpected patterns after round trip: %v", patterns) 319 } 320 } 321 322 func TestInvalidPattern(t *testing.T) { 323 _, err := NewMatcherFromPattern("x x") 324 if err == nil || !strings.Contains(err.Error(), "may not contain whitespace") { 325 t.Errorf("Expected whitespace error. Actual: %v", err) 326 } 327 328 _, err = NewMatcherFromPattern("x\nx") 329 if err == nil || !strings.Contains(err.Error(), "may not contain whitespace") { 330 t.Errorf("Expected whitespace error. Actual: %v", err) 331 } 332 333 _, err = NewMatcherFromPattern("/x") 334 if err == nil || !strings.Contains(err.Error(), "may not start with a leading slash") { 335 t.Errorf("Expected leading slash error. Actual: %v", err) 336 } 337 } 338 339 func TestSimplifyOrthogonalPatterns(t *testing.T) { 340 m, _ := NewMatcherFromPatterns([]string{"a/b/*.go", "!a/c/*.go"}) 341 assertMatch(t, m, "a/b/c.go") 342 assertNotMatch(t, m, "a/c/d.go") 343 assertNotMatch(t, m, "a/d/e.go") 344 345 inv, err := InvertMatcher(m) 346 if err != nil { 347 t.Fatal(err) 348 } 349 assertNotMatch(t, inv, "a/b/c.go") 350 assertMatch(t, inv, "a/c/d.go") 351 assertMatch(t, inv, "a/d/e.go") 352 } 353 354 type equal struct { 355 a *Matcher 356 b *Matcher 357 equal bool 358 } 359 360 func expectEqual(t *testing.T, entry equal) { 361 if entry.equal != MatchersEqual(entry.a, entry.b) { 362 if entry.equal { 363 t.Errorf("Expected matchers to be equal: (%q, %q)", entry.a, entry.b) 364 } else { 365 t.Errorf("Expected matchers to not be equal: (%q, %q)", entry.a, entry.b) 366 } 367 } 368 } 369 370 func TestEquals(t *testing.T) { 371 m1, _ := NewMatcherFromPatterns([]string{"a"}) 372 m2, _ := NewMatcherFromPatterns([]string{"a", "b"}) 373 m3, _ := NewMatcherFromPatterns([]string{"b"}) 374 m4, _ := NewMatcherFromPatterns([]string{"b", "a"}) 375 expectEqual(t, equal{m1, m1, true}) 376 expectEqual(t, equal{m2, m2, true}) 377 expectEqual(t, equal{m3, m3, true}) 378 expectEqual(t, equal{m4, m4, true}) 379 expectEqual(t, equal{m1, m2, false}) 380 expectEqual(t, equal{m1, m3, false}) 381 expectEqual(t, equal{m1, m4, false}) 382 expectEqual(t, equal{m2, m3, false}) 383 expectEqual(t, equal{m2, m4, true}) 384 } 385 386 func assertMatch(t *testing.T, m *Matcher, target string) { 387 if !m.Match(target) { 388 t.Errorf("Matcher %v should have matched %q", m.ToPatterns(), target) 389 } 390 } 391 392 func assertNotMatch(t *testing.T, m *Matcher, target string) { 393 if m.Match(target) { 394 t.Errorf("Matcher %v should not have matched %q", m.ToPatterns(), target) 395 } 396 } 397 398 func assertEmpty(t *testing.T, m pathutil.Matcher) { 399 if !m.Empty() { 400 t.Errorf("Matcher %v should have been empty", m.ToPatterns()) 401 } 402 } 403 404 func assertNotEmpty(t *testing.T, m pathutil.Matcher) { 405 if m.Empty() { 406 t.Errorf("Matcher %v should not have been empty", m.ToPatterns()) 407 } 408 } 409 410 func assertAll(t *testing.T, m pathutil.Matcher) { 411 if !m.All() { 412 t.Errorf("Matcher %v should have been an all matcher", m.ToPatterns()) 413 } 414 } 415 416 func assertNotAll(t *testing.T, m pathutil.Matcher) { 417 if m.All() { 418 t.Errorf("Matcher %v should not have been an all matcher", m.ToPatterns()) 419 } 420 }