//! A number read through serde_json must be the number written (improvise-6yvg, //! improvise-dz8c). The rule and its derivation: `context/code/protocol.md`. use serde_json::Value; /// Every NORMAL serde_json dependency in the workspace, and those lacking /// `float_roundtrip`, each spelled `package (target)`. fn lossy_json_dependencies(metadata: &Value) -> (Vec, Vec) { let mut checked = vec![]; let mut lossy = vec![]; let packages = metadata["packages"] .as_array() .expect("metadata lists packages"); for package in packages { let name = package["name"].as_str().expect("a package has a name"); let deps = package["dependencies"] .as_array() .expect("a package lists deps"); for dep in deps { if dep["name"] != "serde_json" || !dep["kind"].is_null() { continue; } let target = dep["target"].as_str().unwrap_or("all targets"); let spelled = format!("{name} ({target})"); let features = dep["features"].as_array().expect("a dep lists features"); if !features.iter().any(|f| f == "float_roundtrip") { lossy.push(spelled.clone()); } checked.push(spelled); } } (checked, lossy) } /// Derived from `cargo metadata`, not listed: a new crate that can parse JSON /// is covered the day it declares the dependency. Evidence file. #[test] fn every_crate_that_can_parse_json_enables_float_roundtrip() { let out = std::process::Command::new(env!("CARGO")) .current_dir(env!("CARGO_MANIFEST_DIR")) .args(["metadata", "--no-deps", "--format-version", "1"]) .output() .expect("cargo metadata must run"); assert!( out.status.success(), "cargo metadata failed: {}", String::from_utf8_lossy(&out.stderr) ); let metadata: Value = serde_json::from_slice(&out.stdout).expect("metadata is JSON"); let (checked, lossy) = lossy_json_dependencies(&metadata); assert!( checked.len() >= 2, "the derivation found {checked:?}: too few to be reading the metadata right" ); assert!( lossy.is_empty(), "these parse JSON numbers with serde_json's lossy default, one ULP off \ for roughly one decimal in seven; add features = [\"float_roundtrip\"] \ to each crate's own manifest: {lossy:?}" ); }