1package libinput
2
3import (
4 "bytes"
5 "strings"
6 "testing"
7
8 "github.com/bnema/neferwl/internal/ports"
9 "github.com/bnema/zerowrap"
10)
11
12const (
13 testPad uintptr = 1
14 testMouse uintptr = 2
15 testKeyboard uintptr = 3
16)
17
18// Every shared field differs between the two, so a mixed-up route fails.
19var (
20 padCfg = ports.TouchpadConfig{PointerConfig: ports.PointerConfig{NaturalScroll: true, AccelSpeed: 0.5, AccelProfile: ports.AccelFlat}, Tap: true}
21 mouseCfg = ports.PointerConfig{AccelSpeed: -0.25, AccelProfile: ports.AccelAdaptive, LeftHanded: true}
22)
23
24// newState returns an input state over a device config mock, and a logger
25// writing to the returned buffer.
26func newState(t *testing.T) (*inputState, *mockdeviceConfig, zerowrap.Logger, *bytes.Buffer) {
27 t.Helper()
28 dev := newMockdeviceConfig(t)
29 buf := &bytes.Buffer{}
30 log := zerowrap.New(zerowrap.Config{Level: "debug", Format: "json", Output: buf}).WithField("component", "input")
31 return &inputState{cfg: ports.InputDevicesConfig{Touchpad: padCfg, Mouse: mouseCfg}, dev: dev}, dev, log, buf
32}
33
34func TestConfigure(t *testing.T) {
35 for _, tc := range []struct {
36 name string
37 dev uintptr
38 expect func(m *mockdeviceConfig)
39 }{
40 {"touchpad", testPad, func(m *mockdeviceConfig) {
41 m.EXPECT().IsTouchpad(testPad).Return(true)
42 m.EXPECT().SetNaturalScroll(testPad, true).Return(nil).Once()
43 m.EXPECT().SetAccel(testPad, 0.5, ports.AccelFlat).Return(nil).Once()
44 m.EXPECT().SetLeftHanded(testPad, false).Return(nil).Once()
45 m.EXPECT().SetTap(testPad, true).Return(nil).Once()
46 }},
47 // The touchpad settings must not reach the mouse, and a mouse is
48 // never given tapping: SetTap has no expectation.
49 {"mouse", testMouse, func(m *mockdeviceConfig) {
50 m.EXPECT().IsTouchpad(testMouse).Return(false)
51 m.EXPECT().IsPointer(testMouse).Return(true)
52 m.EXPECT().SetNaturalScroll(testMouse, false).Return(nil).Once()
53 m.EXPECT().SetAccel(testMouse, -0.25, ports.AccelAdaptive).Return(nil).Once()
54 m.EXPECT().SetLeftHanded(testMouse, true).Return(nil).Once()
55 }},
56 {"keyboard", testKeyboard, func(m *mockdeviceConfig) {
57 m.EXPECT().IsTouchpad(testKeyboard).Return(false)
58 m.EXPECT().IsPointer(testKeyboard).Return(false)
59 }},
60 } {
61 t.Run(tc.name, func(t *testing.T) {
62 in, dev, log, buf := newState(t)
63 tc.expect(dev)
64 in.configure(tc.dev, log)
65 if buf.Len() != 0 {
66 t.Fatalf("logged: %s", buf)
67 }
68 })
69 }
70}
71
72func TestConfigurable(t *testing.T) {
73 for _, tc := range []struct {
74 name string
75 touchpad, ptr bool
76 want, askedPtr bool
77 }{
78 {"touchpad", true, false, true, false},
79 {"mouse", false, true, true, true},
80 {"keyboard", false, false, false, true},
81 } {
82 t.Run(tc.name, func(t *testing.T) {
83 in, dev, _, _ := newState(t)
84 dev.EXPECT().IsTouchpad(testPad).Return(tc.touchpad)
85 if tc.askedPtr {
86 dev.EXPECT().IsPointer(testPad).Return(tc.ptr)
87 }
88 if got := in.configurable(testPad); got != tc.want {
89 t.Fatalf("configurable = %v, want %v", got, tc.want)
90 }
91 })
92 }
93}
94
95func TestConfigureRejectedSettingLogsAndContinues(t *testing.T) {
96 in, dev, log, buf := newState(t)
97 dev.EXPECT().IsTouchpad(testPad).Return(true)
98 dev.EXPECT().SetNaturalScroll(testPad, true).Return(errRejected).Once()
99 dev.EXPECT().Name(testPad).Return("Synaptics").Once()
100 dev.EXPECT().SetAccel(testPad, 0.5, ports.AccelFlat).Return(nil).Once()
101 dev.EXPECT().SetLeftHanded(testPad, false).Return(nil).Once()
102 dev.EXPECT().SetTap(testPad, true).Return(nil).Once()
103 in.configure(testPad, log)
104 out := buf.String()
105 for _, want := range []string{`"device":"Synaptics"`, `"setting":`, `"component":"input"`, `"level":"warn"`} {
106 if !strings.Contains(out, want) {
107 t.Errorf("log %s lacks %s", out, want)
108 }
109 }
110 if n := strings.Count(out, "\n"); n != 1 {
111 t.Errorf("%d log lines, want 1: %s", n, out)
112 }
113}