From 1898385241045bf89e98b4a5103f660b548e9f72 Mon Sep 17 00:00:00 2001 From: Christopher Regali Date: Sun, 18 Feb 2024 19:47:45 +0100 Subject: [PATCH 1/4] Bump json-diff 0.4, add array sorting option, adapt unit-tests. --- Cargo.toml | 6 +++--- src/json.rs | 18 +++++++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0d0a53f..f57d2ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,8 +33,8 @@ tracing-subscriber = "0.3" serde_json = "1.0" glob = "0.3" test-log = {version="0.2", features=["trace"]} -strsim = "0.10" -itertools = "0.11" +strsim = "0.11" +itertools = "0.12" tera = "1.19" sha2 = "0.10" data-encoding = "2.4" @@ -47,7 +47,7 @@ tempfile = "3.8" fs_extra = "1.3" opener = "0.6" anyhow = "1.0" -json_diff_ng = {version = "0.3"} +json_diff_ng = {version = "0.4"} [dev-dependencies] diff --git a/src/json.rs b/src/json.rs index f5aee0b..b31a15e 100644 --- a/src/json.rs +++ b/src/json.rs @@ -12,6 +12,8 @@ use tracing::error; pub struct JsonConfig { #[serde(default)] ignore_keys: Vec, + #[serde(default)] + sort_arrays: bool, } impl JsonConfig { pub(crate) fn get_ignore_list(&self) -> Result, regex::Error> { @@ -31,7 +33,7 @@ pub(crate) fn compare_files>( let actual = vg_errortools::fat_io_wrap_std(&actual, &std::fs::read_to_string)?; let ignores = config.get_ignore_list()?; - let json_diff = json_diff::process::compare_jsons(&nominal, &actual); + let json_diff = json_diff::process::compare_jsons(&nominal, &actual, config.sort_arrays); let json_diff = match json_diff { Ok(diff) => diff, Err(e) => { @@ -113,6 +115,7 @@ mod test { fn no_filter() { let cfg = JsonConfig { ignore_keys: vec![], + sort_arrays: false, }; let result = compare_files( "tests/integ/data/json/expected/guy.json", @@ -128,12 +131,12 @@ mod test { } = result.detail.first().unwrap() { let differences = trim_split(differences); - assert!(differences.contains(&"car -> { \"RX7\" != \"Panda Trueno\" }")); - assert!(differences.contains(&"age -> { 21 != 18 }")); - assert!(differences.contains(&"name -> { \"Keisuke\" != \"Takumi\" }")); + assert!(differences.contains(&"car->{\"RX7\"!=\"Panda Trueno\"}")); + assert!(differences.contains(&"age->{21!=18}")); + assert!(differences.contains(&"name->{\"Keisuke\"!=\"Takumi\"}")); assert_eq!(differences.len(), 3); - assert_eq!(left.as_str(), " brothers"); + assert_eq!(left.as_str(), "brothers"); assert!(right.is_empty()); assert!(root_mismatch.is_none()); } else { @@ -145,6 +148,7 @@ mod test { fn filter_works() { let cfg = JsonConfig { ignore_keys: vec!["name".to_string(), "brother(s?)".to_string()], + sort_arrays: false, }; let result = compare_files( "tests/integ/data/json/expected/guy.json", @@ -160,8 +164,8 @@ mod test { } = result.detail.first().unwrap() { let differences = trim_split(differences); - assert!(differences.contains(&"car -> { \"RX7\" != \"Panda Trueno\" }")); - assert!(differences.contains(&"age -> { 21 != 18 }")); + assert!(differences.contains(&"car->{\"RX7\"!=\"Panda Trueno\"}")); + assert!(differences.contains(&"age->{21!=18}")); assert_eq!(differences.len(), 2); assert!(right.is_empty()); assert!(left.is_empty()); From 642e68570f7b471bfc68265dca4f51c749d0a6e8 Mon Sep 17 00:00:00 2001 From: Christopher Regali Date: Sun, 18 Feb 2024 21:33:45 +0100 Subject: [PATCH 2/4] Fix pdf tests, add public single file interface. --- src/lib.rs | 20 +++++++++++--------- src/pdf.rs | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 57db3b1..c690167 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,7 +167,12 @@ fn filter_exclude(paths: Vec, excludes: Vec) -> Vec { .collect() } -fn process_file(nominal: impl AsRef, actual: impl AsRef, rule: &Rule) -> Difference { +/// Use this to compare a single file against another file using a given rule +pub fn compare_files( + nominal: impl AsRef, + actual: impl AsRef, + rule: &Rule, +) -> Difference { let file_name_nominal = nominal.as_ref().to_string_lossy(); let file_name_actual = actual.as_ref().to_string_lossy(); let _file_span = span!(tracing::Level::INFO, "Processing"); @@ -283,7 +288,7 @@ fn process_rule( .into_iter() .zip(actual_cleaned_paths) .for_each(|(n, a)| { - let compare_result = process_file(n, a, rule); + let compare_result = compare_files(n, a, rule); all_okay &= !compare_result.is_error; compare_results.push(compare_result); }); @@ -314,13 +319,10 @@ pub fn compare_folders_cfg( let rule_name = rule.name.as_str(); - let result = match okay { - Ok(result) => result, - Err(e) => { - println!("Error occurred during rule-processing for rule {rule_name}: {e}"); - false - } - }; + let result = okay.unwrap_or_else(|e| { + println!("Error occurred during rule-processing for rule {rule_name}: {e}"); + false + }); rule_results.push(report::RuleDifferences { rule, diffs: compare_results, diff --git a/src/pdf.rs b/src/pdf.rs index 1415635..8c7c7d9 100644 --- a/src/pdf.rs +++ b/src/pdf.rs @@ -89,7 +89,7 @@ mod test { "tests/pdf/expected.pdf", &HTMLCompareConfig { threshold: 1.0, - ignore_lines: Some(vec!["/ w o r k s p a c e /".to_owned()]), + ignore_lines: Some(vec!["/workspace/".to_owned()]), }, ) .unwrap(); From 9762bf151c4973a76ed50b2d40ed8473619b5911 Mon Sep 17 00:00:00 2001 From: Christopher Regali Date: Sun, 18 Feb 2024 21:47:09 +0100 Subject: [PATCH 3/4] Refine public test API, add docs --- README.md | 32 ++++++++++++++++++++++++++++++++ src/lib.rs | 6 +++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3147ab1..d8740e6 100644 --- a/README.md +++ b/README.md @@ -243,9 +243,41 @@ rules: - "ignore_this_key(s?)" ``` +### Use HavoCompare in your unit-tests +1. Add havocompare to your dev-dependencies: + ```toml + [dev-dependencies] + havocompare = "0.5" + ``` +2. Use it in a unit-test like + ```rust + #[test] + // works in 0.5 series + fn integ_test_dirs() { + let result_dir = process_whatever_test_data(); + // just write the usual yaml file + let result = havocompare::compare_folders("../tests/data/nominal/integ_test/case", &result_dir, "../tests/data/config.yaml", "../tests/out_report").unwrap; + assert!(result); + } + #[test] + // works starting with 0.5.3 only + fn integ_test_file() { + let result_file = process_generate_image(); + // see docs for all options + let compare_mode = ComparisonMode::Image(ImageCompareConfig{threshold: 0.97}); + let result = havocompare::compare_files("../tests/data/nominal.png", &result_file, &compare_mode).unwrap; + assert!(result); + } + ``` ## Changelog +### 0.5.3 +- Add option to sort json arrays (including deep sorting) +- Make single file comparison function to public api +- Update dependencies, fix broken pdf import regarding whitespaces + + ### 0.5.2 - Preserve white spaces in CSV and PDF report instead of being collapsed by HTML - Add + and - symbols to the report index diff --git a/src/lib.rs b/src/lib.rs index c690167..55efb76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -171,7 +171,7 @@ fn filter_exclude(paths: Vec, excludes: Vec) -> Vec { pub fn compare_files( nominal: impl AsRef, actual: impl AsRef, - rule: &Rule, + comparison_mode: &ComparisonMode, ) -> Difference { let file_name_nominal = nominal.as_ref().to_string_lossy(); let file_name_actual = actual.as_ref().to_string_lossy(); @@ -181,7 +181,7 @@ pub fn compare_files( info!("File: {file_name_nominal} | {file_name_actual}"); let compare_result: Result> = { - match &rule.file_type { + match comparison_mode { ComparisonMode::CSV(conf) => { csv::compare_paths(nominal.as_ref(), actual.as_ref(), conf).map_err(|e| e.into()) } @@ -288,7 +288,7 @@ fn process_rule( .into_iter() .zip(actual_cleaned_paths) .for_each(|(n, a)| { - let compare_result = compare_files(n, a, rule); + let compare_result = compare_files(n, a, &rule.file_type); all_okay &= !compare_result.is_error; compare_results.push(compare_result); }); From 1bf1b63808dd680a87dc3fa9f2ebfdae51ad3f38 Mon Sep 17 00:00:00 2001 From: Christopher Regali Date: Sun, 18 Feb 2024 23:26:30 +0100 Subject: [PATCH 4/4] Update deps --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f57d2ef..c7d2d39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,9 +25,9 @@ serde_yaml = "0.9" schemars = "0.8" schemars_derive = "0.8" thiserror = "1.0" -regex = "1.8" +regex = "1.10" image = "0.24" -image-compare = "0.3.1" +image-compare = "0.3" tracing = "0.1" tracing-subscriber = "0.3" serde_json = "1.0" @@ -37,7 +37,7 @@ strsim = "0.11" itertools = "0.12" tera = "1.19" sha2 = "0.10" -data-encoding = "2.4" +data-encoding = "2.5" permutation = "0.4" pdf-extract = "0.7" vg_errortools = "0.1" @@ -51,6 +51,6 @@ json_diff_ng = {version = "0.4"} [dev-dependencies] -env_logger = "0.10" +env_logger = "0.11" tracing = {version = "0.1", default-features = false} tracing-subscriber = {version = "0.3", default-features = false, features = ["env-filter", "fmt"]}