summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/monkey9p.py12
-rw-r--r--test/panes.zig10
-rw-r--r--test/selfmount.py39
-rw-r--r--test/snapshot.zig5
-rw-r--r--test/snapshots/chordcut.snap15
-rw-r--r--test/snapshots/lspcomplete.snap20
6 files changed, 74 insertions, 27 deletions
diff --git a/test/monkey9p.py b/test/monkey9p.py
index 4d190bbc..87e386b3 100644
--- a/test/monkey9p.py
+++ b/test/monkey9p.py
@@ -674,8 +674,9 @@ def served_lines(data, sizes, room):
(fs.md, tree.zig write): each ended line, and the unended tail of a piece
shorter than a Twrite holds (`room`, msize less 24), which is whole in
itself, as acme takes each write; a piece that fills its Twrite may go
- on, and its tail waits for the next. A line written a byte a Twrite is
- so as many lines as bytes."""
+ on, and its tail waits for the next, and so does one of a multiple of
+ 4096 bytes, where a writer's buffer filled. A line written a byte a
+ Twrite is so as many lines as bytes."""
lines, pending, at = [], b'', 0
for size in sizes:
piece = data[at:at + size]
@@ -683,7 +684,7 @@ def served_lines(data, sizes, room):
pending += piece
*done, pending = pending.split(b'\n')
lines += done
- if pending and len(piece) < room:
+ if pending and len(piece) < room and len(piece) % 4096 != 0:
lines.append(pending)
pending = b''
if pending:
@@ -1615,7 +1616,10 @@ def chunked_equals_whole(ctx, res):
whole_n, chunk_n = dir_names(whole), dir_names(chunked)
if whole_n != chunk_n:
return f'{path}: whole {whole_n} != chunked({size}) {chunk_n}'
- elif whole != chunked:
+ elif whole != chunked and w.read_all(fid) != chunked:
+ # A live file (a tag says `running`, then `exit 0`) may change
+ # between the two reads: only chunks that no whole read matches,
+ # read again, are a chunking fault.
return f'{path}: whole {whole[:200]!r} != chunked({size}) {chunked[:200]!r}'
finally:
w.clunk(fid)
diff --git a/test/panes.zig b/test/panes.zig
index d7fa3514..6f321abf 100644
--- a/test/panes.zig
+++ b/test/panes.zig
@@ -981,10 +981,12 @@ const TtySelectionTests = struct {
const target = p.rects[1];
const tx = target.x + config.GUTTER + 2;
const ty = bodyY(p, target);
- p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = tx, .row = ty } });
- p.update(.{ .mouse = .{ .button = .right, .kind = .press, .col = tx, .row = ty } });
- p.update(.{ .mouse = .{ .button = .right, .kind = .release, .col = tx, .row = ty } });
- p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = tx, .row = ty } });
+ // Shift: over a program that tracks the mouse the chord is
+ // pardes's only so, and elsewhere Shift changes nothing.
+ p.update(.{ .mouse = .{ .button = .left, .kind = .press, .col = tx, .row = ty, .shift = true } });
+ p.update(.{ .mouse = .{ .button = .right, .kind = .press, .col = tx, .row = ty, .shift = true } });
+ p.update(.{ .mouse = .{ .button = .right, .kind = .release, .col = tx, .row = ty, .shift = true } });
+ p.update(.{ .mouse = .{ .button = .left, .kind = .release, .col = tx, .row = ty, .shift = true } });
var written: std.Io.Writer.Allocating = .init(p.gpa);
defer written.deinit();
while (p.nextEffect()) |effect| {
diff --git a/test/selfmount.py b/test/selfmount.py
index 6534aa25..86c32fa8 100644
--- a/test/selfmount.py
+++ b/test/selfmount.py
@@ -20,6 +20,7 @@ import signal
import struct
import sys
import termios
+import threading
import time
sys.path.insert(0, str(Path(__file__).resolve().parent))
@@ -127,12 +128,42 @@ def run(binary):
return exits[-1].split()[2]
time.sleep(.1)
return 'timeout'
+ # Followed from before the burst: a fresh open of the log reads
+ # only what its 64 KiB ring still holds, which a burst this size
+ # outgrows, and a follower the ring outruns reads `lost N`, so
+ # every line is either heard once, in order, or a loss is said.
+ heard = []
+
+ def follow():
+ with Client(sock) as follower:
+ fid = follower.open('/log', 2)
+ start = len(follower.read_fid(fid))
+ follower.rpc(118, struct.pack('<IQI', fid, 0, len(b'follow new\n')) + b'follow new\n')
+ ready.set()
+ deadline = time.monotonic() + 60
+ while time.monotonic() < deadline:
+ record = follower.read_fid(fid, start).decode()
+ heard.append(record)
+ if 'mnt-0999' in record:
+ return
+ ready = threading.Event()
+ reader = threading.Thread(target=follow, daemon=True)
+ reader.start()
+ check(ready.wait(10), 'a follower of the log is waiting')
got = run(f"seq -f 'Msg mnt-%04g' 0 999 > {mount}/exec\n".encode())
check(got == '0', f'a 1000-line burst written through the mount ({got!r})')
- log = client.read('/log').decode()
- said = [line.split(' ', 2)[2] for line in log.splitlines() if line.startswith('msg ') and 'mnt-' in line]
- check(said == ['mnt-%04d' % i for i in range(1000)], f'each line of it ran once, whole ({len(said)} said)')
- check('exit 127' not in log, 'no piece of a line ran as a command')
+ reader.join(60)
+ for r in heard:
+ if r.startswith(('err ', 'exit ')):
+ print(' heard: ' + r.rstrip())
+ said = [r.rstrip('\n').split(' ', 2)[2] for r in heard if r.startswith('msg ') and 'mnt-' in r]
+ lost = [r for r in heard if r.startswith('lost ')]
+ numbers = [int(s[4:]) for s in said]
+ check(numbers == list(range(numbers[0] if numbers else 0, 1000)),
+ f'each line it heard ran once, whole, in order, through the last ({len(said)} heard)')
+ check(len(said) == 1000 or (lost and heard.index(lost[0]) < heard.index(next(r for r in heard if 'mnt-' in r))),
+ f'no line was lost unsaid ({len(said)} heard, {lost!r})')
+ check(not any('exit 127' in r for r in heard), 'no piece of a line ran as a command')
scratch = int(client.read('/pane/new'))
maker = "import sys; sys.stdout.write('Edit ,a\\n' + ''.join('line %05d of the block\\n' % i for i in range(2500)) + '.\\n')"
check(run(f'python3 -c "{maker}" > {mount}/pane/{scratch}/ctl\n'.encode()) == '0', 'a 50 KB Edit block written through the mount')
diff --git a/test/snapshot.zig b/test/snapshot.zig
index a176da7a..5522fbb9 100644
--- a/test/snapshot.zig
+++ b/test/snapshot.zig
@@ -1489,6 +1489,11 @@ fn buttonCode(name: []const u8) ?u16 {
const base = buttonCode(name["ctrl-".len..]) orelse return null;
return base + 16;
}
+ // Shift: over a program that tracks the mouse, pardes's own gesture.
+ if (std.mem.startsWith(u8, name, "shift-")) {
+ const base = buttonCode(name["shift-".len..]) orelse return null;
+ return base + 4;
+ }
if (std.mem.eql(u8, name, "left")) return 0;
if (std.mem.eql(u8, name, "middle")) return 1;
if (std.mem.eql(u8, name, "right")) return 2;
diff --git a/test/snapshots/chordcut.snap b/test/snapshots/chordcut.snap
index 1baef7ec..fddd9e92 100644
--- a/test/snapshots/chordcut.snap
+++ b/test/snapshots/chordcut.snap
@@ -124,9 +124,10 @@ snapstyle clickdismiss
press middle 59 23
release middle 59 23
stable 700 15000
-# tty paste chord: a mouse-listening app gets the click forwarded (SGR,
-# body-relative) then the register between bracketed-paste markers —
-# cat -v prints the received bytes visibly
+# tty paste chord: over a mouse-listening app the chord is pardes's with
+# Shift held; the app gets a click where the text goes (SGR, body-relative)
+# then the register between bracketed-paste markers — cat -v prints the
+# received bytes visibly
press left 35 23
release left 35 23
stable 400 5000
@@ -135,10 +136,10 @@ stable 600 8000
text stty -icanon -echo; printf '\x1b[?2004h\x1b[?1000h\x1b[?1006h'; cat -v
key enter
stable 700 8000
-press left 40 25
-press right 40 25
-release right 40 25
-release left 40 25
+press shift-left 40 25
+press shift-right 40 25
+release shift-right 40 25
+release shift-left 40 25
stable 700 8000
snap ttyprobe
# a plain prompt (mouse modes off) gets no click bytes — just the paste;
diff --git a/test/snapshots/lspcomplete.snap b/test/snapshots/lspcomplete.snap
index d9e165a1..eaa26c61 100644
--- a/test/snapshots/lspcomplete.snap
+++ b/test/snapshots/lspcomplete.snap
@@ -1,4 +1,8 @@
-# Tab after a dot in insert mode: "what could go here". The answer is a
+# Tab after a dot in insert mode: "what could go here".
+#
+# Each wait for zls's answer allows a minute: it returns as soon as the answer
+# is drawn (2 s alone), and a zls slowed by a loaded machine (the parallel
+# snap run) took over 15 s, which failed the old wait. The answer is a
# `+Search` buffer of zls's candidates, one row each at the cursor (a
# completion item names no declaration) — nothing is inserted and nothing pops
# up.
@@ -62,8 +66,8 @@ key tab
# The rows that prove it: `verdigris` and `cinnabar` can only have come from
# resolving the switch's condition to `Shade` and asking what it declares.
# Line 8 still reads `.` and nothing else — a completion INSERTS NOTHING.
-wait 15000 +Search
-stable 700 15000
+wait 60000 +Search
+stable 700 30000
snap completion
# Two more Tabs. Every one of them answers, and every answer REFILLS the one
# `+Search` rather than opening its twin. The SECOND press is already the whole
@@ -78,7 +82,7 @@ settle 150
key tab
settle 150
key tab
-stable 700 20000
+stable 700 30000
snap refill
# The pane is still in insert mode, which is right — the query answered beside
# the cursor and typing goes on — so walking the answer means leaving it first,
@@ -127,8 +131,8 @@ key end
text .
stable 400 5000
key tab
-wait 15000 +Search
-stable 700 15000
+wait 60000 +Search
+stable 700 30000
snap nosemi
# ...and a construct still hanging OPEN. The switch has no closing brace at
# all — the one `}` in the file closes it and leaves the function unclosed —
@@ -148,6 +152,6 @@ key end
text .
stable 400 5000
key tab
-wait 15000 +Search
-stable 700 15000
+wait 60000 +Search
+stable 700 30000
snap nobrace