mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-21 16:02:20 +00:00
test(control): make a new wire variant break the build, not a link
`CONTROL_VERSION`'s doc states the rule — move it whenever a variant is added to or removed from `ControlRequest`, `ReplyOk` or `ControlEvent` — and states what happens when it is missed: the frame fails to decode, the read loop that failed on it takes the whole link down, and a remote workspace opens with no tabs. The same doc records that this is not hypothetical. The v5→v6 drift was most of the dialect, and all of it shipped against a number that never moved. Only one of the three enums was actually protected, and by accident: `ControlRequest::deadline` matches exhaustively, so a new request cannot be added without the compiler asking about it. `ReplyOk` and `ControlEvent` had nothing. Checked rather than assumed — a probe variant added to both compiled clean across the whole workspace, all targets, no warnings. The hand-written `every_reply` / `every_event` lists cannot catch it either. They are cross-checked against other hand-written lists, so a variant missing from the enum coverage *and* the list leaves every count in agreement. So: one exhaustive match per enum, in the test module, called from a test so it cannot rot into dead code. Confirmed it fails for the case it exists for — a probe variant in either enum is now an E0004 naming the variant, at compile time, where it cannot be skipped.
This commit is contained in:
@@ -1557,6 +1557,64 @@ mod tests {
|
||||
]
|
||||
}
|
||||
|
||||
/// Adding or removing a variant of either enum stops this compiling, which
|
||||
/// is the reminder that [`CONTROL_VERSION`] moves with it.
|
||||
///
|
||||
/// [`ControlRequest`] already gets that for free: `deadline` matches it
|
||||
/// exhaustively, so a new request cannot be added without the compiler
|
||||
/// asking about it. These two had nothing — a variant could be added to
|
||||
/// either and the whole workspace still built — and that is the shape of
|
||||
/// the drift v6 had to pay off, where the number never moved and every
|
||||
/// server of that generation answers the hello and then drops the link on
|
||||
/// the first call.
|
||||
///
|
||||
/// The lists in `every_reply` and `every_event` below are hand-written, so
|
||||
/// they cannot catch this themselves: a variant missing from both the enum
|
||||
/// coverage and the list leaves every count in agreement.
|
||||
fn wire_variants_are_pinned(reply: &ReplyOk, event: &ControlEvent) {
|
||||
match reply {
|
||||
ReplyOk::Unit
|
||||
| ReplyOk::Pong
|
||||
| ReplyOk::Entries(..)
|
||||
| ReplyOk::Meta(..)
|
||||
| ReplyOk::Bool(..)
|
||||
| ReplyOk::Path(..)
|
||||
| ReplyOk::OptPath(..)
|
||||
| ReplyOk::FileMeta { .. }
|
||||
| ReplyOk::Hits(..)
|
||||
| ReplyOk::Output(..)
|
||||
| ReplyOk::WatchId(..)
|
||||
| ReplyOk::Shells(..)
|
||||
| ReplyOk::Attached { .. }
|
||||
| ReplyOk::MachineTree(..)
|
||||
| ReplyOk::WorkspaceTree(..)
|
||||
| ReplyOk::TabTree(..)
|
||||
| ReplyOk::Panes(..)
|
||||
| ReplyOk::AgentStates(..)
|
||||
| ReplyOk::Routes(..)
|
||||
| ReplyOk::Status(..) => {}
|
||||
}
|
||||
match event {
|
||||
ControlEvent::Watch { .. }
|
||||
| ControlEvent::WatchOverflow { .. }
|
||||
| ControlEvent::GitChunk { .. }
|
||||
| ControlEvent::GitEnd { .. }
|
||||
| ControlEvent::PaneExited { .. }
|
||||
| ControlEvent::AgentStatus { .. }
|
||||
| ControlEvent::Preempted { .. }
|
||||
| ControlEvent::GuiOpen { .. }
|
||||
| ControlEvent::Layout { .. }
|
||||
| ControlEvent::LayoutResync => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_new_wire_variant_has_to_move_the_dialect_number() {
|
||||
// The two values are stand-ins. The exhaustive matches inside are the
|
||||
// assertion, and the compiler is what checks them.
|
||||
wire_variants_are_pinned(&ReplyOk::Unit, &ControlEvent::LayoutResync);
|
||||
}
|
||||
|
||||
fn every_reply() -> Vec<ControlReply> {
|
||||
vec![
|
||||
ControlReply::Ok(ReplyOk::Unit),
|
||||
|
||||
Reference in New Issue
Block a user