difftreelog
test print current test
in: master
1 file changed
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 // multi output is a CLI part, not an interpreter.148 "multi.jsonnet",149 "multi_no_newline.jsonnet",150 "multi_no_newline_string_output.jsonnet",151 "multi_string_output.jsonnet",152 // Tested otherwise153 "native1.jsonnet",154 "native2.jsonnet",155 "native3.jsonnet",156 "native6.jsonnet",157 // Since when parser should throw an error for that?..158 "number_leading_zero.jsonnet",159 // Jrsonnet has this overload160 "number_times_string.jsonnet",161 // Golang fails with max stack frames exceeded error162 "std.makeArray_recursive_evalutation_order_matters.jsonnet",163 // Jrsonnet has this overload164 "string_times_number.jsonnet",165 // Tailstrict semantics is partially unspecified166 "tailstrict3.jsonnet",167];168169#[test]170fn cpp_test_suite() -> io::Result<()> {171 for root_dir in ["cpp_test_suite", "go_testdata"] {172 let root_tests = PathBuf::from(env!("CARGO_MANIFEST_DIR"));173 let root = root_tests.join(root_dir);174 let root_override = root_tests.join(format!("{root_dir}_golden_override"));175176 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}")))? {177 let entry = entry?;178 if entry.path().extension().is_none_or(|e| e != "jsonnet") {179 continue;180 }181182 if entry183 .path()184 .file_name()185 .and_then(|v| v.to_str())186 .is_some_and(|v| SKIPPED.contains(&v))187 {188 continue;189 }190191 let result = run(&entry.path(), &root);192193 let mut golden_path = entry.path();194 golden_path.set_extension("jsonnet.golden");195196 let mut golden_path2 = entry.path();197 golden_path2.set_extension("golden");198199 let golden_override =200 root_override.join(golden_path.file_name().expect("file has basename"));201202 // .jsonnet.golden for C++ tests203 let mut golden = read_file(&golden_path)?;204 // .golden for Go tests205 if golden.is_none() && let Some(golden_path) = read_file(&dbg!(golden_path2))? {206 golden = Some(golden_path);207 }208209 // Any of them can be overriden by overrides210 if let Some(golden_path) = read_file(&golden_override)? {211 golden = Some(golden_path);212 }213214 // ir-parser has its own override layer215 #[cfg(feature = "ir-parser")]216 let ir_parser_override_path = {217 let p = root_tests218 .join(format!("{root_dir}_golden_override_ir_parser"))219 .join(golden_path.file_name().expect("file has basename"));220 if let Some(golden_path) = read_file(&p)? {221 golden = Some(golden_path);222 }223 p224 };225226 // Otherwise assume test should just not fail and return true.227 let golden = golden.unwrap_or_else(|| "true".to_owned());228229 #[cfg(feature = "ir-parser")]230 let update_golden_path = &ir_parser_override_path;231 #[cfg(not(feature = "ir-parser"))]232 let update_golden_path = &golden_override;233234 match (serde_json::from_str::<serde_json::Value>(&result), serde_json::from_str::<serde_json::Value>(&golden)) {235 (Err(_), Ok(_)) => panic!(236 "unexpected error for golden {}:\n<got>\n{result}\n</got>\n<golden>\n{golden}\n</golden>",237 entry.path().display()238 ),239 (Ok(_), Err(_)) => panic!(240 "expected error for golden {}:\n<got>\n{result}\n</got>\n<golden>\n{golden}\n</golden>",241 entry.path().display()242 ),243 (Ok(result_v), Ok(golden_v)) => {244 if result_v != golden_v {245 if env::var_os("UPDATE_GOLDEN").is_some() {246 fs::write(update_golden_path, result)?;247 } else {248 panic!(249 "Result \n{result_v:#}\n\250 and golden \n{golden_v:#}\n\251 did not match structurally\n\252 for golden {}",253 entry.path().display()254 );255 }256 }257 }258 (Err(_), Err(_)) => {259 if result != golden.trim_end() {260 if env::var_os("UPDATE_GOLDEN").is_some() {261 fs::write(update_golden_path, result)?;262 } else {263 panic!(264 "golden didn't match for {}:\n<got>\n{result}\n</got>\n<golden>\n{golden}\n</golden>",265 entry.path().display()266 )267 }268 }269 }270 }271 }272 }273274 Ok(())275}