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) } }