use fenestra_core::{Fonts, Frame, FrameState, GridTemplate, Theme, Track, build_frame, by, div};
fn frame(container: fenestra_core::Element<()>, size: (f32, f32)) -> Frame {
let theme = Theme::light();
let mut fonts = Fonts::embedded();
let mut state = FrameState::new();
build_frame(&container, &theme, &mut fonts, &mut state, size, 1.0)
}
fn x_of(frame: &Frame, id: &str) -> f64 {
frame.get(&by::id(id)).rect.x0
}
fn y_of(frame: &Frame, id: &str) -> f64 {
frame.get(&by::id(id)).rect.y0
}
fn w_of(frame: &Frame, id: &str) -> f64 {
frame.get(&by::id(id)).rect.width()
}
#[test]
fn auto_fit_minmax_fills_three_columns_at_600() {
let cells: Vec<_> = (0..6)
.map(|i| div::<()>().id(&format!("c{i}")).h(50.0))
.collect();
let grid = div::<()>()
.w(600.0)
.grid_cols([GridTemplate::auto_fit_minmax(180.0)])
.children(cells);
let f = frame(grid, (600.0, 400.0));
assert!(
(x_of(&f, "c0") - 0.0).abs() < 1.0,
"c0 x = {}",
x_of(&f, "c0")
);
assert!(
(x_of(&f, "c1") - 200.0).abs() < 1.0,
"c1 x = {}",
x_of(&f, "c1")
);
assert!(
(x_of(&f, "c2") - 400.0).abs() < 1.0,
"c2 x = {}",
x_of(&f, "c2")
);
assert!(
(w_of(&f, "c0") - 200.0).abs() < 1.0,
"c0 width = {}",
w_of(&f, "c0")
);
assert!(
(x_of(&f, "c3") - 0.0).abs() < 1.0,
"c3 x = {}",
x_of(&f, "c3")
);
assert!(
y_of(&f, "c3") > y_of(&f, "c0"),
"c3 ({}) wraps below c0 ({})",
y_of(&f, "c3"),
y_of(&f, "c0")
);
}
#[test]
fn repeat_count_makes_equal_columns() {
let cells: Vec<_> = (0..3)
.map(|i| div::<()>().id(&format!("r{i}")).h(40.0))
.collect();
let grid = div::<()>()
.w(600.0)
.grid_cols([GridTemplate::repeat(3, [Track::Fr(1.0)])])
.children(cells);
let f = frame(grid, (600.0, 200.0));
assert!(
(x_of(&f, "r0") - 0.0).abs() < 1.0,
"r0 x = {}",
x_of(&f, "r0")
);
assert!(
(x_of(&f, "r1") - 200.0).abs() < 1.0,
"r1 x = {}",
x_of(&f, "r1")
);
assert!(
(x_of(&f, "r2") - 400.0).abs() < 1.0,
"r2 x = {}",
x_of(&f, "r2")
);
}
fn h_of(frame: &Frame, id: &str) -> f64 {
frame.get(&by::id(id)).rect.height()
}
#[test]
fn template_areas_holy_grail() {
let grid = div::<()>()
.w(600.0)
.h(300.0)
.grid_cols([Track::Px(120.0), Track::Fr(1.0)])
.grid_rows([Track::Px(40.0), Track::Fr(1.0), Track::Px(30.0)])
.grid_template_areas(["header header", "nav main", "footer footer"])
.children(vec![
div::<()>().id("header").grid_area("header"),
div::<()>().id("nav").grid_area("nav"),
div::<()>().id("main").grid_area("main"),
div::<()>().id("footer").grid_area("footer"),
]);
let f = frame(grid, (600.0, 300.0));
assert!(
(x_of(&f, "header")).abs() < 1.0,
"header x = {}",
x_of(&f, "header")
);
assert!(
(y_of(&f, "header")).abs() < 1.0,
"header y = {}",
y_of(&f, "header")
);
assert!(
(w_of(&f, "header") - 600.0).abs() < 1.0,
"header w = {}",
w_of(&f, "header")
);
assert!(
(h_of(&f, "header") - 40.0).abs() < 1.0,
"header h = {}",
h_of(&f, "header")
);
assert!((x_of(&f, "nav")).abs() < 1.0, "nav x = {}", x_of(&f, "nav"));
assert!(
(y_of(&f, "nav") - 40.0).abs() < 1.0,
"nav y = {}",
y_of(&f, "nav")
);
assert!(
(w_of(&f, "nav") - 120.0).abs() < 1.0,
"nav w = {}",
w_of(&f, "nav")
);
assert!(
(h_of(&f, "nav") - 230.0).abs() < 1.0,
"nav h = {}",
h_of(&f, "nav")
);
assert!(
(x_of(&f, "main") - 120.0).abs() < 1.0,
"main x = {}",
x_of(&f, "main")
);
assert!(
(y_of(&f, "main") - 40.0).abs() < 1.0,
"main y = {}",
y_of(&f, "main")
);
assert!(
(w_of(&f, "main") - 480.0).abs() < 1.0,
"main w = {}",
w_of(&f, "main")
);
assert!(
(y_of(&f, "footer") - 270.0).abs() < 1.0,
"footer y = {}",
y_of(&f, "footer")
);
assert!(
(w_of(&f, "footer") - 600.0).abs() < 1.0,
"footer w = {}",
w_of(&f, "footer")
);
}
#[test]
fn named_lines_place_a_span() {
let grid = div::<()>()
.w(600.0)
.grid_cols([Track::Px(100.0); 6])
.grid_col_names(["a", "b", "c", "d", "e", "f", "g"])
.children(vec![
div::<()>().id("item").h(40.0).grid_col_lines("b", "e"),
]);
let f = frame(grid, (600.0, 100.0));
assert!(
(x_of(&f, "item") - 100.0).abs() < 1.0,
"item x = {}",
x_of(&f, "item")
);
assert!(
(w_of(&f, "item") - 300.0).abs() < 1.0,
"item w = {}",
w_of(&f, "item")
);
}
#[test]
fn template_areas_imply_auto_tracks() {
let grid = div::<()>()
.w(400.0)
.grid_template_areas(["a b", "a b"])
.children(vec![
div::<()>().id("a").grid_area("a").h(50.0),
div::<()>().id("b").grid_area("b").h(50.0),
]);
let f = frame(grid, (400.0, 100.0));
assert!(
x_of(&f, "b") >= x_of(&f, "a"),
"b ({}) right of a ({})",
x_of(&f, "b"),
x_of(&f, "a")
);
assert!(
(y_of(&f, "a")).abs() < 1.0 && (y_of(&f, "b")).abs() < 1.0,
"both on row 1"
);
}
#[test]
fn huge_repeat_count_is_clamped() {
let child = div::<()>().id("cell").h(10.0);
let grid = div::<()>()
.w(1024.0)
.grid_cols([GridTemplate::repeat(4096, [Track::Fr(1.0)])])
.children(vec![child]);
let f = frame(grid, (1024.0, 64.0));
assert!(
(w_of(&f, "cell") - 1.0).abs() < 0.1,
"clamped track width should be ~1.0, got {}",
w_of(&f, "cell")
);
}
#[test]
fn pathological_repeat_count_survives() {
let child = div::<()>().id("cell").h(10.0);
let grid = div::<()>()
.w(1024.0)
.grid_cols([GridTemplate::repeat(40_000, [Track::Fr(1.0)])])
.children(vec![child]);
let f = frame(grid, (1024.0, 64.0));
let w = w_of(&f, "cell");
assert!(
w.is_finite() && w > 0.0,
"child width should be finite, got {w}"
);
}
#[test]
fn many_clamped_repeats_still_bound_the_axis_total() {
let child = div::<()>().id("cell").h(10.0);
let cols: Vec<_> = (0..33)
.map(|_| GridTemplate::repeat(1024, [Track::Fr(1.0)]))
.collect();
let grid = div::<()>().w(1024.0).grid_cols(cols).children(vec![child]);
let f = frame(grid, (1024.0, 64.0));
let w = w_of(&f, "cell");
assert!(
w.is_finite() && w > 0.0,
"child width should be finite, got {w}"
);
}
#[test]
fn oversized_repeat_fragment_is_bounded() {
let child = div::<()>().id("cell").h(10.0);
let tracks: Vec<_> = (0..2000).map(|_| Track::Fr(1.0)).collect();
let grid = div::<()>()
.w(1024.0)
.grid_cols([GridTemplate::repeat(1, tracks)])
.children(vec![child]);
let f = frame(grid, (1024.0, 64.0));
let w = w_of(&f, "cell");
assert!(
(w - 1.0).abs() < 0.1,
"fragment should be capped to MAX_GRID_TRACKS, giving ~1.0px columns, got {w}"
);
}
#[test]
fn fixed_and_fr_tracks_still_work() {
let a = div::<()>().id("a").h(30.0);
let b = div::<()>().id("b").h(30.0);
let grid = div::<()>()
.w(500.0)
.grid_cols([Track::Px(100.0), Track::Fr(1.0)])
.children(vec![a, b]);
let f = frame(grid, (500.0, 100.0));
assert!((x_of(&f, "a") - 0.0).abs() < 1.0, "a x = {}", x_of(&f, "a"));
assert!(
(x_of(&f, "b") - 100.0).abs() < 1.0,
"b x = {}",
x_of(&f, "b")
);
assert!(
(w_of(&f, "a") - 100.0).abs() < 1.0,
"a width = {}",
w_of(&f, "a")
);
assert!(
(w_of(&f, "b") - 400.0).abs() < 1.0,
"b width = {}",
w_of(&f, "b")
);
}