1//go:build windows 2// +build windows 3 4package file 5 6import ( 7 "fmt" 8 "os" 9 "path/filepath" 10 "testing" 11 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14) 15 16// Basic test from golang's os/path_test.go 17func TestMkdirAll(t *testing.T) { 18 tmpDir, tidy := testDir(t) 19 defer tidy() 20 21 path := tmpDir + "/dir/./dir2" 22 err := MkdirAll(path, 0777) 23 if err != nil { 24 t.Fatalf("MkdirAll %q: %s", path, err) 25 } 26 27 // Already exists, should succeed. 28 err = MkdirAll(path, 0777) 29 if err != nil { 30 t.Fatalf("MkdirAll %q (second time): %s", path, err) 31 } 32 33 // Make file. 34 fpath := path + "/file" 35 f, err := Create(fpath) 36 if err != nil { 37 t.Fatalf("create %q: %s", fpath, err) 38 } 39 defer f.Close() 40 41 // Can't make directory named after file. 42 err = MkdirAll(fpath, 0777) 43 if err == nil { 44 t.Fatalf("MkdirAll %q: no error", fpath) 45 } 46 perr, ok := err.(*os.PathError) 47 if !ok { 48 t.Fatalf("MkdirAll %q returned %T, not *PathError", fpath, err) 49 } 50 if filepath.Clean(perr.Path) != filepath.Clean(fpath) { 51 t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, filepath.Clean(perr.Path), filepath.Clean(fpath)) 52 } 53 54 // Can't make subdirectory of file. 55 ffpath := fpath + "/subdir" 56 err = MkdirAll(ffpath, 0777) 57 if err == nil { 58 t.Fatalf("MkdirAll %q: no error", ffpath) 59 } 60 perr, ok = err.(*os.PathError) 61 if !ok { 62 t.Fatalf("MkdirAll %q returned %T, not *PathError", ffpath, err) 63 } 64 if filepath.Clean(perr.Path) != filepath.Clean(fpath) { 65 t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, filepath.Clean(perr.Path), filepath.Clean(fpath)) 66 } 67 68 path = tmpDir + `\dir\.\dir2\` 69 err = MkdirAll(path, 0777) 70 if err != nil { 71 t.Fatalf("MkdirAll %q: %s", path, err) 72 } 73} 74 75func unusedDrive(t *testing.T) string { 76 letter := FindUnusedDriveLetter() 77 require.NotEqual(t, letter, 0) 78 return string(letter) + ":" 79} 80 81func checkMkdirAll(t *testing.T, path string, valid bool, errormsg string) { 82 if valid { 83 assert.NoError(t, MkdirAll(path, 0777)) 84 } else { 85 err := MkdirAll(path, 0777) 86 assert.Error(t, err) 87 assert.Equal(t, errormsg, err.Error()) 88 } 89} 90 91func checkMkdirAllSubdirs(t *testing.T, path string, valid bool, errormsg string) { 92 checkMkdirAll(t, path, valid, errormsg) 93 checkMkdirAll(t, path+`\`, valid, errormsg) 94 checkMkdirAll(t, path+`\parent`, valid, errormsg) 95 checkMkdirAll(t, path+`\parent\`, valid, errormsg) 96 checkMkdirAll(t, path+`\parent\child`, valid, errormsg) 97 checkMkdirAll(t, path+`\parent\child\`, valid, errormsg) 98} 99 100// Testing paths on existing drive 101func TestMkdirAllOnDrive(t *testing.T) { 102 path, tidy := testDir(t) 103 defer tidy() 104 105 dir, err := os.Stat(path) 106 require.NoError(t, err) 107 require.True(t, dir.IsDir()) 108 109 drive := filepath.VolumeName(path) 110 111 checkMkdirAll(t, drive, true, "") 112 checkMkdirAll(t, drive+`\`, true, "") 113 checkMkdirAll(t, `\\?\`+drive, true, "") 114 checkMkdirAll(t, `\\?\`+drive+`\`, true, "") 115 checkMkdirAllSubdirs(t, path, true, "") 116 checkMkdirAllSubdirs(t, `\\?\`+path, true, "") 117} 118 119// Testing paths on unused drive 120// This is where there is a difference from golang's os.MkdirAll. It would 121// recurse extended-length paths down to the "\\?" prefix and return the 122// noninformative error: 123// "mkdir \\?: The filename, directory name, or volume label syntax is incorrect." 124// Our version stops the recursion at drive's root directory, and reports: 125// "mkdir \\?\A:\: The system cannot find the path specified." 126func TestMkdirAllOnUnusedDrive(t *testing.T) { 127 path := unusedDrive(t) 128 errormsg := fmt.Sprintf("mkdir %s\\: The system cannot find the path specified.", path) 129 checkMkdirAllSubdirs(t, path, false, errormsg) 130 errormsg = fmt.Sprintf("mkdir \\\\?\\%s\\: The system cannot find the path specified.", path) 131 checkMkdirAllSubdirs(t, `\\?\`+path, false, errormsg) 132} 133