Witness every bok4 refusal with a frame test (improvise-9fpl)
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:
@@ -1906,4 +1906,89 @@ mod tests {
|
||||
"a frame with nothing to refuse was refused: {answer:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// A host whose storage holds one file per way `ImportJsonHeadless` can
|
||||
/// fail, plus nothing at the two paths that must fail to read.
|
||||
fn host_with_import_fixtures() -> Host {
|
||||
let storage = MemoryFs::new();
|
||||
let files: [(&str, &[u8]); 4] = [
|
||||
// Every field numeric, so no category is accepted and the build fails.
|
||||
("measures.json", br#"[{"x": 1}, {"x": 2}]"#),
|
||||
("bad.json", b"{not json"),
|
||||
("nested.json", br#"{"data": [{"Region": "North"}]}"#),
|
||||
// A record that is not UTF-8 is a CSV read error, not a warning.
|
||||
("bad.csv", b"Region,Revenue\n\xff\xfe,1\n"),
|
||||
];
|
||||
for (name, bytes) in files {
|
||||
crate::storage::Storage::write(&storage, Path::new(name), bytes)
|
||||
.expect("fixture writes");
|
||||
}
|
||||
let mut app = App::new(workbook(), None);
|
||||
app.storage = Box::new(storage);
|
||||
app.rebuild_layout();
|
||||
Host::new(app)
|
||||
}
|
||||
|
||||
fn import(path: &str, array_path: Option<&str>) -> ModelCommand {
|
||||
ModelCommand::ImportJsonHeadless {
|
||||
path: PathBuf::from(path),
|
||||
model_name: None,
|
||||
array_path: array_path.map(String::from),
|
||||
}
|
||||
}
|
||||
|
||||
/// improvise-9fpl: one case per refusal #181 converted that no other test
|
||||
/// witnesses. Evidence: `context/test-evidence/command.md`.
|
||||
#[test]
|
||||
fn every_failing_model_command_refuses_its_whole_frame() {
|
||||
let cases: Vec<(&str, ModelCommand)> = vec![
|
||||
(
|
||||
"AddItemInGroup into an absent category",
|
||||
ModelCommand::AddItemInGroup {
|
||||
category: "Ghost".into(),
|
||||
item: "East".into(),
|
||||
group: "Coastal".into(),
|
||||
},
|
||||
),
|
||||
(
|
||||
"AddFormula that does not parse",
|
||||
ModelCommand::AddFormula {
|
||||
raw: "Total = (".into(),
|
||||
target_category: "_Measure".into(),
|
||||
},
|
||||
),
|
||||
("ImportJsonHeadless of an absent JSON", import("absent.json", None)),
|
||||
("ImportJsonHeadless of an absent CSV", import("absent.csv", None)),
|
||||
("ImportJsonHeadless of a CSV that is not text", import("bad.csv", None)),
|
||||
("ImportJsonHeadless of JSON that does not parse", import("bad.json", None)),
|
||||
("ImportJsonHeadless at a path with no array", import("nested.json", Some("nope"))),
|
||||
("ImportJsonHeadless that builds no model", import("measures.json", None)),
|
||||
];
|
||||
for (what, failing) in cases {
|
||||
let mut host = host_with_import_fixtures();
|
||||
let (asker, _) = host.connect(10, 10);
|
||||
let landed = ModelCommand::AddItem {
|
||||
category: "Region".into(),
|
||||
item: "Landed".into(),
|
||||
};
|
||||
|
||||
let answer = host.handle(asker, two_command_frame(&host, landed, failing));
|
||||
|
||||
assert_eq!(
|
||||
to(&answer, asker),
|
||||
vec![ServerFrame::Rejected(Rejection::MutationRefused)],
|
||||
"{what}: the frame was not refused: {answer:?}"
|
||||
);
|
||||
assert!(
|
||||
!host
|
||||
.app()
|
||||
.model_state
|
||||
.workbook
|
||||
.model
|
||||
.category("Region")
|
||||
.is_some_and(|c| c.ordered_item_names().contains(&"Landed")),
|
||||
"{what}: the half of the frame that landed was not undone"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user