gopkg.in/docker/docker.v20@v20.10.27/pkg/fileutils/fileutils_test.go (about)

     1  package fileutils // import "github.com/docker/docker/pkg/fileutils"
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path"
     7  	"path/filepath"
     8  	"runtime"
     9  	"strings"
    10  	"testing"
    11  
    12  	"gotest.tools/v3/assert"
    13  	is "gotest.tools/v3/assert/cmp"
    14  )
    15  
    16  // CopyFile with invalid src
    17  func TestCopyFileWithInvalidSrc(t *testing.T) {
    18  	tempFolder, err := os.MkdirTemp("", "docker-fileutils-test") // #nosec G303
    19  	defer os.RemoveAll(tempFolder)
    20  	if err != nil {
    21  		t.Fatal(err)
    22  	}
    23  	bytes, err := CopyFile("/invalid/file/path", path.Join(tempFolder, "dest"))
    24  	if err == nil {
    25  		t.Fatal("Should have fail to copy an invalid src file")
    26  	}
    27  	if bytes != 0 {
    28  		t.Fatal("Should have written 0 bytes")
    29  	}
    30  
    31  }
    32  
    33  // CopyFile with invalid dest
    34  func TestCopyFileWithInvalidDest(t *testing.T) {
    35  	tempFolder, err := os.MkdirTemp("", "docker-fileutils-test")
    36  	defer os.RemoveAll(tempFolder)
    37  	if err != nil {
    38  		t.Fatal(err)
    39  	}
    40  	src := path.Join(tempFolder, "file")
    41  	err = os.WriteFile(src, []byte("content"), 0740)
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  	bytes, err := CopyFile(src, path.Join(tempFolder, "/invalid/dest/path"))
    46  	if err == nil {
    47  		t.Fatal("Should have fail to copy an invalid src file")
    48  	}
    49  	if bytes != 0 {
    50  		t.Fatal("Should have written 0 bytes")
    51  	}
    52  
    53  }
    54  
    55  // CopyFile with same src and dest
    56  func TestCopyFileWithSameSrcAndDest(t *testing.T) {
    57  	tempFolder, err := os.MkdirTemp("", "docker-fileutils-test")
    58  	defer os.RemoveAll(tempFolder)
    59  	if err != nil {
    60  		t.Fatal(err)
    61  	}
    62  	file := path.Join(tempFolder, "file")
    63  	err = os.WriteFile(file, []byte("content"), 0740)
    64  	if err != nil {
    65  		t.Fatal(err)
    66  	}
    67  	bytes, err := CopyFile(file, file)
    68  	if err != nil {
    69  		t.Fatal(err)
    70  	}
    71  	if bytes != 0 {
    72  		t.Fatal("Should have written 0 bytes as it is the same file.")
    73  	}
    74  }
    75  
    76  // CopyFile with same src and dest but path is different and not clean
    77  func TestCopyFileWithSameSrcAndDestWithPathNameDifferent(t *testing.T) {
    78  	tempFolder, err := os.MkdirTemp("", "docker-fileutils-test")
    79  	defer os.RemoveAll(tempFolder)
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  	testFolder := path.Join(tempFolder, "test")
    84  	err = os.MkdirAll(testFolder, 0740)
    85  	if err != nil {
    86  		t.Fatal(err)
    87  	}
    88  	file := path.Join(testFolder, "file")
    89  	sameFile := testFolder + "/../test/file"
    90  	err = os.WriteFile(file, []byte("content"), 0740)
    91  	if err != nil {
    92  		t.Fatal(err)
    93  	}
    94  	bytes, err := CopyFile(file, sameFile)
    95  	if err != nil {
    96  		t.Fatal(err)
    97  	}
    98  	if bytes != 0 {
    99  		t.Fatal("Should have written 0 bytes as it is the same file.")
   100  	}
   101  }
   102  
   103  func TestCopyFile(t *testing.T) {
   104  	tempFolder, err := os.MkdirTemp("", "docker-fileutils-test")
   105  	defer os.RemoveAll(tempFolder)
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  	src := path.Join(tempFolder, "src")
   110  	dest := path.Join(tempFolder, "dest")
   111  	os.WriteFile(src, []byte("content"), 0777)
   112  	os.WriteFile(dest, []byte("destContent"), 0777)
   113  	bytes, err := CopyFile(src, dest)
   114  	if err != nil {
   115  		t.Fatal(err)
   116  	}
   117  	if bytes != 7 {
   118  		t.Fatalf("Should have written %d bytes but wrote %d", 7, bytes)
   119  	}
   120  	actual, err := os.ReadFile(dest)
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  	if string(actual) != "content" {
   125  		t.Fatalf("Dest content was '%s', expected '%s'", string(actual), "content")
   126  	}
   127  }
   128  
   129  // Reading a symlink to a directory must return the directory
   130  func TestReadSymlinkedDirectoryExistingDirectory(t *testing.T) {
   131  	// TODO Windows: Port this test
   132  	if runtime.GOOS == "windows" {
   133  		t.Skip("Needs porting to Windows")
   134  	}
   135  	var err error
   136  	if err = os.Mkdir("/tmp/testReadSymlinkToExistingDirectory", 0777); err != nil {
   137  		t.Errorf("failed to create directory: %s", err)
   138  	}
   139  
   140  	if err = os.Symlink("/tmp/testReadSymlinkToExistingDirectory", "/tmp/dirLinkTest"); err != nil {
   141  		t.Errorf("failed to create symlink: %s", err)
   142  	}
   143  
   144  	var path string
   145  	if path, err = ReadSymlinkedDirectory("/tmp/dirLinkTest"); err != nil {
   146  		t.Fatalf("failed to read symlink to directory: %s", err)
   147  	}
   148  
   149  	if path != "/tmp/testReadSymlinkToExistingDirectory" {
   150  		t.Fatalf("symlink returned unexpected directory: %s", path)
   151  	}
   152  
   153  	if err = os.Remove("/tmp/testReadSymlinkToExistingDirectory"); err != nil {
   154  		t.Errorf("failed to remove temporary directory: %s", err)
   155  	}
   156  
   157  	if err = os.Remove("/tmp/dirLinkTest"); err != nil {
   158  		t.Errorf("failed to remove symlink: %s", err)
   159  	}
   160  }
   161  
   162  // Reading a non-existing symlink must fail
   163  func TestReadSymlinkedDirectoryNonExistingSymlink(t *testing.T) {
   164  	var path string
   165  	var err error
   166  	if path, err = ReadSymlinkedDirectory("/tmp/test/foo/Non/ExistingPath"); err == nil {
   167  		t.Fatalf("error expected for non-existing symlink")
   168  	}
   169  
   170  	if path != "" {
   171  		t.Fatalf("expected empty path, but '%s' was returned", path)
   172  	}
   173  }
   174  
   175  // Reading a symlink to a file must fail
   176  func TestReadSymlinkedDirectoryToFile(t *testing.T) {
   177  	// TODO Windows: Port this test
   178  	if runtime.GOOS == "windows" {
   179  		t.Skip("Needs porting to Windows")
   180  	}
   181  	var err error
   182  	var file *os.File
   183  
   184  	// #nosec G303
   185  	if file, err = os.Create("/tmp/testReadSymlinkToFile"); err != nil {
   186  		t.Fatalf("failed to create file: %s", err)
   187  	}
   188  
   189  	file.Close()
   190  
   191  	if err = os.Symlink("/tmp/testReadSymlinkToFile", "/tmp/fileLinkTest"); err != nil {
   192  		t.Errorf("failed to create symlink: %s", err)
   193  	}
   194  
   195  	var path string
   196  	if path, err = ReadSymlinkedDirectory("/tmp/fileLinkTest"); err == nil {
   197  		t.Fatalf("ReadSymlinkedDirectory on a symlink to a file should've failed")
   198  	}
   199  
   200  	if path != "" {
   201  		t.Fatalf("path should've been empty: %s", path)
   202  	}
   203  
   204  	if err = os.Remove("/tmp/testReadSymlinkToFile"); err != nil {
   205  		t.Errorf("failed to remove file: %s", err)
   206  	}
   207  
   208  	if err = os.Remove("/tmp/fileLinkTest"); err != nil {
   209  		t.Errorf("failed to remove symlink: %s", err)
   210  	}
   211  }
   212  
   213  func TestWildcardMatches(t *testing.T) {
   214  	match, _ := Matches("fileutils.go", []string{"*"})
   215  	if !match {
   216  		t.Errorf("failed to get a wildcard match, got %v", match)
   217  	}
   218  }
   219  
   220  // A simple pattern match should return true.
   221  func TestPatternMatches(t *testing.T) {
   222  	match, _ := Matches("fileutils.go", []string{"*.go"})
   223  	if !match {
   224  		t.Errorf("failed to get a match, got %v", match)
   225  	}
   226  }
   227  
   228  // An exclusion followed by an inclusion should return true.
   229  func TestExclusionPatternMatchesPatternBefore(t *testing.T) {
   230  	match, _ := Matches("fileutils.go", []string{"!fileutils.go", "*.go"})
   231  	if !match {
   232  		t.Errorf("failed to get true match on exclusion pattern, got %v", match)
   233  	}
   234  }
   235  
   236  // A folder pattern followed by an exception should return false.
   237  func TestPatternMatchesFolderExclusions(t *testing.T) {
   238  	match, _ := Matches("docs/README.md", []string{"docs", "!docs/README.md"})
   239  	if match {
   240  		t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
   241  	}
   242  }
   243  
   244  // A folder pattern followed by an exception should return false.
   245  func TestPatternMatchesFolderWithSlashExclusions(t *testing.T) {
   246  	match, _ := Matches("docs/README.md", []string{"docs/", "!docs/README.md"})
   247  	if match {
   248  		t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
   249  	}
   250  }
   251  
   252  // A folder pattern followed by an exception should return false.
   253  func TestPatternMatchesFolderWildcardExclusions(t *testing.T) {
   254  	match, _ := Matches("docs/README.md", []string{"docs/*", "!docs/README.md"})
   255  	if match {
   256  		t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
   257  	}
   258  }
   259  
   260  // A pattern followed by an exclusion should return false.
   261  func TestExclusionPatternMatchesPatternAfter(t *testing.T) {
   262  	match, _ := Matches("fileutils.go", []string{"*.go", "!fileutils.go"})
   263  	if match {
   264  		t.Errorf("failed to get false match on exclusion pattern, got %v", match)
   265  	}
   266  }
   267  
   268  // A filename evaluating to . should return false.
   269  func TestExclusionPatternMatchesWholeDirectory(t *testing.T) {
   270  	match, _ := Matches(".", []string{"*.go"})
   271  	if match {
   272  		t.Errorf("failed to get false match on ., got %v", match)
   273  	}
   274  }
   275  
   276  // A single ! pattern should return an error.
   277  func TestSingleExclamationError(t *testing.T) {
   278  	_, err := Matches("fileutils.go", []string{"!"})
   279  	if err == nil {
   280  		t.Errorf("failed to get an error for a single exclamation point, got %v", err)
   281  	}
   282  }
   283  
   284  // Matches with no patterns
   285  func TestMatchesWithNoPatterns(t *testing.T) {
   286  	matches, err := Matches("/any/path/there", []string{})
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  	if matches {
   291  		t.Fatalf("Should not have match anything")
   292  	}
   293  }
   294  
   295  // Matches with malformed patterns
   296  func TestMatchesWithMalformedPatterns(t *testing.T) {
   297  	matches, err := Matches("/any/path/there", []string{"["})
   298  	if err == nil {
   299  		t.Fatal("Should have failed because of a malformed syntax in the pattern")
   300  	}
   301  	if matches {
   302  		t.Fatalf("Should not have match anything")
   303  	}
   304  }
   305  
   306  type matchesTestCase struct {
   307  	pattern string
   308  	text    string
   309  	pass    bool
   310  }
   311  
   312  func TestMatches(t *testing.T) {
   313  	tests := []matchesTestCase{
   314  		{"**", "file", true},
   315  		{"**", "file/", true},
   316  		{"**/", "file", true}, // weird one
   317  		{"**/", "file/", true},
   318  		{"**", "/", true},
   319  		{"**/", "/", true},
   320  		{"**", "dir/file", true},
   321  		{"**/", "dir/file", true},
   322  		{"**", "dir/file/", true},
   323  		{"**/", "dir/file/", true},
   324  		{"**/**", "dir/file", true},
   325  		{"**/**", "dir/file/", true},
   326  		{"dir/**", "dir/file", true},
   327  		{"dir/**", "dir/file/", true},
   328  		{"dir/**", "dir/dir2/file", true},
   329  		{"dir/**", "dir/dir2/file/", true},
   330  		{"**/dir2/*", "dir/dir2/file", true},
   331  		{"**/dir2/*", "dir/dir2/file/", true},
   332  		{"**/dir2/**", "dir/dir2/dir3/file", true},
   333  		{"**/dir2/**", "dir/dir2/dir3/file/", true},
   334  		{"**file", "file", true},
   335  		{"**file", "dir/file", true},
   336  		{"**/file", "dir/file", true},
   337  		{"**file", "dir/dir/file", true},
   338  		{"**/file", "dir/dir/file", true},
   339  		{"**/file*", "dir/dir/file", true},
   340  		{"**/file*", "dir/dir/file.txt", true},
   341  		{"**/file*txt", "dir/dir/file.txt", true},
   342  		{"**/file*.txt", "dir/dir/file.txt", true},
   343  		{"**/file*.txt*", "dir/dir/file.txt", true},
   344  		{"**/**/*.txt", "dir/dir/file.txt", true},
   345  		{"**/**/*.txt2", "dir/dir/file.txt", false},
   346  		{"**/*.txt", "file.txt", true},
   347  		{"**/**/*.txt", "file.txt", true},
   348  		{"a**/*.txt", "a/file.txt", true},
   349  		{"a**/*.txt", "a/dir/file.txt", true},
   350  		{"a**/*.txt", "a/dir/dir/file.txt", true},
   351  		{"a/*.txt", "a/dir/file.txt", false},
   352  		{"a/*.txt", "a/file.txt", true},
   353  		{"a/*.txt**", "a/file.txt", true},
   354  		{"a[b-d]e", "ae", false},
   355  		{"a[b-d]e", "ace", true},
   356  		{"a[b-d]e", "aae", false},
   357  		{"a[^b-d]e", "aze", true},
   358  		{".*", ".foo", true},
   359  		{".*", "foo", false},
   360  		{"abc.def", "abcdef", false},
   361  		{"abc.def", "abc.def", true},
   362  		{"abc.def", "abcZdef", false},
   363  		{"abc?def", "abcZdef", true},
   364  		{"abc?def", "abcdef", false},
   365  		{"a\\\\", "a\\", true},
   366  		{"**/foo/bar", "foo/bar", true},
   367  		{"**/foo/bar", "dir/foo/bar", true},
   368  		{"**/foo/bar", "dir/dir2/foo/bar", true},
   369  		{"abc/**", "abc", false},
   370  		{"abc/**", "abc/def", true},
   371  		{"abc/**", "abc/def/ghi", true},
   372  		{"**/.foo", ".foo", true},
   373  		{"**/.foo", "bar.foo", false},
   374  	}
   375  
   376  	if runtime.GOOS != "windows" {
   377  		tests = append(tests, []matchesTestCase{
   378  			{"a\\*b", "a*b", true},
   379  		}...)
   380  	}
   381  
   382  	for _, test := range tests {
   383  		desc := fmt.Sprintf("pattern=%q text=%q", test.pattern, test.text)
   384  		pm, err := NewPatternMatcher([]string{test.pattern})
   385  		assert.NilError(t, err, desc)
   386  		res, _ := pm.Matches(test.text)
   387  		assert.Check(t, is.Equal(test.pass, res), desc)
   388  	}
   389  }
   390  
   391  func TestCleanPatterns(t *testing.T) {
   392  	patterns := []string{"docs", "config"}
   393  	pm, err := NewPatternMatcher(patterns)
   394  	if err != nil {
   395  		t.Fatalf("invalid pattern %v", patterns)
   396  	}
   397  	cleaned := pm.Patterns()
   398  	if len(cleaned) != 2 {
   399  		t.Errorf("expected 2 element slice, got %v", len(cleaned))
   400  	}
   401  }
   402  
   403  func TestCleanPatternsStripEmptyPatterns(t *testing.T) {
   404  	patterns := []string{"docs", "config", ""}
   405  	pm, err := NewPatternMatcher(patterns)
   406  	if err != nil {
   407  		t.Fatalf("invalid pattern %v", patterns)
   408  	}
   409  	cleaned := pm.Patterns()
   410  	if len(cleaned) != 2 {
   411  		t.Errorf("expected 2 element slice, got %v", len(cleaned))
   412  	}
   413  }
   414  
   415  func TestCleanPatternsExceptionFlag(t *testing.T) {
   416  	patterns := []string{"docs", "!docs/README.md"}
   417  	pm, err := NewPatternMatcher(patterns)
   418  	if err != nil {
   419  		t.Fatalf("invalid pattern %v", patterns)
   420  	}
   421  	if !pm.Exclusions() {
   422  		t.Errorf("expected exceptions to be true, got %v", pm.Exclusions())
   423  	}
   424  }
   425  
   426  func TestCleanPatternsLeadingSpaceTrimmed(t *testing.T) {
   427  	patterns := []string{"docs", "  !docs/README.md"}
   428  	pm, err := NewPatternMatcher(patterns)
   429  	if err != nil {
   430  		t.Fatalf("invalid pattern %v", patterns)
   431  	}
   432  	if !pm.Exclusions() {
   433  		t.Errorf("expected exceptions to be true, got %v", pm.Exclusions())
   434  	}
   435  }
   436  
   437  func TestCleanPatternsTrailingSpaceTrimmed(t *testing.T) {
   438  	patterns := []string{"docs", "!docs/README.md  "}
   439  	pm, err := NewPatternMatcher(patterns)
   440  	if err != nil {
   441  		t.Fatalf("invalid pattern %v", patterns)
   442  	}
   443  	if !pm.Exclusions() {
   444  		t.Errorf("expected exceptions to be true, got %v", pm.Exclusions())
   445  	}
   446  }
   447  
   448  func TestCleanPatternsErrorSingleException(t *testing.T) {
   449  	patterns := []string{"!"}
   450  	_, err := NewPatternMatcher(patterns)
   451  	if err == nil {
   452  		t.Errorf("expected error on single exclamation point, got %v", err)
   453  	}
   454  }
   455  
   456  func TestCreateIfNotExistsDir(t *testing.T) {
   457  	tempFolder, err := os.MkdirTemp("", "docker-fileutils-test")
   458  	if err != nil {
   459  		t.Fatal(err)
   460  	}
   461  	defer os.RemoveAll(tempFolder)
   462  
   463  	folderToCreate := filepath.Join(tempFolder, "tocreate")
   464  
   465  	if err := CreateIfNotExists(folderToCreate, true); err != nil {
   466  		t.Fatal(err)
   467  	}
   468  	fileinfo, err := os.Stat(folderToCreate)
   469  	if err != nil {
   470  		t.Fatalf("Should have create a folder, got %v", err)
   471  	}
   472  
   473  	if !fileinfo.IsDir() {
   474  		t.Fatalf("Should have been a dir, seems it's not")
   475  	}
   476  }
   477  
   478  func TestCreateIfNotExistsFile(t *testing.T) {
   479  	tempFolder, err := os.MkdirTemp("", "docker-fileutils-test")
   480  	if err != nil {
   481  		t.Fatal(err)
   482  	}
   483  	defer os.RemoveAll(tempFolder)
   484  
   485  	fileToCreate := filepath.Join(tempFolder, "file/to/create")
   486  
   487  	if err := CreateIfNotExists(fileToCreate, false); err != nil {
   488  		t.Fatal(err)
   489  	}
   490  	fileinfo, err := os.Stat(fileToCreate)
   491  	if err != nil {
   492  		t.Fatalf("Should have create a file, got %v", err)
   493  	}
   494  
   495  	if fileinfo.IsDir() {
   496  		t.Fatalf("Should have been a file, seems it's not")
   497  	}
   498  }
   499  
   500  // These matchTests are stolen from go's filepath Match tests.
   501  type matchTest struct {
   502  	pattern, s string
   503  	match      bool
   504  	err        error
   505  }
   506  
   507  var matchTests = []matchTest{
   508  	{"abc", "abc", true, nil},
   509  	{"*", "abc", true, nil},
   510  	{"*c", "abc", true, nil},
   511  	{"a*", "a", true, nil},
   512  	{"a*", "abc", true, nil},
   513  	{"a*", "ab/c", true, nil},
   514  	{"a*/b", "abc/b", true, nil},
   515  	{"a*/b", "a/c/b", false, nil},
   516  	{"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
   517  	{"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
   518  	{"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
   519  	{"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
   520  	{"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
   521  	{"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
   522  	{"ab[c]", "abc", true, nil},
   523  	{"ab[b-d]", "abc", true, nil},
   524  	{"ab[e-g]", "abc", false, nil},
   525  	{"ab[^c]", "abc", false, nil},
   526  	{"ab[^b-d]", "abc", false, nil},
   527  	{"ab[^e-g]", "abc", true, nil},
   528  	{"a\\*b", "a*b", true, nil},
   529  	{"a\\*b", "ab", false, nil},
   530  	{"a?b", "a☺b", true, nil},
   531  	{"a[^a]b", "a☺b", true, nil},
   532  	{"a???b", "a☺b", false, nil},
   533  	{"a[^a][^a][^a]b", "a☺b", false, nil},
   534  	{"[a-ζ]*", "α", true, nil},
   535  	{"*[a-ζ]", "A", false, nil},
   536  	{"a?b", "a/b", false, nil},
   537  	{"a*b", "a/b", false, nil},
   538  	{"[\\]a]", "]", true, nil},
   539  	{"[\\-]", "-", true, nil},
   540  	{"[x\\-]", "x", true, nil},
   541  	{"[x\\-]", "-", true, nil},
   542  	{"[x\\-]", "z", false, nil},
   543  	{"[\\-x]", "x", true, nil},
   544  	{"[\\-x]", "-", true, nil},
   545  	{"[\\-x]", "a", false, nil},
   546  	{"[]a]", "]", false, filepath.ErrBadPattern},
   547  	{"[-]", "-", false, filepath.ErrBadPattern},
   548  	{"[x-]", "x", false, filepath.ErrBadPattern},
   549  	{"[x-]", "-", false, filepath.ErrBadPattern},
   550  	{"[x-]", "z", false, filepath.ErrBadPattern},
   551  	{"[-x]", "x", false, filepath.ErrBadPattern},
   552  	{"[-x]", "-", false, filepath.ErrBadPattern},
   553  	{"[-x]", "a", false, filepath.ErrBadPattern},
   554  	{"\\", "a", false, filepath.ErrBadPattern},
   555  	{"[a-b-c]", "a", false, filepath.ErrBadPattern},
   556  	{"[", "a", false, filepath.ErrBadPattern},
   557  	{"[^", "a", false, filepath.ErrBadPattern},
   558  	{"[^bc", "a", false, filepath.ErrBadPattern},
   559  	{"a[", "a", false, filepath.ErrBadPattern}, // was nil but IMO its wrong
   560  	{"a[", "ab", false, filepath.ErrBadPattern},
   561  	{"*x", "xxx", true, nil},
   562  }
   563  
   564  func errp(e error) string {
   565  	if e == nil {
   566  		return "<nil>"
   567  	}
   568  	return e.Error()
   569  }
   570  
   571  // TestMatch test's our version of filepath.Match, called regexpMatch.
   572  func TestMatch(t *testing.T) {
   573  	for _, tt := range matchTests {
   574  		pattern := tt.pattern
   575  		s := tt.s
   576  		if runtime.GOOS == "windows" {
   577  			if strings.Contains(pattern, "\\") {
   578  				// no escape allowed on windows.
   579  				continue
   580  			}
   581  			pattern = filepath.Clean(pattern)
   582  			s = filepath.Clean(s)
   583  		}
   584  		ok, err := Matches(s, []string{pattern})
   585  		if ok != tt.match || err != tt.err {
   586  			t.Fatalf("Match(%#q, %#q) = %v, %q want %v, %q", pattern, s, ok, errp(err), tt.match, errp(tt.err))
   587  		}
   588  	}
   589  }