1package download
2
3import (
4 "testing"
5
6 "github.com/stretchr/testify/assert"
7)
8
9func TestSanitizeFilename(t *testing.T) {
10 tests := []struct {
11 name string
12 input string
13 expected string
14 }{
15 {
16 name: "normal filename",
17 input: "document.pdf",
18 expected: "document.pdf",
19 },
20 {
21 name: "filename with spaces",
22 input: "my document.pdf",
23 expected: "my document.pdf",
24 },
25 {
26 name: "path traversal with parent dirs",
27 input: "../../../etc/passwd",
28 expected: "passwd",
29 },
30 {
31 name: "path traversal hidden file",
32 input: "../.ssh/id_rsa",
33 expected: "id_rsa",
34 },
35 {
36 name: "nested path",
37 input: "foo/bar/baz.txt",
38 expected: "baz.txt",
39 },
40 {
41 name: "absolute path",
42 input: "/etc/passwd",
43 expected: "passwd",
44 },
45 {
46 name: "dot only",
47 input: ".",
48 expected: "download",
49 },
50 {
51 name: "double dot only",
52 input: "..",
53 expected: "download",
54 },
55 {
56 name: "empty string",
57 input: "",
58 expected: "download",
59 },
60 {
61 name: "hidden file",
62 input: ".bashrc",
63 expected: ".bashrc",
64 },
65 {
66 name: "windows style path",
67 input: "..\\..\\Windows\\System32\\config",
68 expected: "config",
69 },
70 }
71
72 for _, tt := range tests {
73 t.Run(tt.name, func(t *testing.T) {
74 result := SanitizeFilename(tt.input)
75 assert.Equal(t, tt.expected, result)
76 })
77 }
78}
79
80func TestSanitizeFilenameWithExtension(t *testing.T) {
81 tests := []struct {
82 name string
83 input string
84 mimeType string
85 expected string
86 }{
87 {
88 name: "no extension adds inferred",
89 input: "download",
90 mimeType: "application/pdf",
91 expected: "download.pdf",
92 },
93 {
94 name: "existing extension preserved",
95 input: "report.pdf",
96 mimeType: "application/pdf",
97 expected: "report.pdf",
98 },
99 {
100 name: "path traversal with inferred extension",
101 input: "../report",
102 mimeType: "application/pdf",
103 expected: "report.pdf",
104 },
105 {
106 name: "no mime type returns sanitized",
107 input: "report",
108 mimeType: "",
109 expected: "report",
110 },
111 }
112
113 for _, tt := range tests {
114 t.Run(tt.name, func(t *testing.T) {
115 result := SanitizeFilenameWithExtension(tt.input, tt.mimeType)
116 assert.Equal(t, tt.expected, result)
117 })
118 }
119}
120
121func TestGetExtensionFromMimeType(t *testing.T) {
122 tests := []struct {
123 name string
124 input string
125 expected string
126 }{
127 {
128 name: "empty mime type",
129 input: "",
130 expected: "",
131 },
132 {
133 name: "unknown mime type",
134 input: "application/unknown",
135 expected: "",
136 },
137 {
138 name: "pdf mime type",
139 input: "application/pdf",
140 expected: ".pdf",
141 },
142 {
143 name: "pdf mime type with charset param",
144 input: "application/pdf; charset=binary",
145 expected: ".pdf",
146 },
147 {
148 name: "text html with charset",
149 input: "text/html; charset=utf-8",
150 expected: ".html",
151 },
152 {
153 name: "mime type with multiple params",
154 input: "application/json; charset=utf-8; boundary=something",
155 expected: ".json",
156 },
157 {
158 name: "invalid mime type",
159 input: "not-a-valid-mime",
160 expected: "",
161 },
162 }
163
164 for _, tt := range tests {
165 t.Run(tt.name, func(t *testing.T) {
166 result := GetExtensionFromMimeType(tt.input)
167 assert.Equal(t, tt.expected, result)
168 })
169 }
170}
171
172func TestExtractFilenameFromDestination(t *testing.T) {
173 tests := []struct {
174 name string
175 input string
176 expected string
177 }{
178 {
179 name: "file URI with path",
180 input: "file:///home/user/Downloads/document.pdf",
181 expected: "document.pdf",
182 },
183 {
184 name: "file URI root",
185 input: "file:///document.pdf",
186 expected: "document.pdf",
187 },
188 {
189 name: "plain path",
190 input: "/home/user/Downloads/image.png",
191 expected: "image.png",
192 },
193 {
194 name: "filename only",
195 input: "video.mp4",
196 expected: "video.mp4",
197 },
198 {
199 name: "empty string",
200 input: "",
201 expected: "download",
202 },
203 {
204 name: "file URI with spaces",
205 input: "file:///home/user/My Documents/file.txt",
206 expected: "file.txt",
207 },
208 }
209
210 for _, tt := range tests {
211 t.Run(tt.name, func(t *testing.T) {
212 result := ExtractFilenameFromDestination(tt.input)
213 assert.Equal(t, tt.expected, result)
214 })
215 }
216}
217
218func TestExtractFilenameFromURI(t *testing.T) {
219 tests := []struct {
220 name string
221 input string
222 expected string
223 }{
224 {
225 name: "http URL with filename",
226 input: "https://example.com/files/document.pdf",
227 expected: "document.pdf",
228 },
229 {
230 name: "http URL with query params",
231 input: "https://example.com/files/document.pdf?token=abc",
232 expected: "document.pdf",
233 },
234 {
235 name: "http URL without filename",
236 input: "https://example.com/",
237 expected: "download",
238 },
239 {
240 name: "empty string",
241 input: "",
242 expected: "download",
243 },
244 {
245 name: "plain path",
246 input: "/path/to/file.txt",
247 expected: "file.txt",
248 },
249 }
250
251 for _, tt := range tests {
252 t.Run(tt.name, func(t *testing.T) {
253 result := ExtractFilenameFromURI(tt.input)
254 assert.Equal(t, tt.expected, result)
255 })
256 }
257}
258
259func TestMakeUniqueFilename(t *testing.T) {
260 tests := []struct {
261 name string
262 dir string
263 filename string
264 existingFiles map[string]bool
265 expected string
266 }{
267 {
268 name: "file does not exist",
269 dir: "/tmp",
270 filename: "document.pdf",
271 existingFiles: map[string]bool{},
272 expected: "document.pdf",
273 },
274 {
275 name: "file exists, adds _(1)",
276 dir: "/tmp",
277 filename: "document.pdf",
278 existingFiles: map[string]bool{
279 "/tmp/document.pdf": true,
280 },
281 expected: "document_(1).pdf",
282 },
283 {
284 name: "file and _(1) exist, adds _(2)",
285 dir: "/tmp",
286 filename: "document.pdf",
287 existingFiles: map[string]bool{
288 "/tmp/document.pdf": true,
289 "/tmp/document_(1).pdf": true,
290 },
291 expected: "document_(2).pdf",
292 },
293 {
294 name: "no extension",
295 dir: "/tmp",
296 filename: "download",
297 existingFiles: map[string]bool{
298 "/tmp/download": true,
299 },
300 expected: "download_(1)",
301 },
302 {
303 name: "hidden file with extension",
304 dir: "/tmp",
305 filename: ".config.bak",
306 existingFiles: map[string]bool{
307 "/tmp/.config.bak": true,
308 },
309 expected: ".config_(1).bak",
310 },
311 }
312
313 for _, tt := range tests {
314 t.Run(tt.name, func(t *testing.T) {
315 exists := func(path string) bool {
316 return tt.existingFiles[path]
317 }
318 result := MakeUniqueFilename(tt.dir, tt.filename, exists)
319 assert.Equal(t, tt.expected, result)
320 })
321 }
322}