mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-10 07:25:37 -05:00
472 lines
11 KiB
Go
472 lines
11 KiB
Go
package sway
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestAutogenerateComment(t *testing.T) {
|
|
tests := []struct {
|
|
command string
|
|
expected string
|
|
}{
|
|
{"exec kitty", "kitty"},
|
|
{"exec --no-startup-id firefox", "firefox"},
|
|
{"kill", "Close window"},
|
|
{"exit", "Exit Sway"},
|
|
{"reload", "Reload configuration"},
|
|
{"fullscreen toggle", "Toggle fullscreen"},
|
|
{"floating toggle", "Float/unfloat window"},
|
|
{"focus mode_toggle", "Toggle focus mode"},
|
|
{"focus parent", "Focus parent container"},
|
|
{"focus left", "Focus left"},
|
|
{"focus right", "Focus right"},
|
|
{"focus up", "Focus up"},
|
|
{"focus down", "Focus down"},
|
|
{"focus output left", "Focus monitor"},
|
|
{"move left", "Move window left"},
|
|
{"move right", "Move window right"},
|
|
{"move up", "Move window up"},
|
|
{"move down", "Move window down"},
|
|
{"move container to workspace number 1", "Move to workspace 1"},
|
|
{"move container to workspace prev", "Move to previous workspace"},
|
|
{"move container to workspace next", "Move to next workspace"},
|
|
{"move workspace to output left", "Move workspace to monitor"},
|
|
{"workspace number 1", "Workspace 1"},
|
|
{"workspace prev", "Previous workspace"},
|
|
{"workspace next", "Next workspace"},
|
|
{"layout tabbed", "Layout tabbed"},
|
|
{"layout stacking", "Layout stacking"},
|
|
{"splith", "Split horizontal"},
|
|
{"splitv", "Split vertical"},
|
|
{"resize grow width 10 ppt", "Resize window"},
|
|
{"move scratchpad", "Toggle scratchpad"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.command, func(t *testing.T) {
|
|
result := autogenerateComment(tt.command)
|
|
if result != tt.expected {
|
|
t.Errorf("autogenerateComment(%q) = %q, want %q",
|
|
tt.command, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetKeybindAtLine(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
line string
|
|
expected *KeyBinding
|
|
}{
|
|
{
|
|
name: "basic_keybind",
|
|
line: "bindsym Mod4+q kill",
|
|
expected: &KeyBinding{
|
|
Mods: []string{"Mod4"},
|
|
Key: "q",
|
|
Command: "kill",
|
|
Comment: "Close window",
|
|
},
|
|
},
|
|
{
|
|
name: "keybind_with_exec",
|
|
line: "bindsym Mod4+t exec kitty",
|
|
expected: &KeyBinding{
|
|
Mods: []string{"Mod4"},
|
|
Key: "t",
|
|
Command: "exec kitty",
|
|
Comment: "kitty",
|
|
},
|
|
},
|
|
{
|
|
name: "keybind_with_comment",
|
|
line: "bindsym Mod4+Space exec dms ipc call spotlight toggle # Open launcher",
|
|
expected: &KeyBinding{
|
|
Mods: []string{"Mod4"},
|
|
Key: "Space",
|
|
Command: "exec dms ipc call spotlight toggle",
|
|
Comment: "Open launcher",
|
|
},
|
|
},
|
|
{
|
|
name: "keybind_hidden",
|
|
line: "bindsym Mod4+h exec secret # [hidden]",
|
|
expected: nil,
|
|
},
|
|
{
|
|
name: "keybind_multiple_mods",
|
|
line: "bindsym Mod4+Shift+e exit",
|
|
expected: &KeyBinding{
|
|
Mods: []string{"Mod4", "Shift"},
|
|
Key: "e",
|
|
Command: "exit",
|
|
Comment: "Exit Sway",
|
|
},
|
|
},
|
|
{
|
|
name: "keybind_no_mods",
|
|
line: "bindsym Print exec grim screenshot.png",
|
|
expected: &KeyBinding{
|
|
Mods: []string{},
|
|
Key: "Print",
|
|
Command: "exec grim screenshot.png",
|
|
Comment: "grim screenshot.png",
|
|
},
|
|
},
|
|
{
|
|
name: "keybind_with_flags",
|
|
line: "bindsym --release Mod4+x exec notify-send released",
|
|
expected: &KeyBinding{
|
|
Mods: []string{"Mod4"},
|
|
Key: "x",
|
|
Command: "exec notify-send released",
|
|
Comment: "notify-send released",
|
|
},
|
|
},
|
|
{
|
|
name: "keybind_focus_direction",
|
|
line: "bindsym Mod4+Left focus left",
|
|
expected: &KeyBinding{
|
|
Mods: []string{"Mod4"},
|
|
Key: "Left",
|
|
Command: "focus left",
|
|
Comment: "Focus left",
|
|
},
|
|
},
|
|
{
|
|
name: "keybind_workspace",
|
|
line: "bindsym Mod4+1 workspace number 1",
|
|
expected: &KeyBinding{
|
|
Mods: []string{"Mod4"},
|
|
Key: "1",
|
|
Command: "workspace number 1",
|
|
Comment: "Workspace 1",
|
|
},
|
|
},
|
|
}
|
|
|
|
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.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 TestVariableExpansion(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configFile := filepath.Join(tmpDir, "config")
|
|
|
|
content := `set $mod Mod4
|
|
set $term kitty
|
|
set $menu rofi
|
|
|
|
bindsym $mod+t exec $term
|
|
bindsym $mod+d exec $menu
|
|
`
|
|
|
|
if err := os.WriteFile(configFile, []byte(content), 0644); err != nil {
|
|
t.Fatalf("Failed to write test config: %v", err)
|
|
}
|
|
|
|
section, err := ParseKeys(configFile)
|
|
if err != nil {
|
|
t.Fatalf("ParseKeys failed: %v", err)
|
|
}
|
|
|
|
if len(section.Keybinds) != 2 {
|
|
t.Errorf("Expected 2 keybinds, got %d", len(section.Keybinds))
|
|
}
|
|
|
|
if len(section.Keybinds) > 0 {
|
|
if section.Keybinds[0].Mods[0] != "Mod4" {
|
|
t.Errorf("Expected Mod4, got %q", section.Keybinds[0].Mods[0])
|
|
}
|
|
if section.Keybinds[0].Command != "exec kitty" {
|
|
t.Errorf("Expected 'exec kitty', got %q", section.Keybinds[0].Command)
|
|
}
|
|
}
|
|
|
|
if len(section.Keybinds) > 1 {
|
|
if section.Keybinds[1].Command != "exec rofi" {
|
|
t.Errorf("Expected 'exec rofi', got %q", section.Keybinds[1].Command)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseKeysWithSections(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configFile := filepath.Join(tmpDir, "config")
|
|
|
|
content := `set $mod Mod4
|
|
|
|
##! Window Management
|
|
bindsym $mod+q kill
|
|
bindsym $mod+f fullscreen toggle
|
|
|
|
###! Focus
|
|
bindsym $mod+Left focus left
|
|
bindsym $mod+Right focus right
|
|
|
|
##! Applications
|
|
bindsym $mod+t exec kitty # Terminal
|
|
`
|
|
|
|
if err := os.WriteFile(configFile, []byte(content), 0644); err != nil {
|
|
t.Fatalf("Failed to write test config: %v", err)
|
|
}
|
|
|
|
section, err := ParseKeys(tmpDir)
|
|
if err != nil {
|
|
t.Fatalf("ParseKeys failed: %v", err)
|
|
}
|
|
|
|
if len(section.Children) != 2 {
|
|
t.Errorf("Expected 2 top-level sections, got %d", len(section.Children))
|
|
}
|
|
|
|
if len(section.Children) >= 1 {
|
|
windowMgmt := section.Children[0]
|
|
if windowMgmt.Name != "Window Management" {
|
|
t.Errorf("First section name = %q, want %q", windowMgmt.Name, "Window Management")
|
|
}
|
|
if len(windowMgmt.Keybinds) != 2 {
|
|
t.Errorf("Window Management keybinds = %d, want 2", len(windowMgmt.Keybinds))
|
|
}
|
|
|
|
if len(windowMgmt.Children) != 1 {
|
|
t.Errorf("Window Management children = %d, want 1", len(windowMgmt.Children))
|
|
} else {
|
|
focus := windowMgmt.Children[0]
|
|
if focus.Name != "Focus" {
|
|
t.Errorf("Focus section name = %q, want %q", focus.Name, "Focus")
|
|
}
|
|
if len(focus.Keybinds) != 2 {
|
|
t.Errorf("Focus keybinds = %d, want 2", len(focus.Keybinds))
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(section.Children) >= 2 {
|
|
apps := section.Children[1]
|
|
if apps.Name != "Applications" {
|
|
t.Errorf("Second section name = %q, want %q", apps.Name, "Applications")
|
|
}
|
|
if len(apps.Keybinds) != 1 {
|
|
t.Errorf("Applications keybinds = %d, want 1", len(apps.Keybinds))
|
|
}
|
|
if len(apps.Keybinds) > 0 && apps.Keybinds[0].Comment != "Terminal" {
|
|
t.Errorf("Applications keybind comment = %q, want %q", apps.Keybinds[0].Comment, "Terminal")
|
|
}
|
|
}
|
|
}
|
|
|
|
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-sway-"+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")
|
|
if err := os.WriteFile(configFile, []byte("bindsym Mod4+q kill\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")
|
|
|
|
content := `
|
|
# This is a comment
|
|
bindsym Mod4+q kill
|
|
|
|
# Another comment
|
|
|
|
bindsym Mod4+t exec kitty
|
|
`
|
|
|
|
if err := os.WriteFile(configFile, []byte(content), 0644); err != nil {
|
|
t.Fatalf("Failed to write test config: %v", err)
|
|
}
|
|
|
|
section, err := ParseKeys(configFile)
|
|
if err != nil {
|
|
t.Fatalf("ParseKeys failed: %v", err)
|
|
}
|
|
|
|
if len(section.Keybinds) != 2 {
|
|
t.Errorf("Expected 2 keybinds (comments ignored), got %d", len(section.Keybinds))
|
|
}
|
|
}
|
|
|
|
func TestRealWorldConfig(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configFile := filepath.Join(tmpDir, "config")
|
|
|
|
content := `set $mod Mod4
|
|
set $term kitty
|
|
|
|
## Application Launchers
|
|
bindsym $mod+t exec $term
|
|
bindsym $mod+Space exec rofi
|
|
|
|
## Window Management
|
|
bindsym $mod+q kill
|
|
bindsym $mod+f fullscreen toggle
|
|
|
|
## Focus Navigation
|
|
bindsym $mod+Left focus left
|
|
bindsym $mod+Right focus right
|
|
|
|
## Workspace Navigation
|
|
bindsym $mod+1 workspace number 1
|
|
bindsym $mod+2 workspace number 2
|
|
bindsym $mod+Shift+1 move container to workspace number 1
|
|
`
|
|
|
|
if err := os.WriteFile(configFile, []byte(content), 0644); err != nil {
|
|
t.Fatalf("Failed to write test config: %v", err)
|
|
}
|
|
|
|
section, err := ParseKeys(configFile)
|
|
if err != nil {
|
|
t.Fatalf("ParseKeys failed: %v", err)
|
|
}
|
|
|
|
if len(section.Keybinds) < 9 {
|
|
t.Errorf("Expected at least 9 keybinds, got %d", len(section.Keybinds))
|
|
}
|
|
|
|
foundExec := false
|
|
foundKill := false
|
|
foundWorkspace := false
|
|
|
|
for _, kb := range section.Keybinds {
|
|
if kb.Command == "exec kitty" {
|
|
foundExec = true
|
|
}
|
|
if kb.Command == "kill" {
|
|
foundKill = true
|
|
}
|
|
if kb.Command == "workspace number 1" {
|
|
foundWorkspace = true
|
|
}
|
|
}
|
|
|
|
if !foundExec {
|
|
t.Error("Did not find exec kitty keybind")
|
|
}
|
|
if !foundKill {
|
|
t.Error("Did not find kill keybind")
|
|
}
|
|
if !foundWorkspace {
|
|
t.Error("Did not find workspace 1 keybind")
|
|
}
|
|
}
|
|
|
|
func TestIsMod(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expected bool
|
|
}{
|
|
{"Mod4", true},
|
|
{"Shift", true},
|
|
{"Control", true},
|
|
{"Alt", true},
|
|
{"Super", true},
|
|
{"$mod", true},
|
|
{"Left", false},
|
|
{"q", false},
|
|
{"1", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.input, func(t *testing.T) {
|
|
result := isMod(tt.input)
|
|
if result != tt.expected {
|
|
t.Errorf("isMod(%q) = %v, want %v", tt.input, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|