1package input
2
3import (
4 "context"
5 "testing"
6
7 "github.com/bnema/dumber/internal/infrastructure/config"
8 "github.com/jwijenbergh/puregotk/v4/gdk"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/require"
11)
12
13func TestShortcutSet_GlobalToggleFloatingPane(t *testing.T) {
14 cfg := config.DefaultConfig()
15 set := NewShortcutSet(context.Background(), cfg)
16
17 action, ok := set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_f), Modifiers: ModAlt}, ModeNormal)
18 require.True(t, ok)
19 assert.Equal(t, ActionToggleFloatingPane, action)
20}
21
22func TestShortcutSet_FloatingProfiles_RegisterMultiple(t *testing.T) {
23 cfg := config.DefaultConfig()
24 cfg.Workspace.FloatingPane.Profiles = map[string]config.FloatingPaneProfile{
25 "google": {
26 Keys: []string{"alt+g"},
27 URL: "https://google.com",
28 },
29 "github": {
30 Keys: []string{"alt+y"},
31 URL: "https://github.com",
32 },
33 }
34
35 set := NewShortcutSet(context.Background(), cfg)
36
37 googleAction, ok := set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_g), Modifiers: ModAlt}, ModeNormal)
38 require.True(t, ok)
39 googleTarget, ok := ParseFloatingProfileTarget(googleAction)
40 require.True(t, ok)
41 assert.Equal(t, "google", googleTarget.SessionID)
42 assert.Equal(t, "https://google.com", googleTarget.URL)
43
44 githubAction, ok := set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_y), Modifiers: ModAlt}, ModeNormal)
45 require.True(t, ok)
46 githubTarget, ok := ParseFloatingProfileTarget(githubAction)
47 require.True(t, ok)
48 assert.Equal(t, "github", githubTarget.SessionID)
49 assert.Equal(t, "https://github.com", githubTarget.URL)
50}
51
52func TestCollectFloatingProfileShortcuts_SkipsConflicts(t *testing.T) {
53 cfg := config.DefaultConfig()
54 cfg.Workspace.FloatingPane.Profiles = map[string]config.FloatingPaneProfile{
55 "tab-conflict": {
56 Keys: []string{"alt+1"},
57 URL: "https://example.com/tab",
58 },
59 "pane-conflict": {
60 Keys: []string{"alt+["},
61 URL: "https://example.com/pane",
62 },
63 "ok": {
64 Keys: []string{"alt+g"},
65 URL: "https://example.com/ok",
66 },
67 }
68
69 occupied := map[KeyBinding]Action{
70 {Keyval: uint(gdk.KEY_1), Modifiers: ModAlt}: ActionSwitchTabIndex1,
71 {Keyval: uint(gdk.KEY_bracketleft), Modifiers: ModAlt}: ActionConsumeOrExpelLeft,
72 }
73
74 shortcuts := collectFloatingProfileShortcuts(context.Background(), cfg, occupied)
75 require.Len(t, shortcuts, 1)
76 assert.Equal(t, KeyBinding{Keyval: uint(gdk.KEY_g), Modifiers: ModAlt}, shortcuts[0].Binding)
77 target, ok := ParseFloatingProfileTarget(shortcuts[0].Action)
78 require.True(t, ok)
79 assert.Equal(t, "ok", target.SessionID)
80 assert.Equal(t, "https://example.com/ok", target.URL)
81}
82
83func TestShortcutSet_FloatingProfilesPreserveExistingGlobalShortcuts(t *testing.T) {
84 cfg := config.DefaultConfig()
85 cfg.Workspace.FloatingPane.Profiles = map[string]config.FloatingPaneProfile{
86 "conflict": {
87 Keys: []string{"alt+["},
88 URL: "https://example.com/override-attempt",
89 },
90 }
91
92 set := NewShortcutSet(context.Background(), cfg)
93
94 tabAction, ok := set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_bracketleft), Modifiers: ModAlt}, ModeNormal)
95 require.True(t, ok)
96 assert.Equal(t, ActionConsumeOrExpelLeft, tabAction)
97
98 omniboxAction, ok := set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_l), Modifiers: ModCtrl}, ModeNormal)
99 require.True(t, ok)
100 assert.Equal(t, ActionOpenOmnibox, omniboxAction)
101}
102
103func TestShortcutSet_FloatingProfilesSkipGlobalOnlyConflicts(t *testing.T) {
104 cfg := config.DefaultConfig()
105 cfg.Workspace.FloatingPane.Profiles = map[string]config.FloatingPaneProfile{
106 "alt-one-conflict": {
107 Keys: []string{"alt+1"},
108 URL: "https://example.com/one",
109 },
110 "alt-tab-conflict": {
111 Keys: []string{"alt+tab"},
112 URL: "https://example.com/tab",
113 },
114 "ok": {
115 Keys: []string{"alt+g"},
116 URL: "https://example.com/ok",
117 },
118 }
119
120 set := NewShortcutSet(context.Background(), cfg)
121
122 _, ok := set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_1), Modifiers: ModAlt}, ModeNormal)
123 assert.False(t, ok)
124
125 _, ok = set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_Tab), Modifiers: ModAlt}, ModeNormal)
126 assert.False(t, ok)
127
128 action, ok := set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_g), Modifiers: ModAlt}, ModeNormal)
129 require.True(t, ok)
130 target, ok := ParseFloatingProfileTarget(action)
131 require.True(t, ok)
132 assert.Equal(t, "ok", target.SessionID)
133 assert.Equal(t, "https://example.com/ok", target.URL)
134}
135
136func TestShortcutSet_FloatingProfilesWithSameURLGetDistinctSessionIDs(t *testing.T) {
137 cfg := config.DefaultConfig()
138 cfg.Workspace.FloatingPane.Profiles = map[string]config.FloatingPaneProfile{
139 "work-mail": {
140 Keys: []string{"alt+w"},
141 URL: "https://mail.google.com",
142 },
143 "personal-mail": {
144 Keys: []string{"alt+p"},
145 URL: "https://mail.google.com",
146 },
147 }
148
149 set := NewShortcutSet(context.Background(), cfg)
150
151 workAction, ok := set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_w), Modifiers: ModAlt}, ModeNormal)
152 require.True(t, ok)
153 workTarget, ok := ParseFloatingProfileTarget(workAction)
154 require.True(t, ok)
155
156 personalAction, ok := set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_p), Modifiers: ModAlt}, ModeNormal)
157 require.True(t, ok)
158 personalTarget, ok := ParseFloatingProfileTarget(personalAction)
159 require.True(t, ok)
160
161 assert.Equal(t, "https://mail.google.com", workTarget.URL)
162 assert.Equal(t, "https://mail.google.com", personalTarget.URL)
163 assert.NotEqual(t, workTarget.SessionID, personalTarget.SessionID)
164}
165
166func TestShortcutSet_FloatingProfiles_SupportModifierCombos(t *testing.T) {
167 cfg := config.DefaultConfig()
168 cfg.Workspace.FloatingPane.Profiles = map[string]config.FloatingPaneProfile{
169 "mail": {
170 Keys: []string{"ctrl+alt+m"},
171 URL: "https://mail.example.com",
172 },
173 "search": {
174 Keys: []string{"ctrl+shift+y"},
175 URL: "https://search.example.com",
176 },
177 }
178
179 set := NewShortcutSet(context.Background(), cfg)
180
181 mailAction, ok := set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_m), Modifiers: ModCtrl | ModAlt}, ModeNormal)
182 require.True(t, ok)
183 mailTarget, ok := ParseFloatingProfileTarget(mailAction)
184 require.True(t, ok)
185 assert.Equal(t, "mail", mailTarget.SessionID)
186 assert.Equal(t, "https://mail.example.com", mailTarget.URL)
187
188 searchAction, ok := set.Lookup(KeyBinding{Keyval: uint(gdk.KEY_y), Modifiers: ModCtrl | ModShift}, ModeNormal)
189 require.True(t, ok)
190 searchTarget, ok := ParseFloatingProfileTarget(searchAction)
191 require.True(t, ok)
192 assert.Equal(t, "search", searchTarget.SessionID)
193 assert.Equal(t, "https://search.example.com", searchTarget.URL)
194}
195
196func TestParseFloatingProfileTarget_AllowsPipeInURL(t *testing.T) {
197 action := NewFloatingProfileAction("pipe-test", "https://example.com/a|b")
198
199 target, ok := ParseFloatingProfileTarget(action)
200 require.True(t, ok)
201 assert.Equal(t, "pipe-test", target.SessionID)
202 assert.Equal(t, "https://example.com/a|b", target.URL)
203}