1package core
2
3import "testing"
4
5// coverMonitor has, on a 300x200 output, tiles 1 and 2 on one workspace,
6// 2 fullscreen. With float, 2 is a floating game over tile 1 instead.
7func coverMonitor(o Overflow, float bool) *Monitor {
8 m := newMonitor("", "")
9 m.SetOutput(300, 200)
10 m.SetOverflow(o)
11 m.SetMaxColumns(2)
12 m.AddWindow(1)
13 if float {
14 m.AddFloating(2, 300, 200)
15 m.SetFullscreen(2, true)
16 } else {
17 m.AddWindow(2)
18 m.ToggleFullscreen()
19 }
20 return m
21}
22
23// pinnedCases are the setups where the fullscreen window pins its row.
24var pinnedCases = []struct {
25 name string
26 overflow Overflow
27 float bool
28}{
29 {"fixed tile", OverflowFixed, false},
30 {"fixed float", OverflowFixed, true},
31 {"scroll float", OverflowScroll, true},
32}
33
34// uniquePlacements fails when a window is placed twice.
35func uniquePlacements(t *testing.T, ps []Placement) {
36 t.Helper()
37 seen := map[WindowID]bool{}
38 for _, p := range ps {
39 if seen[p.ID] {
40 t.Fatalf("window %d placed twice: %+v", p.ID, ps)
41 }
42 seen[p.ID] = true
43 }
44}
45
46// The overview over a pinned fullscreen window shows it in front, still
47// fullscreen and selected, and the window it hides behind it.
48func TestOverviewCoverShowsWorkspace(t *testing.T) {
49 for _, tc := range pinnedCases {
50 t.Run(tc.name, func(t *testing.T) {
51 m := coverMonitor(tc.overflow, tc.float)
52 if !m.Current().pinned() {
53 t.Fatal("not pinned")
54 }
55 m.ToggleOverview()
56 ps := m.Layout()
57 uniquePlacements(t, ps)
58 game, behind := previewOf(t, ps, 2), previewOf(t, ps, 1)
59 if game.Hidden || !game.Focused || game.Peek || !game.Fullscreen {
60 t.Fatalf("game %+v", game)
61 }
62 if behind.Hidden || !behind.Peek || behind.Focused {
63 t.Fatalf("behind %+v", behind)
64 }
65 })
66 }
67}
68
69// Return or a click on the fullscreen window keeps it fullscreen.
70func TestOverviewCoverConfirmKeeps(t *testing.T) {
71 for _, tc := range pinnedCases {
72 t.Run(tc.name, func(t *testing.T) {
73 for _, pick := range []bool{false, true} {
74 m := coverMonitor(tc.overflow, tc.float)
75 m.ToggleOverview()
76 if pick {
77 m.OverviewPick(2)
78 } else {
79 m.ToggleOverview()
80 }
81 if f, _ := m.Focused(); f != 2 || m.ov.open || m.Current().fullscreen != 2 || !previewOf(t, m.Layout(), 2).Fullscreen {
82 t.Fatalf("pick %v: focused %d, fullscreen %d", pick, f, m.Current().fullscreen)
83 }
84 }
85 })
86 }
87}
88
89// Choosing the window behind leaves fullscreen and focuses it; the left
90// window shows again, a float behind the tiles.
91func TestOverviewCoverPickOther(t *testing.T) {
92 for _, tc := range pinnedCases {
93 t.Run(tc.name, func(t *testing.T) {
94 for _, pick := range []bool{false, true} {
95 m := coverMonitor(tc.overflow, tc.float)
96 m.ToggleOverview()
97 if pick {
98 m.OverviewPick(1)
99 } else {
100 m.OverviewMove(-1, 0)
101 m.ToggleOverview()
102 }
103 w := m.Current()
104 if f, _ := m.Focused(); f != 1 || m.ov.open || w.fullscreen != 0 {
105 t.Fatalf("pick %v: focused %d, fullscreen %d", pick, f, w.fullscreen)
106 }
107 if p := placement(w, 2); p.Fullscreen || (p.Hidden && !tc.float) {
108 t.Fatalf("pick %v: left window %+v", pick, p)
109 }
110 if i := w.floatIndex(2); tc.float && (i < 0 || !w.Floats[i].below) {
111 t.Fatalf("pick %v: float %+v", pick, w.Floats)
112 }
113 }
114 })
115 }
116}
117
118// Escape returns to the fullscreen window, still fullscreen.
119func TestOverviewCoverCancel(t *testing.T) {
120 for _, tc := range pinnedCases {
121 t.Run(tc.name, func(t *testing.T) {
122 m := coverMonitor(tc.overflow, tc.float)
123 m.ToggleOverview()
124 m.OverviewMove(-1, 0)
125 m.CancelOverview()
126 if f, _ := m.Focused(); f != 2 || m.Current().fullscreen != 2 {
127 t.Fatalf("focused %d, fullscreen %d", f, m.Current().fullscreen)
128 }
129 })
130 }
131}
132
133// A stash card is reachable under a fullscreen tile; choosing it leaves
134// fullscreen.
135func TestOverviewCoverPickStashCard(t *testing.T) {
136 m := newMonitor("", "")
137 m.SetOutput(300, 200)
138 m.SetOverflow(OverflowFixed)
139 w := m.Current()
140 w.AddWindow(1)
141 w.AddWindow(5)
142 w.FocusID(5)
143 w.ToggleWindowStash()
144 w.FocusID(1)
145 m.ToggleFullscreen()
146 if !w.pinned() {
147 t.Fatal("not pinned")
148 }
149 m.ToggleOverview()
150 uniquePlacements(t, m.Layout())
151 m.OverviewMove(-1, 0)
152 if m.card() != 5 {
153 t.Fatalf("card %d", m.card())
154 }
155 m.ToggleOverview()
156 if f, _ := m.Focused(); f != 5 || w.fullscreen != 0 {
157 t.Fatalf("focused %d, fullscreen %d", f, w.fullscreen)
158 }
159}
160
161// Window binds act on the selected card: a window behind the fullscreen
162// one moves or closes, not the fullscreen window.
163func TestOverviewCoverActsOnSelection(t *testing.T) {
164 for _, tc := range pinnedCases {
165 t.Run(tc.name, func(t *testing.T) {
166 m := coverMonitor(tc.overflow, tc.float)
167 m.ToggleOverview()
168 if e := m.Apply(ActionCloseWindow); e.Close != 2 {
169 t.Fatalf("front close %d", e.Close)
170 }
171 m.OverviewMove(-1, 0)
172 if e := m.Apply(ActionCloseWindow); e.Close != 1 {
173 t.Fatalf("behind close %d", e.Close)
174 }
175 w := m.Current()
176 m.Apply(ActionMoveWindowToWorkspaceDown)
177 if got, _ := m.find(1); got == w || !w.has(2) {
178 t.Fatalf("moved the wrong window: %v", windows(m))
179 }
180 })
181 }
182}
183
184// A fullscreen tile whose column is also maximized hands the maximized
185// state to the column picked behind it, as a maximized row does.
186func TestOverviewCoverMaximizedPick(t *testing.T) {
187 m := newMonitor("", "")
188 m.SetOutput(300, 200)
189 m.SetOverflow(OverflowFixed)
190 m.AddWindow(1)
191 m.AddWindow(2)
192 w := m.Current()
193 w.ToggleFullWidth()
194 m.ToggleFullscreen()
195 m.ToggleOverview()
196 m.OverviewPick(1)
197 if f, _ := m.Focused(); f != 1 || w.fullscreen != 0 || !w.Columns[0].FullWidth || w.Columns[1].FullWidth {
198 t.Fatalf("focused %d, fullscreen %d, columns %+v", f, w.fullscreen, w.Columns)
199 }
200}
201
202// A fixed fullscreen tile among several columns is the front card, the
203// other columns behind it, as for a maximized column.
204func TestOverviewCoverTileAmongColumns(t *testing.T) {
205 m := newMonitor("", "")
206 m.SetOutput(300, 200)
207 m.SetOverflow(OverflowFixed)
208 m.AddWindow(1)
209 m.AddWindow(2)
210 m.AddWindow(3)
211 m.Current().FocusID(2)
212 m.ToggleFullscreen()
213 m.ToggleOverview()
214 ps := m.Layout()
215 uniquePlacements(t, ps)
216 if g := previewOf(t, ps, 2); g.Hidden || g.Peek || !g.Fullscreen {
217 t.Fatalf("game %+v", g)
218 }
219 for _, id := range []WindowID{1, 3} {
220 if p := previewOf(t, ps, id); p.Hidden || !p.Peek {
221 t.Fatalf("%d: %+v", id, p)
222 }
223 }
224 m.OverviewPick(3)
225 if f, _ := m.Focused(); f != 3 || m.Current().fullscreen != 0 {
226 t.Fatalf("focused %d, fullscreen %d", f, m.Current().fullscreen)
227 }
228}