Source file
src/os/path_windows_test.go
1
2
3
4
5 package os_test
6
7 import (
8 "fmt"
9 "internal/syscall/windows"
10 "internal/testenv"
11 "os"
12 "path/filepath"
13 "strings"
14 "syscall"
15 "testing"
16 )
17
18 func TestAddExtendedPrefix(t *testing.T) {
19
20
21
22 cwd, err := os.Getwd()
23 if err != nil {
24 t.Fatal("cannot get cwd")
25 }
26 drive := strings.ToLower(filepath.VolumeName(cwd))
27 cwd = strings.ToLower(cwd[len(drive)+1:])
28
29
30
31 veryLong := "l" + strings.Repeat("o", 500) + "ng"
32 for _, test := range []struct{ in, want string }{
33
34
35
36
37
38
39 {`C:\long\foo.txt`, `\\?\C:\long\foo.txt`},
40 {`C:/long/foo.txt`, `\\?\C:\long\foo.txt`},
41 {`C:\\\long///foo.txt`, `\\?\C:\long\foo.txt`},
42 {`C:\long\.\foo.txt`, `\\?\C:\long\foo.txt`},
43 {`C:\long\..\foo.txt`, `\\?\C:\foo.txt`},
44 {`C:\long\..\..\foo.txt`, `\\?\C:\foo.txt`},
45
46
47 {`C:long\foo.txt`, `\\?\C:\cwd\long\foo.txt`},
48 {`C:long/foo.txt`, `\\?\C:\cwd\long\foo.txt`},
49 {`C:long///foo.txt`, `\\?\C:\cwd\long\foo.txt`},
50 {`C:long\.\foo.txt`, `\\?\C:\cwd\long\foo.txt`},
51 {`C:long\..\foo.txt`, `\\?\C:\cwd\foo.txt`},
52
53
54 {`\long\foo.txt`, `\\?\C:\long\foo.txt`},
55 {`/long/foo.txt`, `\\?\C:\long\foo.txt`},
56 {`\long///foo.txt`, `\\?\C:\long\foo.txt`},
57 {`\long\.\foo.txt`, `\\?\C:\long\foo.txt`},
58 {`\long\..\foo.txt`, `\\?\C:\foo.txt`},
59
60
61 {`long\foo.txt`, `\\?\C:\cwd\long\foo.txt`},
62 {`long/foo.txt`, `\\?\C:\cwd\long\foo.txt`},
63 {`long///foo.txt`, `\\?\C:\cwd\long\foo.txt`},
64 {`long\.\foo.txt`, `\\?\C:\cwd\long\foo.txt`},
65 {`long\..\foo.txt`, `\\?\C:\cwd\foo.txt`},
66 {`.\long\foo.txt`, `\\?\C:\cwd\long\foo.txt`},
67
68
69 {`\\srv\share\long`, `\\?\UNC\srv\share\long`},
70 {`//srv/share/long`, `\\?\UNC\srv\share\long`},
71 {`/\srv/share/long`, `\\?\UNC\srv\share\long`},
72 {`\\srv\share\long\`, `\\?\UNC\srv\share\long\`},
73 {`\\srv\share\bar\.\long`, `\\?\UNC\srv\share\bar\long`},
74 {`\\srv\share\bar\..\long`, `\\?\UNC\srv\share\long`},
75 {`\\srv\share\bar\..\..\long`, `\\?\UNC\srv\share\long`},
76
77
78 {`\\.\C:\long\foo.txt`, `\\.\C:\long\foo.txt`},
79 {`//./C:/long/foo.txt`, `\\.\C:\long\foo.txt`},
80 {`/\./C:/long/foo.txt`, `\\.\C:\long\foo.txt`},
81 {`\\.\C:\long///foo.txt`, `\\.\C:\long\foo.txt`},
82 {`\\.\C:\long\.\foo.txt`, `\\.\C:\long\foo.txt`},
83 {`\\.\C:\long\..\foo.txt`, `\\.\C:\foo.txt`},
84
85
86 {`C:\short.txt`, `C:\short.txt`},
87 {`C:\`, `C:\`},
88 {`C:`, `C:`},
89 {`\\srv\path`, `\\srv\path`},
90 {`long.txt`, `\\?\C:\cwd\long.txt`},
91 {`C:long.txt`, `\\?\C:\cwd\long.txt`},
92 {`C:\long\.\bar\baz`, `\\?\C:\long\bar\baz`},
93 {`C:long\.\bar\baz`, `\\?\C:\cwd\long\bar\baz`},
94 {`C:\long\..\bar\baz`, `\\?\C:\bar\baz`},
95 {`C:long\..\bar\baz`, `\\?\C:\cwd\bar\baz`},
96 {`C:\long\foo\\bar\.\baz\\`, `\\?\C:\long\foo\bar\baz\`},
97 {`C:\long\..`, `\\?\C:\`},
98 {`C:\.\long\..\.`, `\\?\C:\`},
99 {`\\?\C:\long\foo.txt`, `\\?\C:\long\foo.txt`},
100 {`\\?\C:\long/foo.txt`, `\\?\C:\long/foo.txt`},
101 } {
102 in := strings.ReplaceAll(test.in, "long", veryLong)
103 in = strings.ToLower(in)
104 in = strings.ReplaceAll(in, "c:", drive)
105
106 want := strings.ReplaceAll(test.want, "long", veryLong)
107 want = strings.ToLower(want)
108 want = strings.ReplaceAll(want, "c:", drive)
109 want = strings.ReplaceAll(want, "cwd", cwd)
110
111 got := os.AddExtendedPrefix(in)
112 got = strings.ToLower(got)
113 if got != want {
114 in = strings.ReplaceAll(in, veryLong, "long")
115 got = strings.ReplaceAll(got, veryLong, "long")
116 want = strings.ReplaceAll(want, veryLong, "long")
117 t.Errorf("addExtendedPrefix(%#q) = %#q; want %#q", in, got, want)
118 }
119 }
120 }
121
122 func TestMkdirAllLongPath(t *testing.T) {
123 t.Parallel()
124
125 tmpDir := t.TempDir()
126 path := tmpDir
127 for i := 0; i < 100; i++ {
128 path += `\another-path-component`
129 }
130 if err := os.MkdirAll(path, 0777); err != nil {
131 t.Fatalf("MkdirAll(%q) failed; %v", path, err)
132 }
133 if err := os.RemoveAll(tmpDir); err != nil {
134 t.Fatalf("RemoveAll(%q) failed; %v", tmpDir, err)
135 }
136 }
137
138 func TestMkdirAllExtendedLength(t *testing.T) {
139 t.Parallel()
140 tmpDir := t.TempDir()
141
142 const prefix = `\\?\`
143 if len(tmpDir) < 4 || tmpDir[:4] != prefix {
144 fullPath, err := syscall.FullPath(tmpDir)
145 if err != nil {
146 t.Fatalf("FullPath(%q) fails: %v", tmpDir, err)
147 }
148 tmpDir = prefix + fullPath
149 }
150 path := tmpDir + `\dir\`
151 if err := os.MkdirAll(path, 0777); err != nil {
152 t.Fatalf("MkdirAll(%q) failed: %v", path, err)
153 }
154
155 path = path + `.\dir2`
156 if err := os.MkdirAll(path, 0777); err == nil {
157 t.Fatalf("MkdirAll(%q) should have failed, but did not", path)
158 }
159 }
160
161 func TestOpenRootSlash(t *testing.T) {
162 t.Parallel()
163
164 tests := []string{
165 `/`,
166 `\`,
167 }
168
169 for _, test := range tests {
170 dir, err := os.Open(test)
171 if err != nil {
172 t.Fatalf("Open(%q) failed: %v", test, err)
173 }
174 dir.Close()
175 }
176 }
177
178 func testMkdirAllAtRoot(t *testing.T, root string) {
179
180 base := fmt.Sprintf("%s-%d", t.Name(), os.Getpid())
181 path := filepath.Join(root, base)
182 if err := os.MkdirAll(path, 0777); err != nil {
183 t.Fatalf("MkdirAll(%q) failed: %v", path, err)
184 }
185
186 if err := os.RemoveAll(path); err != nil {
187 t.Fatal(err)
188 }
189 }
190
191 func TestMkdirAllExtendedLengthAtRoot(t *testing.T) {
192 if testenv.Builder() == "" {
193 t.Skipf("skipping non-hermetic test outside of Go builders")
194 }
195
196 const prefix = `\\?\`
197 vol := filepath.VolumeName(t.TempDir()) + `\`
198 if len(vol) < 4 || vol[:4] != prefix {
199 vol = prefix + vol
200 }
201 testMkdirAllAtRoot(t, vol)
202 }
203
204 func TestMkdirAllVolumeNameAtRoot(t *testing.T) {
205 if testenv.Builder() == "" {
206 t.Skipf("skipping non-hermetic test outside of Go builders")
207 }
208
209 vol, err := syscall.UTF16PtrFromString(filepath.VolumeName(t.TempDir()) + `\`)
210 if err != nil {
211 t.Fatal(err)
212 }
213 const maxVolNameLen = 50
214 var buf [maxVolNameLen]uint16
215 err = windows.GetVolumeNameForVolumeMountPoint(vol, &buf[0], maxVolNameLen)
216 if err != nil {
217 t.Fatal(err)
218 }
219 volName := syscall.UTF16ToString(buf[:])
220 testMkdirAllAtRoot(t, volName)
221 }
222
223 func TestRemoveAllLongPathRelative(t *testing.T) {
224
225
226 tmp := t.TempDir()
227 chdir(t, tmp)
228 dir := filepath.Join(tmp, "foo", "bar", strings.Repeat("a", 150), strings.Repeat("b", 150))
229 err := os.MkdirAll(dir, 0755)
230 if err != nil {
231 t.Fatal(err)
232 }
233 err = os.RemoveAll("foo")
234 if err != nil {
235 t.Fatal(err)
236 }
237 }
238
239 func testLongPathAbs(t *testing.T, target string) {
240 t.Helper()
241 testWalkFn := func(path string, info os.FileInfo, err error) error {
242 if err != nil {
243 t.Error(err)
244 }
245 return err
246 }
247 if err := os.MkdirAll(target, 0777); err != nil {
248 t.Fatal(err)
249 }
250
251
252 filepath.Walk(target, testWalkFn)
253
254
255 if err := os.RemoveAll(target); err != nil {
256 t.Error(err)
257 }
258 }
259
260 func TestLongPathAbs(t *testing.T) {
261 t.Parallel()
262
263 target := t.TempDir() + "\\" + strings.Repeat("a\\", 300)
264 testLongPathAbs(t, target)
265 }
266
267 func TestLongPathRel(t *testing.T) {
268 chdir(t, t.TempDir())
269
270 target := strings.Repeat("b\\", 300)
271 testLongPathAbs(t, target)
272 }
273
274 func BenchmarkAddExtendedPrefix(b *testing.B) {
275 veryLong := `C:\l` + strings.Repeat("o", 248) + "ng"
276 b.ReportAllocs()
277 for i := 0; i < b.N; i++ {
278 os.AddExtendedPrefix(veryLong)
279 }
280 }
281
View as plain text