From 9a698aa1ffb1e269a6edad4fdcc36c3a284aaba7 Mon Sep 17 00:00:00 2001 From: MarekSpodBiedry <73122968+MarekSpodBiedry@users.noreply.github.com> Date: Mon, 12 Oct 2026 08:29:31 +0200 Subject: [PATCH] Make gridcraft-cli check compare conditional-format rule contents, not just their count (#559) --- apps/gridcraft-cli/src/check.rs | 37 ++++++++++++++++++++++++++++++++- docs/cli.md | 7 ++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/apps/gridcraft-cli/src/check.rs b/apps/gridcraft-cli/src/check.rs index 9fc81e3..b1ab389 100644 --- a/apps/gridcraft-cli/src/check.rs +++ b/apps/gridcraft-cli/src/check.rs @@ -559,6 +559,14 @@ fn diff_sets(d: &mut Diffs, sheet: &str, a: &BTreeSet, b: &BTreeSet Vec { + let mut cfs: Vec<_> = s.cond_formats.iter().collect(); + cfs.sort_by_key(|c| c.priority); + cfs.iter().map(|c| format!("{:?} {:?} stopIfTrue={}", c.ranges, c.rule, c.stop_if_true)).collect() +} + fn diff_count(d: &mut Diffs, sheet: &str, a: usize, b: usize) { if a != b { d.push(|| format!("{sheet}: {a} → {b}")); @@ -634,7 +642,12 @@ pub fn diff_workbooks(a: &Workbook, b: &Workbook, opts: &Options) -> Vec>(); let (ca, cb) = (chart_list(sa), chart_list(sb)); @@ -1303,6 +1316,28 @@ mod tests { assert_eq!(get("tables").diffs, 0); } + #[test] + fn diff_detects_changed_cond_format_rule() { + use gridcraft_engine::model::{CfRule, CfValueKind, Color, CondFormat}; + let bar = |gradient: bool, priority: u32| CondFormat { + ranges: vec![gridcraft_engine::core::RangeRef::parse("A1").unwrap()], + rule: CfRule::DataBar { min: CfValueKind::Min, max: CfValueKind::Max, color: Color::Rgb(0x638EC6), gradient, show_value: true }, + priority, + stop_if_true: false, + }; + let with = |cf: CondFormat| { + let mut wb = book(&[("A1", "2", n(2.0))]); + wb.sheet_mut(0).unwrap().cond_formats.push(cf); + wb + }; + let diffs = |a: &Workbook, b: &Workbook| { + diff_workbooks(a, b, &Options::default()).into_iter().find(|c| c.name == "condFormats").unwrap().diffs + }; + assert_eq!(diffs(&with(bar(false, 1)), &with(bar(true, 1))), 1); + assert_eq!(diffs(&with(bar(true, 1)), &with(bar(true, 1))), 0); + assert_eq!(diffs(&with(bar(true, 1)), &with(bar(true, 5))), 0); + } + fn zip_of(parts: &[(&str, &str)]) -> Vec { let mut z = zip::ZipWriter::new(Cursor::new(Vec::new())); for (name, body) in parts { diff --git a/docs/cli.md b/docs/cli.md index b3ee318..372f43c 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -86,9 +86,10 @@ up by *signature*, `expected type → actual type` (e.g. `number → #SPILL!`), **Round trip.** The recalculated workbook is written with GridCraft's XLSX writer, the package is validated (every part has a content type, every content-type override and internal relationship target exists, relationship ids are unique: what Excel would "repair") and read back. Categories compared: `package`, `sheets` (names and order), -`values`, `formulas`, `numFmts` (per cell), `merges`, `names`, `tables` (name, range, columns), `condFormats` (rules -per sheet), `validations`, `charts` (kinds and series counts), `comments`, `hyperlinks`, `pivots`. `#SPILL!`/`#CALC!` -compare equal to `#VALUE!` and `#CIRC!` to 0, as that's what the file format stores. +`values`, `formulas`, `numFmts` (per cell), `merges`, `names`, `tables` (name, range, columns), `condFormats` (each +sheet's rules in priority order, priority numbers aside), `validations`, `charts` (kinds and series counts), `comments`, +`hyperlinks`, `pivots`. `#SPILL!`/`#CALC!` compare equal to `#VALUE!` and `#CIRC!` to 0, as +that's what the file format stores. Files that fail to open are reported with GridCraft's error and don't stop the run. Exit code: 0 when every file opened with no mismatch and no round-trip difference, 1 otherwise, 2 on a usage error. `--max-report` caps the