detached fa55dc9

test(wayland): fold the presentation ring tests into one table

The five makeRoomLocked tests (merge past the bound, flip before a flip-less report, interleaved outputs, incoming takes over a flip, no successor) are subtests of TestPresentationRingMakeRoom with the same rings, inputs and assertions. The rate-limited warning test stays apart: it drives enqueueLocked.
commit
fa55dc9edd58e3e6f5b552a54d96b73c47cf2b80
author
brice · · 2026-10-14 03:43 UTC
committer
brice · · 2026-10-14 04:34 UTC
parent
5273ef5
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +118 -78
M internal/adapters/wayland/presented_test.go +118 -78
@@ -174,84 +174,124 @@ func flipOf(seq uint64, shows ...ports.WindowID) *ports.FlipInfo {
174174 return f
175175 }
176176
177-// A full ring merges the oldest flip of an output into its next flip.
178-func TestPresentationRingMergesPastBound(t *testing.T) {
179- p := ringOf()
180- for i := range maxPresentRing {
181- p.ring = append(p.ring, ports.OutputPresented{Output: "A", Flip: flipOf(uint64(i + 1))})
182- }
183- in := ports.OutputPresented{Output: "A", Flip: flipOf(maxPresentRing + 1)}
184- if !p.makeRoomLocked(&in) {
185- t.Fatal("two flips merged but not reported")
186- }
187- if len(p.ring) != maxPresentRing-1 || p.ring[0].Flip.Seq != 2 || p.ring[0].Flip.Merged != 1 {
188- t.Fatalf("ring %d, first seq %d merged %d", len(p.ring), p.ring[0].Flip.Seq, p.ring[0].Flip.Merged)
189- }
190-}
191-
192-// A flip followed by a flip-less report of the same output is not lost: the
193-// later report carries it.
194-func TestPresentationRingKeepsFlipBeforeFliplessReport(t *testing.T) {
195- p := ringOf("A", "A")
196- p.ring[0].Flip = flipOf(7, 3)
197- p.fill()
198- p.ring = p.ring[:maxPresentRing]
199- in := ports.OutputPresented{Output: "B", Flip: flipOf(9)}
200- if p.makeRoomLocked(&in) {
201- t.Fatal("no flips merged, yet reported")
202- }
203- if len(p.ring) != maxPresentRing-1 || p.ring[0].Output != "A" || p.ring[0].Flip == nil || p.ring[0].Flip.Seq != 7 || p.ring[0].Flip.Merged != 0 {
204- t.Fatalf("flip lost: ring %d, first %+v", len(p.ring), p.ring[0])
205- }
206-}
207-
208-// With several outputs interleaved, the victim is the oldest report that has
209-// a successor of its own output; other outputs' reports are untouched.
210-func TestPresentationRingInterleavedOutputs(t *testing.T) {
211- p := ringOf("A", "B", "A", "B")
212- p.ring[0].Flip, p.ring[1].Flip = flipOf(1, 10), flipOf(2, 20)
213- p.ring[2].Flip, p.ring[3].Flip = flipOf(3, 11), nil
214- p.fill()
215- in := ports.OutputPresented{Output: "C"}
216- if !p.makeRoomLocked(&in) {
217- t.Fatal("merge not reported")
218- }
219- if p.ring[0].Output != "B" || p.ring[0].Flip.Seq != 2 || p.ring[0].Flip.Merged != 0 {
220- t.Fatalf("B's flip touched: %+v", p.ring[0])
221- }
222- a := p.ring[1]
223- if a.Output != "A" || a.Flip.Seq != 3 || a.Flip.Merged != 1 || a.Flip.Shows[10] != 1 || a.Flip.Shows[11] != 3 {
224- t.Fatalf("A's flips not merged: %+v", a.Flip)
225- }
226- if p.ring[2].Output != "B" || p.ring[2].Flip != nil {
227- t.Fatalf("B's flip-less report moved: %+v", p.ring[2])
228- }
229-}
230-
231-// The incoming report counts as the successor of a ring report.
232-func TestPresentationRingIncomingTakesOverFlip(t *testing.T) {
233- p := ringOf("A")
234- p.ring[0].Flip = flipOf(4)
235- p.fill()
236- in := ports.OutputPresented{Output: "A"}
237- if p.makeRoomLocked(&in) {
238- t.Fatal("no merge expected")
239- }
240- if in.Flip == nil || in.Flip.Seq != 4 || len(p.ring) != maxPresentRing-1 {
241- t.Fatalf("incoming %+v, ring %d", in.Flip, len(p.ring))
242- }
243-}
244-
245-// With no successor for any report (more outputs than ring slots) nothing is
246-// dropped: the ring grows by one and every flip is still delivered.
247-func TestPresentationRingWithoutSuccessorKeepsEverything(t *testing.T) {
248- p := ringOf()
249- for i := range maxPresentRing {
250- p.ring = append(p.ring, ports.OutputPresented{Output: "o" + string(rune('A'+i/26)) + string(rune('a'+i%26)), Flip: flipOf(uint64(i + 1))})
251- }
252- in := ports.OutputPresented{Output: "other", Flip: flipOf(99)}
253- if p.makeRoomLocked(&in) || len(p.ring) != maxPresentRing {
254- t.Fatalf("merged or dropped: ring %d", len(p.ring))
177+// makeRoomLocked on a full ring: which report it merges or moves, and what it
178+// reports.
179+func TestPresentationRingMakeRoom(t *testing.T) {
180+ tests := []struct {
181+ name string
182+ ring func() *presentSink
183+ in ports.OutputPresented
184+ wantMerged bool
185+ check func(t *testing.T, p *presentSink, in *ports.OutputPresented)
186+ }{
187+ {
188+ // A full ring merges the oldest flip of an output into its next flip.
189+ name: "merges past the bound",
190+ ring: func() *presentSink {
191+ p := ringOf()
192+ for i := range maxPresentRing {
193+ p.ring = append(p.ring, ports.OutputPresented{Output: "A", Flip: flipOf(uint64(i + 1))})
194+ }
195+ return p
196+ },
197+ in: ports.OutputPresented{Output: "A", Flip: flipOf(maxPresentRing + 1)},
198+ wantMerged: true,
199+ check: func(t *testing.T, p *presentSink, _ *ports.OutputPresented) {
200+ if len(p.ring) != maxPresentRing-1 || p.ring[0].Flip.Seq != 2 || p.ring[0].Flip.Merged != 1 {
201+ t.Fatalf("ring %d, first seq %d merged %d", len(p.ring), p.ring[0].Flip.Seq, p.ring[0].Flip.Merged)
202+ }
203+ },
204+ },
205+ {
206+ // A flip followed by a flip-less report of the same output is not
207+ // lost: the later report carries it.
208+ name: "keeps a flip before a flip-less report",
209+ ring: func() *presentSink {
210+ p := ringOf("A", "A")
211+ p.ring[0].Flip = flipOf(7, 3)
212+ p.fill()
213+ p.ring = p.ring[:maxPresentRing]
214+ return p
215+ },
216+ in: ports.OutputPresented{Output: "B", Flip: flipOf(9)},
217+ check: func(t *testing.T, p *presentSink, _ *ports.OutputPresented) {
218+ if len(p.ring) != maxPresentRing-1 || p.ring[0].Output != "A" || p.ring[0].Flip == nil || p.ring[0].Flip.Seq != 7 || p.ring[0].Flip.Merged != 0 {
219+ t.Fatalf("flip lost: ring %d, first %+v", len(p.ring), p.ring[0])
220+ }
221+ },
222+ },
223+ {
224+ // With several outputs interleaved, the victim is the oldest report
225+ // that has a successor of its own output; other outputs' reports are
226+ // untouched.
227+ name: "interleaved outputs",
228+ ring: func() *presentSink {
229+ p := ringOf("A", "B", "A", "B")
230+ p.ring[0].Flip, p.ring[1].Flip = flipOf(1, 10), flipOf(2, 20)
231+ p.ring[2].Flip, p.ring[3].Flip = flipOf(3, 11), nil
232+ p.fill()
233+ return p
234+ },
235+ in: ports.OutputPresented{Output: "C"},
236+ wantMerged: true,
237+ check: func(t *testing.T, p *presentSink, _ *ports.OutputPresented) {
238+ if p.ring[0].Output != "B" || p.ring[0].Flip.Seq != 2 || p.ring[0].Flip.Merged != 0 {
239+ t.Fatalf("B's flip touched: %+v", p.ring[0])
240+ }
241+ a := p.ring[1]
242+ if a.Output != "A" || a.Flip.Seq != 3 || a.Flip.Merged != 1 || a.Flip.Shows[10] != 1 || a.Flip.Shows[11] != 3 {
243+ t.Fatalf("A's flips not merged: %+v", a.Flip)
244+ }
245+ if p.ring[2].Output != "B" || p.ring[2].Flip != nil {
246+ t.Fatalf("B's flip-less report moved: %+v", p.ring[2])
247+ }
248+ },
249+ },
250+ {
251+ // The incoming report counts as the successor of a ring report.
252+ name: "incoming takes over a flip",
253+ ring: func() *presentSink {
254+ p := ringOf("A")
255+ p.ring[0].Flip = flipOf(4)
256+ p.fill()
257+ return p
258+ },
259+ in: ports.OutputPresented{Output: "A"},
260+ check: func(t *testing.T, p *presentSink, in *ports.OutputPresented) {
261+ if in.Flip == nil || in.Flip.Seq != 4 || len(p.ring) != maxPresentRing-1 {
262+ t.Fatalf("incoming %+v, ring %d", in.Flip, len(p.ring))
263+ }
264+ },
265+ },
266+ {
267+ // With no successor for any report (more outputs than ring slots)
268+ // nothing is dropped: the ring grows by one and every flip is still
269+ // delivered.
270+ name: "without a successor keeps everything",
271+ ring: func() *presentSink {
272+ p := ringOf()
273+ for i := range maxPresentRing {
274+ p.ring = append(p.ring, ports.OutputPresented{Output: "o" + string(rune('A'+i/26)) + string(rune('a'+i%26)), Flip: flipOf(uint64(i + 1))})
275+ }
276+ return p
277+ },
278+ in: ports.OutputPresented{Output: "other", Flip: flipOf(99)},
279+ check: func(t *testing.T, p *presentSink, _ *ports.OutputPresented) {
280+ if len(p.ring) != maxPresentRing {
281+ t.Fatalf("merged or dropped: ring %d", len(p.ring))
282+ }
283+ },
284+ },
285+ }
286+ for _, tt := range tests {
287+ t.Run(tt.name, func(t *testing.T) {
288+ p := tt.ring()
289+ in := tt.in
290+ if merged := p.makeRoomLocked(&in); merged != tt.wantMerged {
291+ t.Fatalf("merged %v, want %v", merged, tt.wantMerged)
292+ }
293+ tt.check(t, p, &in)
294+ })
255295 }
256296 }
257297
@@ -174,84 +174,124 @@ func flipOf(seq uint64, shows ...ports.WindowID) *ports.FlipInfo {
174 return f174 return f
175 }175 }
176 176
177-// A full ring merges the oldest flip of an output into its next flip.177+// makeRoomLocked on a full ring: which report it merges or moves, and what it
178-func TestPresentationRingMergesPastBound(t *testing.T) {178+// reports.
179- p := ringOf()179+func TestPresentationRingMakeRoom(t *testing.T) {
180- for i := range maxPresentRing {180+ tests := []struct {
181- p.ring = append(p.ring, ports.OutputPresented{Output: "A", Flip: flipOf(uint64(i + 1))})181+ name string
182- }182+ ring func() *presentSink
183- in := ports.OutputPresented{Output: "A", Flip: flipOf(maxPresentRing + 1)}183+ in ports.OutputPresented
184- if !p.makeRoomLocked(&in) {184+ wantMerged bool
185- t.Fatal("two flips merged but not reported")185+ check func(t *testing.T, p *presentSink, in *ports.OutputPresented)
186- }186+ }{
187- if len(p.ring) != maxPresentRing-1 || p.ring[0].Flip.Seq != 2 || p.ring[0].Flip.Merged != 1 {187+ {
188- t.Fatalf("ring %d, first seq %d merged %d", len(p.ring), p.ring[0].Flip.Seq, p.ring[0].Flip.Merged)188+ // A full ring merges the oldest flip of an output into its next flip.
189- }189+ name: "merges past the bound",
190-}190+ ring: func() *presentSink {
191-191+ p := ringOf()
192-// A flip followed by a flip-less report of the same output is not lost: the192+ for i := range maxPresentRing {
193-// later report carries it.193+ p.ring = append(p.ring, ports.OutputPresented{Output: "A", Flip: flipOf(uint64(i + 1))})
194-func TestPresentationRingKeepsFlipBeforeFliplessReport(t *testing.T) {194+ }
195- p := ringOf("A", "A")195+ return p
196- p.ring[0].Flip = flipOf(7, 3)196+ },
197- p.fill()197+ in: ports.OutputPresented{Output: "A", Flip: flipOf(maxPresentRing + 1)},
198- p.ring = p.ring[:maxPresentRing]198+ wantMerged: true,
199- in := ports.OutputPresented{Output: "B", Flip: flipOf(9)}199+ check: func(t *testing.T, p *presentSink, _ *ports.OutputPresented) {
200- if p.makeRoomLocked(&in) {200+ if len(p.ring) != maxPresentRing-1 || p.ring[0].Flip.Seq != 2 || p.ring[0].Flip.Merged != 1 {
201- t.Fatal("no flips merged, yet reported")201+ t.Fatalf("ring %d, first seq %d merged %d", len(p.ring), p.ring[0].Flip.Seq, p.ring[0].Flip.Merged)
202- }202+ }
203- if len(p.ring) != maxPresentRing-1 || p.ring[0].Output != "A" || p.ring[0].Flip == nil || p.ring[0].Flip.Seq != 7 || p.ring[0].Flip.Merged != 0 {203+ },
204- t.Fatalf("flip lost: ring %d, first %+v", len(p.ring), p.ring[0])204+ },
205- }205+ {
206-}206+ // A flip followed by a flip-less report of the same output is not
207-207+ // lost: the later report carries it.
208-// With several outputs interleaved, the victim is the oldest report that has208+ name: "keeps a flip before a flip-less report",
209-// a successor of its own output; other outputs' reports are untouched.209+ ring: func() *presentSink {
210-func TestPresentationRingInterleavedOutputs(t *testing.T) {210+ p := ringOf("A", "A")
211- p := ringOf("A", "B", "A", "B")211+ p.ring[0].Flip = flipOf(7, 3)
212- p.ring[0].Flip, p.ring[1].Flip = flipOf(1, 10), flipOf(2, 20)212+ p.fill()
213- p.ring[2].Flip, p.ring[3].Flip = flipOf(3, 11), nil213+ p.ring = p.ring[:maxPresentRing]
214- p.fill()214+ return p
215- in := ports.OutputPresented{Output: "C"}215+ },
216- if !p.makeRoomLocked(&in) {216+ in: ports.OutputPresented{Output: "B", Flip: flipOf(9)},
217- t.Fatal("merge not reported")217+ check: func(t *testing.T, p *presentSink, _ *ports.OutputPresented) {
218- }218+ if len(p.ring) != maxPresentRing-1 || p.ring[0].Output != "A" || p.ring[0].Flip == nil || p.ring[0].Flip.Seq != 7 || p.ring[0].Flip.Merged != 0 {
219- if p.ring[0].Output != "B" || p.ring[0].Flip.Seq != 2 || p.ring[0].Flip.Merged != 0 {219+ t.Fatalf("flip lost: ring %d, first %+v", len(p.ring), p.ring[0])
220- t.Fatalf("B's flip touched: %+v", p.ring[0])220+ }
221- }221+ },
222- a := p.ring[1]222+ },
223- if a.Output != "A" || a.Flip.Seq != 3 || a.Flip.Merged != 1 || a.Flip.Shows[10] != 1 || a.Flip.Shows[11] != 3 {223+ {
224- t.Fatalf("A's flips not merged: %+v", a.Flip)224+ // With several outputs interleaved, the victim is the oldest report
225- }225+ // that has a successor of its own output; other outputs' reports are
226- if p.ring[2].Output != "B" || p.ring[2].Flip != nil {226+ // untouched.
227- t.Fatalf("B's flip-less report moved: %+v", p.ring[2])227+ name: "interleaved outputs",
228- }228+ ring: func() *presentSink {
229-}229+ p := ringOf("A", "B", "A", "B")
230-230+ p.ring[0].Flip, p.ring[1].Flip = flipOf(1, 10), flipOf(2, 20)
231-// The incoming report counts as the successor of a ring report.231+ p.ring[2].Flip, p.ring[3].Flip = flipOf(3, 11), nil
232-func TestPresentationRingIncomingTakesOverFlip(t *testing.T) {232+ p.fill()
233- p := ringOf("A")233+ return p
234- p.ring[0].Flip = flipOf(4)234+ },
235- p.fill()235+ in: ports.OutputPresented{Output: "C"},
236- in := ports.OutputPresented{Output: "A"}236+ wantMerged: true,
237- if p.makeRoomLocked(&in) {237+ check: func(t *testing.T, p *presentSink, _ *ports.OutputPresented) {
238- t.Fatal("no merge expected")238+ if p.ring[0].Output != "B" || p.ring[0].Flip.Seq != 2 || p.ring[0].Flip.Merged != 0 {
239- }239+ t.Fatalf("B's flip touched: %+v", p.ring[0])
240- if in.Flip == nil || in.Flip.Seq != 4 || len(p.ring) != maxPresentRing-1 {240+ }
241- t.Fatalf("incoming %+v, ring %d", in.Flip, len(p.ring))241+ a := p.ring[1]
242- }242+ if a.Output != "A" || a.Flip.Seq != 3 || a.Flip.Merged != 1 || a.Flip.Shows[10] != 1 || a.Flip.Shows[11] != 3 {
243-}243+ t.Fatalf("A's flips not merged: %+v", a.Flip)
244-244+ }
245-// With no successor for any report (more outputs than ring slots) nothing is245+ if p.ring[2].Output != "B" || p.ring[2].Flip != nil {
246-// dropped: the ring grows by one and every flip is still delivered.246+ t.Fatalf("B's flip-less report moved: %+v", p.ring[2])
247-func TestPresentationRingWithoutSuccessorKeepsEverything(t *testing.T) {247+ }
248- p := ringOf()248+ },
249- for i := range maxPresentRing {249+ },
250- p.ring = append(p.ring, ports.OutputPresented{Output: "o" + string(rune('A'+i/26)) + string(rune('a'+i%26)), Flip: flipOf(uint64(i + 1))})250+ {
251- }251+ // The incoming report counts as the successor of a ring report.
252- in := ports.OutputPresented{Output: "other", Flip: flipOf(99)}252+ name: "incoming takes over a flip",
253- if p.makeRoomLocked(&in) || len(p.ring) != maxPresentRing {253+ ring: func() *presentSink {
254- t.Fatalf("merged or dropped: ring %d", len(p.ring))254+ p := ringOf("A")
255+ p.ring[0].Flip = flipOf(4)
256+ p.fill()
257+ return p
258+ },
259+ in: ports.OutputPresented{Output: "A"},
260+ check: func(t *testing.T, p *presentSink, in *ports.OutputPresented) {
261+ if in.Flip == nil || in.Flip.Seq != 4 || len(p.ring) != maxPresentRing-1 {
262+ t.Fatalf("incoming %+v, ring %d", in.Flip, len(p.ring))
263+ }
264+ },
265+ },
266+ {
267+ // With no successor for any report (more outputs than ring slots)
268+ // nothing is dropped: the ring grows by one and every flip is still
269+ // delivered.
270+ name: "without a successor keeps everything",
271+ ring: func() *presentSink {
272+ p := ringOf()
273+ for i := range maxPresentRing {
274+ p.ring = append(p.ring, ports.OutputPresented{Output: "o" + string(rune('A'+i/26)) + string(rune('a'+i%26)), Flip: flipOf(uint64(i + 1))})
275+ }
276+ return p
277+ },
278+ in: ports.OutputPresented{Output: "other", Flip: flipOf(99)},
279+ check: func(t *testing.T, p *presentSink, _ *ports.OutputPresented) {
280+ if len(p.ring) != maxPresentRing {
281+ t.Fatalf("merged or dropped: ring %d", len(p.ring))
282+ }
283+ },
284+ },
285+ }
286+ for _, tt := range tests {
287+ t.Run(tt.name, func(t *testing.T) {
288+ p := tt.ring()
289+ in := tt.in
290+ if merged := p.makeRoomLocked(&in); merged != tt.wantMerged {
291+ t.Fatalf("merged %v, want %v", merged, tt.wantMerged)
292+ }
293+ tt.check(t, p, &in)
294+ })
255 }295 }
256 }296 }
257 297

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 26

Tags 10

↑↓ moveenter openesc close