okami.mom/ultraviolet

git clone https://git.nkp.pet/okami.mom/ultraviolet

jane michelle arcfix: give event loop its own copy per read (#178)d4534d5

main
2.0 KiB78 linesraw
1package uv
2
3import (
4	"fmt"
5	"testing"
6	"time"
7)
8
9// TestInputLoopDoesNotReuseTheReadBuffer is the regression test for #176. the
10// input loop handed the event loop a slice of its own read buffer, and its
11// next read could overwrite those bytes before the event loop had copied them,
12// so one input sequence arrived as the bytes of the next.
13//
14// two different replies go in back to back, the way a terminal answers two
15// queries, and every round must produce them in order.
16func TestInputLoopDoesNotReuseTheReadBuffer(t *testing.T) {
17	const (
18		rounds = 2000
19		decrpm = "\x1b[?1016;2$y"      // a mode report, eleven bytes
20		kitty  = "\x1b_Gi=31;OK\x1b\\" // a kitty graphics reply; its first eleven bytes differ
21	)
22
23	con := newPipeConsole()
24	tm := NewTerminal(con, nil)
25	if err := tm.Start(); err != nil {
26		t.Fatalf("Start: %v", err)
27	}
28	defer stopAfterInputEnds(t, tm, con)
29
30	for i := range rounds {
31		con.send(decrpm)
32		con.send(kitty)
33		got := nextReplies(tm, 2)
34		if len(got) != 2 || !isModeReport(got[0]) || !isKittyReply(got[1]) {
35			t.Fatalf("round %d: replies arrived as %s, want [uv.ModeReportEvent uv.KittyGraphicsEvent]",
36				i, typesOf(got))
37		}
38	}
39}
40
41// nextReplies collects up to n events other than the window size Start
42// reports on its own, and returns early with what it has if they stop
43// coming. a reply the corruption swallowed shows up as a short result, not a
44// hang.
45func nextReplies(tm *Terminal, n int) []Event {
46	deadline := time.After(time.Second)
47	var got []Event
48	for len(got) < n {
49		select {
50		case ev := <-tm.Events():
51			if _, ok := ev.(WindowSizeEvent); ok {
52				continue
53			}
54			got = append(got, ev)
55		case <-deadline:
56			return got
57		}
58	}
59	return got
60}
61
62func isModeReport(ev Event) bool {
63	_, ok := ev.(ModeReportEvent)
64	return ok
65}
66
67func isKittyReply(ev Event) bool {
68	_, ok := ev.(KittyGraphicsEvent)
69	return ok
70}
71
72func typesOf(evs []Event) string {
73	names := make([]string, len(evs))
74	for i, ev := range evs {
75		names[i] = fmt.Sprintf("%T", ev)
76	}
77	return fmt.Sprint(names)
78}