1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
package main
import (
"strings"
"testing"
)
// The arguments are compared against what the python implementation this
// replaced produced for the same input, so that the rewrite is a port rather
// than a redesign.
func TestTwoMonitorArgs(t *testing.T) {
outputs := Parse(readFixture(t, "rolery-two-monitors.txt"))
args, err := TwoMonitorArgs(outputs)
if err != nil {
t.Fatalf("TwoMonitorArgs: %s", err)
}
want := []string{
"--verbose",
"--output", "HDMI-A-0", "--primary",
"--mode", "2560x1440",
"--pos", "1920x0",
"--output", "eDP",
"--mode", "1920x1080",
// 1440 - 1080 = 360: the laptop panel is pushed down so the two screens
// line up along their bottom edge.
"--pos", "0x360",
}
assertArgs(t, args, want)
}
func TestLaptopOnlyArgs(t *testing.T) {
outputs := Parse(readFixture(t, "rolery-laptop-only.txt"))
args, err := LaptopOnlyArgs(outputs)
if err != nil {
t.Fatalf("LaptopOnlyArgs: %s", err)
}
assertArgs(t, args, []string{
"--verbose",
"--output", "eDP", "--primary",
"--mode", "1920x1080",
})
}
// With only the laptop panel attached, the desk layout cannot be applied. The
// error matters as much as the failure: the xbindkeys binding chains further
// commands with `&&`, so this has to be a non-zero exit rather than a warning.
func TestTwoMonitorArgsFailsWithOneMonitor(t *testing.T) {
outputs := Parse(readFixture(t, "rolery-laptop-only.txt"))
_, err := TwoMonitorArgs(outputs)
if err == nil {
t.Fatal("got no error with a single connected monitor, want one")
}
if !strings.Contains(err.Error(), "two monitors") {
t.Errorf("got error %q, want it to mention the monitor count", err)
}
}
func TestLayoutFailsWithoutLaptopPanel(t *testing.T) {
outputs := Parse(`Screen 0: minimum 320 x 200, current 2560 x 1440, maximum 16384 x 16384
HDMI-A-0 connected primary 2560x1440+0+0 (normal left inverted right x axis y axis) 597mm x 336mm
2560x1440 59.95*+
`)
for _, tc := range []struct {
name string
fn func([]Output) ([]string, error)
}{
{"home", TwoMonitorArgs},
{"laptop-only", LaptopOnlyArgs},
} {
t.Run(tc.name, func(t *testing.T) {
_, err := tc.fn(outputs)
if err == nil {
t.Fatal("got no error without eDP, want one")
}
if !strings.Contains(err.Error(), "eDP") {
t.Errorf("got error %q, want it to mention eDP", err)
}
})
}
}
// The laptop panel is bottom-aligned against the external monitor, so an
// external monitor shorter than the laptop would need a negative offset. The
// python version asserted on this; here it is a real error message.
func TestTwoMonitorArgsFailsWhenExternalIsShorter(t *testing.T) {
outputs := Parse(`Screen 0: minimum 320 x 200, current 3200 x 1080, maximum 16384 x 16384
eDP connected 1920x1080+0+0 (normal left inverted right x axis y axis) 309mm x 173mm
1920x1080 60.03*+
HDMI-A-0 connected 1280x720+1920+0 (normal left inverted right x axis y axis) 597mm x 336mm
1280x720 60.00*+
`)
_, err := TwoMonitorArgs(outputs)
if err == nil {
t.Fatal("got no error with an external monitor shorter than the laptop, want one")
}
if !strings.Contains(err.Error(), "shorter") {
t.Errorf("got error %q, want it to explain the height mismatch", err)
}
}
// A connected panel with no active mode has no `*` in its mode list.
func TestLayoutFailsWhenLaptopHasNoActiveMode(t *testing.T) {
outputs := Parse(`Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 16384 x 16384
eDP connected (normal left inverted right x axis y axis) 309mm x 173mm
1920x1080 60.03 +
`)
if _, err := LaptopOnlyArgs(outputs); err == nil {
t.Error("got no error when eDP has no active mode, want one")
}
}
func assertArgs(t *testing.T, got, want []string) {
t.Helper()
if len(got) != len(want) {
t.Fatalf("got %d args, want %d\n got: %v\nwant: %v", len(got), len(want), got, want)
}
for i := range want {
if got[i] != want[i] {
t.Errorf("arg %d: got %q, want %q\n got: %v\nwant: %v", i, got[i], want[i], got, want)
}
}
}
|