improvise-sjdb: red — an empty cell beside a collapsed measure group

The host projects Feb x Units as a Record, and #217 refuses the write:
aggregate_refusal judges the record at its first column, the Money fold.
Also pins that a stored record stays writable whatever the host view does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
Edward Langley
2026-09-23 08:07:38 -07:00
parent bc060f6760
commit 6e021699d4
+69
View File
@@ -1512,6 +1512,75 @@ mod tests {
assert_eq!(value, Some(&CellValue::Number(7.0)));
}
/// improvise-sjdb: an empty record is judged at its own cell, not at the first
/// column carrying it — see context/test-evidence/command.md.
#[test]
fn an_empty_cell_beside_a_collapsed_measure_group_is_writable() {
let mut wb = Workbook::new("T");
wb.add_category("Month").unwrap();
for month in ["Jan", "Feb"] {
wb.add_item("Month", month).unwrap();
}
for measure in ["Revenue", "Cost"] {
wb.add_item_in_group("_Measure", measure, "Money").unwrap();
}
wb.add_item("_Measure", "Units").unwrap();
let jan = month_cell("Jan", "Revenue");
wb.model.set_cell(jan, CellValue::Number(10.0));
wb.active_view_mut().set_axis("Month", Axis::Row);
wb.active_view_mut().set_axis("_Measure", Axis::Column);
wb.active_view_mut().toggle_group_collapse("_Measure", "Money");
let mut app = App::new(wb, None);
app.rebuild_layout();
let target = month_cell("Feb", "Units");
let units = (0..app.layout.col_count())
.find(|&c| app.layout.cell_key(1, c).as_ref() == Some(&target))
.expect("setup: Feb x Units is drawn");
let fold = (0..app.layout.col_count())
.find(|&c| app.layout.folds_a_group(1, c))
.expect("setup: a folded measure column");
assert!(fold < units, "setup: the fold comes first on Feb's row");
let id = crate::ui::project::cell_id(&app, &app.layout, 1, units);
let projected = matches!(id, Some(improvise_protocol::CellId::Record(_)));
assert!(projected, "setup: Feb x Units projects as {id:?}");
let mut host = Host::new(app);
let answer = wire_write(&mut host, &target, false);
let accepted = answer
.iter()
.any(|a| matches!(a.msg, ServerFrame::Accepted));
assert!(accepted, "a projected Record was refused: {answer:?}");
let model = &host.app().model_state.workbook.model;
assert_eq!(model.get_cell(&target), Some(&CellValue::Number(7.0)));
}
/// A STORED record is writable whatever the host's view does to it — see
/// context/test-evidence/command.md (improvise-sjdb).
#[test]
fn a_stored_record_the_hosts_view_aggregates_is_writable() {
let mut wb = workbook();
wb.model.set_cell(cell("South"), CellValue::Number(1.0));
wb.add_category("Product").unwrap();
wb.add_item("Product", "Widget").unwrap();
wb.active_view_mut().set_axis("Product", Axis::None);
let mut app = App::new(wb, None);
app.rebuild_layout();
let south = (0..app.layout.row_count())
.flat_map(|r| (0..app.layout.col_count()).map(move |c| (r, c)))
.find(|&(r, c)| app.layout.cell_key(r, c).as_ref() == Some(&cell("South")))
.expect("setup: South's cell is drawn");
let id = crate::ui::project::cell_id(&app, &app.layout, south.0, south.1);
let aggregate = matches!(id, Some(improvise_protocol::CellId::Aggregate(_)));
assert!(aggregate, "setup: the host's view aggregates South: {id:?}");
let mut host = Host::new(app);
let answer = wire_write(&mut host, &cell("South"), false);
let accepted = answer
.iter()
.any(|a| matches!(a.msg, ServerFrame::Accepted));
assert!(accepted, "a stored record was refused: {answer:?}");
let model = &host.app().model_state.workbook.model;
assert_eq!(model.get_cell(&cell("South")), Some(&CellValue::Number(7.0)));
}
/// Clause 4 must not fire on a frame that merely names a record it is
/// creating. See `context/test-evidence/command.md`.
#[test]