use super::*;
#[test]
#[ignore = "manual release timing probe"]
fn density_read_timing() {
use std::hint::black_box;
use cranpose_core::{Composition, MemoryApplier, location_key};
use web_time::Instant;
fn probe(label: &str, iterations: usize) {
for _ in 0..1000 {
black_box(density());
}
let start = Instant::now();
for _ in 0..iterations {
black_box(density());
}
let ns_per_read = start.elapsed().as_nanos() as f64 / iterations as f64;
println!("DENSITY_READ {label} iterations={iterations} ns_per_read={ns_per_read:.3}");
}
let _context = crate::render_state::app_context_test_scope();
let iterations = std::env::var("DENSITY_READ_ITERATIONS")
.ok()
.and_then(|value| value.parse::<usize>().ok())
.unwrap_or(5_000_000);
for provided in [false, true] {
let mut composition = Composition::new(MemoryApplier::new());
composition
.render(location_key(file!(), line!(), column!()), move || {
if provided {
ProvideDensity(Density::new(2.5, 1.3), || probe("provided", iterations));
} else {
probe("host", iterations);
}
})
.expect("density timing composition");
}
}
#[test]
fn a_surviving_density_scope_keeps_its_entry_when_a_sibling_leaves() {
use std::{cell::Cell, rc::Rc};
use cranpose_core::{Composition, MemoryApplier, MutableState, location_key};
let mut composition = Composition::new(MemoryApplier::new());
let runtime = composition.runtime_handle();
let with_leading = MutableState::with_runtime(true, runtime.clone());
let survivor = MutableState::with_runtime(3.0_f32, runtime);
let seen = Rc::new(Cell::new(0.0_f32));
#[cranpose_macros::composable]
fn Reader(seen: Rc<Cell<f32>>) {
seen.set(density().density());
}
fn tree(with_leading: bool, survivor: f32, seen: Rc<Cell<f32>>) {
if with_leading {
ProvideDensity(Density::new(2.0, 1.0), || {});
}
ProvideDensity(Density::new(survivor, 1.0), move || Reader(seen));
}
#[cranpose_macros::composable]
fn Panel(with_leading: MutableState<bool>, survivor: MutableState<f32>, seen: Rc<Cell<f32>>) {
tree(with_leading.value(), survivor.value(), seen);
}
let key = location_key(file!(), line!(), column!());
{
let seen = Rc::clone(&seen);
composition
.render(key, move || Panel(with_leading, survivor, Rc::clone(&seen)))
.expect("initial composition");
}
assert_eq!(seen.get(), 3.0);
with_leading.set_value(false);
while composition
.process_invalid_scopes()
.expect("drop the leading density scope")
{}
survivor.set_value(4.0);
while composition
.process_invalid_scopes()
.expect("change the surviving density")
{}
assert_eq!(
seen.get(),
4.0,
"the surviving density scope must keep its entry and its reader's \
subscription when the sibling leaves"
);
}
#[test]
fn a_provided_density_reaches_the_content_and_ends_with_it() {
use std::{cell::Cell, rc::Rc};
use cranpose_core::{Composition, MemoryApplier, location_key};
let mut composition = Composition::new(MemoryApplier::new());
let outer = Rc::new(Cell::new(0.0_f32));
let inside = Rc::new(Cell::new(0.0_f32));
let after = Rc::new(Cell::new(0.0_f32));
let key = location_key(file!(), line!(), column!());
{
let (outer, inside, after) = (Rc::clone(&outer), Rc::clone(&inside), Rc::clone(&after));
let mut render = move || {
outer.set(density().density());
ProvideDensity(Density::new(3.0, 1.0), || inside.set(density().density()));
after.set(density().density());
};
composition.render(key, &mut render).expect("render");
}
assert_eq!(inside.get(), 3.0, "the subtree reads the grid it was given");
assert_ne!(
outer.get(),
3.0,
"the provision does not escape upwards out of its content"
);
assert_eq!(
after.get(),
outer.get(),
"nor does it leak into what follows it"
);
}
#[test]
fn a_dp_length_lands_on_a_whole_device_pixel() {
let density = Density::new(2.0, 1.0);
assert_eq!(density.dp(13.3), 13.5);
assert_eq!(density.to_px(density.dp(13.3)), 27.0);
assert_eq!(density.dp(0.25), 0.5);
}
#[test]
fn a_text_size_moves_with_the_font_scale_and_a_dp_length_does_not() {
let density = Density::new(2.0, 1.24);
assert_eq!(density.dp(15.0), 15.0);
assert_eq!(density.to_px(density.sp(15.0)), 37.0);
}
#[test]
fn centring_puts_the_leading_gap_on_a_pixel_boundary() {
let density = Density::new(2.0, 1.0);
let leading = density.centre(52.0, 46.5);
assert_eq!(density.to_px(leading), 6.0);
}
#[test]
fn floor_and_ceil_move_whole_pixels_only() {
let density = Density::new(2.0, 1.0);
assert_eq!(density.floor(13.3), 13.0);
assert_eq!(density.ceil(13.3), 13.5);
assert_eq!(density.ceil(13.5), 13.5);
}
#[test]
fn a_nonsense_grid_falls_back_to_one_rather_than_dividing_by_zero() {
let density = Density::new(0.0, f32::NAN);
assert_eq!(density.density(), 1.0);
assert_eq!(density.font_scale(), 1.0);
assert_eq!(density.dp(3.7), 4.0);
}