- TestReadPPID, TestReadPPIDMissing - TestResolveWorkspace, TestResolveWorkspaceNotFound, TestResolveWorkspaceMaxDepth - TestBuildTerminalWorkspaceMapUnit - Add go.i3wm.org/i3/v4 dependency
170 lines
3.6 KiB
Go
170 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
i3 "go.i3wm.org/i3/v4"
|
|
)
|
|
|
|
// --- Helpers ---
|
|
|
|
func writeFakeStatus(t *testing.T, procDir string, pid, ppid int) {
|
|
t.Helper()
|
|
pidDir := filepath.Join(procDir, fmt.Sprintf("%d", pid))
|
|
if err := os.MkdirAll(pidDir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
content := fmt.Sprintf("Name:\tprocess\nPPid:\t%d\nUid:\t1000\n", ppid)
|
|
if err := os.WriteFile(filepath.Join(pidDir, "status"), []byte(content), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// --- Mock types ---
|
|
|
|
type mockI3TreeProvider struct {
|
|
tree i3.Tree
|
|
err error
|
|
}
|
|
|
|
func (m *mockI3TreeProvider) GetTree() (i3.Tree, error) {
|
|
return m.tree, m.err
|
|
}
|
|
|
|
type mockX11PIDResolver struct {
|
|
pids map[int64]int // windowID -> PID
|
|
}
|
|
|
|
func (m *mockX11PIDResolver) GetPID(windowID int64) (int, error) {
|
|
pid, ok := m.pids[windowID]
|
|
if !ok {
|
|
return 0, fmt.Errorf("no PID for window %d", windowID)
|
|
}
|
|
return pid, nil
|
|
}
|
|
|
|
// --- ReadPPID tests ---
|
|
|
|
func TestReadPPID(t *testing.T) {
|
|
procDir := t.TempDir()
|
|
writeFakeStatus(t, procDir, 100, 50)
|
|
|
|
ppid, err := ReadPPID(procDir, 100)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if ppid != 50 {
|
|
t.Errorf("ReadPPID = %d, want 50", ppid)
|
|
}
|
|
}
|
|
|
|
func TestReadPPIDMissing(t *testing.T) {
|
|
procDir := t.TempDir()
|
|
|
|
_, err := ReadPPID(procDir, 999)
|
|
if err == nil {
|
|
t.Fatal("expected error for missing PID, got nil")
|
|
}
|
|
}
|
|
|
|
// --- ResolveWorkspace tests ---
|
|
|
|
func TestResolveWorkspace(t *testing.T) {
|
|
procDir := t.TempDir()
|
|
// Chain: 100 -> 50 -> 10
|
|
writeFakeStatus(t, procDir, 100, 50)
|
|
writeFakeStatus(t, procDir, 50, 10)
|
|
writeFakeStatus(t, procDir, 10, 1)
|
|
|
|
terminalMap := map[int]string{10: "workspace 3"}
|
|
|
|
ws := ResolveWorkspace(procDir, 100, terminalMap)
|
|
if ws != "workspace 3" {
|
|
t.Errorf("ResolveWorkspace = %q, want %q", ws, "workspace 3")
|
|
}
|
|
}
|
|
|
|
func TestResolveWorkspaceNotFound(t *testing.T) {
|
|
procDir := t.TempDir()
|
|
writeFakeStatus(t, procDir, 100, 50)
|
|
writeFakeStatus(t, procDir, 50, 1)
|
|
writeFakeStatus(t, procDir, 1, 0)
|
|
|
|
terminalMap := map[int]string{999: "workspace 5"}
|
|
|
|
ws := ResolveWorkspace(procDir, 100, terminalMap)
|
|
if ws != "" {
|
|
t.Errorf("ResolveWorkspace = %q, want empty", ws)
|
|
}
|
|
}
|
|
|
|
func TestResolveWorkspaceMaxDepth(t *testing.T) {
|
|
procDir := t.TempDir()
|
|
// Chain of 25 PIDs: 100 -> 99 -> 98 -> ... -> 76
|
|
for pid := 100; pid > 75; pid-- {
|
|
writeFakeStatus(t, procDir, pid, pid-1)
|
|
}
|
|
// PID 75 is in the terminal map but depth > 20
|
|
terminalMap := map[int]string{75: "workspace 1"}
|
|
|
|
ws := ResolveWorkspace(procDir, 100, terminalMap)
|
|
if ws != "" {
|
|
t.Errorf("ResolveWorkspace should return empty after max depth, got %q", ws)
|
|
}
|
|
}
|
|
|
|
// --- BuildTerminalWorkspaceMap tests ---
|
|
|
|
func TestBuildTerminalWorkspaceMapUnit(t *testing.T) {
|
|
// Mock i3 tree with 2 workspaces, each containing a window
|
|
tree := i3.Tree{
|
|
Root: &i3.Node{
|
|
Type: i3.Root,
|
|
Nodes: []*i3.Node{
|
|
{
|
|
Type: i3.OutputNode,
|
|
Name: "eDP-1",
|
|
Nodes: []*i3.Node{
|
|
{
|
|
Type: i3.WorkspaceNode,
|
|
Name: "1",
|
|
Nodes: []*i3.Node{
|
|
{Type: i3.Con, Window: 12345},
|
|
},
|
|
},
|
|
{
|
|
Type: i3.WorkspaceNode,
|
|
Name: "3",
|
|
Nodes: []*i3.Node{
|
|
{Type: i3.Con, Window: 67890},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
x11 := &mockX11PIDResolver{
|
|
pids: map[int64]int{
|
|
12345: 1000,
|
|
67890: 2000,
|
|
},
|
|
}
|
|
|
|
result, err := BuildTerminalWorkspaceMap(&mockI3TreeProvider{tree: tree}, x11)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
|
|
if result[1000] != "1" {
|
|
t.Errorf("PID 1000 workspace = %q, want %q", result[1000], "1")
|
|
}
|
|
if result[2000] != "3" {
|
|
t.Errorf("PID 2000 workspace = %q, want %q", result[2000], "3")
|
|
}
|
|
}
|