1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package path_test
6
7import (
8	. "path"
9	"runtime"
10	"testing"
11)
12
13type PathTest struct {
14	path, result string
15}
16
17var cleantests = []PathTest{
18	// Already clean
19	{"", "."},
20	{"abc", "abc"},
21	{"abc/def", "abc/def"},
22	{"a/b/c", "a/b/c"},
23	{".", "."},
24	{"..", ".."},
25	{"../..", "../.."},
26	{"../../abc", "../../abc"},
27	{"/abc", "/abc"},
28	{"/", "/"},
29
30	// Remove trailing slash
31	{"abc/", "abc"},
32	{"abc/def/", "abc/def"},
33	{"a/b/c/", "a/b/c"},
34	{"./", "."},
35	{"../", ".."},
36	{"../../", "../.."},
37	{"/abc/", "/abc"},
38
39	// Remove doubled slash
40	{"abc//def//ghi", "abc/def/ghi"},
41	{"//abc", "/abc"},
42	{"///abc", "/abc"},
43	{"//abc//", "/abc"},
44	{"abc//", "abc"},
45
46	// Remove . elements
47	{"abc/./def", "abc/def"},
48	{"/./abc/def", "/abc/def"},
49	{"abc/.", "abc"},
50
51	// Remove .. elements
52	{"abc/def/ghi/../jkl", "abc/def/jkl"},
53	{"abc/def/../ghi/../jkl", "abc/jkl"},
54	{"abc/def/..", "abc"},
55	{"abc/def/../..", "."},
56	{"/abc/def/../..", "/"},
57	{"abc/def/../../..", ".."},
58	{"/abc/def/../../..", "/"},
59	{"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
60
61	// Combinations
62	{"abc/./../def", "def"},
63	{"abc//./../def", "def"},
64	{"abc/../../././../def", "../../def"},
65}
66
67func TestClean(t *testing.T) {
68	for _, test := range cleantests {
69		if s := Clean(test.path); s != test.result {
70			t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)
71		}
72		if s := Clean(test.result); s != test.result {
73			t.Errorf("Clean(%q) = %q, want %q", test.result, s, test.result)
74		}
75	}
76}
77
78func TestCleanMallocs(t *testing.T) {
79	if testing.Short() {
80		t.Skip("skipping malloc count in short mode")
81	}
82	if runtime.GOMAXPROCS(0) > 1 {
83		t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1")
84		return
85	}
86
87	for _, test := range cleantests {
88		allocs := testing.AllocsPerRun(100, func() { Clean(test.result) })
89		if allocs > 0 {
90			t.Errorf("Clean(%q): %v allocs, want zero", test.result, allocs)
91		}
92	}
93}
94
95type SplitTest struct {
96	path, dir, file string
97}
98
99var splittests = []SplitTest{
100	{"a/b", "a/", "b"},
101	{"a/b/", "a/b/", ""},
102	{"a/", "a/", ""},
103	{"a", "", "a"},
104	{"/", "/", ""},
105}
106
107func TestSplit(t *testing.T) {
108	for _, test := range splittests {
109		if d, f := Split(test.path); d != test.dir || f != test.file {
110			t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
111		}
112	}
113}
114
115type JoinTest struct {
116	elem []string
117	path string
118}
119
120var jointests = []JoinTest{
121	// zero parameters
122	{[]string{}, ""},
123
124	// one parameter
125	{[]string{""}, ""},
126	{[]string{"a"}, "a"},
127
128	// two parameters
129	{[]string{"a", "b"}, "a/b"},
130	{[]string{"a", ""}, "a"},
131	{[]string{"", "b"}, "b"},
132	{[]string{"/", "a"}, "/a"},
133	{[]string{"/", ""}, "/"},
134	{[]string{"a/", "b"}, "a/b"},
135	{[]string{"a/", ""}, "a"},
136	{[]string{"", ""}, ""},
137}
138
139func TestJoin(t *testing.T) {
140	for _, test := range jointests {
141		if p := Join(test.elem...); p != test.path {
142			t.Errorf("Join(%q) = %q, want %q", test.elem, p, test.path)
143		}
144	}
145}
146
147type ExtTest struct {
148	path, ext string
149}
150
151var exttests = []ExtTest{
152	{"path.go", ".go"},
153	{"path.pb.go", ".go"},
154	{"a.dir/b", ""},
155	{"a.dir/b.go", ".go"},
156	{"a.dir/", ""},
157}
158
159func TestExt(t *testing.T) {
160	for _, test := range exttests {
161		if x := Ext(test.path); x != test.ext {
162			t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)
163		}
164	}
165}
166
167var basetests = []PathTest{
168	// Already clean
169	{"", "."},
170	{".", "."},
171	{"/.", "."},
172	{"/", "/"},
173	{"////", "/"},
174	{"x/", "x"},
175	{"abc", "abc"},
176	{"abc/def", "def"},
177	{"a/b/.x", ".x"},
178	{"a/b/c.", "c."},
179	{"a/b/c.x", "c.x"},
180}
181
182func TestBase(t *testing.T) {
183	for _, test := range basetests {
184		if s := Base(test.path); s != test.result {
185			t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
186		}
187	}
188}
189
190var dirtests = []PathTest{
191	{"", "."},
192	{".", "."},
193	{"/.", "/"},
194	{"/", "/"},
195	{"////", "/"},
196	{"/foo", "/"},
197	{"x/", "x"},
198	{"abc", "."},
199	{"abc/def", "abc"},
200	{"abc////def", "abc"},
201	{"a/b/.x", "a/b"},
202	{"a/b/c.", "a/b"},
203	{"a/b/c.x", "a/b"},
204}
205
206func TestDir(t *testing.T) {
207	for _, test := range dirtests {
208		if s := Dir(test.path); s != test.result {
209			t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result)
210		}
211	}
212}
213
214type IsAbsTest struct {
215	path  string
216	isAbs bool
217}
218
219var isAbsTests = []IsAbsTest{
220	{"", false},
221	{"/", true},
222	{"/usr/bin/gcc", true},
223	{"..", false},
224	{"/a/../bb", true},
225	{".", false},
226	{"./", false},
227	{"lala", false},
228}
229
230func TestIsAbs(t *testing.T) {
231	for _, test := range isAbsTests {
232		if r := IsAbs(test.path); r != test.isAbs {
233			t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
234		}
235	}
236}
237