test(gui-1b): the split row now guarantees its own setup
The row claimed to target the inactive pane and did not. It hit-tested a hardcoded column, took whichever pane that resolved to, and then branched its assertions to match. If the layout ever put the active pane under that column, an active-window-routing mutant would pass and the focus assertion would be a tautology --- the row would look like evidence while proving nothing. It now SCANS for a cell the hit-test actually resolves to the inactive pane, asserts `under_pointer == other` before dispatching, and asserts directly with no adaptive branch: the inactive pane moves by three the active pane's origin is unchanged the active window id is unchanged The setup guard is itself falsifiable: pointing the scan at the active pane makes the row fail on "setup: the pointer must be over the INACTIVE pane" rather than passing quietly. That check matters more than the mutation --- a setup assertion nothing can break is the same defect one level up. The routing mutant still fires the row, and only it.
This commit is contained in:
parent
951c6447b3
commit
5371229b9a
|
|
@ -10660,46 +10660,57 @@ mod tests {
|
|||
|
||||
let active = s.core.borrow().active_window_id();
|
||||
let other = *ids.iter().find(|id| **id != active).expect("a second pane");
|
||||
// A 50/50 vertical split: column 60 is inside the right pane.
|
||||
// Whichever pane that is, it must be the one that moves.
|
||||
let target_col: u16 = 60;
|
||||
let under_pointer = {
|
||||
|
||||
// **Find a cell the hit-test actually resolves to the INACTIVE
|
||||
// pane**, rather than assuming a column lands there. A row that
|
||||
// adapts to whichever pane it hits cannot fail an
|
||||
// active-window-routing mutant, and its focus assertion becomes
|
||||
// a tautology.
|
||||
let size = term_size_24x80();
|
||||
let target = {
|
||||
let core = s.core.borrow();
|
||||
window_at_cell(
|
||||
&core,
|
||||
FrontendId::LOCAL,
|
||||
term_size_24x80(),
|
||||
5,
|
||||
u32::from(target_col),
|
||||
)
|
||||
.map_or(other, |(id, _)| id)
|
||||
(0..size.rows.saturating_sub(1))
|
||||
.flat_map(|row| (0..size.cols).map(move |col| (row, col)))
|
||||
.find(|(row, col)| {
|
||||
window_at_cell(&core, FrontendId::LOCAL, size, *row, *col)
|
||||
.is_some_and(|(id, _)| id == other)
|
||||
})
|
||||
};
|
||||
let (target_row, target_col) = target.expect("some cell must resolve to the inactive pane");
|
||||
{
|
||||
let core = s.core.borrow();
|
||||
let (under_pointer, _) =
|
||||
window_at_cell(&core, FrontendId::LOCAL, size, target_row, target_col)
|
||||
.expect("the cell resolves to a pane");
|
||||
assert_eq!(
|
||||
under_pointer, other,
|
||||
"setup: the pointer must be over the INACTIVE pane"
|
||||
);
|
||||
}
|
||||
|
||||
let before_active = s.core.borrow().windows[&active].view_left;
|
||||
let before_other = s.core.borrow().windows[&other].view_left;
|
||||
|
||||
s.dispatch_mouse(
|
||||
FrontendId::LOCAL,
|
||||
mouse(MouseEventKind::ScrollRight, 5, target_col),
|
||||
term_size_24x80(),
|
||||
mouse(
|
||||
MouseEventKind::ScrollRight,
|
||||
u16::try_from(target_row).unwrap_or(0),
|
||||
u16::try_from(target_col).unwrap_or(0),
|
||||
),
|
||||
size,
|
||||
);
|
||||
|
||||
let after_active = s.core.borrow().windows[&active].view_left;
|
||||
let after_other = s.core.borrow().windows[&other].view_left;
|
||||
let (moved, still) = if under_pointer == active {
|
||||
((after_active, before_active), (after_other, before_other))
|
||||
} else {
|
||||
((after_other, before_other), (after_active, before_active))
|
||||
};
|
||||
assert_eq!(
|
||||
moved.0 - moved.1,
|
||||
s.core.borrow().windows[&other].view_left - before_other,
|
||||
SCROLL_COLUMNS as u32,
|
||||
"the pane under the pointer moves by one notch"
|
||||
"the INACTIVE pane, under the pointer, moves by one notch"
|
||||
);
|
||||
assert_eq!(
|
||||
still.0, still.1,
|
||||
"and the other pane's origin is untouched — horizontal state \
|
||||
is per-window"
|
||||
s.core.borrow().windows[&active].view_left,
|
||||
before_active,
|
||||
"the ACTIVE pane's origin is untouched — horizontal state is \
|
||||
per-window, and routing to the active pane would move this"
|
||||
);
|
||||
assert_eq!(
|
||||
s.core.borrow().active_window_id(),
|
||||
|
|
|
|||
Loading…
Reference in New Issue