test(model,ui): add tests for precision and cat tree

Add unit tests for model precision and category tree rendering:

- `src/model/types.rs` : Added `formula_chain_preserves_full_precision` to
  ensure formulas use full `f64` precision for calculations, even when
  display is rounded.
- `src/ui/cat_tree.rs` : Added comprehensive tests for `build_cat_tree` ,
  covering empty models (virtual categories), expanded/collapsed states,
  and item rendering.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q5_K_XL)
This commit is contained in:
Edward Langley
2026-04-08 22:27:37 -07:00
parent 433a20928a
commit da076eadc8
2 changed files with 162 additions and 0 deletions

View File

@ -49,3 +49,117 @@ pub fn build_cat_tree(model: &Model, expanded: &HashSet<String>) -> Vec<CatTreeE
}
entries
}
#[cfg(test)]
mod tests {
use super::*;
fn make_model_with_categories(cats: &[(&str, &[&str])]) -> Model {
let mut m = Model::new("Test");
for &(cat_name, items) in cats {
m.add_category(cat_name).unwrap();
let cat = m.category_mut(cat_name).unwrap();
for &item in items {
cat.add_item(item);
}
}
m
}
#[test]
fn empty_model_has_only_virtual_categories() {
let m = Model::new("Test");
let tree = build_cat_tree(&m, &HashSet::new());
// Virtual categories (_Index, _Dim) should appear
let names: Vec<&str> = tree.iter().map(|e| e.cat_name()).collect();
assert!(names.contains(&"_Index"));
assert!(names.contains(&"_Dim"));
}
#[test]
fn collapsed_category_shows_header_only() {
let m = make_model_with_categories(&[("Region", &["North", "South"])]);
let tree = build_cat_tree(&m, &HashSet::new());
let region_entries: Vec<_> = tree
.iter()
.filter(|e| e.cat_name() == "Region")
.collect();
assert_eq!(region_entries.len(), 1); // just the header
assert!(matches!(
region_entries[0],
CatTreeEntry::Category {
expanded: false,
item_count: 2,
..
}
));
}
#[test]
fn expanded_category_shows_items() {
let m = make_model_with_categories(&[("Region", &["North", "South"])]);
let mut expanded = HashSet::new();
expanded.insert("Region".to_string());
let tree = build_cat_tree(&m, &expanded);
let region_entries: Vec<_> = tree
.iter()
.filter(|e| e.cat_name() == "Region")
.collect();
// Header + 2 items
assert_eq!(region_entries.len(), 3);
assert!(matches!(region_entries[0], CatTreeEntry::Category { expanded: true, .. }));
assert!(matches!(region_entries[1], CatTreeEntry::Item { .. }));
assert!(matches!(region_entries[2], CatTreeEntry::Item { .. }));
}
#[test]
fn mixed_expanded_and_collapsed() {
let m = make_model_with_categories(&[
("Region", &["North", "South"]),
("Product", &["Shirts", "Pants", "Hats"]),
]);
let mut expanded = HashSet::new();
expanded.insert("Product".to_string());
let tree = build_cat_tree(&m, &expanded);
let region_items: Vec<_> = tree
.iter()
.filter(|e| {
e.cat_name() == "Region" && matches!(e, CatTreeEntry::Item { .. })
})
.collect();
let product_items: Vec<_> = tree
.iter()
.filter(|e| {
e.cat_name() == "Product" && matches!(e, CatTreeEntry::Item { .. })
})
.collect();
assert_eq!(region_items.len(), 0); // collapsed
assert_eq!(product_items.len(), 3); // expanded
}
#[test]
fn cat_name_works_for_both_variants() {
let header = CatTreeEntry::Category {
name: "Region".into(),
item_count: 2,
expanded: false,
};
let item = CatTreeEntry::Item {
cat_name: "Region".into(),
item_name: "North".into(),
};
assert_eq!(header.cat_name(), "Region");
assert_eq!(item.cat_name(), "Region");
}
#[test]
fn expanding_nonexistent_category_is_harmless() {
let m = Model::new("Test");
let mut expanded = HashSet::new();
expanded.insert("DoesNotExist".to_string());
let tree = build_cat_tree(&m, &expanded);
// Should just have virtual categories, no crash
assert!(!tree.is_empty());
}
}