Antonio Mika
·
2025-03-12
calc_route_test.go
1package pgs
2
3import (
4 "testing"
5
6 "github.com/google/go-cmp/cmp"
7)
8
9type RouteFixture struct {
10 Name string
11 Actual []*HttpReply
12 Expected []*HttpReply
13}
14
15func TestCalcRoutes(t *testing.T) {
16 fixtures := []RouteFixture{
17 {
18 Name: "basic-index",
19 Actual: calcRoutes("test", "/index.html", []*RedirectRule{}),
20 Expected: []*HttpReply{
21 {Filepath: "test/index.html", Status: 200},
22 {Filepath: "/index.html/", Status: 301},
23 {Filepath: "test/404.html", Status: 404},
24 },
25 },
26 {
27 Name: "basic-txt",
28 Actual: calcRoutes("test", "/index.txt", []*RedirectRule{}),
29 Expected: []*HttpReply{
30 {Filepath: "test/index.txt", Status: 200},
31 {Filepath: "/index.txt/", Status: 301},
32 {Filepath: "test/404.html", Status: 404},
33 },
34 },
35 {
36 Name: "basic-named",
37 Actual: calcRoutes("test", "/wow.html", []*RedirectRule{}),
38 Expected: []*HttpReply{
39 {Filepath: "test/wow.html", Status: 200},
40 {Filepath: "/wow.html/", Status: 301},
41 {Filepath: "test/404.html", Status: 404},
42 },
43 },
44 {
45 Name: "subdirectory-index",
46 Actual: calcRoutes("test", "/nice/index.html", []*RedirectRule{}),
47 Expected: []*HttpReply{
48 {Filepath: "test/nice/index.html", Status: 200},
49 {Filepath: "/nice/index.html/", Status: 301},
50 {Filepath: "test/404.html", Status: 404},
51 },
52 },
53 {
54 Name: "subdirectory-named",
55 Actual: calcRoutes("test", "/nice/wow.html", []*RedirectRule{}),
56 Expected: []*HttpReply{
57 {Filepath: "test/nice/wow.html", Status: 200},
58 {Filepath: "/nice/wow.html/", Status: 301},
59 {Filepath: "test/404.html", Status: 404},
60 },
61 },
62 {
63 Name: "subdirectory-bare",
64 Actual: calcRoutes("test", "/nice/", []*RedirectRule{}),
65 Expected: []*HttpReply{
66 {Filepath: "test/nice/index.html", Status: 200},
67 {Filepath: "test/404.html", Status: 404},
68 },
69 },
70 {
71 Name: "trailing-slash",
72 Actual: calcRoutes("test", "/folder", []*RedirectRule{}),
73 Expected: []*HttpReply{
74 {Filepath: "test/folder", Status: 200},
75 {Filepath: "test/folder.html", Status: 200},
76 {Filepath: "/folder/", Status: 301},
77 {Filepath: "test/404.html", Status: 404},
78 },
79 },
80 {
81 Name: "spa",
82 Actual: calcRoutes("test", "/nice.html", []*RedirectRule{
83 {
84 From: "/*",
85 To: "/index.html",
86 Status: 200,
87 },
88 }),
89 Expected: []*HttpReply{
90 {Filepath: "test/nice.html", Status: 200},
91 {Filepath: "test/index.html", Status: 200},
92 {Filepath: "/index.html/", Status: 301},
93 {Filepath: "test/404.html", Status: 404},
94 },
95 },
96 {
97 Name: "xml",
98 Actual: calcRoutes("test", "/index.xml", []*RedirectRule{}),
99 Expected: []*HttpReply{
100 {Filepath: "test/index.xml", Status: 200},
101 {Filepath: "/index.xml/", Status: 301},
102 {Filepath: "test/404.html", Status: 404},
103 },
104 },
105 {
106 Name: "redirect-rule",
107 Actual: calcRoutes(
108 "test",
109 "/wow",
110 []*RedirectRule{
111 {
112 From: "/wow",
113 To: "/index.html",
114 Status: 301,
115 },
116 },
117 ),
118 Expected: []*HttpReply{
119 {Filepath: "test/wow", Status: 200},
120 {Filepath: "test/wow.html", Status: 200},
121 {Filepath: "/index.html", Status: 301},
122 {Filepath: "/wow/", Status: 301},
123 {Filepath: "test/404.html", Status: 404},
124 },
125 },
126 {
127 Name: "redirect-to-pico",
128 Actual: calcRoutes(
129 "test",
130 "/tester1",
131 []*RedirectRule{
132 {
133 From: "/tester1",
134 To: "https://pico.sh",
135 Status: 301,
136 },
137 },
138 ),
139 Expected: []*HttpReply{
140 {Filepath: "test/tester1", Status: 200},
141 {Filepath: "test/tester1.html", Status: 200},
142 {Filepath: "https://pico.sh", Status: 301},
143 },
144 },
145 {
146 Name: "root",
147 Actual: calcRoutes(
148 "test",
149 "",
150 []*RedirectRule{},
151 ),
152 Expected: []*HttpReply{
153 {Filepath: "test/index.html", Status: 200},
154 {Filepath: "test/404.html", Status: 404},
155 },
156 },
157 {
158 Name: "redirect-to-root",
159 Actual: calcRoutes(
160 "test",
161 "/wow/",
162 []*RedirectRule{
163 {
164 From: "/wow/",
165 To: "/",
166 Status: 301,
167 },
168 },
169 ),
170 Expected: []*HttpReply{
171 {Filepath: "test/wow/index.html", Status: 200},
172 {Filepath: "/", Status: 301},
173 {Filepath: "test/404.html", Status: 404},
174 },
175 },
176 {
177 Name: "force",
178 Actual: calcRoutes(
179 "test",
180 "/wow",
181 []*RedirectRule{
182 {
183 From: "/wow",
184 To: "/",
185 Status: 301,
186 Force: true,
187 },
188 },
189 ),
190 Expected: []*HttpReply{
191 {Filepath: "/", Status: 301},
192 {Filepath: "/wow/", Status: 301},
193 {Filepath: "test/404.html", Status: 404},
194 },
195 },
196 {
197 Name: "redirect-full-url",
198 Actual: calcRoutes(
199 "test",
200 "/wow.html",
201 []*RedirectRule{
202 {
203 From: "/wow",
204 To: "https://pico.sh",
205 Status: 301,
206 },
207 },
208 ),
209 Expected: []*HttpReply{
210 {Filepath: "test/wow.html", Status: 200},
211 {Filepath: "/wow.html/", Status: 301},
212 {Filepath: "test/404.html", Status: 404},
213 },
214 },
215 {
216 Name: "redirect-root-full-url",
217 Actual: calcRoutes(
218 "test",
219 "/",
220 []*RedirectRule{
221 {
222 From: "/*",
223 To: "https://pico.sh",
224 Status: 301,
225 },
226 },
227 ),
228 Expected: []*HttpReply{
229 {Filepath: "test/index.html", Status: 200},
230 {Filepath: "https://pico.sh", Status: 301},
231 },
232 },
233 {
234 Name: "redirect-empty-route-full-url",
235 Actual: calcRoutes(
236 "test",
237 "",
238 []*RedirectRule{
239 {
240 From: "/*",
241 To: "https://pico.sh",
242 Status: 301,
243 },
244 },
245 ),
246 Expected: []*HttpReply{
247 {Filepath: "test/index.html", Status: 200},
248 {Filepath: "https://pico.sh", Status: 301},
249 },
250 },
251 {
252 Name: "redirect-full-url-directory",
253 Actual: calcRoutes(
254 "test",
255 "/wow",
256 []*RedirectRule{
257 {
258 From: "/wow",
259 To: "https://pico.sh",
260 Status: 301,
261 },
262 },
263 ),
264 Expected: []*HttpReply{
265 {Filepath: "test/wow", Status: 200},
266 {Filepath: "test/wow.html", Status: 200},
267 {Filepath: "https://pico.sh", Status: 301},
268 },
269 },
270 {
271 Name: "redirect-directory",
272 Actual: calcRoutes(
273 "public",
274 "/xyz",
275 []*RedirectRule{
276 {
277 From: "/xyz",
278 To: "/wrk-xyz",
279 Status: 301,
280 },
281 },
282 ),
283 Expected: []*HttpReply{
284 {Filepath: "public/xyz", Status: 200},
285 {Filepath: "public/xyz.html", Status: 200},
286 {Filepath: "/wrk-xyz", Status: 301},
287 {Filepath: "/xyz/", Status: 301},
288 {Filepath: "public/404.html", Status: 404},
289 },
290 },
291 {
292 Name: "redirect-sub-directory",
293 Actual: calcRoutes(
294 "public",
295 "/folder2",
296 []*RedirectRule{
297 {
298 From: "/folder2",
299 To: "/folder",
300 Status: 200,
301 },
302 },
303 ),
304 Expected: []*HttpReply{
305 {Filepath: "public/folder2", Status: 200},
306 {Filepath: "public/folder2.html", Status: 200},
307 {Filepath: "public/folder", Status: 200},
308 {Filepath: "public/folder.html", Status: 200},
309 {Filepath: "/folder/", Status: 301},
310 {Filepath: "public/404.html", Status: 404},
311 },
312 },
313 {
314 Name: "redirect-from-and-to-same",
315 Actual: calcRoutes(
316 "public",
317 "/folder2",
318 []*RedirectRule{
319 {
320 From: "/folder2",
321 To: "/folder2",
322 Status: 200,
323 },
324 },
325 ),
326 Expected: []*HttpReply{
327 {Filepath: "public/folder2", Status: 200},
328 {Filepath: "public/folder2.html", Status: 200},
329 {Filepath: "/folder2/", Status: 301},
330 {Filepath: "public/404.html", Status: 404},
331 },
332 },
333 {
334 Name: "redirect-no-trailing-slash",
335 Actual: calcRoutes(
336 "public",
337 "/space/",
338 []*RedirectRule{
339 {
340 From: "/space",
341 To: "/frontier/",
342 Status: 301,
343 },
344 },
345 ),
346 Expected: []*HttpReply{
347 {Filepath: "public/space/index.html", Status: 200},
348 {Filepath: "/frontier/", Status: 301},
349 {Filepath: "public/404.html", Status: 404},
350 },
351 },
352 {
353 Name: "redirect-with-trailing-slash",
354 Actual: calcRoutes(
355 "public",
356 "/space",
357 []*RedirectRule{
358 {
359 From: "/space/",
360 To: "/frontier/",
361 Status: 301,
362 },
363 },
364 ),
365 Expected: []*HttpReply{
366 {Filepath: "public/space", Status: 200},
367 {Filepath: "public/space.html", Status: 200},
368 {Filepath: "/frontier/", Status: 301},
369 {Filepath: "/space/", Status: 301},
370 {Filepath: "public/404.html", Status: 404},
371 },
372 },
373 {
374 Name: "directory-with-extension",
375 Actual: calcRoutes(
376 "public",
377 "/space.nvim",
378 []*RedirectRule{},
379 ),
380 Expected: []*HttpReply{
381 {Filepath: "public/space.nvim", Status: 200},
382 {Filepath: "public/space.nvim.html", Status: 200},
383 {Filepath: "/space.nvim/", Status: 301},
384 {Filepath: "public/404.html", Status: 404},
385 },
386 },
387 {
388 Name: "rewrite-to-site",
389 Actual: calcRoutes(
390 "public",
391 "/",
392 []*RedirectRule{
393 {
394 From: "/*",
395 To: "https://my-other-site.pgs.sh/:splat",
396 Status: 200,
397 },
398 },
399 ),
400 Expected: []*HttpReply{
401 {Filepath: "public/index.html", Status: 200},
402 {Filepath: "https://my-other-site.pgs.sh/", Status: 200},
403 },
404 },
405 {
406 Name: "rewrite-to-site-subdir",
407 Actual: calcRoutes(
408 "public",
409 "/plugin/nice/",
410 []*RedirectRule{
411 {
412 From: "/*",
413 To: "https://my-other-site.pgs.sh/:splat",
414 Status: 200,
415 },
416 },
417 ),
418 Expected: []*HttpReply{
419 {Filepath: "public/plugin/nice/index.html", Status: 200},
420 {Filepath: "https://my-other-site.pgs.sh/plugin/nice/", Status: 200},
421 },
422 },
423 {
424 Name: "rewrite-to-another-pgs-site",
425 Actual: calcRoutes(
426 "public",
427 "/my-site/index.html",
428 []*RedirectRule{
429 {
430 From: "/my-site/*",
431 To: "https://my-other-site.pgs.sh/:splat",
432 Status: 200,
433 },
434 },
435 ),
436 Expected: []*HttpReply{
437 {Filepath: "public/my-site/index.html", Status: 200},
438 {Filepath: "https://my-other-site.pgs.sh/index.html", Status: 200},
439 },
440 },
441 {
442 Name: "rewrite-placeholders",
443 Actual: calcRoutes(
444 "public",
445 "/news/02/12/2004/my-story",
446 []*RedirectRule{
447 {
448 From: "/news/:month/:date/:year/*",
449 To: "/blog/:year/:month/:date/:splat",
450 Status: 200,
451 },
452 },
453 ),
454 Expected: []*HttpReply{
455 {Filepath: "public/news/02/12/2004/my-story", Status: 200},
456 {Filepath: "public/news/02/12/2004/my-story.html", Status: 200},
457 {Filepath: "public/blog/2004/02/12/my-story", Status: 200},
458 {Filepath: "public/blog/2004/02/12/my-story.html", Status: 200},
459 {Filepath: "/blog/2004/02/12/my-story/", Status: 301},
460 {Filepath: "public/404.html", Status: 404},
461 },
462 },
463 {
464 Name: "302-redirect",
465 Actual: calcRoutes(
466 "public",
467 "/pages/chem351.html",
468 []*RedirectRule{
469 {
470 From: "/pages/chem351.html",
471 To: "/pages/chem351",
472 Status: 302,
473 Force: true,
474 },
475 },
476 ),
477 Expected: []*HttpReply{
478 {Filepath: "/pages/chem351", Status: 302},
479 {Filepath: "/pages/chem351.html/", Status: 301},
480 {Filepath: "public/404.html", Status: 404},
481 },
482 },
483 {
484 Name: "302-redirect-non-match",
485 Actual: calcRoutes(
486 "public",
487 "/pages/chem351",
488 []*RedirectRule{
489 {
490 From: "/pages/chem351.html",
491 To: "/pages/chem351",
492 Status: 302,
493 Force: true,
494 },
495 },
496 ),
497 Expected: []*HttpReply{
498 {Filepath: "public/pages/chem351", Status: 200},
499 {Filepath: "public/pages/chem351.html", Status: 200},
500 {Filepath: "/pages/chem351/", Status: 301},
501 {Filepath: "public/404.html", Status: 404},
502 },
503 },
504 {
505 Name: "wildcard-with-word",
506 Actual: calcRoutes(
507 "public",
508 "/pictures/soup",
509 []*RedirectRule{
510 {
511 From: "/pictures*",
512 To: "https://super.fly.sh/:splat",
513 Status: 200,
514 },
515 {
516 From: "/*",
517 To: "https://super.fly.sh/:splat",
518 Status: 302,
519 },
520 },
521 ),
522 Expected: []*HttpReply{
523 {Filepath: "public/pictures/soup", Status: 200},
524 {Filepath: "public/pictures/soup.html", Status: 200},
525 {Filepath: "https://super.fly.sh/soup", Status: 200},
526 },
527 },
528 {
529 Name: "wildcard-multiple",
530 Actual: calcRoutes(
531 "public",
532 "/super/ficial.html",
533 []*RedirectRule{
534 {
535 From: "/pictures*",
536 To: "https://super.fly.sh/:splat",
537 Status: 200,
538 },
539 {
540 From: "/*",
541 To: "https://super.fly.sh/:splat",
542 Status: 302,
543 },
544 },
545 ),
546 Expected: []*HttpReply{
547 {Filepath: "public/super/ficial.html", Status: 200},
548 {Filepath: "https://super.fly.sh/super/ficial.html", Status: 302},
549 },
550 },
551 {
552 Name: "well-known-splat-suffix",
553 Actual: calcRoutes(
554 "public",
555 "/.well-known/nodeinfo",
556 []*RedirectRule{
557 {
558 From: "/.well-known/nodeinfo*",
559 To: "https://some.dev/.well-known/nodeinfo:splat",
560 Status: 301,
561 },
562 },
563 ),
564 Expected: []*HttpReply{
565 {Filepath: "public/.well-known/nodeinfo", Status: 200},
566 {Filepath: "public/.well-known/nodeinfo.html", Status: 200},
567 {Filepath: "https://some.dev/.well-known/nodeinfo", Status: 301},
568 },
569 },
570 {
571 Name: "wildcard-query-param",
572 Actual: calcRoutes(
573 "public",
574 "/.well-known/webfinger?query=nice",
575 []*RedirectRule{
576 {
577 From: "/.well-known/webfinger*",
578 To: "https://some.dev/.well-known/webfinger:splat",
579 Status: 301,
580 },
581 },
582 ),
583 Expected: []*HttpReply{
584 {Filepath: "public/.well-known/webfinger?query=nice", Status: 200},
585 {Filepath: "public/.well-known/webfinger?query=nice.html", Status: 200},
586 {Filepath: "https://some.dev/.well-known/webfinger?query=nice", Status: 301},
587 },
588 },
589 {
590 Name: "well-known-splat-suffix-error",
591 Actual: calcRoutes(
592 "public",
593 "/software/",
594 []*RedirectRule{
595 {
596 From: "/.well-known/nodeinfo*",
597 To: "https://some.dev/.well-known/nodeinfo:splat",
598 Status: 301,
599 },
600 },
601 ),
602 Expected: []*HttpReply{
603 {Filepath: "public/software/index.html", Status: 200},
604 {Filepath: "public/404.html", Status: 404},
605 },
606 },
607 {
608 Name: "non-match-dont-redirect",
609 Actual: calcRoutes(
610 "public",
611 "/scripts/asd",
612 []*RedirectRule{
613 {
614 From: "/concat/*",
615 To: "/scripts/:splat",
616 Status: 301,
617 },
618 },
619 ),
620 Expected: []*HttpReply{
621 {Filepath: "public/scripts/asd", Status: 200},
622 {Filepath: "public/scripts/asd.html", Status: 200},
623 {Filepath: "/scripts/asd/", Status: 301},
624 {Filepath: "public/404.html", Status: 404},
625 },
626 },
627 {
628 Name: "implicit-prefix-slash-redirect",
629 Actual: calcRoutes(
630 "public",
631 "software/scripts",
632 []*RedirectRule{
633 {
634 From: "/software/concat/*",
635 To: "/software/scripts/:splat",
636 Status: 301,
637 },
638 },
639 ),
640 Expected: []*HttpReply{
641 {Filepath: "public/software/scripts", Status: 200},
642 {Filepath: "public/software/scripts.html", Status: 200},
643 {Filepath: "/software/scripts/", Status: 301},
644 {Filepath: "public/404.html", Status: 404},
645 },
646 },
647 }
648
649 for _, fixture := range fixtures {
650 t.Run(fixture.Name, func(t *testing.T) {
651 if cmp.Equal(fixture.Actual, fixture.Expected) == false {
652 //nolint
653 t.Fatal(cmp.Diff(fixture.Expected, fixture.Actual))
654 }
655 })
656 }
657}