Files
iris/tests/cases/determinism.rs
T
iris-ai beb138632a Say narrow_rel_base, and let a container pass None for it
`narrow` said what the argument did to a value it never named, so a reader
had to go and find out which value. It is `narrow_rel_base`, and the
resolved one stays the bare `rel_base` -- which is also the only one in
`Painter`, `Placing` and `LayoutHolds`, where there is nothing to tell it
apart from.

It takes `impl Into<Option<[Option<Len>; 2]>>`, so a container that does not
narrow anything writes `None` rather than `[None; 2]`, and `Span` builds the
one case that does with a `then` instead of a mutable array.

Cold layout is byte-identical to `84dad21`.
2026-09-19 16:55:48 -04:00

104 lines
3.8 KiB
Rust

//! A measurement that decides control flow.
//!
//! Comparing boxes catches a widget that moved. It does not catch a widget
//! that measured a child, believed a different answer from the one a cold
//! start would give, and took the other branch -- which is the same defect
//! arriving somewhere it cannot be ignored. A widget here branches on what it
//! measured, so a disagreement shows up as a different tree.
use iris::harness::Harness;
use iris::prelude::*;
/// Measures `probe` across `axis` and draws one of two children on the
/// answer. Its own configuration never changes, so which child is drawn is a
/// property of the layout alone.
struct BranchesOnMeasurement {
probe: StrongWidget,
wide: StrongWidget,
narrow: StrongWidget,
threshold: f32,
}
impl Widget for BranchesOnMeasurement {
fn draw(&mut self, painter: &mut Painter) -> Size {
let cut = Len::from_parts(Rel::ZERO, Px::from_int(40));
let top = Place::Within(Part::From(UiSpan::new(Len::ZERO, cut)));
let measured = painter
.widget_at(&self.probe, None, [Place::Within(Part::WHOLE), top])
.len(Axis::X);
let px = painter.to_px(measured.apply_leftover(), Axis::X);
let below = Place::Within(Part::From(UiSpan::new(cut, painter.region_len(Axis::Y))));
let place = [Place::Within(Part::WHOLE), below];
match px > Px::from_f32(self.threshold) {
true => painter.widget_at(&self.wide, None, place),
false => painter.widget_at(&self.narrow, None, place),
};
Size::LEFTOVER
}
}
fn plant(h: &mut Harness, threshold: f32) -> (WidgetId, WidgetId) {
let words = "the quick brown fox jumps over the lazy dog and keeps running";
let probe = wtext(words).size(16).wrap(true).add(&mut h.rsc);
let wide = rect(Color::RED).add(&mut h.rsc);
let narrow = rect(Color::BLUE).add(&mut h.rsc);
let branch = BranchesOnMeasurement {
probe: probe.add_strong(&mut h.rsc),
wide: wide.add_strong(&mut h.rsc),
narrow: narrow.add_strong(&mut h.rsc),
threshold,
}
.add(&mut h.rsc);
let side = rect(Color::GREEN).width(120).add(&mut h.rsc);
h.set_root((side, branch).span(Dir::RIGHT));
(wide.id(), narrow.id())
}
/// Which of the two branches drew, as a pair a test can compare.
fn taken(h: &Harness, wide: WidgetId, narrow: WidgetId) -> (bool, bool) {
(h.region(&wide).is_some(), h.region(&narrow).is_some())
}
#[test]
fn a_branch_taken_on_a_measurement_holds_across_repaints() {
for threshold in [0.0, 200.0, 400.0, 600.0, 779.0, 780.0, 781.0, 2000.0] {
let mut h = Harness::new((900, 600));
let (wide, narrow) = plant(&mut h, threshold);
let first = taken(&h, wide, narrow);
assert_ne!(first, (false, false), "threshold {threshold}: neither drew");
for frame in 0..4 {
h.rsc.widgets_mut().get_dyn_mut(wide);
h.rsc.widgets_mut().get_dyn_mut(narrow);
h.frame();
assert_eq!(
taken(&h, wide, narrow),
first,
"threshold {threshold}, repaint {frame}: the branch moved when nothing did"
);
}
}
}
#[test]
fn a_branch_taken_on_a_measurement_is_the_one_a_cold_start_takes() {
for threshold in [0.0, 200.0, 400.0, 600.0, 779.0, 780.0, 781.0, 2000.0] {
let mut warm = Harness::new((900, 600));
let (wide, narrow) = plant(&mut warm, threshold);
warm.resize((640, 480));
warm.frame();
warm.rsc.widgets_mut().get_dyn_mut(wide);
warm.frame();
let mut cold = Harness::new((640, 480));
let (cwide, cnarrow) = plant(&mut cold, threshold);
assert_eq!(
taken(&warm, wide, narrow),
taken(&cold, cwide, cnarrow),
"threshold {threshold}: warm and cold took different branches"
);
}
}