atagen

monolith

public
Star0
Watch0
9b87063809e160feaf6efbc66c42eab48e513825
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git

Blame: crates/layout/src/tests.rs

9baaafa4b167atagen2026-10-16 10:04 UTC1
use super::*;
9baaafa4b167atagen2026-10-16 10:04 UTC2
use proptest::prelude::*;
9baaafa4b167atagen2026-10-16 10:04 UTC3
9baaafa4b167atagen2026-10-16 10:04 UTC4
const AREA: Rect = Rect::new(0.0, 0.0, 1000.0, 600.0);
9baaafa4b167atagen2026-10-16 10:04 UTC5
9baaafa4b167atagen2026-10-16 10:04 UTC6
#[derive(Clone, Debug)]
9baaafa4b167atagen2026-10-16 10:04 UTC7
enum Op {
9baaafa4b167atagen2026-10-16 10:04 UTC8
    Add(u8, bool),
9baaafa4b167atagen2026-10-16 10:04 UTC9
    Remove(u8),
9baaafa4b167atagen2026-10-16 10:04 UTC10
    Focus(u8),
9baaafa4b167atagen2026-10-16 10:04 UTC11
    Move(Dir),
9baaafa4b167atagen2026-10-16 10:04 UTC12
    Block(Dir),
4444c779eb48atagen2026-10-16 12:07 UTC13
    Merge(Dir),
9baaafa4b167atagen2026-10-16 10:04 UTC14
    View(u8),
9baaafa4b167atagen2026-10-16 10:04 UTC15
    ToggleView(u8),
9baaafa4b167atagen2026-10-16 10:04 UTC16
    Retag(u8, u8),
9baaafa4b167atagen2026-10-16 10:04 UTC17
    Float(u8),
9baaafa4b167atagen2026-10-16 10:04 UTC18
    Expand(u8),
9baaafa4b167atagen2026-10-16 10:04 UTC19
    Flip,
9baaafa4b167atagen2026-10-16 10:04 UTC20
    Resize(bool, i8),
9baaafa4b167atagen2026-10-16 10:04 UTC21
    Scratch(u8),
9baaafa4b167atagen2026-10-16 10:04 UTC22
    Summon,
9baaafa4b167atagen2026-10-16 10:04 UTC23
    Unplug,
9baaafa4b167atagen2026-10-16 10:04 UTC24
    Replug,
9baaafa4b167atagen2026-10-16 10:04 UTC25
}
9baaafa4b167atagen2026-10-16 10:04 UTC26
9baaafa4b167atagen2026-10-16 10:04 UTC27
fn dir() -> impl Strategy<Value = Dir> {
9baaafa4b167atagen2026-10-16 10:04 UTC28
    prop_oneof![
9baaafa4b167atagen2026-10-16 10:04 UTC29
        Just(Dir::Left),
9baaafa4b167atagen2026-10-16 10:04 UTC30
        Just(Dir::Right),
9baaafa4b167atagen2026-10-16 10:04 UTC31
        Just(Dir::Up),
9baaafa4b167atagen2026-10-16 10:04 UTC32
        Just(Dir::Down)
9baaafa4b167atagen2026-10-16 10:04 UTC33
    ]
9baaafa4b167atagen2026-10-16 10:04 UTC34
}
9baaafa4b167atagen2026-10-16 10:04 UTC35
9baaafa4b167atagen2026-10-16 10:04 UTC36
fn op() -> impl Strategy<Value = Op> {
9baaafa4b167atagen2026-10-16 10:04 UTC37
    prop_oneof![
9baaafa4b167atagen2026-10-16 10:04 UTC38
        4 => (0u8..4, prop::bool::weighted(0.15)).prop_map(|(t, f)| Op::Add(t, f)),
9baaafa4b167atagen2026-10-16 10:04 UTC39
        1 => any::<u8>().prop_map(Op::Remove),
9baaafa4b167atagen2026-10-16 10:04 UTC40
        3 => any::<u8>().prop_map(Op::Focus),
9baaafa4b167atagen2026-10-16 10:04 UTC41
        4 => dir().prop_map(Op::Move),
9baaafa4b167atagen2026-10-16 10:04 UTC42
        2 => dir().prop_map(Op::Block),
4444c779eb48atagen2026-10-16 12:07 UTC43
        3 => dir().prop_map(Op::Merge),
9baaafa4b167atagen2026-10-16 10:04 UTC44
        1 => (0u8..4).prop_map(Op::View),
9baaafa4b167atagen2026-10-16 10:04 UTC45
        2 => (0u8..4).prop_map(Op::ToggleView),
9baaafa4b167atagen2026-10-16 10:04 UTC46
        1 => (any::<u8>(), 0u8..4).prop_map(|(w, t)| Op::Retag(w, t)),
9baaafa4b167atagen2026-10-16 10:04 UTC47
        1 => any::<u8>().prop_map(Op::Float),
9baaafa4b167atagen2026-10-16 10:04 UTC48
        1 => (0u8..3).prop_map(Op::Expand),
9baaafa4b167atagen2026-10-16 10:04 UTC49
        1 => Just(Op::Flip),
9baaafa4b167atagen2026-10-16 10:04 UTC50
        1 => (any::<bool>(), any::<i8>()).prop_map(|(a, d)| Op::Resize(a, d)),
9baaafa4b167atagen2026-10-16 10:04 UTC51
        1 => any::<u8>().prop_map(Op::Scratch),
9baaafa4b167atagen2026-10-16 10:04 UTC52
        1 => Just(Op::Summon),
9baaafa4b167atagen2026-10-16 10:04 UTC53
        1 => Just(Op::Unplug),
9baaafa4b167atagen2026-10-16 10:04 UTC54
        1 => Just(Op::Replug),
9baaafa4b167atagen2026-10-16 10:04 UTC55
    ]
9baaafa4b167atagen2026-10-16 10:04 UTC56
}
9baaafa4b167atagen2026-10-16 10:04 UTC57
9baaafa4b167atagen2026-10-16 10:04 UTC58
fn nth(l: &Layout, i: u8) -> Option<WindowId> {
9baaafa4b167atagen2026-10-16 10:04 UTC59
    let ids: Vec<WindowId> = l.windows().map(|(id, _)| id).collect();
9baaafa4b167atagen2026-10-16 10:04 UTC60
    (!ids.is_empty()).then(|| ids[i as usize % ids.len()])
9baaafa4b167atagen2026-10-16 10:04 UTC61
}
9baaafa4b167atagen2026-10-16 10:04 UTC62
9baaafa4b167atagen2026-10-16 10:04 UTC63
fn apply(l: &mut Layout, tags: &[TagId], op: &Op) {
9baaafa4b167atagen2026-10-16 10:04 UTC64
    let active = l.active_output();
9baaafa4b167atagen2026-10-16 10:04 UTC65
    match *op {
9baaafa4b167atagen2026-10-16 10:04 UTC66
        Op::Add(t, f) => {
9baaafa4b167atagen2026-10-16 10:04 UTC67
            let w = l.add_window(
9baaafa4b167atagen2026-10-16 10:04 UTC68
                None,
9baaafa4b167atagen2026-10-16 10:04 UTC69
                Some(tags[t as usize]),
9baaafa4b167atagen2026-10-16 10:04 UTC70
                f.then(|| Rect::new(10.0, 10.0, 200.0, 100.0)),
9baaafa4b167atagen2026-10-16 10:04 UTC71
            );
9baaafa4b167atagen2026-10-16 10:04 UTC72
            if l.visible(w) {
9baaafa4b167atagen2026-10-16 10:04 UTC73
                l.focus(w);
9baaafa4b167atagen2026-10-16 10:04 UTC74
            }
9baaafa4b167atagen2026-10-16 10:04 UTC75
        }
9baaafa4b167atagen2026-10-16 10:04 UTC76
        Op::Remove(i) => nth(l, i).into_iter().for_each(|w| l.remove_window(w)),
9baaafa4b167atagen2026-10-16 10:04 UTC77
        Op::Focus(i) => {
9baaafa4b167atagen2026-10-16 10:04 UTC78
            if let Some(w) = nth(l, i).filter(|&w| l.visible(w)) {
9baaafa4b167atagen2026-10-16 10:04 UTC79
                l.focus(w);
9baaafa4b167atagen2026-10-16 10:04 UTC80
            }
9baaafa4b167atagen2026-10-16 10:04 UTC81
        }
9baaafa4b167atagen2026-10-16 10:04 UTC82
        Op::Move(d) => {
9baaafa4b167atagen2026-10-16 10:04 UTC83
            l.move_window(d);
9baaafa4b167atagen2026-10-16 10:04 UTC84
        }
9baaafa4b167atagen2026-10-16 10:04 UTC85
        Op::Block(d) => {
4444c779eb48atagen2026-10-16 12:07 UTC86
            l.move_container(d);
4444c779eb48atagen2026-10-16 12:07 UTC87
        }
4444c779eb48atagen2026-10-16 12:07 UTC88
        Op::Merge(d) => {
4444c779eb48atagen2026-10-16 12:07 UTC89
            l.merge_window(d);
9baaafa4b167atagen2026-10-16 10:04 UTC90
        }
9baaafa4b167atagen2026-10-16 10:04 UTC91
        Op::View(t) => active.into_iter().for_each(|o| l.view(o, tags[t as usize])),
9baaafa4b167atagen2026-10-16 10:04 UTC92
        Op::ToggleView(t) => active
9baaafa4b167atagen2026-10-16 10:04 UTC93
            .into_iter()
9baaafa4b167atagen2026-10-16 10:04 UTC94
            .for_each(|o| l.toggle_view(o, tags[t as usize])),
9baaafa4b167atagen2026-10-16 10:04 UTC95
        Op::Retag(i, t) => nth(l, i)
9baaafa4b167atagen2026-10-16 10:04 UTC96
            .into_iter()
9baaafa4b167atagen2026-10-16 10:04 UTC97
            .for_each(|w| l.set_tag(w, tags[t as usize])),
9baaafa4b167atagen2026-10-16 10:04 UTC98
        Op::Float(i) => nth(l, i).into_iter().for_each(|w| l.toggle_floating(w)),
9baaafa4b167atagen2026-10-16 10:04 UTC99
        Op::Expand(s) => {
4444c779eb48atagen2026-10-16 12:07 UTC100
            l.expand(
4444c779eb48atagen2026-10-16 12:07 UTC101
                [
4444c779eb48atagen2026-10-16 12:07 UTC102
                    ExpandScope::Window,
4444c779eb48atagen2026-10-16 12:07 UTC103
                    ExpandScope::Container,
4444c779eb48atagen2026-10-16 12:07 UTC104
                    ExpandScope::All,
4444c779eb48atagen2026-10-16 12:07 UTC105
                ][s as usize],
4444c779eb48atagen2026-10-16 12:07 UTC106
            );
9baaafa4b167atagen2026-10-16 10:04 UTC107
        }
9baaafa4b167atagen2026-10-16 10:04 UTC108
        Op::Flip => active.into_iter().for_each(|o| l.flip(o)),
9baaafa4b167atagen2026-10-16 10:04 UTC109
        Op::Resize(h, d) => {
9baaafa4b167atagen2026-10-16 10:04 UTC110
            let axis = if h { Axis::Horizontal } else { Axis::Vertical };
9baaafa4b167atagen2026-10-16 10:04 UTC111
            l.resize(axis, f64::from(d) / 200.0);
9baaafa4b167atagen2026-10-16 10:04 UTC112
        }
9baaafa4b167atagen2026-10-16 10:04 UTC113
        Op::Scratch(i) => nth(l, i).into_iter().for_each(|w| l.scratchpad_add(w, "s")),
9baaafa4b167atagen2026-10-16 10:04 UTC114
        Op::Summon => {
9baaafa4b167atagen2026-10-16 10:04 UTC115
            l.summon("s");
9baaafa4b167atagen2026-10-16 10:04 UTC116
        }
9baaafa4b167atagen2026-10-16 10:04 UTC117
        Op::Unplug => {
9baaafa4b167atagen2026-10-16 10:04 UTC118
            let b = l.outputs().find(|(_, out)| out.name == "b").map(|(o, _)| o);
9baaafa4b167atagen2026-10-16 10:04 UTC119
            if let Some(o) = b {
9baaafa4b167atagen2026-10-16 10:04 UTC120
                l.remove_output(o);
9baaafa4b167atagen2026-10-16 10:04 UTC121
            }
9baaafa4b167atagen2026-10-16 10:04 UTC122
        }
9baaafa4b167atagen2026-10-16 10:04 UTC123
        Op::Replug => {
9baaafa4b167atagen2026-10-16 10:04 UTC124
            if !l.outputs().any(|(_, out)| out.name == "b") {
9baaafa4b167atagen2026-10-16 10:04 UTC125
                l.add_output("b", Rect::new(1000.0, 0.0, 800.0, 600.0));
9baaafa4b167atagen2026-10-16 10:04 UTC126
            }
9baaafa4b167atagen2026-10-16 10:04 UTC127
        }
9baaafa4b167atagen2026-10-16 10:04 UTC128
    }
9baaafa4b167atagen2026-10-16 10:04 UTC129
}
9baaafa4b167atagen2026-10-16 10:04 UTC130
9baaafa4b167atagen2026-10-16 10:04 UTC131
fn check_geometry(l: &Layout) {
9baaafa4b167atagen2026-10-16 10:04 UTC132
    for (o, out) in l.outputs() {
9baaafa4b167atagen2026-10-16 10:04 UTC133
        let arr = l.arrange(o);
38125b3487d7atagen2026-10-17 05:02 UTC134
        let mut drawn: Vec<WindowId> = arr
38125b3487d7atagen2026-10-17 05:02 UTC135
            .tiled
38125b3487d7atagen2026-10-17 05:02 UTC136
            .iter()
38125b3487d7atagen2026-10-17 05:02 UTC137
            .filter(|p| p.visible)
38125b3487d7atagen2026-10-17 05:02 UTC138
            .map(|p| p.window)
38125b3487d7atagen2026-10-17 05:02 UTC139
            .chain(arr.floating.iter().map(|&(w, _)| w))
38125b3487d7atagen2026-10-17 05:02 UTC140
            .chain(arr.fullscreen)
38125b3487d7atagen2026-10-17 05:02 UTC141
            .collect();
38125b3487d7atagen2026-10-17 05:02 UTC142
        drawn.sort();
38125b3487d7atagen2026-10-17 05:02 UTC143
        drawn.dedup();
38125b3487d7atagen2026-10-17 05:02 UTC144
        let mut visible: Vec<WindowId> = l
38125b3487d7atagen2026-10-17 05:02 UTC145
            .windows()
38125b3487d7atagen2026-10-17 05:02 UTC146
            .filter(|&(w, win)| win.output == Some(o) && l.visible(w))
38125b3487d7atagen2026-10-17 05:02 UTC147
            .map(|(w, _)| w)
38125b3487d7atagen2026-10-17 05:02 UTC148
            .collect();
38125b3487d7atagen2026-10-17 05:02 UTC149
        visible.sort();
38125b3487d7atagen2026-10-17 05:02 UTC150
        assert_eq!(drawn, visible, "arrangement disagrees with visible()");
9baaafa4b167atagen2026-10-16 10:04 UTC151
        let shown: Vec<Rect> = arr
9baaafa4b167atagen2026-10-16 10:04 UTC152
            .tiled
9baaafa4b167atagen2026-10-16 10:04 UTC153
            .iter()
9baaafa4b167atagen2026-10-16 10:04 UTC154
            .filter(|p| p.visible)
9baaafa4b167atagen2026-10-16 10:04 UTC155
            .map(|p| p.rect)
9baaafa4b167atagen2026-10-16 10:04 UTC156
            .collect();
1c8e1b4009f5atagen2026-10-16 23:19 UTC157
        for p in arr.tiled.iter().filter(|p| !p.visible) {
1c8e1b4009f5atagen2026-10-16 23:19 UTC158
            assert!(p.rect.w * p.rect.h <= 1e-6, "hidden {:?} has area", p.rect);
1c8e1b4009f5atagen2026-10-16 23:19 UTC159
        }
9baaafa4b167atagen2026-10-16 10:04 UTC160
        for r in &shown {
9baaafa4b167atagen2026-10-16 10:04 UTC161
            assert!(r.w >= 0.0 && r.h >= 0.0);
9baaafa4b167atagen2026-10-16 10:04 UTC162
            assert!(r.x >= out.area.x - 1e-6 && r.right() <= out.area.right() + 1e-6);
9baaafa4b167atagen2026-10-16 10:04 UTC163
            assert!(r.y >= out.area.y - 1e-6 && r.bottom() <= out.area.bottom() + 1e-6);
9baaafa4b167atagen2026-10-16 10:04 UTC164
        }
9baaafa4b167atagen2026-10-16 10:04 UTC165
        for (i, a) in shown.iter().enumerate() {
9baaafa4b167atagen2026-10-16 10:04 UTC166
            for b in &shown[i + 1..] {
9baaafa4b167atagen2026-10-16 10:04 UTC167
                let ox = a.right().min(b.right()) - a.x.max(b.x);
9baaafa4b167atagen2026-10-16 10:04 UTC168
                let oy = a.bottom().min(b.bottom()) - a.y.max(b.y);
9baaafa4b167atagen2026-10-16 10:04 UTC169
                assert!(ox <= 1e-6 || oy <= 1e-6, "{a:?} overlaps {b:?}");
9baaafa4b167atagen2026-10-16 10:04 UTC170
            }
9baaafa4b167atagen2026-10-16 10:04 UTC171
        }
9baaafa4b167atagen2026-10-16 10:04 UTC172
    }
9baaafa4b167atagen2026-10-16 10:04 UTC173
}
9baaafa4b167atagen2026-10-16 10:04 UTC174
9baaafa4b167atagen2026-10-16 10:04 UTC175
proptest! {
9baaafa4b167atagen2026-10-16 10:04 UTC176
    #![proptest_config(ProptestConfig::with_cases(2000))]
9baaafa4b167atagen2026-10-16 10:04 UTC177
9baaafa4b167atagen2026-10-16 10:04 UTC178
    #[test]
9baaafa4b167atagen2026-10-16 10:04 UTC179
    fn random_commands_keep_the_model_sound(ops in prop::collection::vec(op(), 1..80)) {
9baaafa4b167atagen2026-10-16 10:04 UTC180
        let mut l = Layout::default();
9baaafa4b167atagen2026-10-16 10:04 UTC181
        l.add_output("a", AREA);
9baaafa4b167atagen2026-10-16 10:04 UTC182
        l.add_output("b", Rect::new(1000.0, 0.0, 800.0, 600.0));
9baaafa4b167atagen2026-10-16 10:04 UTC183
        let tags = [l.homeless(), l.tag("1"), l.tag("2"), l.tag("3")];
9baaafa4b167atagen2026-10-16 10:04 UTC184
        for op in &ops {
9baaafa4b167atagen2026-10-16 10:04 UTC185
            apply(&mut l, &tags, op);
9baaafa4b167atagen2026-10-16 10:04 UTC186
            l.check();
9baaafa4b167atagen2026-10-16 10:04 UTC187
            check_geometry(&l);
9baaafa4b167atagen2026-10-16 10:04 UTC188
        }
9baaafa4b167atagen2026-10-16 10:04 UTC189
    }
38125b3487d7atagen2026-10-17 05:02 UTC190
38125b3487d7atagen2026-10-17 05:02 UTC191
    #[test]
38125b3487d7atagen2026-10-17 05:02 UTC192
    fn replugging_restores_what_unplugging_moved(ops in prop::collection::vec(op(), 1..60)) {
38125b3487d7atagen2026-10-17 05:02 UTC193
        let mut l = Layout::default();
38125b3487d7atagen2026-10-17 05:02 UTC194
        l.add_output("a", AREA);
38125b3487d7atagen2026-10-17 05:02 UTC195
        l.add_output("b", Rect::new(1000.0, 0.0, 800.0, 600.0));
38125b3487d7atagen2026-10-17 05:02 UTC196
        let tags = [l.homeless(), l.tag("1"), l.tag("2"), l.tag("3")];
38125b3487d7atagen2026-10-17 05:02 UTC197
        for op in &ops {
38125b3487d7atagen2026-10-17 05:02 UTC198
            apply(&mut l, &tags, op);
38125b3487d7atagen2026-10-17 05:02 UTC199
        }
38125b3487d7atagen2026-10-17 05:02 UTC200
        let Some(b) = l.outputs().find(|(_, out)| out.name == "b").map(|(o, _)| o) else {
38125b3487d7atagen2026-10-17 05:02 UTC201
            return Ok(());
38125b3487d7atagen2026-10-17 05:02 UTC202
        };
38125b3487d7atagen2026-10-17 05:02 UTC203
        let before = |l: &Layout, o| {
38125b3487d7atagen2026-10-17 05:02 UTC204
            let out = l.output(o).unwrap();
38125b3487d7atagen2026-10-17 05:02 UTC205
            (out.tree.windows().collect::<Vec<_>>(), out.floating.clone(), out.viewed.clone())
38125b3487d7atagen2026-10-17 05:02 UTC206
        };
38125b3487d7atagen2026-10-17 05:02 UTC207
        let was = before(&l, b);
38125b3487d7atagen2026-10-17 05:02 UTC208
        l.remove_output(b);
38125b3487d7atagen2026-10-17 05:02 UTC209
        let b = l.add_output("b", Rect::new(1000.0, 0.0, 800.0, 600.0));
38125b3487d7atagen2026-10-17 05:02 UTC210
        l.check();
38125b3487d7atagen2026-10-17 05:02 UTC211
        prop_assert_eq!(before(&l, b), was);
38125b3487d7atagen2026-10-17 05:02 UTC212
    }
9baaafa4b167atagen2026-10-16 10:04 UTC213
}
9baaafa4b167atagen2026-10-16 10:04 UTC214
9baaafa4b167atagen2026-10-16 10:04 UTC215
/// The hidden-slot rules from planner.html, demo 11.
9baaafa4b167atagen2026-10-16 10:04 UTC216
#[test]
9baaafa4b167atagen2026-10-16 10:04 UTC217
fn hidden_windows_keep_their_slots() {
9baaafa4b167atagen2026-10-16 10:04 UTC218
    let (a, b, c, d, e) = (1, 2, 3, 4, 5);
9baaafa4b167atagen2026-10-16 10:04 UTC219
    let mut t: Tree<u32> = Tree::default();
9baaafa4b167atagen2026-10-16 10:04 UTC220
    t.insert_row(a);
9baaafa4b167atagen2026-10-16 10:04 UTC221
    t.insert_after(d, a);
9baaafa4b167atagen2026-10-16 10:04 UTC222
    t.insert_after(b, d);
9baaafa4b167atagen2026-10-16 10:04 UTC223
    t.insert_row(c);
9baaafa4b167atagen2026-10-16 10:04 UTC224
    t.insert_after(e, c);
9baaafa4b167atagen2026-10-16 10:04 UTC225
    t.check();
9baaafa4b167atagen2026-10-16 10:04 UTC226
    let hidden = |w: u32| w != d && w != e;
9baaafa4b167atagen2026-10-16 10:04 UTC227
    let all = |_| true;
9baaafa4b167atagen2026-10-16 10:04 UTC228
    let rect = |t: &Tree<u32>, w| {
9baaafa4b167atagen2026-10-16 10:04 UTC229
        t.arrange(AREA, 0.0, all)
9baaafa4b167atagen2026-10-16 10:04 UTC230
            .into_iter()
9baaafa4b167atagen2026-10-16 10:04 UTC231
            .find(|p| p.0 == w)
9baaafa4b167atagen2026-10-16 10:04 UTC232
            .unwrap()
9baaafa4b167atagen2026-10-16 10:04 UTC233
            .1
9baaafa4b167atagen2026-10-16 10:04 UTC234
    };
9baaafa4b167atagen2026-10-16 10:04 UTC235
9baaafa4b167atagen2026-10-16 10:04 UTC236
    assert!(t.move_window(a, Dir::Right, hidden));
9baaafa4b167atagen2026-10-16 10:04 UTC237
    assert!(rect(&t, b).x < rect(&t, d).x && rect(&t, d).x < rect(&t, a).x);
9baaafa4b167atagen2026-10-16 10:04 UTC238
9baaafa4b167atagen2026-10-16 10:04 UTC239
    assert!(t.move_window(c, Dir::Up, hidden));
9baaafa4b167atagen2026-10-16 10:04 UTC240
    t.check();
9baaafa4b167atagen2026-10-16 10:04 UTC241
    assert_eq!(rect(&t, e).w, AREA.w, "E is demoted to a row of its own");
9baaafa4b167atagen2026-10-16 10:04 UTC242
}
60f00dd4f2beatagen2026-10-16 11:50 UTC243
60f00dd4f2beatagen2026-10-16 11:50 UTC244
/// Moving out of a row toward a lane of hidden windows joins that lane, so
60f00dd4f2beatagen2026-10-16 11:50 UTC245
/// they share it when shown again instead of a new lane opening between.
60f00dd4f2beatagen2026-10-16 11:50 UTC246
#[test]
60f00dd4f2beatagen2026-10-16 11:50 UTC247
fn moving_toward_a_hidden_lane_joins_it() {
60f00dd4f2beatagen2026-10-16 11:50 UTC248
    let (a, b, c, d, e) = (1, 2, 3, 4, 5);
60f00dd4f2beatagen2026-10-16 11:50 UTC249
    let mut t: Tree<u32> = Tree::default();
60f00dd4f2beatagen2026-10-16 11:50 UTC250
    t.insert_row(a);
60f00dd4f2beatagen2026-10-16 11:50 UTC251
    t.insert_after(b, a);
60f00dd4f2beatagen2026-10-16 11:50 UTC252
    t.insert_after(c, b);
60f00dd4f2beatagen2026-10-16 11:50 UTC253
    t.insert_row(d);
60f00dd4f2beatagen2026-10-16 11:50 UTC254
    t.insert_after(e, c);
60f00dd4f2beatagen2026-10-16 11:50 UTC255
    let tag_two = |w: u32| w != a && w != d;
60f00dd4f2beatagen2026-10-16 11:50 UTC256
    assert!(t.move_window(e, Dir::Down, tag_two));
60f00dd4f2beatagen2026-10-16 11:50 UTC257
    t.check();
60f00dd4f2beatagen2026-10-16 11:50 UTC258
    let all = t.arrange(AREA, 0.0, |_| true);
60f00dd4f2beatagen2026-10-16 11:50 UTC259
    let rect = |w| all.iter().find(|p| p.0 == w).unwrap().1;
60f00dd4f2beatagen2026-10-16 11:50 UTC260
    assert_eq!(rect(e).y, rect(d).y);
60f00dd4f2beatagen2026-10-16 11:50 UTC261
    assert!(rect(d).x < rect(e).x);
60f00dd4f2beatagen2026-10-16 11:50 UTC262
    assert!(rect(a).y < rect(d).y);
60f00dd4f2beatagen2026-10-16 11:50 UTC263
}
91957f0ae29eatagen2026-10-17 09:24 UTC264
91957f0ae29eatagen2026-10-17 09:24 UTC265
#[test]
605c44c8c5fcatagen2026-10-17 09:57 UTC266
fn merging_steps_out_of_a_stack_before_joining_another() {
91957f0ae29eatagen2026-10-17 09:24 UTC267
    let (a, b, c) = (1, 2, 3);
605c44c8c5fcatagen2026-10-17 09:57 UTC268
    let stacked = || {
605c44c8c5fcatagen2026-10-17 09:57 UTC269
        let mut t: Tree<u32> = Tree::default();
605c44c8c5fcatagen2026-10-17 09:57 UTC270
        t.insert_row(a);
605c44c8c5fcatagen2026-10-17 09:57 UTC271
        t.insert_after(b, a);
605c44c8c5fcatagen2026-10-17 09:57 UTC272
        t.insert_after(c, b);
605c44c8c5fcatagen2026-10-17 09:57 UTC273
        assert!(t.merge_window(b, Dir::Left, |_| true));
605c44c8c5fcatagen2026-10-17 09:57 UTC274
        t
605c44c8c5fcatagen2026-10-17 09:57 UTC275
    };
605c44c8c5fcatagen2026-10-17 09:57 UTC276
    let rects = |t: &Tree<u32>| {
605c44c8c5fcatagen2026-10-17 09:57 UTC277
        t.check();
605c44c8c5fcatagen2026-10-17 09:57 UTC278
        let all = t.arrange(AREA, 0.0, |_| true);
605c44c8c5fcatagen2026-10-17 09:57 UTC279
        move |w| all.iter().find(|p: &&(u32, Rect)| p.0 == w).unwrap().1
605c44c8c5fcatagen2026-10-17 09:57 UTC280
    };
605c44c8c5fcatagen2026-10-17 09:57 UTC281
605c44c8c5fcatagen2026-10-17 09:57 UTC282
    let mut t = stacked();
605c44c8c5fcatagen2026-10-17 09:57 UTC283
    assert!(t.merge_window(a, Dir::Right, |_| true));
605c44c8c5fcatagen2026-10-17 09:57 UTC284
    let rect = rects(&t);
605c44c8c5fcatagen2026-10-17 09:57 UTC285
    assert!(rect(b).x < rect(a).x && rect(a).x < rect(c).x);
605c44c8c5fcatagen2026-10-17 09:57 UTC286
    assert_eq!(rect(a).h, AREA.h);
605c44c8c5fcatagen2026-10-17 09:57 UTC287
    assert!(t.merge_window(a, Dir::Right, |_| true));
605c44c8c5fcatagen2026-10-17 09:57 UTC288
    let rect = rects(&t);
605c44c8c5fcatagen2026-10-17 09:57 UTC289
    assert_eq!(rect(a).x, rect(c).x);
605c44c8c5fcatagen2026-10-17 09:57 UTC290
605c44c8c5fcatagen2026-10-17 09:57 UTC291
    let mut t = stacked();
91957f0ae29eatagen2026-10-17 09:24 UTC292
    assert!(t.merge_window(a, Dir::Up, |_| true));
605c44c8c5fcatagen2026-10-17 09:57 UTC293
    let rect = rects(&t);
91957f0ae29eatagen2026-10-17 09:24 UTC294
    assert_eq!(rect(a).w, AREA.w);
91957f0ae29eatagen2026-10-17 09:24 UTC295
    assert!(rect(a).bottom() <= rect(b).y && rect(b).y == rect(c).y);
91957f0ae29eatagen2026-10-17 09:24 UTC296
}