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