git.delta.rocks / jrsonnet / refs/commits / 48e38361db94

difftreelog

test print current test

nrkzzxllYaroslav Bolyukin2026-04-25parent: #449686f.patch.diff
in: master

1 file changed

modifiedtests/tests/cpp_test_suite.rsdiffbeforeafterboth
after · tests/tests/cpp_test_suite.rs
1use 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	// Golang fails with max stack frames exceeded error160	"std.makeArray_recursive_evalutation_order_matters.jsonnet",161	// Tailstrict semantics is partially unspecified162	"tailstrict3.jsonnet",163	// Jrsonnet has this overload164	"number_times_string.jsonnet",165	// Jrsonnet has this overload166	"string_times_number.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		println!("test: {}", entry.path().display());192193		let result = run(&entry.path(), &root);194195		let mut golden_path = entry.path();196		golden_path.set_extension("jsonnet.golden");197198		let mut golden_path2 = entry.path();199		golden_path2.set_extension("golden");200201		let golden_override =202			root_override.join(golden_path.file_name().expect("file has basename"));203204		// .jsonnet.golden for C++ tests205		let mut golden = read_file(&golden_path)?;206		// .golden for Go tests207		if golden.is_none() && let Some(golden_path) = read_file(&golden_path2)? {208			golden = Some(golden_path);209		}210211		// Any of them can be overriden by overrides212		if let Some(golden_path) = read_file(&golden_override)? {213			golden = Some(golden_path);214		}215216		// ir-parser has its own override layer217		#[cfg(feature = "ir-parser")]218		let ir_parser_override_path = {219			let p = root_tests220				.join(format!("{root_dir}_golden_override_ir_parser"))221				.join(golden_path.file_name().expect("file has basename"));222			if let Some(golden_path) = read_file(&p)? {223				golden = Some(golden_path);224			}225			p226		};227228		// Otherwise assume test should just not fail and return true.229		let golden = golden.unwrap_or_else(|| "true".to_owned());230231		#[cfg(feature = "ir-parser")]232		let update_golden_path = &ir_parser_override_path;233		#[cfg(not(feature = "ir-parser"))]234		let update_golden_path = &golden_override;235236		match (serde_json::from_str::<serde_json::Value>(&result), serde_json::from_str::<serde_json::Value>(&golden)) {237			(Err(_), Ok(_)) => panic!(238				"unexpected error for golden {}:\n<got>\n{result}\n</got>\n<golden>\n{golden}\n</golden>",239				entry.path().display()240			),241			(Ok(_), Err(_)) => panic!(242				"expected error for golden {}:\n<got>\n{result}\n</got>\n<golden>\n{golden}\n</golden>",243				entry.path().display()244			),245			(Ok(result_v), Ok(golden_v)) => {246				if result_v != golden_v {247					if env::var_os("UPDATE_GOLDEN").is_some() {248						fs::write(update_golden_path, result)?;249					} else {250						panic!(251							"Result \n{result_v:#}\n\252								and golden \n{golden_v:#}\n\253								did not match structurally\n\254								for golden {}",255							entry.path().display()256						);257					}258				}259			}260			(Err(_), Err(_)) => {261				if result != golden.trim_end() {262					if env::var_os("UPDATE_GOLDEN").is_some() {263						fs::write(update_golden_path, result)?;264					} else {265						panic!(266						"golden didn't match for {}:\n<got>\n{result}\n</got>\n<golden>\n{golden}\n</golden>",267						entry.path().display()268					)269					}270				}271			}272		}273	}274	}275276	Ok(())277}