summaryrefslogtreecommitdiff
path: root/internal/ui/history_test.go
blob: b251460b034ce04a466b10ce3fd434e17e74ea73 (plain)
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")
}