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  }