1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
package ui
import (
"testing"
"github.com/shiv/internal/store"
"github.com/stretchr/testify/assert"
)
func TestTreePathOf(t *testing.T) {
tests := []struct {
name string
url string
expected string
}{
{"absolute https no query", "https://example.com/api/v1", "/api/v1"},
{"absolute https with query", "https://example.com/api/v1?page=1&limit=10", "/api/v1"},
{"absolute http with query", "http://example.com/search?q=foo&lang=en", "/search"},
{"root with query", "https://example.com/?utm_source=x", "/"},
{"no path", "https://example.com", "/"},
{"path only no query", "/api/users", "/api/users"},
{"path only with query", "/api/users?id=123", "/api/users"},
{"root path with query", "/?q=foo", "/"},
{"empty string", "", ""},
{"query only after root", "https://example.com?x=1", "/"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, treePathOf(tt.url))
})
}
}
func TestSiteMap_Add_DeduplicatesQueryStrings(t *testing.T) {
sm := newSiteMap()
sm.add(store.Transaction{Host: "example.com", Port: 443, URL: "https://example.com/api?page=1"})
sm.add(store.Transaction{Host: "example.com", Port: 443, URL: "https://example.com/api?page=2"})
sm.add(store.Transaction{Host: "example.com", Port: 443, URL: "https://example.com/api?page=3"})
hostUIDs := sm.childUIDs("")
assert.Len(t, hostUIDs, 1, "should have exactly one host")
pathUIDs := sm.childUIDs(hostUIDs[0])
assert.Len(t, pathUIDs, 1, "query strings must be deduplicated to a single /api node")
}
func TestSiteMap_Add_SeparatesByPort(t *testing.T) {
sm := newSiteMap()
sm.add(store.Transaction{Host: "example.com", Port: 80, URL: "http://example.com/"})
sm.add(store.Transaction{Host: "example.com", Port: 8080, URL: "http://example.com:8080/"})
sm.add(store.Transaction{Host: "example.com", Port: 443, URL: "https://example.com/"})
assert.Len(t, sm.childUIDs(""), 3, "each port must be a separate tree entry")
}
func TestSiteMap_TextFilter(t *testing.T) {
sm := newSiteMap()
sm.add(store.Transaction{Host: "example.com", Port: 80, URL: "http://example.com/"})
sm.add(store.Transaction{Host: "other.com", Port: 80, URL: "http://other.com/"})
sm.add(store.Transaction{Host: "test.example.com", Port: 80, URL: "http://test.example.com/"})
assert.Len(t, sm.childUIDs(""), 3, "no filter: all hosts visible")
sm.mu.Lock()
sm.textFilter = "example"
sm.mu.Unlock()
assert.Len(t, sm.childUIDs(""), 2, "filter 'example': matches example.com and test.example.com")
sm.mu.Lock()
sm.textFilter = "other"
sm.mu.Unlock()
assert.Len(t, sm.childUIDs(""), 1, "filter 'other': matches only other.com")
sm.mu.Lock()
sm.textFilter = "EXAMPLE"
sm.mu.Unlock()
assert.Len(t, sm.childUIDs(""), 2, "filter must be case-insensitive")
sm.mu.Lock()
sm.textFilter = "xyz"
sm.mu.Unlock()
assert.Len(t, sm.childUIDs(""), 0, "filter 'xyz': no matches")
sm.mu.Lock()
sm.textFilter = ""
sm.mu.Unlock()
assert.Len(t, sm.childUIDs(""), 3, "cleared filter: all hosts visible again")
}
func TestSiteMap_TextFilter_NonStandardPort(t *testing.T) {
sm := newSiteMap()
sm.add(store.Transaction{Host: "portquiz.net", Port: 8080, URL: "http://portquiz.net:8080/"})
sm.add(store.Transaction{Host: "portquiz.net", Port: 80, URL: "http://portquiz.net/"})
// Port 8080 displays as "portquiz.net:8080" — filter on port should work
sm.mu.Lock()
sm.textFilter = "8080"
sm.mu.Unlock()
assert.Len(t, sm.childUIDs(""), 1, "filter on port number must match display host")
// Filter on hostname alone must match both ports
sm.mu.Lock()
sm.textFilter = "portquiz"
sm.mu.Unlock()
assert.Len(t, sm.childUIDs(""), 2, "filter on hostname must match all ports")
}
func TestSiteMap_Add_DeepPaths(t *testing.T) {
sm := newSiteMap()
sm.add(store.Transaction{Host: "example.com", Port: 443, URL: "https://example.com/api/v1/users"})
sm.add(store.Transaction{Host: "example.com", Port: 443, URL: "https://example.com/api/v1/posts"})
sm.add(store.Transaction{Host: "example.com", Port: 443, URL: "https://example.com/api/v2/users"})
hostUIDs := sm.childUIDs("")
assert.Len(t, hostUIDs, 1)
// /api
apiUIDs := sm.childUIDs(hostUIDs[0])
assert.Len(t, apiUIDs, 1, "should have one /api child")
// /api/v1 and /api/v2
versionUIDs := sm.childUIDs(apiUIDs[0])
assert.Len(t, versionUIDs, 2, "should have v1 and v2 children")
}
|