navigation_url_normalizer_test.go RawHistoryFolder
1package usecase
2
3import (
4 "context"
5 "errors"
6 stdurl "net/url"
7 "path/filepath"
8 "testing"
9)
10
11type spyLocalPathResolver struct {
12 calls int
13}
14
15func (r *spyLocalPathResolver) ResolveExistingPath(_ context.Context, _ string) (string, bool, error) {
16 r.calls++
17 return filepath.Join(string(filepath.Separator), "tmp", "should-not-be-used.html"), true, nil
18}
19
20func TestNavigationURLNormalizerResolvesExistingLocalPaths(t *testing.T) {
21 ctx := context.Background()
22 absFile := filepath.Join(string(filepath.Separator), "tmp", "page.html")
23 normalizer := NewNavigationURLNormalizer(fakeLocalPathResolver{paths: map[string]string{
24 absFile: absFile,
25 "page.html": absFile,
26 "~/page.html": absFile,
27 "notes:2026.txt": absFile,
28 "http:notes.txt": absFile,
29 "http:notes": absFile,
30 }})
31
32 for _, input := range []string{absFile, "page.html", "~/page.html", "notes:2026.txt", "http:notes.txt", "http:notes"} {
33 t.Run(input, func(t *testing.T) {
34 got := normalizer.Normalize(ctx, input)
35 want := (&stdurl.URL{Scheme: "file", Path: absFile}).String()
36 if got != want {
37 t.Fatalf("Normalize(%q) = %q, want %q", input, got, want)
38 }
39 })
40 }
41}
42
43func TestNavigationURLNormalizerFallsBackToDomainNormalize(t *testing.T) {
44 ctx := context.Background()
45 normalizer := NewNavigationURLNormalizer(fakeLocalPathResolver{err: errors.New("boom")})
46
47 if got := normalizer.Normalize(ctx, "example.com"); got != "https://example.com" {
48 t.Fatalf("Normalize(example.com) = %q", got)
49 }
50 if got := normalizer.Normalize(ctx, "./missing.html"); got != "./missing.html" {
51 t.Fatalf("Normalize(./missing.html) = %q", got)
52 }
53}
54func TestNavigationURLNormalizerBuildNavigationURLCentralizesSearchFallback(t *testing.T) {
55 ctx := context.Background()
56 absFile := filepath.Join(string(filepath.Separator), "tmp", "page.html")
57 normalizer := NewNavigationURLNormalizer(fakeLocalPathResolver{paths: map[string]string{
58 "page.html": absFile,
59 }})
60 shortcuts := map[string]string{"g": "https://google.com/search?q=%s"}
61
62 if got := normalizer.BuildNavigationURL(ctx, "page.html", shortcuts, "https://search.example/?q=%s"); got != "file://"+absFile {
63 t.Fatalf("BuildNavigationURL(local file) = %q, want file URL", got)
64 }
65 if got := normalizer.BuildNavigationURL(ctx, "!g cats", shortcuts, "https://search.example/?q=%s"); got != "https://google.com/search?q=cats" {
66 t.Fatalf("BuildNavigationURL(shortcut) = %q, want shortcut search", got)
67 }
68}
69
70func TestNavigationURLNormalizerDoesNotProbeSchemeBearingInputs(t *testing.T) {
71 ctx := context.Background()
72
73 tests := []struct {
74 name string
75 input string
76 want string
77 }{
78 {
79 name: "https scheme",
80 input: "https://example.com/page",
81 want: "https://example.com/page",
82 },
83 {
84 name: "file scheme",
85 input: "file:///tmp/page.html",
86 want: "file:///tmp/page.html",
87 },
88 {
89 name: "about scheme",
90 input: "about:blank",
91 want: "about:blank",
92 },
93 {
94 name: "external scheme without slashes",
95 input: "mailto:user@example.com",
96 want: "mailto:user@example.com",
97 },
98 {
99 name: "data scheme",
100 input: "data:text/plain,hello",
101 want: "data:text/plain,hello",
102 },
103 }
104
105 for _, tt := range tests {
106 t.Run(tt.name, func(t *testing.T) {
107 resolver := &spyLocalPathResolver{}
108 normalizer := NewNavigationURLNormalizer(resolver)
109
110 got := normalizer.Normalize(ctx, tt.input)
111 if got != tt.want {
112 t.Fatalf("Normalize(%q) = %q, want %q", tt.input, got, tt.want)
113 }
114 if resolver.calls != 0 {
115 t.Fatalf("ResolveExistingPath called %d times for %q, want 0", resolver.calls, tt.input)
116 }
117 })
118 }
119}