tawasuyu

tawasuyu/llimphi

Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.

Rust 614Markdown 274TOML 149RON 310606 Definiciones

⎇ main modules/diff-viewer/tests/smoke.rs Rust · 155 líneas · 5.2 KB Historia Quién tocó qué crudo

chore: refresco desde el monorepo — 128 miembros, los 76 widgets y los 11 módulos b3f12e136 · Sergio ·

1//! Smoke tests del cómputo de filas y el routing de teclas. Sin
2//! backend gráfico — pruebas puras sobre `compute_rows` y `apply`.
3
4use llimphi_module_diff_viewer::{
5    self as diff, DiffAction, DiffKind, DiffMsg, DiffState,
6};
7
8#[test]
9fn diff_basico_inserts_y_deletes() {
10    let before = "a\nb\nc\n";
11    let after = "a\nB\nc\nd\n";
12    let (rows, stats) = diff::compute_rows(before, after);
13
14    // El diff esperado:
15    //   = a / a
16    //   - b
17    //   + B
18    //   = c / c
19    //   + d
20    assert_eq!(stats.equals, 2);
21    assert_eq!(stats.deletes, 1);
22    assert_eq!(stats.inserts, 2);
23
24    assert_eq!(rows[0].kind, DiffKind::Equal);
25    assert_eq!(rows[0].left.as_ref().unwrap().text, "a");
26    assert_eq!(rows[0].right.as_ref().unwrap().text, "a");
27
28    // El primer cambio debe ser un Delete o Insert (similar agrupa);
29    // verificamos que B aparezca y b no.
30    let texts_left: Vec<&str> = rows
31        .iter()
32        .filter_map(|r| r.left.as_ref().map(|c| c.text.as_str()))
33        .collect();
34    let texts_right: Vec<&str> = rows
35        .iter()
36        .filter_map(|r| r.right.as_ref().map(|c| c.text.as_str()))
37        .collect();
38    assert!(texts_left.contains(&"b"));
39    assert!(texts_right.contains(&"B"));
40    assert!(texts_right.contains(&"d"));
41}
42
43#[test]
44fn numeros_de_linea_son_correctos() {
45    let before = "alpha\nbeta\ngamma\n";
46    let after = "alpha\nBETA\ngamma\ndelta\n";
47    let (rows, _) = diff::compute_rows(before, after);
48
49    // alpha en línea 1 de ambos.
50    let alpha_row = rows.iter().find(|r| {
51        r.left.as_ref().map(|c| c.text == "alpha").unwrap_or(false)
52    }).unwrap();
53    assert_eq!(alpha_row.left.as_ref().unwrap().line_no, 1);
54    assert_eq!(alpha_row.right.as_ref().unwrap().line_no, 1);
55
56    // beta (delete) en línea 2 izquierda.
57    let beta_row = rows.iter().find(|r| {
58        r.left.as_ref().map(|c| c.text == "beta").unwrap_or(false)
59    }).unwrap();
60    assert_eq!(beta_row.left.as_ref().unwrap().line_no, 2);
61    assert!(beta_row.right.is_none());
62
63    // delta (insert) en línea 4 derecha.
64    let delta_row = rows.iter().find(|r| {
65        r.right.as_ref().map(|c| c.text == "delta").unwrap_or(false)
66    }).unwrap();
67    assert_eq!(delta_row.right.as_ref().unwrap().line_no, 4);
68    assert!(delta_row.left.is_none());
69}
70
71#[test]
72fn textos_identicos_solo_equal() {
73    let text = "uno\ndos\ntres\n";
74    let (rows, stats) = diff::compute_rows(text, text);
75    assert_eq!(rows.len(), 3);
76    assert!(rows.iter().all(|r| r.kind == DiffKind::Equal));
77    assert_eq!(stats.inserts, 0);
78    assert_eq!(stats.deletes, 0);
79    assert_eq!(stats.equals, 3);
80}
81
82#[test]
83fn scroll_no_excede_los_limites() {
84    let before = (0..50).map(|i| i.to_string()).collect::<Vec<_>>().join("\n");
85    let after = before.clone(); // identical → 50 Equal rows
86    let mut state = DiffState::new("a", "b", &before, &after);
87    assert_eq!(state.scroll, 0);
88
89    // Scroll grande hacia abajo: tope = 50 - visible_rows.
90    diff::apply(&mut state, DiffMsg::Scroll(1000), 10);
91    assert_eq!(state.scroll, 40);
92
93    // Scroll arriba: tope mínimo 0.
94    diff::apply(&mut state, DiffMsg::Scroll(-1000), 10);
95    assert_eq!(state.scroll, 0);
96}
97
98#[test]
99fn next_hunk_salta_a_la_proxima_diferencia() {
100    // 20 líneas iguales + 2 cambios + 20 más. visible_rows=5 deja
101    // espacio real para scrollear.
102    let mut before = String::new();
103    let mut after = String::new();
104    for i in 0..20 {
105        before.push_str(&format!("eq{i}\n"));
106        after.push_str(&format!("eq{i}\n"));
107    }
108    before.push_str("DEL\n");
109    after.push_str("INS\n");
110    for i in 20..40 {
111        before.push_str(&format!("eq{i}\n"));
112        after.push_str(&format!("eq{i}\n"));
113    }
114    let mut state = DiffState::new("a", "b", &before, &after);
115    assert_eq!(state.scroll, 0);
116
117    diff::apply(&mut state, DiffMsg::NextHunk, 5);
118    assert!(state.scroll > 0, "scroll quedó en 0 — no saltó al hunk");
119    let row = &state.rows[state.scroll];
120    assert!(
121        !matches!(row.kind, DiffKind::Equal),
122        "esperaba aterrizar en un hunk, vi {:?}",
123        row.kind
124    );
125
126    // PrevHunk: vuelve al inicio (no hay hunk antes del primer cambio).
127    diff::apply(&mut state, DiffMsg::PrevHunk, 5);
128    // Puede quedarse en el mismo hunk si era el único accesible hacia
129    // atrás, o saltar más arriba. Lo único que verificamos es que no
130    // hubo panic ni scroll fuera de rango.
131    assert!(state.scroll < state.rows.len());
132}
133
134#[test]
135fn escape_cierra() {
136    let mut state = DiffState::new("a", "b", "x\n", "y\n");
137    let action = diff::apply(&mut state, DiffMsg::Close, 10);
138    assert_eq!(action, DiffAction::Close);
139}
140
141#[test]
142fn open_shortcut_es_ctrl_shift_d() {
143    use llimphi_compositor::{Key, KeyEvent, KeyState, Modifiers};
144    let mk = |ctrl: bool, shift: bool, c: &str| KeyEvent {
145        key: Key::Character(c.into()),
146        state: KeyState::Pressed,
147        text: Some(c.into()),
148        modifiers: Modifiers { ctrl, shift, ..Modifiers::default() },
149        repeat: false,
150    };
151    assert!(diff::open_shortcut(&mk(true, true, "d")));
152    assert!(diff::open_shortcut(&mk(true, true, "D")));
153    assert!(!diff::open_shortcut(&mk(true, false, "d")));
154    assert!(!diff::open_shortcut(&mk(false, true, "d")));
155}