test(incremental): rivals for covers, totals and occupancy; drawn cells; no exponential walk (improvise-bw4p.3, improvise-bw4p.4)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
committed by
Edward Langley
parent
07dffa4183
commit
5967f8de91
@@ -800,3 +800,145 @@ fn the_harness_checks_a_cell_a_view_draws_that_drops_four_coordinates() {
|
||||
assert_eq!(d.step, 0);
|
||||
assert_eq!(d.probe, Probe::Value(wide_cell(), Aggregation::Exact));
|
||||
}
|
||||
|
||||
/// East is hidden and Coastal is collapsed (a group is, by default), so the Coastal row folds West only;
|
||||
/// Inland has a cell under A only, so B's column holds just Coastal's.
|
||||
fn hidden_workbook() -> improvise_core::workbook::Workbook {
|
||||
let mut wb = improvise_core::workbook::Workbook::new("hidden");
|
||||
for c in ["Region", "Product"] {
|
||||
wb.add_category(c).unwrap();
|
||||
}
|
||||
wb.add_item_in_group("Region", "East", "Coastal").unwrap();
|
||||
wb.add_item_in_group("Region", "West", "Coastal").unwrap();
|
||||
wb.add_item("Region", "Inland").unwrap();
|
||||
wb.add_item("Product", "A").unwrap();
|
||||
wb.add_item("Product", "B").unwrap();
|
||||
wb.add_item("_Measure", "Revenue").unwrap();
|
||||
let cells = [
|
||||
("East", "A", 10.0),
|
||||
("West", "A", 5.0),
|
||||
("East", "B", 20.0),
|
||||
("West", "B", 1.0),
|
||||
("Inland", "A", 2.0),
|
||||
];
|
||||
for (r, p, v) in cells {
|
||||
wb.model.set_cell(key(r, p, "Revenue"), CellValue::Number(v));
|
||||
}
|
||||
let view = wb.active_view_mut();
|
||||
view.set_axis("Region", Axis::Row);
|
||||
view.set_axis("Product", Axis::Column);
|
||||
view.set_axis("_Measure", Axis::None);
|
||||
view.hide_item("Region", "East");
|
||||
wb
|
||||
}
|
||||
|
||||
/// A backend that reads the view wrongly in exactly one way.
|
||||
#[derive(Clone, Copy)]
|
||||
enum Blindness {
|
||||
CoversIgnoreHidden,
|
||||
TotalsIgnoreHidden,
|
||||
TotalsDoNotSpan,
|
||||
OccupancyCountsHidden,
|
||||
}
|
||||
|
||||
struct Blind(Eager, Blindness);
|
||||
|
||||
impl Derived for Blind {
|
||||
fn value(&self, k: &CellKey, agg: Aggregation) -> Option<CellValue> {
|
||||
self.0.value(k, agg)
|
||||
}
|
||||
fn raw_fold(&self, p: &CellKey) -> Option<CellValue> {
|
||||
self.0.raw_fold(p)
|
||||
}
|
||||
fn covered(&self, k: &CellKey, r: &Reading) -> Option<CellValue> {
|
||||
match self.1 {
|
||||
Blindness::CoversIgnoreHidden => self.0.covered(k, &Reading::new(r.agg, [])),
|
||||
_ => self.0.covered(k, r),
|
||||
}
|
||||
}
|
||||
fn total(&self, k: &CellKey, over: &[String], r: &Reading) -> Option<CellValue> {
|
||||
match self.1 {
|
||||
Blindness::TotalsIgnoreHidden => self.0.total(k, over, &Reading::new(r.agg, [])),
|
||||
Blindness::TotalsDoNotSpan => self.0.covered(k, r),
|
||||
_ => self.0.total(k, over, r),
|
||||
}
|
||||
}
|
||||
fn occupancy(&self, p: &CellKey, r: &Reading) -> usize {
|
||||
match self.1 {
|
||||
Blindness::OccupancyCountsHidden => self.0.occupancy(p, &Reading::new(r.agg, [])),
|
||||
_ => self.0.occupancy(p, r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Maintained for Blind {
|
||||
fn apply(&mut self, edit: &Edit) {
|
||||
self.0.apply(edit);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_blind(fault: Option<Blindness>) -> Result<improvise_incremental::Report, Divergence> {
|
||||
let wb = hidden_workbook();
|
||||
let none = vec!["_Measure".to_string()];
|
||||
let eager = Eager::new(wb.model.clone(), none.clone());
|
||||
let views: Vec<_> = wb.views.values().cloned().collect();
|
||||
let edit = Edit::SetCell(key("West", "A", "Revenue"), CellValue::Number(6.0));
|
||||
match fault {
|
||||
Some(f) => differential_in(&wb.model, &views, &none, Blind(eager, f), &[edit]),
|
||||
None => differential_in(&wb.model, &views, &none, eager, &[edit]),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_harness_passes_a_view_reader_that_is_right() {
|
||||
run_blind(None).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_harness_catches_a_fold_that_covers_a_hidden_item() {
|
||||
let d = run_blind(Some(Blindness::CoversIgnoreHidden)).unwrap_err();
|
||||
assert!(matches!(d.probe, Probe::Covered(..)), "{d}");
|
||||
assert_eq!((d.eager, d.candidate), (num(5.0), num(15.0)), "Coastal/A");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_harness_catches_a_total_that_counts_a_hidden_item() {
|
||||
let d = run_blind(Some(Blindness::TotalsIgnoreHidden)).unwrap_err();
|
||||
assert!(matches!(d.probe, Probe::Total(..)), "{d}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_harness_catches_a_total_that_does_not_span_its_rows() {
|
||||
let d = run_blind(Some(Blindness::TotalsDoNotSpan)).unwrap_err();
|
||||
assert!(matches!(d.probe, Probe::Total(..)), "{d}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_harness_catches_an_occupancy_that_counts_a_hidden_item() {
|
||||
let d = run_blind(Some(Blindness::OccupancyCountsHidden)).unwrap_err();
|
||||
assert!(matches!(d.probe, Probe::Occupancy(..)), "{d}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_view_is_drawn_as_cells_totals_and_occupancy() {
|
||||
let wb = hidden_workbook();
|
||||
let views: Vec<_> = wb.views.values().cloned().collect();
|
||||
let drawn = drawn_probes(&wb.model, &views);
|
||||
let kinds = [
|
||||
drawn.iter().any(|p| matches!(p, Probe::Covered(..))),
|
||||
drawn.iter().any(|p| matches!(p, Probe::Total(..))),
|
||||
drawn.iter().any(|p| matches!(p, Probe::Occupancy(..))),
|
||||
];
|
||||
assert_eq!(kinds, [true; 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probing_a_key_of_twenty_two_coordinates_is_not_exponential() {
|
||||
let coords = (0..22).map(|i| (format!("C{i:02}"), "a".to_string())).collect();
|
||||
let mut m = Model::new("deep");
|
||||
m.set_cell(CellKey::new(coords), CellValue::Number(1.0));
|
||||
let started = std::time::Instant::now();
|
||||
let n = probes(&m).len();
|
||||
assert!(n > 0);
|
||||
assert!(started.elapsed().as_millis() < 100, "{:?}", started.elapsed());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user