test: A8's contrast waited for a prefix, not the sequence
**A partial write could have failed correct code.** The contrast broke out of its poll as soon as `ESC[200~` appeared and then required `pasted` and `ESC[201~` in the same breath --- but PTY delivery and the child's writes split anywhere, so the closer may simply not have arrived. A flake that only ever fires on a loaded machine, and one that would have been read as an A8 regression. It now polls for the COMPLETE `ESC[200~pastedESC[201~`, which makes a partial write indistinguishable from "not yet" --- which is what it is. Same rule the vterm suite already follows when it waits for `row19` rather than for a prefix of it. **The typed-text read above it is sound and is now documented as such**, because the two loops look alike and are not. Its gate is a LOWER BOUND ON LENGTH: a split delivery keeps waiting rather than being mistaken for a wrong answer, and the exact-equality assertion afterwards can still fail for the real reason. A wait-for-exact-content loop there would have been tautological. Stating the difference beside the two loops is worth more than making them superficially uniform. M-1a-4 re-run after the change: still fails the row, so the fix removed a race without removing the discrimination. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
This commit is contained in:
parent
e3a19a4e63
commit
42a0a91f58
|
|
@ -324,6 +324,12 @@ fn a8_a_terminal_receives_raw_utf8_with_bracketed_paste_enabled() {
|
|||
let typed = "h\u{e9}llo\u{301}";
|
||||
s.dispatch_text_input(FID, typed);
|
||||
|
||||
// Waits for AT LEAST the full payload, then asserts exact equality.
|
||||
// Sound against a split write for a reason the contrast below does
|
||||
// not share: the gate is a lower bound on length, so a partial
|
||||
// delivery keeps waiting rather than being mistaken for a wrong
|
||||
// answer — and the equality can still fail for the real reason,
|
||||
// which a wait-for-exact-content loop could not.
|
||||
let deadline = Instant::now() + Duration::from_secs(10);
|
||||
let got = loop {
|
||||
s.tick_processes();
|
||||
|
|
@ -356,20 +362,27 @@ fn a8_a_terminal_receives_raw_utf8_with_bracketed_paste_enabled() {
|
|||
s.dispatch_paste(FID, b"pasted"),
|
||||
"the terminal claims the paste"
|
||||
);
|
||||
//
|
||||
// **Wait for the COMPLETE sequence, not the opening marker.** PTY
|
||||
// delivery and the child's writes can split anywhere, so breaking
|
||||
// as soon as `ESC[200~` appears and then requiring the payload and
|
||||
// the closer is a race that fails on correct code — the closer may
|
||||
// simply not have arrived yet. Polling for the whole string makes a
|
||||
// partial write indistinguishable from "not yet", which is what it
|
||||
// is. Same rule the vterm suite follows when it waits for `row19`
|
||||
// rather than for a prefix of it.
|
||||
let want = "\u{1b}[200~pasted\u{1b}[201~";
|
||||
let deadline = Instant::now() + Duration::from_secs(10);
|
||||
loop {
|
||||
s.tick_processes();
|
||||
let all = String::from_utf8_lossy(&std::fs::read(&sink).unwrap_or_default()).into_owned();
|
||||
if all.contains("\u{1b}[200~") {
|
||||
assert!(
|
||||
all.contains("pasted") && all.contains("\u{1b}[201~"),
|
||||
"a paste is bracketed on both sides: {all:?}"
|
||||
);
|
||||
if all.contains(want) {
|
||||
break;
|
||||
}
|
||||
assert!(
|
||||
Instant::now() < deadline,
|
||||
"a paste through the same terminal must be bracketed; got {all:?}"
|
||||
"a paste through the same terminal must be bracketed on both \
|
||||
sides; waited for {want:?}, saw {all:?}"
|
||||
);
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue