github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/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  type multiPatternTestCase struct {
   313  	patterns []string
   314  	text     string
   315  	pass     bool
   316  }
   317  
   318  func TestMatches(t *testing.T) {
   319  	tests := []matchesTestCase{
   320  		{"**", "file", true},
   321  		{"**", "file/", true},
   322  		{"**/", "file", true}, // weird one
   323  		{"**/", "file/", true},
   324  		{"**", "/", true},
   325  		{"**/", "/", true},
   326  		{"**", "dir/file", true},
   327  		{"**/", "dir/file", true},
   328  		{"**", "dir/file/", true},
   329  		{"**/", "dir/file/", true},
   330  		{"**/**", "dir/file", true},
   331  		{"**/**", "dir/file/", true},
   332  		{"dir/**", "dir/file", true},
   333  		{"dir/**", "dir/file/", true},
   334  		{"dir/**", "dir/dir2/file", true},
   335  		{"dir/**", "dir/dir2/file/", true},
   336  		{"**/dir", "dir", true},
   337  		{"**/dir", "dir/file", true},
   338  		{"**/dir2/*", "dir/dir2/file", true},
   339  		{"**/dir2/*", "dir/dir2/file/", true},
   340  		{"**/dir2/**", "dir/dir2/dir3/file", true},
   341  		{"**/dir2/**", "dir/dir2/dir3/file/", true},
   342  		{"**file", "file", true},
   343  		{"**file", "dir/file", true},
   344  		{"**/file", "dir/file", true},
   345  		{"**file", "dir/dir/file", true},
   346  		{"**/file", "dir/dir/file", true},
   347  		{"**/file*", "dir/dir/file", true},
   348  		{"**/file*", "dir/dir/file.txt", true},
   349  		{"**/file*txt", "dir/dir/file.txt", true},
   350  		{"**/file*.txt", "dir/dir/file.txt", true},
   351  		{"**/file*.txt*", "dir/dir/file.txt", true},
   352  		{"**/**/*.txt", "dir/dir/file.txt", true},
   353  		{"**/**/*.txt2", "dir/dir/file.txt", false},
   354  		{"**/*.txt", "file.txt", true},
   355  		{"**/**/*.txt", "file.txt", true},
   356  		{"a**/*.txt", "a/file.txt", true},
   357  		{"a**/*.txt", "a/dir/file.txt", true},
   358  		{"a**/*.txt", "a/dir/dir/file.txt", true},
   359  		{"a/*.txt", "a/dir/file.txt", false},
   360  		{"a/*.txt", "a/file.txt", true},
   361  		{"a/*.txt**", "a/file.txt", true},
   362  		{"a[b-d]e", "ae", false},
   363  		{"a[b-d]e", "ace", true},
   364  		{"a[b-d]e", "aae", false},
   365  		{"a[^b-d]e", "aze", true},
   366  		{".*", ".foo", true},
   367  		{".*", "foo", false},
   368  		{"abc.def", "abcdef", false},
   369  		{"abc.def", "abc.def", true},
   370  		{"abc.def", "abcZdef", false},
   371  		{"abc?def", "abcZdef", true},
   372  		{"abc?def", "abcdef", false},
   373  		{"a\\\\", "a\\", true},
   374  		{"**/foo/bar", "foo/bar", true},
   375  		{"**/foo/bar", "dir/foo/bar", true},
   376  		{"**/foo/bar", "dir/dir2/foo/bar", true},
   377  		{"abc/**", "abc", false},
   378  		{"abc/**", "abc/def", true},
   379  		{"abc/**", "abc/def/ghi", true},
   380  		{"**/.foo", ".foo", true},
   381  		{"**/.foo", "bar.foo", false},
   382  		{"a(b)c/def", "a(b)c/def", true},
   383  		{"a(b)c/def", "a(b)c/xyz", false},
   384  		{"a.|)$(}+{bc", "a.|)$(}+{bc", true},
   385  	}
   386  	multiPatternTests := []multiPatternTestCase{
   387  		{[]string{"**", "!util/docker/web"}, "util/docker/web/foo", false},
   388  		{[]string{"**", "!util/docker/web", "util/docker/web/foo"}, "util/docker/web/foo", true},
   389  	}
   390  
   391  	if runtime.GOOS != "windows" {
   392  		tests = append(tests, []matchesTestCase{
   393  			{"a\\*b", "a*b", true},
   394  		}...)
   395  	}
   396  
   397  	t.Run("MatchesOrParentMatches", func(t *testing.T) {
   398  		for _, test := range tests {
   399  			desc := fmt.Sprintf("pattern=%q text=%q", test.pattern, test.text)
   400  			pm, err := NewPatternMatcher([]string{test.pattern})
   401  			assert.NilError(t, err, desc)
   402  			res, _ := pm.MatchesOrParentMatches(test.text)
   403  			assert.Check(t, is.Equal(test.pass, res), desc)
   404  		}
   405  
   406  		for _, test := range multiPatternTests {
   407  			desc := fmt.Sprintf("patterns=%q text=%q", test.patterns, test.text)
   408  			pm, err := NewPatternMatcher(test.patterns)
   409  			assert.NilError(t, err, desc)
   410  			res, _ := pm.MatchesOrParentMatches(test.text)
   411  			assert.Check(t, is.Equal(test.pass, res), desc)
   412  		}
   413  	})
   414  
   415  	t.Run("MatchesUsingParentResult", func(t *testing.T) {
   416  		for _, test := range tests {
   417  			desc := fmt.Sprintf("pattern=%q text=%q", test.pattern, test.text)
   418  			pm, err := NewPatternMatcher([]string{test.pattern})
   419  			assert.NilError(t, err, desc)
   420  
   421  			parentPath := filepath.Dir(filepath.FromSlash(test.text))
   422  			parentPathDirs := strings.Split(parentPath, string(os.PathSeparator))
   423  
   424  			parentMatched := false
   425  			if parentPath != "." {
   426  				for i := range parentPathDirs {
   427  					parentMatched, _ = pm.MatchesUsingParentResult(strings.Join(parentPathDirs[:i+1], "/"), parentMatched)
   428  				}
   429  			}
   430  
   431  			res, _ := pm.MatchesUsingParentResult(test.text, parentMatched)
   432  			assert.Check(t, is.Equal(test.pass, res), desc)
   433  		}
   434  	})
   435  
   436  	t.Run("MatchesUsingParentResults", func(t *testing.T) {
   437  		check := func(pm *PatternMatcher, text string, pass bool, desc string) {
   438  			parentPath := filepath.Dir(filepath.FromSlash(text))
   439  			parentPathDirs := strings.Split(parentPath, string(os.PathSeparator))
   440  
   441  			parentMatchInfo := MatchInfo{}
   442  			if parentPath != "." {
   443  				for i := range parentPathDirs {
   444  					_, parentMatchInfo, _ = pm.MatchesUsingParentResults(strings.Join(parentPathDirs[:i+1], "/"), parentMatchInfo)
   445  				}
   446  			}
   447  
   448  			res, _, _ := pm.MatchesUsingParentResults(text, parentMatchInfo)
   449  			assert.Check(t, is.Equal(pass, res), desc)
   450  		}
   451  
   452  		for _, test := range tests {
   453  			desc := fmt.Sprintf("pattern=%q text=%q", test.pattern, test.text)
   454  			pm, err := NewPatternMatcher([]string{test.pattern})
   455  			assert.NilError(t, err, desc)
   456  
   457  			check(pm, test.text, test.pass, desc)
   458  		}
   459  
   460  		for _, test := range multiPatternTests {
   461  			desc := fmt.Sprintf("pattern=%q text=%q", test.patterns, test.text)
   462  			pm, err := NewPatternMatcher(test.patterns)
   463  			assert.NilError(t, err, desc)
   464  
   465  			check(pm, test.text, test.pass, desc)
   466  		}
   467  	})
   468  
   469  	t.Run("MatchesUsingParentResultsNoContext", func(t *testing.T) {
   470  		check := func(pm *PatternMatcher, text string, pass bool, desc string) {
   471  			res, _, _ := pm.MatchesUsingParentResults(text, MatchInfo{})
   472  			assert.Check(t, is.Equal(pass, res), desc)
   473  		}
   474  
   475  		for _, test := range tests {
   476  			desc := fmt.Sprintf("pattern=%q text=%q", test.pattern, test.text)
   477  			pm, err := NewPatternMatcher([]string{test.pattern})
   478  			assert.NilError(t, err, desc)
   479  
   480  			check(pm, test.text, test.pass, desc)
   481  		}
   482  
   483  		for _, test := range multiPatternTests {
   484  			desc := fmt.Sprintf("pattern=%q text=%q", test.patterns, test.text)
   485  			pm, err := NewPatternMatcher(test.patterns)
   486  			assert.NilError(t, err, desc)
   487  
   488  			check(pm, test.text, test.pass, desc)
   489  		}
   490  	})
   491  
   492  }
   493  
   494  func TestCleanPatterns(t *testing.T) {
   495  	patterns := []string{"docs", "config"}
   496  	pm, err := NewPatternMatcher(patterns)
   497  	if err != nil {
   498  		t.Fatalf("invalid pattern %v", patterns)
   499  	}
   500  	cleaned := pm.Patterns()
   501  	if len(cleaned) != 2 {
   502  		t.Errorf("expected 2 element slice, got %v", len(cleaned))
   503  	}
   504  }
   505  
   506  func TestCleanPatternsStripEmptyPatterns(t *testing.T) {
   507  	patterns := []string{"docs", "config", ""}
   508  	pm, err := NewPatternMatcher(patterns)
   509  	if err != nil {
   510  		t.Fatalf("invalid pattern %v", patterns)
   511  	}
   512  	cleaned := pm.Patterns()
   513  	if len(cleaned) != 2 {
   514  		t.Errorf("expected 2 element slice, got %v", len(cleaned))
   515  	}
   516  }
   517  
   518  func TestCleanPatternsExceptionFlag(t *testing.T) {
   519  	patterns := []string{"docs", "!docs/README.md"}
   520  	pm, err := NewPatternMatcher(patterns)
   521  	if err != nil {
   522  		t.Fatalf("invalid pattern %v", patterns)
   523  	}
   524  	if !pm.Exclusions() {
   525  		t.Errorf("expected exceptions to be true, got %v", pm.Exclusions())
   526  	}
   527  }
   528  
   529  func TestCleanPatternsLeadingSpaceTrimmed(t *testing.T) {
   530  	patterns := []string{"docs", "  !docs/README.md"}
   531  	pm, err := NewPatternMatcher(patterns)
   532  	if err != nil {
   533  		t.Fatalf("invalid pattern %v", patterns)
   534  	}
   535  	if !pm.Exclusions() {
   536  		t.Errorf("expected exceptions to be true, got %v", pm.Exclusions())
   537  	}
   538  }
   539  
   540  func TestCleanPatternsTrailingSpaceTrimmed(t *testing.T) {
   541  	patterns := []string{"docs", "!docs/README.md  "}
   542  	pm, err := NewPatternMatcher(patterns)
   543  	if err != nil {
   544  		t.Fatalf("invalid pattern %v", patterns)
   545  	}
   546  	if !pm.Exclusions() {
   547  		t.Errorf("expected exceptions to be true, got %v", pm.Exclusions())
   548  	}
   549  }
   550  
   551  func TestCleanPatternsErrorSingleException(t *testing.T) {
   552  	patterns := []string{"!"}
   553  	_, err := NewPatternMatcher(patterns)
   554  	if err == nil {
   555  		t.Errorf("expected error on single exclamation point, got %v", err)
   556  	}
   557  }
   558  
   559  func TestCreateIfNotExistsDir(t *testing.T) {
   560  	tempFolder, err := os.MkdirTemp("", "docker-fileutils-test")
   561  	if err != nil {
   562  		t.Fatal(err)
   563  	}
   564  	defer os.RemoveAll(tempFolder)
   565  
   566  	folderToCreate := filepath.Join(tempFolder, "tocreate")
   567  
   568  	if err := CreateIfNotExists(folderToCreate, true); err != nil {
   569  		t.Fatal(err)
   570  	}
   571  	fileinfo, err := os.Stat(folderToCreate)
   572  	if err != nil {
   573  		t.Fatalf("Should have create a folder, got %v", err)
   574  	}
   575  
   576  	if !fileinfo.IsDir() {
   577  		t.Fatalf("Should have been a dir, seems it's not")
   578  	}
   579  }
   580  
   581  func TestCreateIfNotExistsFile(t *testing.T) {
   582  	tempFolder, err := os.MkdirTemp("", "docker-fileutils-test")
   583  	if err != nil {
   584  		t.Fatal(err)
   585  	}
   586  	defer os.RemoveAll(tempFolder)
   587  
   588  	fileToCreate := filepath.Join(tempFolder, "file/to/create")
   589  
   590  	if err := CreateIfNotExists(fileToCreate, false); err != nil {
   591  		t.Fatal(err)
   592  	}
   593  	fileinfo, err := os.Stat(fileToCreate)
   594  	if err != nil {
   595  		t.Fatalf("Should have create a file, got %v", err)
   596  	}
   597  
   598  	if fileinfo.IsDir() {
   599  		t.Fatalf("Should have been a file, seems it's not")
   600  	}
   601  }
   602  
   603  // These matchTests are stolen from go's filepath Match tests.
   604  type matchTest struct {
   605  	pattern, s string
   606  	match      bool
   607  	err        error
   608  }
   609  
   610  var matchTests = []matchTest{
   611  	{"abc", "abc", true, nil},
   612  	{"*", "abc", true, nil},
   613  	{"*c", "abc", true, nil},
   614  	{"a*", "a", true, nil},
   615  	{"a*", "abc", true, nil},
   616  	{"a*", "ab/c", true, nil},
   617  	{"a*/b", "abc/b", true, nil},
   618  	{"a*/b", "a/c/b", false, nil},
   619  	{"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
   620  	{"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
   621  	{"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
   622  	{"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
   623  	{"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
   624  	{"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
   625  	{"ab[c]", "abc", true, nil},
   626  	{"ab[b-d]", "abc", true, nil},
   627  	{"ab[e-g]", "abc", false, nil},
   628  	{"ab[^c]", "abc", false, nil},
   629  	{"ab[^b-d]", "abc", false, nil},
   630  	{"ab[^e-g]", "abc", true, nil},
   631  	{"a\\*b", "a*b", true, nil},
   632  	{"a\\*b", "ab", false, nil},
   633  	{"a?b", "a☺b", true, nil},
   634  	{"a[^a]b", "a☺b", true, nil},
   635  	{"a???b", "a☺b", false, nil},
   636  	{"a[^a][^a][^a]b", "a☺b", false, nil},
   637  	{"[a-ζ]*", "α", true, nil},
   638  	{"*[a-ζ]", "A", false, nil},
   639  	{"a?b", "a/b", false, nil},
   640  	{"a*b", "a/b", false, nil},
   641  	{"[\\]a]", "]", true, nil},
   642  	{"[\\-]", "-", true, nil},
   643  	{"[x\\-]", "x", true, nil},
   644  	{"[x\\-]", "-", true, nil},
   645  	{"[x\\-]", "z", false, nil},
   646  	{"[\\-x]", "x", true, nil},
   647  	{"[\\-x]", "-", true, nil},
   648  	{"[\\-x]", "a", false, nil},
   649  	{"[]a]", "]", false, filepath.ErrBadPattern},
   650  	{"[-]", "-", false, filepath.ErrBadPattern},
   651  	{"[x-]", "x", false, filepath.ErrBadPattern},
   652  	{"[x-]", "-", false, filepath.ErrBadPattern},
   653  	{"[x-]", "z", false, filepath.ErrBadPattern},
   654  	{"[-x]", "x", false, filepath.ErrBadPattern},
   655  	{"[-x]", "-", false, filepath.ErrBadPattern},
   656  	{"[-x]", "a", false, filepath.ErrBadPattern},
   657  	{"\\", "a", false, filepath.ErrBadPattern},
   658  	{"[a-b-c]", "a", false, filepath.ErrBadPattern},
   659  	{"[", "a", false, filepath.ErrBadPattern},
   660  	{"[^", "a", false, filepath.ErrBadPattern},
   661  	{"[^bc", "a", false, filepath.ErrBadPattern},
   662  	{"a[", "a", false, filepath.ErrBadPattern}, // was nil but IMO its wrong
   663  	{"a[", "ab", false, filepath.ErrBadPattern},
   664  	{"*x", "xxx", true, nil},
   665  }
   666  
   667  func errp(e error) string {
   668  	if e == nil {
   669  		return "<nil>"
   670  	}
   671  	return e.Error()
   672  }
   673  
   674  // TestMatch test's our version of filepath.Match, called regexpMatch.
   675  func TestMatch(t *testing.T) {
   676  	for _, tt := range matchTests {
   677  		pattern := tt.pattern
   678  		s := tt.s
   679  		if runtime.GOOS == "windows" {
   680  			if strings.Contains(pattern, "\\") {
   681  				// no escape allowed on windows.
   682  				continue
   683  			}
   684  			pattern = filepath.Clean(pattern)
   685  			s = filepath.Clean(s)
   686  		}
   687  		ok, err := Matches(s, []string{pattern})
   688  		if ok != tt.match || err != tt.err {
   689  			t.Fatalf("Match(%#q, %#q) = %v, %q want %v, %q", pattern, s, ok, errp(err), tt.match, errp(tt.err))
   690  		}
   691  	}
   692  }