From 8baa4c4865bad484823b48368d59c871392e7138 Mon Sep 17 00:00:00 2001 From: Edward Langley Date: Tue, 14 Apr 2026 00:49:31 -0700 Subject: [PATCH] test(grid): ensure formulas are recomputed before rendering The render helper used in Grid tests previously did not recompute formulas, meaning tests for computed values were either ignored or required manual setup that didn't reflect actual application behavior. Update the render helper to identify 'None' axis categories and trigger recompute_formulas, and update all call sites to pass a mutable model. Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-31B-it-UD-Q4_K_XL.gguf) --- src/ui/grid.rs | 59 +++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/ui/grid.rs b/src/ui/grid.rs index 198c227..cdfe70a 100644 --- a/src/ui/grid.rs +++ b/src/ui/grid.rs @@ -682,7 +682,14 @@ mod tests { // ── Helpers ─────────────────────────────────────────────────────────────── /// Render a GridWidget into a fresh buffer of the given size. - fn render(model: &Model, width: u16, height: u16) -> Buffer { + fn render(model: &mut Model, width: u16, height: u16) -> Buffer { + let none_cats: Vec = model + .active_view() + .categories_on(crate::view::Axis::None) + .into_iter() + .map(String::from) + .collect(); + model.recompute_formulas(&none_cats); let area = Rect::new(0, 0, width, height); let mut buf = Buffer::empty(area); let bufs = std::collections::HashMap::new(); @@ -743,8 +750,8 @@ mod tests { #[test] fn column_headers_appear() { - let m = two_cat_model(); - let text = buf_text(&render(&m, 80, 24)); + let mut m = two_cat_model(); + let text = buf_text(&render(&mut m, 80, 24)); assert!(text.contains("Jan"), "expected 'Jan' in:\n{text}"); assert!(text.contains("Feb"), "expected 'Feb' in:\n{text}"); } @@ -753,8 +760,8 @@ mod tests { #[test] fn row_headers_appear() { - let m = two_cat_model(); - let text = buf_text(&render(&m, 80, 24)); + let mut m = two_cat_model(); + let text = buf_text(&render(&mut m, 80, 24)); assert!(text.contains("Food"), "expected 'Food' in:\n{text}"); assert!(text.contains("Clothing"), "expected 'Clothing' in:\n{text}"); } @@ -768,7 +775,7 @@ mod tests { coord(&[("Type", "Food"), ("Month", "Jan")]), CellValue::Number(123.0), ); - let text = buf_text(&render(&m, 80, 24)); + let text = buf_text(&render(&mut m, 80, 24)); assert!(text.contains("123"), "expected '123' in:\n{text}"); } @@ -787,7 +794,7 @@ mod tests { coord(&[("Type", "Clothing"), ("Month", "Jan")]), CellValue::Number(50.0), ); - let text = buf_text(&render(&m, 80, 24)); + let text = buf_text(&render(&mut m, 80, 24)); assert!(text.contains("100"), "expected '100' in:\n{text}"); assert!(text.contains("200"), "expected '200' in:\n{text}"); assert!(text.contains("50"), "expected '50' in:\n{text}"); @@ -806,7 +813,7 @@ mod tests { coord(&[("Type", "Food"), ("Month", "Jan")]), CellValue::Number(1.0), ); - let text = buf_text(&render(&m, 80, 24)); + let text = buf_text(&render(&mut m, 80, 24)); // Should not contain large numbers that weren't set assert!(!text.contains("100"), "unexpected '100' in:\n{text}"); } @@ -815,8 +822,8 @@ mod tests { #[test] fn total_row_label_appears() { - let m = two_cat_model(); - let text = buf_text(&render(&m, 80, 24)); + let mut m = two_cat_model(); + let text = buf_text(&render(&mut m, 80, 24)); assert!(text.contains("Total"), "expected 'Total' in:\n{text}"); } @@ -831,7 +838,7 @@ mod tests { coord(&[("Type", "Clothing"), ("Month", "Jan")]), CellValue::Number(50.0), ); - let text = buf_text(&render(&m, 80, 24)); + let text = buf_text(&render(&mut m, 80, 24)); // Food(100) + Clothing(50) = 150 for Jan assert!( text.contains("150"), @@ -858,7 +865,7 @@ mod tests { c.add_item("Bob"); } m.active_view_mut().set_page_selection("Payer", "Bob"); - let text = buf_text(&render(&m, 80, 24)); + let text = buf_text(&render(&mut m, 80, 24)); assert!( text.contains("Payer = Bob"), "expected 'Payer = Bob' in:\n{text}" @@ -882,7 +889,7 @@ mod tests { c.add_item("Bob"); } // No explicit selection — should default to first item - let text = buf_text(&render(&m, 80, 24)); + let text = buf_text(&render(&mut m, 80, 24)); assert!( text.contains("Payer = Alice"), "expected 'Payer = Alice' in:\n{text}" @@ -892,19 +899,13 @@ mod tests { // ── Formula evaluation ──────────────────────────────────────────────────── #[test] - #[ignore = "needs render harness update for _Measure virtual category"] fn formula_cell_renders_computed_value() { let mut m = Model::new("Test"); - m.add_category("_Measure").unwrap(); // → Row m.add_category("Region").unwrap(); // → Column - if let Some(c) = m.category_mut("_Measure") { - c.add_item("Revenue"); - c.add_item("Cost"); - c.add_item("Profit"); - } - if let Some(c) = m.category_mut("Region") { - c.add_item("East"); - } + m.category_mut("_Measure").unwrap().add_item("Revenue"); + m.category_mut("_Measure").unwrap().add_item("Cost"); + // Profit is a formula target — dynamically included in _Measure + m.category_mut("Region").unwrap().add_item("East"); m.set_cell( coord(&[("_Measure", "Revenue"), ("Region", "East")]), CellValue::Number(1000.0), @@ -914,12 +915,16 @@ mod tests { CellValue::Number(600.0), ); m.add_formula(parse_formula("Profit = Revenue - Cost", "_Measure").unwrap()); + m.active_view_mut() + .set_axis("_Index", crate::view::Axis::None); + m.active_view_mut() + .set_axis("_Dim", crate::view::Axis::None); m.active_view_mut() .set_axis("_Measure", crate::view::Axis::Row); m.active_view_mut() .set_axis("Region", crate::view::Axis::Column); - let text = buf_text(&render(&m, 80, 24)); + let text = buf_text(&render(&mut m, 80, 24)); assert!(text.contains("400"), "expected '400' (Profit) in:\n{text}"); } @@ -954,7 +959,7 @@ mod tests { } } - let text = buf_text(&render(&m, 80, 24)); + let text = buf_text(&render(&mut m, 80, 24)); // Multi-level row headers: category values shown separately, not joined with / assert!( !text.contains("Food/Alice"), @@ -994,7 +999,7 @@ mod tests { coord(&[("Month", "Jan"), ("Recipient", "Alice"), ("Type", "Food")]), CellValue::Number(77.0), ); - let text = buf_text(&render(&m, 80, 24)); + let text = buf_text(&render(&mut m, 80, 24)); assert!(text.contains("77"), "expected '77' in:\n{text}"); } @@ -1024,7 +1029,7 @@ mod tests { ); } - let text = buf_text(&render(&m, 80, 24)); + let text = buf_text(&render(&mut m, 80, 24)); // Multi-level column headers: category values shown separately, not joined with / assert!( !text.contains("Jan/2024"),