1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-05 21:15:38 -05:00
Files
DankMaterialShell/backend/internal/mangowc/keybinds_test.go
2025-11-12 17:18:45 -05:00

500 lines
12 KiB
Go

package mangowc
import (
"os"
"path/filepath"
"testing"
)
func TestAutogenerateComment(t *testing.T) {
tests := []struct {
command string
params string
expected string
}{
{"spawn", "kitty", "kitty"},
{"spawn_shell", "firefox", "firefox"},
{"killclient", "", "Close window"},
{"quit", "", "Exit MangoWC"},
{"reload_config", "", "Reload configuration"},
{"focusstack", "next", "Focus next window"},
{"focusstack", "prev", "Focus previous window"},
{"focusdir", "left", "Focus left"},
{"focusdir", "right", "Focus right"},
{"focusdir", "up", "Focus up"},
{"focusdir", "down", "Focus down"},
{"exchange_client", "left", "Swap window left"},
{"exchange_client", "right", "Swap window right"},
{"togglefloating", "", "Float/unfloat window"},
{"togglefullscreen", "", "Toggle fullscreen"},
{"togglefakefullscreen", "", "Toggle fake fullscreen"},
{"togglemaximizescreen", "", "Toggle maximize"},
{"toggleglobal", "", "Toggle global"},
{"toggleoverview", "", "Toggle overview"},
{"toggleoverlay", "", "Toggle overlay"},
{"minimized", "", "Minimize window"},
{"restore_minimized", "", "Restore minimized"},
{"toggle_scratchpad", "", "Toggle scratchpad"},
{"setlayout", "tile", "Set layout tile"},
{"switch_layout", "", "Switch layout"},
{"view", "1,0", "View tag 1"},
{"tag", "2,0", "Move to tag 2"},
{"toggleview", "3,0", "Toggle tag 3"},
{"viewtoleft", "", "View left tag"},
{"viewtoright", "", "View right tag"},
{"viewtoleft_have_client", "", "View left tag"},
{"viewtoright_have_client", "", "View right tag"},
{"tagtoleft", "", "Move to left tag"},
{"tagtoright", "", "Move to right tag"},
{"focusmon", "left", "Focus monitor left"},
{"tagmon", "right", "Move to monitor right"},
{"incgaps", "1", "Increase gaps"},
{"incgaps", "-1", "Decrease gaps"},
{"togglegaps", "", "Toggle gaps"},
{"movewin", "+0,-50", "Move window by +0,-50"},
{"resizewin", "+0,+50", "Resize window by +0,+50"},
{"set_proportion", "1.0", "Set proportion 1.0"},
{"switch_proportion_preset", "", "Switch proportion preset"},
{"unknown", "", ""},
}
for _, tt := range tests {
t.Run(tt.command+"_"+tt.params, func(t *testing.T) {
result := autogenerateComment(tt.command, tt.params)
if result != tt.expected {
t.Errorf("autogenerateComment(%q, %q) = %q, want %q",
tt.command, tt.params, result, tt.expected)
}
})
}
}
func TestGetKeybindAtLine(t *testing.T) {
tests := []struct {
name string
line string
expected *KeyBinding
}{
{
name: "basic_keybind",
line: "bind=ALT,q,killclient,",
expected: &KeyBinding{
Mods: []string{"ALT"},
Key: "q",
Command: "killclient",
Params: "",
Comment: "Close window",
},
},
{
name: "keybind_with_params",
line: "bind=ALT,Left,focusdir,left",
expected: &KeyBinding{
Mods: []string{"ALT"},
Key: "Left",
Command: "focusdir",
Params: "left",
Comment: "Focus left",
},
},
{
name: "keybind_with_comment",
line: "bind=Alt,t,spawn,kitty # Open terminal",
expected: &KeyBinding{
Mods: []string{"Alt"},
Key: "t",
Command: "spawn",
Params: "kitty",
Comment: "Open terminal",
},
},
{
name: "keybind_hidden",
line: "bind=SUPER,h,spawn,secret # [hidden]",
expected: nil,
},
{
name: "keybind_multiple_mods",
line: "bind=SUPER+SHIFT,Up,exchange_client,up",
expected: &KeyBinding{
Mods: []string{"SUPER", "SHIFT"},
Key: "Up",
Command: "exchange_client",
Params: "up",
Comment: "Swap window up",
},
},
{
name: "keybind_no_mods",
line: "bind=NONE,Print,spawn,screenshot",
expected: &KeyBinding{
Mods: []string{},
Key: "Print",
Command: "spawn",
Params: "screenshot",
Comment: "screenshot",
},
},
{
name: "keybind_multiple_params",
line: "bind=Ctrl,1,view,1,0",
expected: &KeyBinding{
Mods: []string{"Ctrl"},
Key: "1",
Command: "view",
Params: "1,0",
Comment: "View tag 1",
},
},
{
name: "bindl_flag",
line: "bindl=SUPER+ALT,l,spawn,dms ipc call lock lock",
expected: &KeyBinding{
Mods: []string{"SUPER", "ALT"},
Key: "l",
Command: "spawn",
Params: "dms ipc call lock lock",
Comment: "dms ipc call lock lock",
},
},
{
name: "keybind_with_spaces",
line: "bind = SUPER, r, reload_config",
expected: &KeyBinding{
Mods: []string{"SUPER"},
Key: "r",
Command: "reload_config",
Params: "",
Comment: "Reload configuration",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
parser := NewParser()
parser.contentLines = []string{tt.line}
result := parser.getKeybindAtLine(0)
if tt.expected == nil {
if result != nil {
t.Errorf("expected nil, got %+v", result)
}
return
}
if result == nil {
t.Errorf("expected %+v, got nil", tt.expected)
return
}
if result.Key != tt.expected.Key {
t.Errorf("Key = %q, want %q", result.Key, tt.expected.Key)
}
if result.Command != tt.expected.Command {
t.Errorf("Command = %q, want %q", result.Command, tt.expected.Command)
}
if result.Params != tt.expected.Params {
t.Errorf("Params = %q, want %q", result.Params, tt.expected.Params)
}
if result.Comment != tt.expected.Comment {
t.Errorf("Comment = %q, want %q", result.Comment, tt.expected.Comment)
}
if len(result.Mods) != len(tt.expected.Mods) {
t.Errorf("Mods length = %d, want %d", len(result.Mods), len(tt.expected.Mods))
} else {
for i := range result.Mods {
if result.Mods[i] != tt.expected.Mods[i] {
t.Errorf("Mods[%d] = %q, want %q", i, result.Mods[i], tt.expected.Mods[i])
}
}
}
})
}
}
func TestParseKeys(t *testing.T) {
tmpDir := t.TempDir()
configFile := filepath.Join(tmpDir, "config.conf")
content := `# MangoWC Configuration
blur=0
border_radius=12
# Key Bindings
bind=SUPER,r,reload_config
bind=Alt,t,spawn,kitty # Terminal
bind=ALT,q,killclient,
bind=ALT,Left,focusdir,left
# Hidden binding
bind=SUPER,h,spawn,secret # [hidden]
# Multiple modifiers
bind=SUPER+SHIFT,Up,exchange_client,up
# Workspace bindings
bind=Ctrl,1,view,1,0
bind=Ctrl,2,view,2,0
`
if err := os.WriteFile(configFile, []byte(content), 0644); err != nil {
t.Fatalf("Failed to write test config: %v", err)
}
keybinds, err := ParseKeys(configFile)
if err != nil {
t.Fatalf("ParseKeys failed: %v", err)
}
expectedCount := 7
if len(keybinds) != expectedCount {
t.Errorf("Expected %d keybinds, got %d", expectedCount, len(keybinds))
}
if len(keybinds) > 0 && keybinds[0].Command != "reload_config" {
t.Errorf("First keybind command = %q, want %q", keybinds[0].Command, "reload_config")
}
foundHidden := false
for _, kb := range keybinds {
if kb.Command == "spawn" && kb.Params == "secret" {
foundHidden = true
}
}
if foundHidden {
t.Error("Hidden keybind should not be included in results")
}
}
func TestReadContentMultipleFiles(t *testing.T) {
tmpDir := t.TempDir()
file1 := filepath.Join(tmpDir, "a.conf")
file2 := filepath.Join(tmpDir, "b.conf")
content1 := "bind=ALT,q,killclient,\n"
content2 := "bind=Alt,t,spawn,kitty\n"
if err := os.WriteFile(file1, []byte(content1), 0644); err != nil {
t.Fatalf("Failed to write file1: %v", err)
}
if err := os.WriteFile(file2, []byte(content2), 0644); err != nil {
t.Fatalf("Failed to write file2: %v", err)
}
parser := NewParser()
if err := parser.ReadContent(tmpDir); err != nil {
t.Fatalf("ReadContent failed: %v", err)
}
keybinds := parser.ParseKeys()
if len(keybinds) != 2 {
t.Errorf("Expected 2 keybinds from multiple files, got %d", len(keybinds))
}
}
func TestReadContentSingleFile(t *testing.T) {
tmpDir := t.TempDir()
configFile := filepath.Join(tmpDir, "config.conf")
content := "bind=ALT,q,killclient,\n"
if err := os.WriteFile(configFile, []byte(content), 0644); err != nil {
t.Fatalf("Failed to write config: %v", err)
}
parser := NewParser()
if err := parser.ReadContent(configFile); err != nil {
t.Fatalf("ReadContent failed: %v", err)
}
keybinds := parser.ParseKeys()
if len(keybinds) != 1 {
t.Errorf("Expected 1 keybind, got %d", len(keybinds))
}
}
func TestReadContentErrors(t *testing.T) {
tests := []struct {
name string
path string
}{
{
name: "nonexistent_directory",
path: "/nonexistent/path/that/does/not/exist",
},
{
name: "empty_directory",
path: t.TempDir(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := ParseKeys(tt.path)
if err == nil {
t.Error("Expected error, got nil")
}
})
}
}
func TestReadContentWithTildeExpansion(t *testing.T) {
homeDir, err := os.UserHomeDir()
if err != nil {
t.Skip("Cannot get home directory")
}
tmpSubdir := filepath.Join(homeDir, ".config", "test-mango-"+t.Name())
if err := os.MkdirAll(tmpSubdir, 0755); err != nil {
t.Skip("Cannot create test directory in home")
}
defer os.RemoveAll(tmpSubdir)
configFile := filepath.Join(tmpSubdir, "config.conf")
if err := os.WriteFile(configFile, []byte("bind=ALT,q,killclient,\n"), 0644); err != nil {
t.Fatalf("Failed to write test config: %v", err)
}
relPath, err := filepath.Rel(homeDir, tmpSubdir)
if err != nil {
t.Skip("Cannot create relative path")
}
parser := NewParser()
tildePathMatch := "~/" + relPath
err = parser.ReadContent(tildePathMatch)
if err != nil {
t.Errorf("ReadContent with tilde path failed: %v", err)
}
}
func TestEmptyAndCommentLines(t *testing.T) {
tmpDir := t.TempDir()
configFile := filepath.Join(tmpDir, "config.conf")
content := `
# This is a comment
bind=ALT,q,killclient,
# Another comment
bind=Alt,t,spawn,kitty
`
if err := os.WriteFile(configFile, []byte(content), 0644); err != nil {
t.Fatalf("Failed to write test config: %v", err)
}
keybinds, err := ParseKeys(configFile)
if err != nil {
t.Fatalf("ParseKeys failed: %v", err)
}
if len(keybinds) != 2 {
t.Errorf("Expected 2 keybinds (comments ignored), got %d", len(keybinds))
}
}
func TestInvalidBindLines(t *testing.T) {
tests := []struct {
name string
line string
}{
{
name: "missing_parts",
line: "bind=SUPER,q",
},
{
name: "not_bind",
line: "blur=0",
},
{
name: "empty_line",
line: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
parser := NewParser()
parser.contentLines = []string{tt.line}
result := parser.getKeybindAtLine(0)
if result != nil {
t.Errorf("expected nil for invalid line, got %+v", result)
}
})
}
}
func TestRealWorldConfig(t *testing.T) {
tmpDir := t.TempDir()
configFile := filepath.Join(tmpDir, "config.conf")
content := `# Application Launchers
bind=Alt,t,spawn,kitty
bind=Alt,space,spawn,dms ipc call spotlight toggle
bind=Alt,v,spawn,dms ipc call clipboard toggle
# exit
bind=ALT+SHIFT,e,quit
bind=ALT,q,killclient,
# switch window focus
bind=SUPER,Tab,focusstack,next
bind=ALT,Left,focusdir,left
bind=ALT,Right,focusdir,right
# tag switch
bind=SUPER,Left,viewtoleft,0
bind=CTRL,Left,viewtoleft_have_client,0
bind=SUPER,Right,viewtoright,0
bind=Ctrl,1,view,1,0
bind=Ctrl,2,view,2,0
bind=Ctrl,3,view,3,0
`
if err := os.WriteFile(configFile, []byte(content), 0644); err != nil {
t.Fatalf("Failed to write test config: %v", err)
}
keybinds, err := ParseKeys(configFile)
if err != nil {
t.Fatalf("ParseKeys failed: %v", err)
}
if len(keybinds) < 14 {
t.Errorf("Expected at least 14 keybinds, got %d", len(keybinds))
}
foundSpawn := false
foundQuit := false
foundView := false
for _, kb := range keybinds {
if kb.Command == "spawn" && kb.Params == "kitty" {
foundSpawn = true
}
if kb.Command == "quit" {
foundQuit = true
}
if kb.Command == "view" && kb.Params == "1,0" {
foundView = true
}
}
if !foundSpawn {
t.Error("Did not find spawn kitty keybind")
}
if !foundQuit {
t.Error("Did not find quit keybind")
}
if !foundView {
t.Error("Did not find view workspace 1 keybind")
}
}