package main import ( "context" "os" "path/filepath" "reflect" "strings" "testing" "time" ) func fakeRoot(t *testing.T, files map[string]string) string { t.Helper() root := t.TempDir() for p, c := range files { full := filepath.Join(root, p) if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(full, []byte(c), 0o644); err != nil { t.Fatal(err) } } return root } const meshConf = "# The machine's hotkeys, written by the mesh (module triggerhappy).\n" + "# asus-zephyrus-g14\nKEY_PROG1\t1\t/usr/local/lib/x/media play-pause\n# a note of several words\nKEY_F21\t1\t/usr/local/lib/x/touchpad reset\n" + "# other\nKEY_MUTE\t1\tmute\n" func TestTriggersAreAttributedToTheModuleThatContributedThem(t *testing.T) { m := &Machine{Root: fakeRoot(t, map[string]string{TriggerDir + "/mesh.conf": meshConf})} ts, err := m.Triggers() if err != nil { t.Fatal(err) } var got []string for _, tr := range ts { got = append(got, tr.Key+"="+tr.Module+"/"+tr.When) } want := []string{"KEY_PROG1=asus-zephyrus-g14/pressed", "KEY_F21=asus-zephyrus-g14/pressed", "KEY_MUTE=other/pressed"} if !reflect.DeepEqual(got, want) { t.Fatalf("%v, want %v", got, want) } } func TestAKeyBoundTwiceIsWarnedAboutAndFailsTheCheck(t *testing.T) { m := &Machine{Root: fakeRoot(t, map[string]string{ TriggerDir + "/mesh.conf": meshConf, TriggerDir + "/asus-g14.conf": "KEY_PROG1\t1\t/home/op/scripts/as-user media-control play-pause\n", }), Timeout: time.Second, Run: func(_ context.Context, name string, args ...string) (string, error) { if strings.Join(args, " ") == "is-active triggerhappy.service" { return "active\n", nil } return "/usr/bin/thd --user op", nil }} k, err := m.Keys() if err != nil { t.Fatal(err) } if len(k.Warnings) != 1 || !strings.Contains(k.Warnings[0], "KEY_PROG1 pressed is bound 2 times") { t.Fatalf("%v", k.Warnings) } c, err := m.Check() if err != nil { t.Fatal(err) } if c["failing"] != 2 { t.Fatalf("the predecessor's file and the duplicate should fail: %+v", c) } } func TestADumpSaysEachKeyAndStateOnce(t *testing.T) { out := "EV_KEY\tKEY_PROG1\t1\t/dev/input/event5\n# KEY_PROG1\t1\tcommand\n" + "EV_KEY\tKEY_PROG1\t0\t/dev/input/event5\n# KEY_PROG1\t0\tcommand\n# KEY_PROG1\t1\tcommand\n" m := &Machine{Timeout: time.Second, Run: func(context.Context, string, ...string) (string, error) { return out, context.DeadlineExceeded }} a, err := m.Dump(2) if err != nil { t.Fatal(err) } if want := []string{"KEY_PROG1 pressed", "KEY_PROG1 released"}; !reflect.DeepEqual(a.Events, want) { t.Fatalf("%v, want %v", a.Events, want) } } func TestDevicesWithAnEventHandlerAreListed(t *testing.T) { m := &Machine{Root: fakeRoot(t, map[string]string{"/proc/bus/input/devices": "N: Name=\"Asus WMI hotkeys\"\nH: Handlers=kbd event5\n\nN: Name=\"Nothing\"\nH: Handlers=mouse0\n\n"})} d, err := m.Devices() if err != nil { t.Fatal(err) } if len(d) != 1 || d[0].Name != "Asus WMI hotkeys" { t.Fatalf("%+v", d) } }