WIP: float_roundtrip on frame parsers; failing NaN quiescence test (improvise-6oy4, improvise-4w09)
This commit is contained in:
@@ -1280,6 +1280,66 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// `.improv` carries `nan` as a value (improvise-55v2); the NaN sits at
|
||||
/// (1, 1), off the origin. Evidence file.
|
||||
fn app_with_a_nan_cell() -> App {
|
||||
let wb = crate::persistence::parse_md(
|
||||
"v2025-04-09\n# NaN\nInitial View: Default\n\n\
|
||||
## View: Default\nRegion: row\n_Measure: column\n_Index: none\n_Dim: none\n\n\
|
||||
## Category: _Measure\n- Revenue, Cost\n\n\
|
||||
## Category: Region\n- North, South\n\n\
|
||||
## Data\n\
|
||||
Region=North, _Measure=Revenue = 1\n\
|
||||
Region=North, _Measure=Cost = 2\n\
|
||||
Region=South, _Measure=Revenue = 3\n\
|
||||
Region=South, _Measure=Cost = nan\n",
|
||||
)
|
||||
.expect("a document holding nan parses");
|
||||
let mut app = App::new(wb, None);
|
||||
app.rebuild_layout();
|
||||
app
|
||||
}
|
||||
|
||||
/// A NaN cell compares unequal to itself under `CellValue`'s `PartialEq`,
|
||||
/// so the grid never quiesced (improvise-4w09). Evidence file.
|
||||
#[test]
|
||||
fn a_grid_holding_nan_quiesces() {
|
||||
let app = app_with_a_nan_cell();
|
||||
let grid = grid_of(
|
||||
&app,
|
||||
Viewport {
|
||||
row_offset: 0,
|
||||
col_offset: 0,
|
||||
rows: 10,
|
||||
cols: 10,
|
||||
},
|
||||
);
|
||||
assert!(
|
||||
matches!(grid.cell(1, 1).and_then(|c| c.value.clone()),
|
||||
Some(CellValue::Number(n)) if n.is_nan()),
|
||||
"precondition: the NaN must be projected, or nothing below is tested"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
grid_updates(&grid, &grid),
|
||||
vec![],
|
||||
"a grid diffed against itself owes the client nothing"
|
||||
);
|
||||
assert!(
|
||||
GridCache::folded(&grid.seed()) == grid,
|
||||
"the seed must compact to the cache it came from (gotcha 32)"
|
||||
);
|
||||
|
||||
let mut sessions = Sessions::default();
|
||||
sessions.connect(&app, 10, 10);
|
||||
sessions.project_all(&app, Dirty::EVERYTHING);
|
||||
let again = sessions.project_all(&app, Dirty::EVERYTHING);
|
||||
assert!(
|
||||
again.is_empty(),
|
||||
"an unchanged grid must not be re-sent: {again:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// Region on Row with `East` in a group that comes **last**, so the header is
|
||||
/// the final entry and nothing follows it: `axis_frame`'s trailing rule.
|
||||
fn app_with_a_trailing_group(collapsed: bool) -> App {
|
||||
|
||||
@@ -12,7 +12,9 @@ crate-type = ["cdylib", "rlib"]
|
||||
[dependencies]
|
||||
improvise-protocol = { path = "../improvise-protocol" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
# Parses frames, so it must read back the f64 that was written: per crate, because
|
||||
# the wasm bundle builds alone (improvise-6oy4, context/code/protocol.md).
|
||||
serde_json = { version = "1", features = ["float_roundtrip"] }
|
||||
wasm-bindgen = "0.2"
|
||||
|
||||
# Deliberately NOT a dependency: `improvise-command`. A keymap binding names
|
||||
|
||||
@@ -701,6 +701,44 @@ fn a_yanked_number_crosses_the_serialized_wire_exactly() {
|
||||
);
|
||||
}
|
||||
|
||||
/// The two tests around this one share a feature-unified build, so neither can
|
||||
/// see ONE frame-parsing crate lacking `float_roundtrip`. Evidence file.
|
||||
#[test]
|
||||
fn every_build_that_parses_a_frame_enables_float_roundtrip() {
|
||||
for (krate, target) in [
|
||||
("improvise-wasm-client", Some("wasm32-unknown-unknown")),
|
||||
("improvise-worker-server", Some("wasm32-unknown-unknown")),
|
||||
("improvise-ws-server", None),
|
||||
] {
|
||||
let mut cargo = std::process::Command::new(env!("CARGO"));
|
||||
cargo.current_dir(env!("CARGO_MANIFEST_DIR")).args([
|
||||
"tree",
|
||||
"--locked",
|
||||
"--edges",
|
||||
"normal,features",
|
||||
"--invert",
|
||||
"serde_json",
|
||||
"--package",
|
||||
krate,
|
||||
]);
|
||||
if let Some(target) = target {
|
||||
cargo.args(["--target", target]);
|
||||
}
|
||||
let out = cargo.output().expect("cargo tree must run");
|
||||
assert!(
|
||||
out.status.success(),
|
||||
"{krate}: cargo tree failed: {}",
|
||||
String::from_utf8_lossy(&out.stderr)
|
||||
);
|
||||
let tree = String::from_utf8(out.stdout).expect("cargo tree prints UTF-8");
|
||||
assert!(
|
||||
tree.contains(r#"serde_json feature "float_roundtrip""#),
|
||||
"{krate} parses frames without float_roundtrip, so its numbers land \
|
||||
one ULP off:\n{tree}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A typed number is parsed exactly in the client and re-parsed from JSON by
|
||||
/// the host. Evidence file.
|
||||
#[test]
|
||||
|
||||
@@ -17,7 +17,9 @@ improvise-protocol = { path = "../improvise-protocol" }
|
||||
improvise-command = { path = "../improvise-command" }
|
||||
anyhow = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
# Parses frames, so it must read back the f64 that was written: per crate, because
|
||||
# the wasm bundle builds alone (improvise-6oy4, context/code/protocol.md).
|
||||
serde_json = { version = "1", features = ["float_roundtrip"] }
|
||||
|
||||
# The browser half. Only the wasm build pulls these in, so `cargo test` on the
|
||||
# host builds and drives `worker.rs`/`vfs.rs` with no JS anywhere near them —
|
||||
|
||||
@@ -17,7 +17,9 @@ improvise-io = { path = "../improvise-io" }
|
||||
improvise-protocol = { path = "../improvise-protocol" }
|
||||
improvise-command = { path = "../improvise-command" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
# Parses frames, so it must read back the f64 that was written (improvise-6oy4,
|
||||
# context/code/protocol.md).
|
||||
serde_json = { version = "1", features = ["float_roundtrip"] }
|
||||
anyhow = "1"
|
||||
clap = { version = "4.6.7", features = ["derive"] }
|
||||
tokio = { version = "1", features = ["rt", "macros", "net", "sync"] }
|
||||
|
||||
Reference in New Issue
Block a user