difftreelog
test re-enable structural matching
in: master
4 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -283,12 +283,6 @@
]
[[package]]
-name = "difflib"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
-
-[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -807,17 +801,6 @@
dependencies = [
"once_cell",
"wasm-bindgen",
-]
-
-[[package]]
-name = "json-structural-diff"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e878e36a8a44c158505c2c818abdc1350413ad83dcb774a0459f6a7ef2b65cbf"
-dependencies = [
- "difflib",
- "regex",
- "serde_json",
]
[[package]]
@@ -1448,7 +1431,6 @@
"jrsonnet-evaluator",
"jrsonnet-gcmodule",
"jrsonnet-stdlib",
- "json-structural-diff",
"serde",
"serde_json",
]
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -85,7 +85,6 @@
regex = "1.12"
lru = "0.16.3"
-json-structural-diff = "0.2.0"
syn-dissect-closure = "0.1.0"
[workspace.lints.rust]
tests/Cargo.tomldiffbeforeafterboth--- a/tests/Cargo.toml
+++ b/tests/Cargo.toml
@@ -19,7 +19,6 @@
jrsonnet-gcmodule.workspace = true
jrsonnet-stdlib.workspace = true
serde.workspace = true
-json-structural-diff.workspace = true
serde_json.workspace = true
[dev-dependencies]
tests/tests/cpp_test_suite.rsdiffbeforeafterboth1use std::{2 env, fs,3 io::{self, ErrorKind},4 path::{Path, PathBuf},5};67use jrsonnet_evaluator::{8 FileImportResolver, IStr, ObjValueBuilder, State, Val, apply_tla,9 gc::WithCapacityExt as _,10 manifest::JsonFormat,11 rustc_hash::FxHashMap,12 tla::TlaArg,13 trace::{CompactFormat, PathResolver, TraceFormat},14};15use jrsonnet_stdlib::ContextInitializer;16mod common;17use common::ContextInitializer as TestContextInitializer;1819fn run(file: &Path, root: &Path) -> String {20 let mut s = State::builder();2122 let std_context = ContextInitializer::new(PathResolver::Relative(root.to_owned()));23 // C++ test suite24 std_context.add_ext_str("var1".into(), "test".into());25 std_context26 .add_ext_code("var2", "{x:1,y:2}")27 .expect("code is valid");2829 // Golang test suite30 std_context31 .add_ext_code("codeVar", "3+3")32 .expect("code is valid");33 std_context.add_ext_str("stringVar".into(), "2 + 2".into());34 std_context35 .add_ext_code(36 "selfRecursiveVar",37 r#"[42, std.extVar("selfRecursiveVar")[0] + 1]"#,38 )39 .expect("code is valid");40 std_context41 .add_ext_code(42 "mutuallyRecursiveVar1",43 r#"[42, std.extVar("mutuallyRecursiveVar2")[0] + 1]"#,44 )45 .expect("code is valid");46 std_context47 .add_ext_code(48 "mutuallyRecursiveVar2",49 r#"[42, std.extVar("mutuallyRecursiveVar1")[0] + 1]"#,50 )51 .expect("code is valid");5253 s.context_initializer((std_context, TestContextInitializer))54 .import_resolver(FileImportResolver::default());55 let s = s.build();5657 let _entered = s.enter();5859 let trace_format = CompactFormat {60 resolver: PathResolver::FileName,61 max_trace: 20,62 padding: 4,63 };6465 let mut v = match s.import(file) {66 Ok(v) => v,67 Err(e) => return trace_format.format(&e).unwrap(),68 };6970 if file71 .file_name()72 .expect("file has basename")73 .to_str()74 .expect("jsonnet testsuite has ascii names")75 .starts_with("tla.")76 {77 let mut args = FxHashMap::new();78 args.insert(IStr::from("var1"), TlaArg::String("test".into()));79 args.insert(80 IStr::from("var2"),81 TlaArg::Val({82 let mut o = ObjValueBuilder::new();8384 o.field("x").value(Val::num(1));85 o.field("y").value(Val::num(2));8687 Val::Obj(o.build())88 }),89 );90 v = apply_tla(&args, v).expect("failed to apply tla");91 } else {92 v = match apply_tla(&FxHashMap::new(), v) {93 Ok(v) => v,94 Err(e) => return trace_format.format(&e).unwrap(),95 };96 }9798 match v.manifest(JsonFormat::default()) {99 Ok(v) => v,100 Err(e) => trace_format.format(&e).unwrap(),101 }102}103104fn read_file(path: &Path) -> io::Result<Option<String>> {105 match fs::read_to_string(path) {106 Ok(v) => Ok(Some(v)),107 Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),108 Err(e) => Err(e),109 }110}111112const SKIPPED: &[&str] = &[113 // C++ tests:114115 // Parser fails with stack overflow. While is a bug, this is a too unusual116 // thing to run untrusted jsonnet code? Will be fixed with nom/rowan.117 "error.parse.deep_array_nesting.jsonnet",118 // Runtime, not static error in jrsonnet119 "error.parse.object_local_clash.jsonnet",120 "error.function_duplicate_param.jsonnet",121 // Too slow to throw due to how lazyness is implemented in jrsonnet122 "error.recursive_object_non_term.jsonnet",123 // In jrsonnet returns the one passed argument, works as Rust's dbg!()124 "error.trace_one_param.jsonnet",125 // In jrsonnet can display any value126 "error.trace_two_param.jsonnet",127 // Depends on unsafe handling of strings as arrays in jsonnet stdlib128 "invariant_manifest.jsonnet",129 // Little bit hard to capture trace logs in this test suite at this moment130 "trace.jsonnet",131 // Go tests:132133 // Something is wrong, go-jsonnet skips safe integer range check here134 "bitwise_or9.jsonnet",135 // Jrsonnet does not use byte strings, all utf8 is converted to bytes first136 "builtinBase64_string_high_codepoint.jsonnet",137 // Split by empty string is string characters, same as everywhere else138 "builtinSplitLimitR6.jsonnet",139 // escapeStringJson only accepts string in jrsonnet140 "builtin_escapeStringJson.jsonnet",141 // golang float formatting is inefficient and not portable142 "builtin_manifestTomlEx.jsonnet",143 "div3.jsonnet",144 "pow6.jsonnet",145 // golang escapes "e" yaml key, does it think it is float?146 "builtin_manifestYamlDoc.jsonnet",147 // Wtf?..148 // Result149 // [150 // {},151 // {},152 // []153 // ]154 // and golden155 // [156 // {},157 // {},158 // []159 // ]160 // did not match structurally:161 // [162 // ...163 // - {164 // - }165 // + {166 // + }167 // [168 // ]169 // ]170 "empty_object_comp.jsonnet",171 "object_hidden.jsonnet",172 // multi output is a CLI part, not an interpreter.173 "multi.jsonnet",174 "multi_no_newline.jsonnet",175 "multi_no_newline_string_output.jsonnet",176 "multi_string_output.jsonnet",177 // Tested otherwise178 "native1.jsonnet",179 "native2.jsonnet",180 "native3.jsonnet",181 "native6.jsonnet",182 // Since when parser should throw an error for that?..183 "number_leading_zero.jsonnet",184 // Jrsonnet has this overload185 "number_times_string.jsonnet",186 // Jrsonnet has stricter implementations, this is a dumb thing that the filter value might not be187 // evaluated anyway...188 "std.filter7.jsonnet",189 // Golang fails with max stack frames exceeded error190 "std.makeArray_recursive_evalutation_order_matters.jsonnet",191 // Jrsonnet has this overload192 "string_times_number.jsonnet",193 // Tailstrict semantics is partially unspecified194 "tailstrict3.jsonnet",195];196197#[test]198fn cpp_test_suite() -> io::Result<()> {199 use json_structural_diff::JsonDiff;200201 for root_dir in ["cpp_test_suite", "go_testdata"] {202 let root_tests = PathBuf::from(env!("CARGO_MANIFEST_DIR"));203 let root = root_tests.join(root_dir);204 let root_override = root_tests.join(format!("{root_dir}_golden_override"));205206 for entry in fs::read_dir(&root).map_err(|e| io::Error::other(format!("failed to enumerate cpp_test_suite dir (Note: it needs to be cloned from C++ jsonnet repo for this test): {e}")))? {207 let entry = entry?;208 if entry.path().extension().is_none_or(|e| e != "jsonnet") {209 continue;210 }211212 if entry213 .path()214 .file_name()215 .and_then(|v| v.to_str())216 .is_some_and(|v| SKIPPED.contains(&v))217 {218 continue;219 }220221 let result = run(&entry.path(), &root);222223 let mut golden_path = entry.path();224 golden_path.set_extension("jsonnet.golden");225226 let mut golden_path2 = entry.path();227 golden_path2.set_extension("golden");228229 let golden_override =230 root_override.join(golden_path.file_name().expect("file has basename"));231232 // .jsonnet.golden for C++ tests233 let mut golden = read_file(&golden_path)?;234 // .golden for Go tests235 if golden.is_none() && let Some(golden_path) = read_file(&dbg!(golden_path2))? {236 golden = Some(golden_path);237 }238239 // Any of them can be overriden by overrides240 if let Some(golden_path) = read_file(&golden_override)? {241 golden = Some(golden_path);242 }243244 // ir-parser has its own override layer245 #[cfg(feature = "ir-parser")]246 let ir_parser_override_path = {247 let p = root_tests248 .join(format!("{root_dir}_golden_override_ir_parser"))249 .join(golden_path.file_name().expect("file has basename"));250 if let Some(golden_path) = read_file(&p)? {251 golden = Some(golden_path);252 }253 p254 };255256 // Otherwise assume test should just not fail and return true.257 let golden = golden.unwrap_or_else(|| "true".to_owned());258259 #[cfg(feature = "ir-parser")]260 let update_golden_path = &ir_parser_override_path;261 #[cfg(not(feature = "ir-parser"))]262 let update_golden_path = &golden_override;263264 match (serde_json::from_str(&result), serde_json::from_str(&golden)) {265 (Err(_), Ok(_)) => panic!(266 "unexpected error for golden {}:\n<got>\n{result}\n</got>\n<golden>\n{golden}\n</golden>",267 entry.path().display()268 ),269 (Ok(_), Err(_)) => panic!(270 "expected error for golden {}:\n<got>\n{result}\n</got>\n<golden>\n{golden}\n</golden>",271 entry.path().display()272 ),273 (Ok(result_v), Ok(golden)) => {274 // Show diff relative to golden`.275 let diff = JsonDiff::diff_string(&golden, &result_v, false);276 if let Some(diff) = diff {277 if env::var_os("UPDATE_GOLDEN").is_some() {278 fs::write(update_golden_path, result)?;279 } else {280 panic!(281 "Result \n{result_v:#}\n\282 and golden \n{golden:#}\n\283 did not match structurally:\n{diff:#}\n\284 for golden {}",285 entry.path().display()286 );287 }288 }289 }290 (Err(_), Err(_)) => {291 if result != golden.trim_end() {292 if env::var_os("UPDATE_GOLDEN").is_some() {293 fs::write(update_golden_path, result)?;294 } else {295 panic!(296 "golden didn't match for {}:\n<got>\n{result}\n</got>\n<golden>\n{golden}\n</golden>",297 entry.path().display()298 )299 }300 }301 }302 }303 }304 }305306 Ok(())307}