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