...

Source file src/github.com/danwakefield/fnmatch/fnmatch_test.go

Documentation: github.com/danwakefield/fnmatch

     1  package fnmatch_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/danwakefield/fnmatch"
     7  )
     8  
     9  // This is a set of tests ported from a set of tests for C fnmatch
    10  // found at http://www.mail-archive.com/bug-gnulib@gnu.org/msg14048.html
    11  func TestMatch(t *testing.T) {
    12  	assert := func(p, s string) {
    13  		if !fnmatch.Match(p, s, 0) {
    14  			t.Errorf("Assertion failed: Match(%#v, %#v, 0)", p, s)
    15  		}
    16  	}
    17  	assert("", "")
    18  	assert("*", "")
    19  	assert("*", "foo")
    20  	assert("*", "bar")
    21  	assert("*", "*")
    22  	assert("**", "f")
    23  	assert("**", "foo.txt")
    24  	assert("*.*", "foo.txt")
    25  	assert("foo*.txt", "foobar.txt")
    26  	assert("foo.txt", "foo.txt")
    27  	assert("foo\\.txt", "foo.txt")
    28  	if fnmatch.Match("foo\\.txt", "foo.txt", fnmatch.FNM_NOESCAPE) {
    29  		t.Errorf("Assertion failed: Match(%#v, %#v, FNM_NOESCAPE) == false", "foo\\.txt", "foo.txt")
    30  	}
    31  }
    32  
    33  func TestWildcard(t *testing.T) {
    34  	// A wildcard pattern "*" should match anything
    35  	cases := []struct {
    36  		pattern string
    37  		input   string
    38  		flags   int
    39  		want    bool
    40  	}{
    41  		{"*", "", 0, true},
    42  		{"*", "foo", 0, true},
    43  		{"*", "*", 0, true},
    44  		{"*", "   ", 0, true},
    45  		{"*", ".foo", 0, true},
    46  		{"*", "わたし", 0, true},
    47  	}
    48  
    49  	for tc, c := range cases {
    50  		got := fnmatch.Match(c.pattern, c.input, c.flags)
    51  		if got != c.want {
    52  			t.Errorf(
    53  				"Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
    54  				tc, c.pattern, c.input, c.flags, c.want, got,
    55  			)
    56  		}
    57  	}
    58  }
    59  
    60  func TestWildcardSlash(t *testing.T) {
    61  	cases := []struct {
    62  		pattern string
    63  		input   string
    64  		flags   int
    65  		want    bool
    66  	}{
    67  		// Should match / when flags are 0
    68  		{"*", "foo/bar", 0, true},
    69  		{"*", "/", 0, true},
    70  		{"*", "/foo", 0, true},
    71  		{"*", "foo/", 0, true},
    72  		// Shouldnt match / when flags include FNM_PATHNAME
    73  		{"*", "foo/bar", fnmatch.FNM_PATHNAME, false},
    74  		{"*", "/", fnmatch.FNM_PATHNAME, false},
    75  		{"*", "/foo", fnmatch.FNM_PATHNAME, false},
    76  		{"*", "foo/", fnmatch.FNM_PATHNAME, false},
    77  	}
    78  
    79  	for tc, c := range cases {
    80  		got := fnmatch.Match(c.pattern, c.input, c.flags)
    81  		if got != c.want {
    82  			t.Errorf(
    83  				"Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
    84  				tc, c.pattern, c.input, c.flags, c.want, got,
    85  			)
    86  		}
    87  	}
    88  	for _, c := range cases {
    89  		got := fnmatch.Match(c.pattern, c.input, c.flags)
    90  		if got != c.want {
    91  			t.Errorf(
    92  				"fnmatch.Match('%s', '%s', %d) should be %v not %v",
    93  				c.pattern, c.input, c.flags, c.want, got,
    94  			)
    95  		}
    96  	}
    97  }
    98  
    99  func TestWildcardFNMPeriod(t *testing.T) {
   100  	// FNM_PERIOD means that . is not matched in some circumstances.
   101  	cases := []struct {
   102  		pattern string
   103  		input   string
   104  		flags   int
   105  		want    bool
   106  	}{
   107  		{"*", ".foo", fnmatch.FNM_PERIOD, false},
   108  		{"/*", "/.foo", fnmatch.FNM_PERIOD, true},
   109  		{"/*", "/.foo", fnmatch.FNM_PERIOD | fnmatch.FNM_PATHNAME, false},
   110  	}
   111  
   112  	for tc, c := range cases {
   113  		got := fnmatch.Match(c.pattern, c.input, c.flags)
   114  		if got != c.want {
   115  			t.Errorf(
   116  				"Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
   117  				tc, c.pattern, c.input, c.flags, c.want, got,
   118  			)
   119  		}
   120  	}
   121  }
   122  
   123  func TestQuestionMark(t *testing.T) {
   124  	//A question mark pattern "?" should match a single character
   125  	cases := []struct {
   126  		pattern string
   127  		input   string
   128  		flags   int
   129  		want    bool
   130  	}{
   131  		{"?", "", 0, false},
   132  		{"?", "f", 0, true},
   133  		{"?", ".", 0, true},
   134  		{"?", "?", 0, true},
   135  		{"?", "foo", 0, false},
   136  		{"?", "わ", 0, true},
   137  		{"?", "わた", 0, false},
   138  		// Even '/' when flags are 0
   139  		{"?", "/", 0, true},
   140  		// Except '/' when flags include FNM_PATHNAME
   141  		{"?", "/", fnmatch.FNM_PATHNAME, false},
   142  	}
   143  
   144  	for tc, c := range cases {
   145  		got := fnmatch.Match(c.pattern, c.input, c.flags)
   146  		if got != c.want {
   147  			t.Errorf(
   148  				"Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
   149  				tc, c.pattern, c.input, c.flags, c.want, got,
   150  			)
   151  		}
   152  	}
   153  }
   154  
   155  func TestQuestionMarkExceptions(t *testing.T) {
   156  	//When flags include FNM_PERIOD a '?' might not match a '.' character.
   157  	cases := []struct {
   158  		pattern string
   159  		input   string
   160  		flags   int
   161  		want    bool
   162  	}{
   163  		{"?", ".", fnmatch.FNM_PERIOD, false},
   164  		{"foo?", "foo.", fnmatch.FNM_PERIOD, true},
   165  		{"/?", "/.", fnmatch.FNM_PERIOD, true},
   166  		{"/?", "/.", fnmatch.FNM_PERIOD | fnmatch.FNM_PATHNAME, false},
   167  	}
   168  
   169  	for tc, c := range cases {
   170  		got := fnmatch.Match(c.pattern, c.input, c.flags)
   171  		if got != c.want {
   172  			t.Errorf(
   173  				"Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
   174  				tc, c.pattern, c.input, c.flags, c.want, got,
   175  			)
   176  		}
   177  	}
   178  }
   179  
   180  func TestRange(t *testing.T) {
   181  	azPat := "[a-z]"
   182  	cases := []struct {
   183  		pattern string
   184  		input   string
   185  		flags   int
   186  		want    bool
   187  	}{
   188  		// Should match a single character inside its range
   189  		{azPat, "a", 0, true},
   190  		{azPat, "q", 0, true},
   191  		{azPat, "z", 0, true},
   192  		{"[わ]", "わ", 0, true},
   193  
   194  		// Should not match characters outside its range
   195  		{azPat, "-", 0, false},
   196  		{azPat, " ", 0, false},
   197  		{azPat, "D", 0, false},
   198  		{azPat, "é", 0, false},
   199  
   200  		//Should only match one character
   201  		{azPat, "ab", 0, false},
   202  		{azPat, "", 0, false},
   203  
   204  		// Should not consume more of the pattern than necessary
   205  		{azPat + "foo", "afoo", 0, true},
   206  
   207  		// Should match '-' if it is the first/last character or is
   208  		// backslash escaped
   209  		{"[-az]", "-", 0, true},
   210  		{"[-az]", "a", 0, true},
   211  		{"[-az]", "b", 0, false},
   212  		{"[az-]", "-", 0, true},
   213  		{"[a\\-z]", "-", 0, true},
   214  		{"[a\\-z]", "b", 0, false},
   215  
   216  		// ignore '\\' when FNM_NOESCAPE is given
   217  		{"[a\\-z]", "\\", fnmatch.FNM_NOESCAPE, true},
   218  		{"[a\\-z]", "-", fnmatch.FNM_NOESCAPE, false},
   219  
   220  		// Should be negated if starting with ^ or !"
   221  		{"[^a-z]", "a", 0, false},
   222  		{"[!a-z]", "b", 0, false},
   223  		{"[!a-z]", "é", 0, true},
   224  		{"[!a-z]", "わ", 0, true},
   225  
   226  		// Still match '-' if following the negation character
   227  		{"[^-az]", "-", 0, false},
   228  		{"[^-az]", "b", 0, true},
   229  
   230  		// Should support multiple characters/ranges
   231  		{"[abc]", "a", 0, true},
   232  		{"[abc]", "c", 0, true},
   233  		{"[abc]", "d", 0, false},
   234  		{"[a-cg-z]", "c", 0, true},
   235  		{"[a-cg-z]", "h", 0, true},
   236  		{"[a-cg-z]", "d", 0, false},
   237  
   238  		//Should not match '/' when flags is FNM_PATHNAME
   239  		{"[abc/def]", "/", 0, true},
   240  		{"[abc/def]", "/", fnmatch.FNM_PATHNAME, false},
   241  		{"[.-0]", "/", 0, true}, // The range [.-0] includes /
   242  		{"[.-0]", "/", fnmatch.FNM_PATHNAME, false},
   243  
   244  		// Should normally be case-sensitive
   245  		{"[a-z]", "A", 0, false},
   246  		{"[A-Z]", "a", 0, false},
   247  		//Except when FNM_CASEFOLD is given
   248  		{"[a-z]", "A", fnmatch.FNM_CASEFOLD, true},
   249  		{"[A-Z]", "a", fnmatch.FNM_CASEFOLD, true},
   250  	}
   251  
   252  	for tc, c := range cases {
   253  		got := fnmatch.Match(c.pattern, c.input, c.flags)
   254  		if got != c.want {
   255  			t.Errorf(
   256  				"Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
   257  				tc, c.pattern, c.input, c.flags, c.want, got,
   258  			)
   259  		}
   260  	}
   261  }
   262  
   263  func TestBackSlash(t *testing.T) {
   264  	cases := []struct {
   265  		pattern string
   266  		input   string
   267  		flags   int
   268  		want    bool
   269  	}{
   270  		//A backslash should escape the following characters
   271  		{"\\\\", "\\", 0, true},
   272  		{"\\*", "*", 0, true},
   273  		{"\\*", "foo", 0, false},
   274  		{"\\?", "?", 0, true},
   275  		{"\\?", "f", 0, false},
   276  		{"\\[a-z]", "[a-z]", 0, true},
   277  		{"\\[a-z]", "a", 0, false},
   278  		{"\\foo", "foo", 0, true},
   279  		{"\\わ", "わ", 0, true},
   280  
   281  		// Unless FNM_NOESCAPE is given
   282  		{"\\\\", "\\", fnmatch.FNM_NOESCAPE, false},
   283  		{"\\\\", "\\\\", fnmatch.FNM_NOESCAPE, true},
   284  		{"\\*", "foo", fnmatch.FNM_NOESCAPE, false},
   285  		{"\\*", "\\*", fnmatch.FNM_NOESCAPE, true},
   286  	}
   287  
   288  	for tc, c := range cases {
   289  		got := fnmatch.Match(c.pattern, c.input, c.flags)
   290  		if got != c.want {
   291  			t.Errorf(
   292  				"Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
   293  				tc, c.pattern, c.input, c.flags, c.want, got,
   294  			)
   295  		}
   296  	}
   297  }
   298  
   299  func TestLiteral(t *testing.T) {
   300  	cases := []struct {
   301  		pattern string
   302  		input   string
   303  		flags   int
   304  		want    bool
   305  	}{
   306  		//Literal characters should match themselves
   307  		{"foo", "foo", 0, true},
   308  		{"foo", "foobar", 0, false},
   309  		{"foobar", "foo", 0, false},
   310  		{"foo", "Foo", 0, false},
   311  		{"わたし", "わたし", 0, true},
   312  		// And perform case-folding when FNM_CASEFOLD is given
   313  		{"foo", "FOO", fnmatch.FNM_CASEFOLD, true},
   314  		{"FoO", "fOo", fnmatch.FNM_CASEFOLD, true},
   315  	}
   316  
   317  	for tc, c := range cases {
   318  		got := fnmatch.Match(c.pattern, c.input, c.flags)
   319  		if got != c.want {
   320  			t.Errorf(
   321  				"Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
   322  				tc, c.pattern, c.input, c.flags, c.want, got,
   323  			)
   324  		}
   325  	}
   326  }
   327  
   328  func TestFNMLeadingDir(t *testing.T) {
   329  	cases := []struct {
   330  		pattern string
   331  		input   string
   332  		flags   int
   333  		want    bool
   334  	}{
   335  		// FNM_LEADING_DIR should ignore trailing '/*'
   336  		{"foo", "foo/bar", 0, false},
   337  		{"foo", "foo/bar", fnmatch.FNM_LEADING_DIR, true},
   338  		{"*", "foo/bar", fnmatch.FNM_PATHNAME, false},
   339  		{"*", "foo/bar", fnmatch.FNM_PATHNAME | fnmatch.FNM_LEADING_DIR, true},
   340  	}
   341  
   342  	for tc, c := range cases {
   343  		got := fnmatch.Match(c.pattern, c.input, c.flags)
   344  		if got != c.want {
   345  			t.Errorf(
   346  				"Testcase #%d failed: fnmatch.Match('%s', '%s', %d) should be %v not %v",
   347  				tc, c.pattern, c.input, c.flags, c.want, got,
   348  			)
   349  		}
   350  	}
   351  }
   352  

View as plain text