path_test.go - hugo - [fork] hugo port for 9front
HTML git clone https://git.drkhsh.at/hugo.git
DIR Log
DIR Files
DIR Refs
DIR Submodules
DIR README
DIR LICENSE
---
path_test.go (9146B)
---
1 // Copyright 2024 The Hugo Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package paths
15
16 import (
17 "path/filepath"
18 "testing"
19
20 qt "github.com/frankban/quicktest"
21 )
22
23 func TestGetRelativePath(t *testing.T) {
24 tests := []struct {
25 path string
26 base string
27 expect any
28 }{
29 {filepath.FromSlash("/a/b"), filepath.FromSlash("/a"), filepath.FromSlash("b")},
30 {filepath.FromSlash("/a/b/c/"), filepath.FromSlash("/a"), filepath.FromSlash("b/c/")},
31 {filepath.FromSlash("/c"), filepath.FromSlash("/a/b"), filepath.FromSlash("../../c")},
32 {filepath.FromSlash("/c"), "", false},
33 }
34 for i, this := range tests {
35 // ultimately a fancy wrapper around filepath.Rel
36 result, err := GetRelativePath(this.path, this.base)
37
38 if b, ok := this.expect.(bool); ok && !b {
39 if err == nil {
40 t.Errorf("[%d] GetRelativePath didn't return an expected error", i)
41 }
42 } else {
43 if err != nil {
44 t.Errorf("[%d] GetRelativePath failed: %s", i, err)
45 continue
46 }
47 if result != this.expect {
48 t.Errorf("[%d] GetRelativePath got %v but expected %v", i, result, this.expect)
49 }
50 }
51
52 }
53 }
54
55 func TestMakePathRelative(t *testing.T) {
56 type test struct {
57 inPath, path1, path2, output string
58 }
59
60 data := []test{
61 {"/abc/bcd/ab.css", "/abc/bcd", "/bbc/bcd", "/ab.css"},
62 {"/abc/bcd/ab.css", "/abcd/bcd", "/abc/bcd", "/ab.css"},
63 }
64
65 for i, d := range data {
66 output, _ := makePathRelative(d.inPath, d.path1, d.path2)
67 if d.output != output {
68 t.Errorf("Test #%d failed. Expected %q got %q", i, d.output, output)
69 }
70 }
71 _, error := makePathRelative("a/b/c.ss", "/a/c", "/d/c", "/e/f")
72
73 if error == nil {
74 t.Errorf("Test failed, expected error")
75 }
76 }
77
78 func TestMakeTitle(t *testing.T) {
79 type test struct {
80 input, expected string
81 }
82 data := []test{
83 {"Make-Title", "Make Title"},
84 {"MakeTitle", "MakeTitle"},
85 {"make_title", "make_title"},
86 }
87 for i, d := range data {
88 output := MakeTitle(d.input)
89 if d.expected != output {
90 t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
91 }
92 }
93 }
94
95 // Replace Extension is probably poorly named, but the intent of the
96 // function is to accept a path and return only the file name with a
97 // new extension. It's intentionally designed to strip out the path
98 // and only provide the name. We should probably rename the function to
99 // be more explicit at some point.
100 func TestReplaceExtension(t *testing.T) {
101 type test struct {
102 input, newext, expected string
103 }
104 data := []test{
105 // These work according to the above definition
106 {"/some/random/path/file.xml", "html", "file.html"},
107 {"/banana.html", "xml", "banana.xml"},
108 {"./banana.html", "xml", "banana.xml"},
109 {"banana/pie/index.html", "xml", "index.xml"},
110 {"../pies/fish/index.html", "xml", "index.xml"},
111 // but these all fail
112 {"filename-without-an-ext", "ext", "filename-without-an-ext.ext"},
113 {"/filename-without-an-ext", "ext", "filename-without-an-ext.ext"},
114 {"/directory/mydir/", "ext", ".ext"},
115 {"mydir/", "ext", ".ext"},
116 }
117
118 for i, d := range data {
119 output := ReplaceExtension(filepath.FromSlash(d.input), d.newext)
120 if d.expected != output {
121 t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
122 }
123 }
124 }
125
126 func TestExtNoDelimiter(t *testing.T) {
127 c := qt.New(t)
128 c.Assert(ExtNoDelimiter(filepath.FromSlash("/my/data.json")), qt.Equals, "json")
129 }
130
131 func TestFilename(t *testing.T) {
132 type test struct {
133 input, expected string
134 }
135 data := []test{
136 {"index.html", "index"},
137 {"./index.html", "index"},
138 {"/index.html", "index"},
139 {"index", "index"},
140 {"/tmp/index.html", "index"},
141 {"./filename-no-ext", "filename-no-ext"},
142 {"/filename-no-ext", "filename-no-ext"},
143 {"filename-no-ext", "filename-no-ext"},
144 {"directory/", ""}, // no filename case??
145 {"directory/.hidden.ext", ".hidden"},
146 {"./directory/../~/banana/gold.fish", "gold"},
147 {"../directory/banana.man", "banana"},
148 {"~/mydir/filename.ext", "filename"},
149 {"./directory//tmp/filename.ext", "filename"},
150 }
151
152 for i, d := range data {
153 output := Filename(filepath.FromSlash(d.input))
154 if d.expected != output {
155 t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, output)
156 }
157 }
158 }
159
160 func TestFileAndExt(t *testing.T) {
161 type test struct {
162 input, expectedFile, expectedExt string
163 }
164 data := []test{
165 {"index.html", "index", ".html"},
166 {"./index.html", "index", ".html"},
167 {"/index.html", "index", ".html"},
168 {"index", "index", ""},
169 {"/tmp/index.html", "index", ".html"},
170 {"./filename-no-ext", "filename-no-ext", ""},
171 {"/filename-no-ext", "filename-no-ext", ""},
172 {"filename-no-ext", "filename-no-ext", ""},
173 {"directory/", "", ""}, // no filename case??
174 {"directory/.hidden.ext", ".hidden", ".ext"},
175 {"./directory/../~/banana/gold.fish", "gold", ".fish"},
176 {"../directory/banana.man", "banana", ".man"},
177 {"~/mydir/filename.ext", "filename", ".ext"},
178 {"./directory//tmp/filename.ext", "filename", ".ext"},
179 }
180
181 for i, d := range data {
182 file, ext := fileAndExt(filepath.FromSlash(d.input), fpb)
183 if d.expectedFile != file {
184 t.Errorf("Test %d failed. Expected filename %q got %q.", i, d.expectedFile, file)
185 }
186 if d.expectedExt != ext {
187 t.Errorf("Test %d failed. Expected extension %q got %q.", i, d.expectedExt, ext)
188 }
189 }
190 }
191
192 func TestSanitize(t *testing.T) {
193 c := qt.New(t)
194 tests := []struct {
195 input string
196 expected string
197 }{
198 {" Foo bar ", "Foo-bar"},
199 {"Foo.Bar/foo_Bar-Foo", "Foo.Bar/foo_Bar-Foo"},
200 {"fOO,bar:foobAR", "fOObarfoobAR"},
201 {"FOo/BaR.html", "FOo/BaR.html"},
202 {"FOo/Ba---R.html", "FOo/Ba---R.html"}, /// See #10104
203 {"FOo/Ba R.html", "FOo/Ba-R.html"},
204 {"трям/трям", "трям/трям"},
205 {"은행", "은행"},
206 {"Банковский кассир", "Банковский-кассир"},
207 // Issue #1488
208 {"संस्कृत", "संस्कृत"},
209 {"a%C3%B1ame", "a%C3%B1ame"}, // Issue #1292
210 {"this+is+a+test", "this+is+a+test"}, // Issue #1290
211 {"~foo", "~foo"}, // Issue #2177
212
213 }
214
215 for _, test := range tests {
216 c.Assert(Sanitize(test.input), qt.Equals, test.expected)
217 }
218 }
219
220 func BenchmarkSanitize(b *testing.B) {
221 const (
222 allAlowedPath = "foo/bar"
223 spacePath = "foo bar"
224 )
225
226 // This should not allocate any memory.
227 b.Run("All allowed", func(b *testing.B) {
228 for i := 0; i < b.N; i++ {
229 got := Sanitize(allAlowedPath)
230 if got != allAlowedPath {
231 b.Fatal(got)
232 }
233 }
234 })
235
236 // This will allocate some memory.
237 b.Run("Spaces", func(b *testing.B) {
238 for i := 0; i < b.N; i++ {
239 got := Sanitize(spacePath)
240 if got != "foo-bar" {
241 b.Fatal(got)
242 }
243 }
244 })
245 }
246
247 func TestDir(t *testing.T) {
248 c := qt.New(t)
249 c.Assert(Dir("/a/b/c/d"), qt.Equals, "/a/b/c")
250 c.Assert(Dir("/a"), qt.Equals, "/")
251 c.Assert(Dir("/"), qt.Equals, "/")
252 c.Assert(Dir(""), qt.Equals, "")
253 }
254
255 func TestFieldsSlash(t *testing.T) {
256 c := qt.New(t)
257
258 c.Assert(FieldsSlash("a/b/c"), qt.DeepEquals, []string{"a", "b", "c"})
259 c.Assert(FieldsSlash("/a/b/c"), qt.DeepEquals, []string{"a", "b", "c"})
260 c.Assert(FieldsSlash("/a/b/c/"), qt.DeepEquals, []string{"a", "b", "c"})
261 c.Assert(FieldsSlash("a/b/c/"), qt.DeepEquals, []string{"a", "b", "c"})
262 c.Assert(FieldsSlash("/"), qt.DeepEquals, []string{})
263 c.Assert(FieldsSlash(""), qt.DeepEquals, []string{})
264 }
265
266 func TestCommonDirPath(t *testing.T) {
267 c := qt.New(t)
268
269 for _, this := range []struct {
270 a, b, expected string
271 }{
272 {"/a/b/c", "/a/b/d", "/a/b"},
273 {"/a/b/c", "a/b/d", "/a/b"},
274 {"a/b/c", "/a/b/d", "/a/b"},
275 {"a/b/c", "a/b/d", "a/b"},
276 {"/a/b/c", "/a/b/c", "/a/b/c"},
277 {"/a/b/c", "/a/b/c/d", "/a/b/c"},
278 {"/a/b/c", "/a/b", "/a/b"},
279 {"/a/b/c", "/a", "/a"},
280 {"/a/b/c", "/d/e/f", ""},
281 } {
282 c.Assert(CommonDirPath(this.a, this.b), qt.Equals, this.expected, qt.Commentf("a: %s b: %s", this.a, this.b))
283 }
284 }
285
286 func TestIsSameFilePath(t *testing.T) {
287 c := qt.New(t)
288
289 for _, this := range []struct {
290 a, b string
291 expected bool
292 }{
293 {"/a/b/c", "/a/b/c", true},
294 {"/a/b/c", "/a/b/c/", true},
295 {"/a/b/c", "/a/b/d", false},
296 {"/a/b/c", "/a/b", false},
297 {"/a/b/c", "/a/b/c/d", false},
298 {"/a/b/c", "/a/b/cd", false},
299 {"/a/b/c", "/a/b/cc", false},
300 {"/a/b/c", "/a/b/c/", true},
301 {"/a/b/c", "/a/b/c//", true},
302 {"/a/b/c", "/a/b/c/.", true},
303 {"/a/b/c", "/a/b/c/./", true},
304 {"/a/b/c", "/a/b/c/./.", true},
305 {"/a/b/c", "/a/b/c/././", true},
306 {"/a/b/c", "/a/b/c/././.", true},
307 {"/a/b/c", "/a/b/c/./././", true},
308 {"/a/b/c", "/a/b/c/./././.", true},
309 {"/a/b/c", "/a/b/c/././././", true},
310 } {
311 c.Assert(IsSameFilePath(filepath.FromSlash(this.a), filepath.FromSlash(this.b)), qt.Equals, this.expected, qt.Commentf("a: %s b: %s", this.a, this.b))
312 }
313 }