1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package path
20
21 import (
22 "fmt"
23 "reflect"
24 "runtime"
25 "testing"
26 )
27
28 func testEachOS(t *testing.T, list []OS, fn func(t *testing.T, os OS)) {
29 for _, os := range list {
30 t.Run(fmt.Sprintf("OS=%s", os), func(t *testing.T) {
31 fn(t, os)
32 })
33 }
34 }
35
36 type PathTest struct {
37 path, result string
38 }
39
40 var cleantests = []PathTest{
41
42 {"abc", "abc"},
43 {"abc/def", "abc/def"},
44 {"a/b/c", "a/b/c"},
45 {".", "."},
46 {"..", ".."},
47 {"../..", "../.."},
48 {"../../abc", "../../abc"},
49 {"/abc", "/abc"},
50 {"/", "/"},
51
52
53 {"", "."},
54
55
56 {"abc/", "abc"},
57 {"abc/def/", "abc/def"},
58 {"a/b/c/", "a/b/c"},
59 {"./", "."},
60 {"../", ".."},
61 {"../../", "../.."},
62 {"/abc/", "/abc"},
63
64
65 {"abc//def//ghi", "abc/def/ghi"},
66 {"//abc", "/abc"},
67 {"///abc", "/abc"},
68 {"//abc//", "/abc"},
69 {"abc//", "abc"},
70
71
72 {"abc/./def", "abc/def"},
73 {"/./abc/def", "/abc/def"},
74 {"abc/.", "abc"},
75
76
77 {"abc/def/ghi/../jkl", "abc/def/jkl"},
78 {"abc/def/../ghi/../jkl", "abc/jkl"},
79 {"abc/def/..", "abc"},
80 {"abc/def/../..", "."},
81 {"/abc/def/../..", "/"},
82 {"abc/def/../../..", ".."},
83 {"/abc/def/../../..", "/"},
84 {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
85 {"/../abc", "/abc"},
86
87
88 {"abc/./../def", "def"},
89 {"abc//./../def", "def"},
90 {"abc/../../././../def", "../../def"},
91 }
92
93 var wincleantests = []PathTest{
94 {`c:`, `c:.`},
95 {`c:\`, `c:\`},
96 {`c:\abc`, `c:\abc`},
97 {`c:abc\..\..\.\.\..\def`, `c:..\..\def`},
98 {`c:\abc\def\..\..`, `c:\`},
99 {`c:\..\abc`, `c:\abc`},
100 {`c:..\abc`, `c:..\abc`},
101 {`\`, `\`},
102 {`/`, `\`},
103 {`\\i\..\c$`, `\c$`},
104 {`\\i\..\i\c$`, `\i\c$`},
105 {`\\i\..\I\c$`, `\I\c$`},
106 {`\\host\share\foo\..\bar`, `\\host\share\bar`},
107 {`//host/share/foo/../baz`, `\\host\share\baz`},
108 {`\\a\b\..\c`, `\\a\b\c`},
109 {`\\a\b`, `\\a\b`},
110 }
111
112 func TestClean(t *testing.T) {
113 testEachOS(t, []OS{Unix, Windows, Plan9}, func(t *testing.T, os OS) {
114 tests := append([]PathTest{}, cleantests...)
115 if os == Windows {
116 for i := range tests {
117 tests[i].result = FromSlash(tests[i].result, os)
118 }
119 tests = append(tests, wincleantests...)
120 }
121 for _, test := range tests {
122 if s := Clean(test.path, os); s != test.result {
123 t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)
124 }
125 if s := Clean(test.result, os); s != test.result {
126 t.Errorf("Clean(%q) = %q, want %q", test.result, s, test.result)
127 }
128 }
129
130 if testing.Short() {
131 t.Skip("skipping malloc count in short mode")
132 }
133 if runtime.GOMAXPROCS(0) > 1 {
134 t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1")
135 return
136 }
137
138 for _, test := range tests {
139 allocs := testing.AllocsPerRun(100, func() { Clean(test.result, os) })
140 if allocs > 0 {
141 t.Errorf("Clean(%q): %v allocs, want zero", test.result, allocs)
142 }
143 }
144 })
145 }
146
147 func TestFromAndToSlash(t *testing.T) {
148 for _, o := range []OS{Unix, Windows, Plan9} {
149 sep := getOS(o).Separator
150
151 var slashtests = []PathTest{
152 {"", ""},
153 {"/", string(sep)},
154 {"/a/b", string([]byte{sep, 'a', sep, 'b'})},
155 {"a//b", string([]byte{'a', sep, sep, 'b'})},
156 }
157
158 for _, test := range slashtests {
159 if s := FromSlash(test.path, o); s != test.result {
160 t.Errorf("FromSlash(%q) = %q, want %q", test.path, s, test.result)
161 }
162 if s := ToSlash(test.result, o); s != test.path {
163 t.Errorf("ToSlash(%q) = %q, want %q", test.result, s, test.path)
164 }
165 }
166 }
167 }
168
169 type SplitListTest struct {
170 list string
171 result []string
172 }
173
174 var winsplitlisttests = []SplitListTest{
175
176 {`"a"`, []string{`a`}},
177
178
179 {`";"`, []string{`;`}},
180 {`"a;b"`, []string{`a;b`}},
181 {`";";`, []string{`;`, ``}},
182 {`;";"`, []string{``, `;`}},
183
184
185 {`a";"b`, []string{`a;b`}},
186 {`a; ""b`, []string{`a`, ` b`}},
187 {`"a;b`, []string{`a;b`}},
188 {`""a;b`, []string{`a`, `b`}},
189 {`"""a;b`, []string{`a;b`}},
190 {`""""a;b`, []string{`a`, `b`}},
191 {`a";b`, []string{`a;b`}},
192 {`a;b";c`, []string{`a`, `b;c`}},
193 {`"a";b";c`, []string{`a`, `b;c`}},
194 }
195
196 func TestSplitList(t *testing.T) {
197 testEachOS(t, []OS{Unix, Windows, Plan9}, func(t *testing.T, os OS) {
198 sep := getOS(os).ListSeparator
199
200 tests := []SplitListTest{
201 {"", []string{}},
202 {string([]byte{'a', sep, 'b'}), []string{"a", "b"}},
203 {string([]byte{sep, 'a', sep, 'b'}), []string{"", "a", "b"}},
204 }
205 if os == Windows {
206 tests = append(tests, winsplitlisttests...)
207 }
208 for _, test := range tests {
209 if l := SplitList(test.list, os); !reflect.DeepEqual(l, test.result) {
210 t.Errorf("SplitList(%#q, %q) = %#q, want %#q", test.list, os, l, test.result)
211 }
212 }
213 })
214 }
215
216 type SplitTest struct {
217 path, dir, file string
218 }
219
220 var unixsplittests = []SplitTest{
221 {"a/b", "a/", "b"},
222 {"a/b/", "a/b/", ""},
223 {"a/", "a/", ""},
224 {"a", "", "a"},
225 {"/", "/", ""},
226 }
227
228 var winsplittests = []SplitTest{
229 {`c:`, `c:`, ``},
230 {`c:/`, `c:/`, ``},
231 {`c:/foo`, `c:/`, `foo`},
232 {`c:/foo/bar`, `c:/foo/`, `bar`},
233 {`//host/share`, `//host/share`, ``},
234 {`//host/share/`, `//host/share/`, ``},
235 {`//host/share/foo`, `//host/share/`, `foo`},
236 {`\\host\share`, `\\host\share`, ``},
237 {`\\host\share\`, `\\host\share\`, ``},
238 {`\\host\share\foo`, `\\host\share\`, `foo`},
239 }
240
241 func TestSplit(t *testing.T) {
242 testEachOS(t, []OS{Unix, Windows}, func(t *testing.T, os OS) {
243 tests := unixsplittests
244 if os == Windows {
245 tests = append(tests, winsplittests...)
246 }
247 for _, test := range tests {
248 pair := Split(test.path, os)
249 d, f := pair[0], pair[1]
250 if d != test.dir || f != test.file {
251 t.Errorf("Split(%q, %q) = %q, %q, want %q, %q",
252 test.path, os, d, f, test.dir, test.file)
253 }
254 }
255 })
256 }
257
258 type JoinTest struct {
259 elem []string
260 path string
261 }
262
263 var jointests = []JoinTest{
264
265 {[]string{}, ""},
266
267
268 {[]string{""}, ""},
269 {[]string{"/"}, "/"},
270 {[]string{"a"}, "a"},
271
272
273 {[]string{"a", "b"}, "a/b"},
274 {[]string{"a", ""}, "a"},
275 {[]string{"", "b"}, "b"},
276 {[]string{"/", "a"}, "/a"},
277 {[]string{"/", "a/b"}, "/a/b"},
278 {[]string{"/", ""}, "/"},
279 {[]string{"//", "a"}, "/a"},
280 {[]string{"/a", "b"}, "/a/b"},
281 {[]string{"a/", "b"}, "a/b"},
282 {[]string{"a/", ""}, "a"},
283 {[]string{"", ""}, ""},
284
285
286 {[]string{"/", "a", "b"}, "/a/b"},
287 }
288
289 var winjointests = []JoinTest{
290 {[]string{`directory`, `file`}, `directory\file`},
291 {[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`},
292 {[]string{`C:\Windows\`, ``}, `C:\Windows`},
293 {[]string{`C:\`, `Windows`}, `C:\Windows`},
294 {[]string{`C:`, `a`}, `C:a`},
295 {[]string{`C:`, `a\b`}, `C:a\b`},
296 {[]string{`C:`, `a`, `b`}, `C:a\b`},
297 {[]string{`C:`, ``, `b`}, `C:b`},
298 {[]string{`C:`, ``, ``, `b`}, `C:b`},
299 {[]string{`C:`, ``}, `C:.`},
300 {[]string{`C:`, ``, ``}, `C:.`},
301 {[]string{`C:.`, `a`}, `C:a`},
302 {[]string{`C:a`, `b`}, `C:a\b`},
303 {[]string{`C:a`, `b`, `d`}, `C:a\b\d`},
304 {[]string{`\\host\share`, `foo`}, `\\host\share\foo`},
305 {[]string{`\\host\share\foo`}, `\\host\share\foo`},
306 {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
307 {[]string{`\`}, `\`},
308 {[]string{`\`, ``}, `\`},
309 {[]string{`\`, `a`}, `\a`},
310 {[]string{`\\`, `a`}, `\a`},
311 {[]string{`\`, `a`, `b`}, `\a\b`},
312 {[]string{`\\`, `a`, `b`}, `\a\b`},
313 {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`},
314 {[]string{`\\a`, `b`, `c`}, `\a\b\c`},
315 {[]string{`\\a\`, `b`, `c`}, `\a\b\c`},
316 }
317
318 func TestJoin(t *testing.T) {
319 testEachOS(t, []OS{Unix, Windows}, func(t *testing.T, os OS) {
320 tests := jointests
321 if os == Windows {
322 tests = append(tests, winjointests...)
323 }
324 for _, test := range tests {
325 expected := FromSlash(test.path, os)
326 if p := Join(test.elem, os); p != expected {
327 t.Errorf("join(%q, %q) = %q, want %q", test.elem, os, p, expected)
328 }
329 }
330 })
331 }
332
333 type ExtTest struct {
334 path, ext string
335 }
336
337 var exttests = []ExtTest{
338 {"path.go", ".go"},
339 {"path.pb.go", ".go"},
340 {"a.dir/b", ""},
341 {"a.dir/b.go", ".go"},
342 {"a.dir/", ""},
343 }
344
345 func TestExt(t *testing.T) {
346 testEachOS(t, []OS{Unix, Windows}, func(t *testing.T, os OS) {
347 for _, test := range exttests {
348 if x := Ext(test.path, os); x != test.ext {
349 t.Errorf("Ext(%q, %q) = %q, want %q", test.path, os, x, test.ext)
350 }
351 }
352 })
353 }
354
355 var basetests = []PathTest{
356 {"", "."},
357 {".", "."},
358 {"/.", "."},
359 {"/", "/"},
360 {"////", "/"},
361 {"x/", "x"},
362 {"abc", "abc"},
363 {"abc/def", "def"},
364 {"a/b/.x", ".x"},
365 {"a/b/c.", "c."},
366 {"a/b/c.x", "c.x"},
367 }
368
369 var winbasetests = []PathTest{
370 {`c:\`, `\`},
371 {`c:.`, `.`},
372 {`c:\a\b`, `b`},
373 {`c:a\b`, `b`},
374 {`c:a\b\c`, `c`},
375 {`\\host\share\`, `\`},
376 {`\\host\share\a`, `a`},
377 {`\\host\share\a\b`, `b`},
378 }
379
380 func TestBase(t *testing.T) {
381 tests := basetests
382 testEachOS(t, []OS{Unix, Windows}, func(t *testing.T, os OS) {
383 if os == Windows {
384
385 for i := range tests {
386 tests[i].result = Clean(tests[i].result, os)
387 }
388
389 tests = append(tests, winbasetests...)
390 }
391 for _, test := range tests {
392 if s := Base(test.path, os); s != test.result {
393 t.Errorf("Base(%q, %q) = %q, want %q", test.path, os, s, test.result)
394 }
395 }
396 })
397 }
398
399 var dirtests = []PathTest{
400 {"", "."},
401 {".", "."},
402 {"/.", "/"},
403 {"/", "/"},
404 {"////", "/"},
405 {"/foo", "/"},
406 {"x/", "x"},
407 {"abc", "."},
408 {"abc/def", "abc"},
409 {"a/b/.x", "a/b"},
410 {"a/b/c.", "a/b"},
411 {"a/b/c.x", "a/b"},
412 }
413
414 var windirtests = []PathTest{
415 {`c:\`, `c:\`},
416 {`c:.`, `c:.`},
417 {`c:\a\b`, `c:\a`},
418 {`c:a\b`, `c:a`},
419 {`c:a\b\c`, `c:a\b`},
420 {`\\host\share`, `\\host\share`},
421 {`\\host\share\`, `\\host\share\`},
422 {`\\host\share\a`, `\\host\share\`},
423 {`\\host\share\a\b`, `\\host\share\a`},
424 }
425
426 func TestDir(t *testing.T) {
427 testEachOS(t, []OS{Unix, Windows}, func(t *testing.T, os OS) {
428 tests := dirtests
429 if os == Windows {
430
431 for i := range tests {
432 tests[i].result = Clean(tests[i].result, os)
433 }
434
435 tests = append(tests, windirtests...)
436 }
437 for _, test := range tests {
438 if s := Dir(test.path, os); s != test.result {
439 t.Errorf("Dir(%q, %q) = %q, want %q", test.path, os, s, test.result)
440 }
441 }
442 })
443 }
444
445 type IsAbsTest struct {
446 path string
447 isAbs bool
448 }
449
450 var isabstests = []IsAbsTest{
451 {"", false},
452 {"/", true},
453 {"/usr/bin/gcc", true},
454 {"..", false},
455 {"/a/../bb", true},
456 {".", false},
457 {"./", false},
458 {"lala", false},
459 }
460
461 var winisabstests = []IsAbsTest{
462 {`C:\`, true},
463 {`c\`, false},
464 {`c::`, false},
465 {`c:`, false},
466 {`/`, false},
467 {`\`, false},
468 {`\Windows`, false},
469 {`c:a\b`, false},
470 {`c:\a\b`, true},
471 {`c:/a/b`, true},
472 {`\\host\share\foo`, true},
473 {`//host/share/foo/bar`, true},
474 }
475
476 func TestIsAbs(t *testing.T) {
477 testEachOS(t, []OS{Unix, Windows}, func(t *testing.T, os OS) {
478 var tests []IsAbsTest
479 if os == Windows {
480 tests = append(tests, winisabstests...)
481
482 for _, test := range isabstests {
483 tests = append(tests, IsAbsTest{test.path, false})
484 }
485
486 for _, test := range isabstests {
487 tests = append(tests, IsAbsTest{"c:" + test.path, test.isAbs})
488 }
489
490
491 tests = append(tests, IsAbsTest{"NUL", true})
492 tests = append(tests, IsAbsTest{"nul", true})
493 tests = append(tests, IsAbsTest{"CON", true})
494 } else {
495 tests = isabstests
496 }
497
498 for _, test := range tests {
499 if r := IsAbs(test.path, os); r != test.isAbs {
500 t.Errorf("IsAbs(%q, %q) = %v, want %v", test.path, os, r, test.isAbs)
501 }
502 }
503 })
504 }
505
506 type RelTests struct {
507 root, path, want string
508 }
509
510 var reltests = []RelTests{
511 {"a/b", "a/b", "."},
512 {"a/b/.", "a/b", "."},
513 {"a/b", "a/b/.", "."},
514 {"./a/b", "a/b", "."},
515 {"a/b", "./a/b", "."},
516 {"ab/cd", "ab/cde", "../cde"},
517 {"ab/cd", "ab/c", "../c"},
518 {"a/b", "a/b/c/d", "c/d"},
519 {"a/b", "a/b/../c", "../c"},
520 {"a/b/../c", "a/b", "../b"},
521 {"a/b/c", "a/c/d", "../../c/d"},
522 {"a/b", "c/d", "../../c/d"},
523 {"a/b/c/d", "a/b", "../.."},
524 {"a/b/c/d", "a/b/", "../.."},
525 {"a/b/c/d/", "a/b", "../.."},
526 {"a/b/c/d/", "a/b/", "../.."},
527 {"../../a/b", "../../a/b/c/d", "c/d"},
528 {"/a/b", "/a/b", "."},
529 {"/a/b/.", "/a/b", "."},
530 {"/a/b", "/a/b/.", "."},
531 {"/ab/cd", "/ab/cde", "../cde"},
532 {"/ab/cd", "/ab/c", "../c"},
533 {"/a/b", "/a/b/c/d", "c/d"},
534 {"/a/b", "/a/b/../c", "../c"},
535 {"/a/b/../c", "/a/b", "../b"},
536 {"/a/b/c", "/a/c/d", "../../c/d"},
537 {"/a/b", "/c/d", "../../c/d"},
538 {"/a/b/c/d", "/a/b", "../.."},
539 {"/a/b/c/d", "/a/b/", "../.."},
540 {"/a/b/c/d/", "/a/b", "../.."},
541 {"/a/b/c/d/", "/a/b/", "../.."},
542 {"/../../a/b", "/../../a/b/c/d", "c/d"},
543 {".", "a/b", "a/b"},
544 {".", "..", ".."},
545
546
547 {"..", ".", "err"},
548 {"..", "a", "err"},
549 {"../..", "..", "err"},
550 {"a", "/a", "err"},
551 {"/a", "a", "err"},
552 }
553
554 var winreltests = []RelTests{
555 {`C:a\b\c`, `C:a/b/d`, `..\d`},
556 {`C:\`, `D:\`, `err`},
557 {`C:`, `D:`, `err`},
558 {`C:\Projects`, `c:\projects\src`, `src`},
559 {`C:\Projects`, `c:\projects`, `.`},
560 {`C:\Projects\a\..`, `c:\projects`, `.`},
561 }
562
563 func TestRel(t *testing.T) {
564 testEachOS(t, []OS{Unix, Windows}, func(t *testing.T, os OS) {
565 tests := append([]RelTests{}, reltests...)
566 if os == Windows {
567 for i := range tests {
568 tests[i].want = FromSlash(tests[i].want, Windows)
569 }
570 tests = append(tests, winreltests...)
571 }
572 for _, test := range tests {
573 got, err := Rel(test.root, test.path, os)
574 if test.want == "err" {
575 if err == nil {
576 t.Errorf("Rel(%q, %q, %q)=%q, want error", test.root, test.path, os, got)
577 }
578 continue
579 }
580 if err != nil {
581 t.Errorf("Rel(%q, %q, %q): want %q, got error: %s", test.root, test.path, os, test.want, err)
582 }
583 if got != test.want {
584 t.Errorf("Rel(%q, %q, %q)=%q, want %q", test.root, test.path, os, got, test.want)
585 }
586 }
587 })
588 }
589
590 type VolumeNameTest struct {
591 path string
592 vol string
593 }
594
595 var volumenametests = []VolumeNameTest{
596 {`c:/foo/bar`, `c:`},
597 {`c:`, `c:`},
598 {`2:`, ``},
599 {``, ``},
600 {`\\\host`, ``},
601 {`\\\host\`, ``},
602 {`\\\host\share`, ``},
603 {`\\\host\\share`, ``},
604 {`\\host`, ``},
605 {`//host`, ``},
606 {`\\host\`, ``},
607 {`//host/`, ``},
608 {`\\host\share`, `\\host\share`},
609 {`//host/share`, `//host/share`},
610 {`\\host\share\`, `\\host\share`},
611 {`//host/share/`, `//host/share`},
612 {`\\host\share\foo`, `\\host\share`},
613 {`//host/share/foo`, `//host/share`},
614 {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`},
615 {`//host/share//foo///bar////baz`, `//host/share`},
616 {`\\host\share\foo\..\bar`, `\\host\share`},
617 {`//host/share/foo/../bar`, `//host/share`},
618 }
619
620 func TestVolumeName(t *testing.T) {
621 os := Windows
622 for _, v := range volumenametests {
623 if vol := VolumeName(v.path, os); vol != v.vol {
624 t.Errorf("VolumeName(%q, %q)=%q, want %q", v.path, os, vol, v.vol)
625 }
626 }
627 }
628
View as plain text