Research 026/04 counted two plain dmenu calls failing with dmenu installed nowhere. Measured, they are one line on each workstation: dunst's `dmenu = /usr/bin/dmenu -p dunst:`. Installing the package fixes both by existing; the line stays the dunst module's. No claim: node-launcher is not in the controller's seat table yet, and the module says so. Two Go tools: menu, shaped like that seat's verb (chosen line, index, typed, cancelled, timed out within 25 s), and session.
109 lines
3.8 KiB
Go
109 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestTheManifestIsThePackageAndClaimsNoSeatYet(t *testing.T) {
|
|
m := readManifest(t)
|
|
// holdsTheBundle also holds it to no claim: node-launcher is not in the controller's seat table
|
|
// yet (README).
|
|
holdsTheBundle(t, m, "dmenu")
|
|
if got := strings.Join(m.packages(), ","); got != "dmenu" || len(m.Resources) != 1 {
|
|
t.Errorf("packages %s, resources %v", got, m.Resources)
|
|
}
|
|
}
|
|
|
|
func aSession(t *testing.T) {
|
|
t.Helper()
|
|
_, sockets := aMachine(t, map[string]string{"DISPLAY": ":1", "XAUTHORITY": "/home/op/.Xauthority"})
|
|
aSocket(t, sockets, "X1")
|
|
}
|
|
|
|
func TestMenuShowsTheChoicesInTheSessionAndAnswersTheOneTaken(t *testing.T) {
|
|
aSession(t)
|
|
f := using(t, func(string, Cmd) Result { return ok("Lock\n") })
|
|
got, err := Menu(Ask{Choices: []string{"Shutdown", "Lock"}, Prompt: "power:", Lines: 5, CaseInsensitive: true, Timeout: 20})
|
|
if err != nil || got.Chosen != "Lock" || got.Index != 1 || got.Typed || got.Cancelled || got.TimedOut {
|
|
t.Fatalf("%+v %v", got, err)
|
|
}
|
|
c := f.asked[0]
|
|
if f.lines()[0] != "dmenu -i -l 5 -p power:" || c.Stdin != "Shutdown\nLock\n" || c.Timeout != 20*time.Second {
|
|
t.Errorf("%v %+v", f.lines(), c)
|
|
}
|
|
if strings.Join(c.Env, " ") != "DISPLAY=:1 XAUTHORITY=/home/op/.Xauthority" {
|
|
t.Errorf("env %v", c.Env)
|
|
}
|
|
}
|
|
|
|
func TestMenuTellsTypedDismissedAndUnansweredApart(t *testing.T) {
|
|
aSession(t)
|
|
answer := ok("something else\n")
|
|
using(t, func(string, Cmd) Result { return answer })
|
|
got, err := Menu(Ask{Choices: []string{"a"}, Timeout: 5})
|
|
if err != nil || !got.Typed || got.Index != -1 || got.Chosen != "something else" {
|
|
t.Errorf("typed: %+v %v", got, err)
|
|
}
|
|
answer = Result{Status: 1}
|
|
got, err = Menu(Ask{Choices: []string{"a"}, Timeout: 5})
|
|
if err != nil || !got.Cancelled || got.Chosen != "" {
|
|
t.Errorf("dismissed: %+v %v", got, err)
|
|
}
|
|
answer = Result{Status: 124, Error: "timeout"}
|
|
got, err = Menu(Ask{Choices: []string{"a"}, Timeout: 5})
|
|
if err != nil || !got.TimedOut {
|
|
t.Errorf("unanswered: %+v %v", got, err)
|
|
}
|
|
answer = Result{Status: 1, Stderr: "cannot grab keyboard\n"}
|
|
if _, err := Menu(Ask{Choices: []string{"a"}, Timeout: 5}); err == nil || !strings.Contains(err.Error(), "keyboard") {
|
|
t.Errorf("a held keyboard: %v", err)
|
|
}
|
|
answer = Result{Status: 1, Stderr: "cannot open display\n"}
|
|
if _, err := Menu(Ask{Choices: []string{"a"}, Timeout: 5}); err == nil || !strings.Contains(err.Error(), "refused") {
|
|
t.Errorf("a refusing display: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMenuRefusesWhatCannotBeShownAndRunsNothingWithoutASession(t *testing.T) {
|
|
aSession(t)
|
|
f := using(t, func(string, Cmd) Result { return ok("") })
|
|
for _, bad := range []Ask{{}, {Choices: []string{"a\nb"}}, {Choices: []string{"a"}, Prompt: "x\ny"}, {Choices: make([]string, MostChoices+1)}} {
|
|
if _, err := Menu(bad); err == nil {
|
|
t.Errorf("%+v accepted", bad)
|
|
}
|
|
}
|
|
aMachine(t, map[string]string{})
|
|
if _, err := Menu(Ask{Choices: []string{"a"}, Timeout: 5}); err == nil || !strings.Contains(err.Error(), "no graphical session") {
|
|
t.Errorf("%v", err)
|
|
}
|
|
if len(f.asked) != 0 {
|
|
t.Errorf("ran %v", f.lines())
|
|
}
|
|
}
|
|
|
|
func TestTheWaitIsBelowTheRuntimesCallLimit(t *testing.T) {
|
|
if MostWait >= 30 {
|
|
t.Fatalf("a menu may stay open %d s; the runtime gives a call 30", MostWait)
|
|
}
|
|
n, _ := optWhole(map[string]any{"timeout_seconds": float64(600)}, "timeout_seconds", 20, 1, MostWait)
|
|
if n != MostWait {
|
|
t.Errorf("%d", n)
|
|
}
|
|
}
|
|
|
|
func TestSessionCheckSaysTheVersionAndTheSession(t *testing.T) {
|
|
aSession(t)
|
|
using(t, func(string, Cmd) Result { return ok("dmenu-5.4\n") })
|
|
got, err := SessionCheck()
|
|
if err != nil || got["dmenu"] != "dmenu-5.4" || got["found"] != true {
|
|
t.Fatalf("%v %v", got, err)
|
|
}
|
|
using(t, func(string, Cmd) Result { return Result{Status: 127, Error: "not-found"} })
|
|
got, _ = SessionCheck()
|
|
if !strings.Contains(got["dmenu"].(string), "not installed") {
|
|
t.Errorf("%v", got)
|
|
}
|
|
}
|