tawasuyu/llimphi
Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.
chore: refresco desde el monorepo — vello 0.9 / wgpu 29, 120 miembros
1//! La familia monoespaciada embebida tiene que dar **ancho fijo de verdad**.
2//!
3//! Es un test de regresión con evidencia numérica: si el registro de
4//! Liberation Mono falla (o alguien le cambia el nombre de familia), parley
5//! resuelve la proporcional y las tablas de la consola se tuercen sin que
6//! nada compile mal. Acá se ve en números.
7
8// Este test mide anchos, que NO necesitan vello — pero construye `TextBlock`
9// con `peniko::Color`, que antes llegaba vía vello. Se toma del reexport del
10// propio crate, que existe en los dos perfiles (W2).
11use llimphi_text::peniko::Color;
12use llimphi_text::{Typesetter, TextBlock, MONOSPACE};
13
14fn ancho(ts: &mut Typesetter, texto: &str, familia: Option<&str>) -> f32 {
15 let mut b = TextBlock::simple(texto, 12.0, Color::WHITE, (0.0, 0.0));
16 b.font_family = familia.map(str::to_string);
17 llimphi_text::measure(ts, &b).width
18}
19
20#[test]
21fn mono_da_el_mismo_ancho_para_anchas_y_angostas() {
22 let mut ts = Typesetter::new();
23 let m = ancho(&mut ts, "MMMMMMMMMM", Some(MONOSPACE));
24 let i = ancho(&mut ts, "iiiiiiiiii", Some(MONOSPACE));
25 println!("mono M×10={m:.2} i×10={i:.2}");
26 assert!(
27 (m - i).abs() < 0.5,
28 "la familia mono no da ancho fijo: M×10={m:.2} vs i×10={i:.2}"
29 );
30}
31
32#[test]
33fn la_proporcional_si_difiere_el_test_anterior_no_es_trivial() {
34 let mut ts = Typesetter::new();
35 let m = ancho(&mut ts, "MMMMMMMMMM", None);
36 let i = ancho(&mut ts, "iiiiiiiiii", None);
37 println!("sans M×10={m:.2} i×10={i:.2}");
38 assert!((m - i).abs() > 2.0, "la sans mide igual: el test de mono no prueba nada");
39}
40
41/// El agujero real: `layout_runs` (texto con color por tramos) no recibía
42/// familia, así que shapeaba con la sans aunque la vista pidiera `.mono()`.
43/// Nada compilaba mal — la consola simplemente salía torcida.
44#[test]
45fn el_camino_multicolor_respeta_la_familia_mono() {
46 use llimphi_text::Alignment;
47 let mut ts = Typesetter::new();
48 let tramos = |t: &str| -> Vec<(usize, usize, Color)> { vec![(0, t.len(), Color::WHITE)] };
49 let mut medir = |t: &str| {
50 ts.layout_runs(t, 12.0, Color::WHITE, &tramos(t), Alignment::Start, 1.2, 400.0, false, false, Some(MONOSPACE))
51 .width()
52 };
53 let m = medir("MMMMMMMMMM");
54 let i = medir("iiiiiiiiii");
55 println!("runs M×10={m:.2} i×10={i:.2}");
56 assert!(
57 (m - i).abs() < 0.5,
58 "el texto con tramos de color perdió el ancho fijo: M×10={m:.2} vs i×10={i:.2}"
59 );
60}
61
62#[test]
63fn los_caracteres_de_caja_no_se_caen_a_otra_fuente() {
64 // Si Liberation Mono no tiene el glifo, parley busca en el fallback y ese
65 // no es mono: la tabla se tuerce justo donde más se nota.
66 let mut ts = Typesetter::new();
67 let ascii = ancho(&mut ts, "++++++++++", Some(MONOSPACE));
68 let caja = ancho(&mut ts, "┌┬┐├┼┤└┴┘─", Some(MONOSPACE));
69 println!("mono +×10={ascii:.2} caja×10={caja:.2}");
70 assert!(
71 (ascii - caja).abs() < 0.5,
72 "los caracteres de caja no salen en la mono: +×10={ascii:.2} vs caja×10={caja:.2}"
73 );
74}