mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
500 lines
12 KiB
Go
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")
|
|
}
|
|
}
|