1170 lines · 26.8 KB · Go
RawDownload
// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file. package filepath_test import (	"errors"	"io/ioutil"	"os"	"path/filepath"	"reflect"	"runtime"	"strings"	"testing") var supportsSymlinks = true type PathTest struct {	path, result string} var cleantests = []PathTest{	// Already clean	{"abc", "abc"},	{"abc/def", "abc/def"},	{"a/b/c", "a/b/c"},	{".", "."},	{"..", ".."},	{"../..", "../.."},	{"../../abc", "../../abc"},	{"/abc", "/abc"},	{"/", "/"}, 	// Empty is current dir	{"", "."}, 	// Remove trailing slash	{"abc/", "abc"},	{"abc/def/", "abc/def"},	{"a/b/c/", "a/b/c"},	{"./", "."},	{"../", ".."},	{"../../", "../.."},	{"/abc/", "/abc"}, 	// Remove doubled slash	{"abc//def//ghi", "abc/def/ghi"},	{"//abc", "/abc"},	{"///abc", "/abc"},	{"//abc//", "/abc"},	{"abc//", "abc"}, 	// Remove . elements	{"abc/./def", "abc/def"},	{"/./abc/def", "/abc/def"},	{"abc/.", "abc"}, 	// Remove .. elements	{"abc/def/ghi/../jkl", "abc/def/jkl"},	{"abc/def/../ghi/../jkl", "abc/jkl"},	{"abc/def/..", "abc"},	{"abc/def/../..", "."},	{"/abc/def/../..", "/"},	{"abc/def/../../..", ".."},	{"/abc/def/../../..", "/"},	{"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},	{"/../abc", "/abc"}, 	// Combinations	{"abc/./../def", "def"},	{"abc//./../def", "def"},	{"abc/../../././../def", "../../def"},} var wincleantests = []PathTest{	{`c:`, `c:.`},	{`c:\`, `c:\`},	{`c:\abc`, `c:\abc`},	{`c:abc\..\..\.\.\..\def`, `c:..\..\def`},	{`c:\abc\def\..\..`, `c:\`},	{`c:\..\abc`, `c:\abc`},	{`c:..\abc`, `c:..\abc`},	{`\`, `\`},	{`/`, `\`},	{`\\i\..\c$`, `\c$`},	{`\\i\..\i\c$`, `\i\c$`},	{`\\i\..\I\c$`, `\I\c$`},	{`\\host\share\foo\..\bar`, `\\host\share\bar`},	{`//host/share/foo/../baz`, `\\host\share\baz`},	{`\\a\b\..\c`, `\\a\b\c`},	{`\\a\b`, `\\a\b`},} func TestClean(t *testing.T) {	tests := cleantests	if runtime.GOOS == "windows" {		for i := range tests {			tests[i].result = filepath.FromSlash(tests[i].result)		}		tests = append(tests, wincleantests...)	}	for _, test := range tests {		if s := filepath.Clean(test.path); s != test.result {			t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)		}		if s := filepath.Clean(test.result); s != test.result {			t.Errorf("Clean(%q) = %q, want %q", test.result, s, test.result)		}	} 	if testing.Short() {		t.Skip("skipping malloc count in short mode")	}	if runtime.GOMAXPROCS(0) > 1 {		t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1")		return	} 	for _, test := range tests {		allocs := testing.AllocsPerRun(100, func() { filepath.Clean(test.result) })		if allocs > 0 {			t.Errorf("Clean(%q): %v allocs, want zero", test.result, allocs)		}	}} const sep = filepath.Separator var slashtests = []PathTest{	{"", ""},	{"/", string(sep)},	{"/a/b", string([]byte{sep, 'a', sep, 'b'})},	{"a//b", string([]byte{'a', sep, sep, 'b'})},} func TestFromAndToSlash(t *testing.T) {	for _, test := range slashtests {		if s := filepath.FromSlash(test.path); s != test.result {			t.Errorf("FromSlash(%q) = %q, want %q", test.path, s, test.result)		}		if s := filepath.ToSlash(test.result); s != test.path {			t.Errorf("ToSlash(%q) = %q, want %q", test.result, s, test.path)		}	}} type SplitListTest struct {	list   string	result []string} const lsep = filepath.ListSeparator var splitlisttests = []SplitListTest{	{"", []string{}},	{string([]byte{'a', lsep, 'b'}), []string{"a", "b"}},	{string([]byte{lsep, 'a', lsep, 'b'}), []string{"", "a", "b"}},} var winsplitlisttests = []SplitListTest{	// quoted	{`"a"`, []string{`a`}}, 	// semicolon	{`";"`, []string{`;`}},	{`"a;b"`, []string{`a;b`}},	{`";";`, []string{`;`, ``}},	{`;";"`, []string{``, `;`}}, 	// partially quoted	{`a";"b`, []string{`a;b`}},	{`a; ""b`, []string{`a`, ` b`}},	{`"a;b`, []string{`a;b`}},	{`""a;b`, []string{`a`, `b`}},	{`"""a;b`, []string{`a;b`}},	{`""""a;b`, []string{`a`, `b`}},	{`a";b`, []string{`a;b`}},	{`a;b";c`, []string{`a`, `b;c`}},	{`"a";b";c`, []string{`a`, `b;c`}},} func TestSplitList(t *testing.T) {	tests := splitlisttests	if runtime.GOOS == "windows" {		tests = append(tests, winsplitlisttests...)	}	for _, test := range tests {		if l := filepath.SplitList(test.list); !reflect.DeepEqual(l, test.result) {			t.Errorf("SplitList(%#q) = %#q, want %#q", test.list, l, test.result)		}	}} type SplitTest struct {	path, dir, file string} var unixsplittests = []SplitTest{	{"a/b", "a/", "b"},	{"a/b/", "a/b/", ""},	{"a/", "a/", ""},	{"a", "", "a"},	{"/", "/", ""},} var winsplittests = []SplitTest{	{`c:`, `c:`, ``},	{`c:/`, `c:/`, ``},	{`c:/foo`, `c:/`, `foo`},	{`c:/foo/bar`, `c:/foo/`, `bar`},	{`//host/share`, `//host/share`, ``},	{`//host/share/`, `//host/share/`, ``},	{`//host/share/foo`, `//host/share/`, `foo`},	{`\\host\share`, `\\host\share`, ``},	{`\\host\share\`, `\\host\share\`, ``},	{`\\host\share\foo`, `\\host\share\`, `foo`},} func TestSplit(t *testing.T) {	var splittests []SplitTest	splittests = unixsplittests	if runtime.GOOS == "windows" {		splittests = append(splittests, winsplittests...)	}	for _, test := range splittests {		if d, f := filepath.Split(test.path); d != test.dir || f != test.file {			t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)		}	}} type JoinTest struct {	elem []string	path string} var jointests = []JoinTest{	// zero parameters	{[]string{}, ""}, 	// one parameter	{[]string{""}, ""},	{[]string{"/"}, "/"},	{[]string{"a"}, "a"}, 	// two parameters	{[]string{"a", "b"}, "a/b"},	{[]string{"a", ""}, "a"},	{[]string{"", "b"}, "b"},	{[]string{"/", "a"}, "/a"},	{[]string{"/", "a/b"}, "/a/b"},	{[]string{"/", ""}, "/"},	{[]string{"//", "a"}, "/a"},	{[]string{"/a", "b"}, "/a/b"},	{[]string{"a/", "b"}, "a/b"},	{[]string{"a/", ""}, "a"},	{[]string{"", ""}, ""}, 	// three parameters	{[]string{"/", "a", "b"}, "/a/b"},} var winjointests = []JoinTest{	{[]string{`directory`, `file`}, `directory\file`},	{[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`},	{[]string{`C:\Windows\`, ``}, `C:\Windows`},	{[]string{`C:\`, `Windows`}, `C:\Windows`},	{[]string{`C:`, `a`}, `C:a`},	{[]string{`C:`, `a\b`}, `C:a\b`},	{[]string{`C:`, `a`, `b`}, `C:a\b`},	{[]string{`C:.`, `a`}, `C:a`},	{[]string{`C:a`, `b`}, `C:a\b`},	{[]string{`C:a`, `b`, `d`}, `C:a\b\d`},	{[]string{`\\host\share`, `foo`}, `\\host\share\foo`},	{[]string{`\\host\share\foo`}, `\\host\share\foo`},	{[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},	{[]string{`\`}, `\`},	{[]string{`\`, ``}, `\`},	{[]string{`\`, `a`}, `\a`},	{[]string{`\\`, `a`}, `\a`},	{[]string{`\`, `a`, `b`}, `\a\b`},	{[]string{`\\`, `a`, `b`}, `\a\b`},	{[]string{`\`, `\\a\b`, `c`}, `\a\b\c`},	{[]string{`\\a`, `b`, `c`}, `\a\b\c`},	{[]string{`\\a\`, `b`, `c`}, `\a\b\c`},} func TestJoin(t *testing.T) {	if runtime.GOOS == "windows" {		jointests = append(jointests, winjointests...)	}	for _, test := range jointests {		expected := filepath.FromSlash(test.path)		if p := filepath.Join(test.elem...); p != expected {			t.Errorf("join(%q) = %q, want %q", test.elem, p, expected)		}	}} type ExtTest struct {	path, ext string} var exttests = []ExtTest{	{"path.go", ".go"},	{"path.pb.go", ".go"},	{"a.dir/b", ""},	{"a.dir/b.go", ".go"},	{"a.dir/", ""},} func TestExt(t *testing.T) {	for _, test := range exttests {		if x := filepath.Ext(test.path); x != test.ext {			t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)		}	}} type Node struct {	name    string	entries []*Node // nil if the entry is a file	mark    int} var tree = &Node{	"testdata",	[]*Node{		{"a", nil, 0},		{"b", []*Node{}, 0},		{"c", nil, 0},		{			"d",			[]*Node{				{"x", nil, 0},				{"y", []*Node{}, 0},				{					"z",					[]*Node{						{"u", nil, 0},						{"v", nil, 0},					},					0,				},			},			0,		},	},	0,} func walkTree(n *Node, path string, f func(path string, n *Node)) {	f(path, n)	for _, e := range n.entries {		walkTree(e, filepath.Join(path, e.name), f)	}} func makeTree(t *testing.T) {	walkTree(tree, tree.name, func(path string, n *Node) {		if n.entries == nil {			fd, err := os.Create(path)			if err != nil {				t.Errorf("makeTree: %v", err)				return			}			fd.Close()		} else {			os.Mkdir(path, 0770)		}	})} func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) } func checkMarks(t *testing.T, report bool) {	walkTree(tree, tree.name, func(path string, n *Node) {		if n.mark != 1 && report {			t.Errorf("node %s mark = %d; expected 1", path, n.mark)		}		n.mark = 0	})} // Assumes that each node name is unique. Good enough for a test.// If clear is true, any incoming error is cleared before return. The errors// are always accumulated, though.func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error {	if err != nil {		*errors = append(*errors, err)		if clear {			return nil		}		return err	}	name := info.Name()	walkTree(tree, tree.name, func(path string, n *Node) {		if n.name == name {			n.mark++		}	})	return nil} func chtmpdir(t *testing.T) (restore func()) {	oldwd, err := os.Getwd()	if err != nil {		t.Fatalf("chtmpdir: %v", err)	}	d, err := ioutil.TempDir("", "test")	if err != nil {		t.Fatalf("chtmpdir: %v", err)	}	if err := os.Chdir(d); err != nil {		t.Fatalf("chtmpdir: %v", err)	}	return func() {		if err := os.Chdir(oldwd); err != nil {			t.Fatalf("chtmpdir: %v", err)		}		os.RemoveAll(d)	}} func TestWalk(t *testing.T) {	if runtime.GOOS == "darwin" {		switch runtime.GOARCH {		case "arm", "arm64":			restore := chtmpdir(t)			defer restore()		}	}	makeTree(t)	errors := make([]error, 0, 10)	clear := true	markFn := func(path string, info os.FileInfo, err error) error {		return mark(path, info, err, &errors, clear)	}	// Expect no errors.	err := filepath.Walk(tree.name, markFn)	if err != nil {		t.Fatalf("no error expected, found: %s", err)	}	if len(errors) != 0 {		t.Fatalf("unexpected errors: %s", errors)	}	checkMarks(t, true)	errors = errors[0:0] 	// Test permission errors.  Only possible if we're not root	// and only on some file systems (AFS, FAT).  To avoid errors during	// all.bash on those file systems, skip during go test -short.	if os.Getuid() > 0 && !testing.Short() {		// introduce 2 errors: chmod top-level directories to 0		os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0)		os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0) 		// 3) capture errors, expect two.		// mark respective subtrees manually		markTree(tree.entries[1])		markTree(tree.entries[3])		// correct double-marking of directory itself		tree.entries[1].mark--		tree.entries[3].mark--		err := filepath.Walk(tree.name, markFn)		if err != nil {			t.Fatalf("expected no error return from Walk, got %s", err)		}		if len(errors) != 2 {			t.Errorf("expected 2 errors, got %d: %s", len(errors), errors)		}		// the inaccessible subtrees were marked manually		checkMarks(t, true)		errors = errors[0:0] 		// 4) capture errors, stop after first error.		// mark respective subtrees manually		markTree(tree.entries[1])		markTree(tree.entries[3])		// correct double-marking of directory itself		tree.entries[1].mark--		tree.entries[3].mark--		clear = false // error will stop processing		err = filepath.Walk(tree.name, markFn)		if err == nil {			t.Fatalf("expected error return from Walk")		}		if len(errors) != 1 {			t.Errorf("expected 1 error, got %d: %s", len(errors), errors)		}		// the inaccessible subtrees were marked manually		checkMarks(t, false)		errors = errors[0:0] 		// restore permissions		os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770)		os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770)	}

Lines 1–500 of 1170.