github.com/hms58/moby@v1.13.1/pkg/fileutils/fileutils_test.go (about)

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