From 5f9657289c33d4d29946a83d6c8efd20c40e18f6 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Sun, 08 Feb 2026 19:16:06 +0000 Subject: [PATCH] test: pass full go-jsonnet test suite --- --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -532,17 +532,23 @@ )), (Val::Str(s), Val::Num(n)) => Val::Str({ + let n = n.get(); + if n.fract() > f64::EPSILON { + bail!(FractionalIndex) + } + if n < 0.0 { + bail!(ArrayBoundsError(n as isize, s.into_flat().chars().count())); + } let v: IStr = s .clone() .into_flat() .chars() - .skip(n.get() as usize) + .skip(n as usize) .take(1) .collect::() .into(); if v.is_empty() { - let size = s.into_flat().chars().count(); - bail!(StringBoundsError(n.get() as usize, size)) + bail!(StringBoundsError(n as usize, s.into_flat().chars().count())) } StrValue::Flat(v) }), --- a/crates/jrsonnet-stdlib/src/math.rs +++ b/crates/jrsonnet-stdlib/src/math.rs @@ -168,12 +168,12 @@ #[builtin] pub fn builtin_deg2rad(x: f64) -> f64 { - x * f64::consts::PI / 180.0 + x.to_radians() } #[builtin] pub fn builtin_rad2deg(x: f64) -> f64 { - x * 180.0 / f64::consts::PI + x.to_degrees() } #[builtin] --- a/crates/jrsonnet-stdlib/src/sort.rs +++ b/crates/jrsonnet-stdlib/src/sort.rs @@ -17,6 +17,7 @@ enum SortKeyType { Number, String, + Unspecialized, Unknown, } @@ -31,7 +32,7 @@ (Val::Str(_) | Val::Num(_), _) => { bail!("sort elements should have the same types") } - _ => {} + (_, _) => return Ok(SortKeyType::Unspecialized), } } Ok(sort_type) @@ -49,7 +50,7 @@ Val::Str(s) => s.clone(), _ => unreachable!(), }), - SortKeyType::Unknown => { + SortKeyType::Unknown | SortKeyType::Unspecialized => { let mut err = None; // evaluate_compare_op will never return equal on types, which are different from // jsonnet perspective @@ -88,7 +89,7 @@ Val::Str(s) => s.clone(), _ => unreachable!(), }), - SortKeyType::Unknown => { + SortKeyType::Unknown | SortKeyType::Unspecialized => { let mut err = None; // evaluate_compare_op will never return equal on types, which are different from // jsonnet perspective --- a/crates/jrsonnet-stdlib/src/strings.rs +++ b/crates/jrsonnet-stdlib/src/strings.rs @@ -25,8 +25,11 @@ } #[builtin] -pub fn builtin_str_replace(str: String, from: IStr, to: IStr) -> String { - str.replace(&from as &str, &to as &str) +pub fn builtin_str_replace(str: String, from: IStr, to: IStr) -> Result { + if from.is_empty() { + bail!("'from' string must not be zero length"); + } + Ok(str.replace(&from as &str, &to as &str)) } #[builtin] --- /dev/null +++ b/tests/go_testdata_golden_override/builtinObjectRemoveKey_super_assert.jsonnet.golden @@ -0,0 +1,3 @@ +no such field: x + builtinObjectRemoveKey_super_assert.jsonnet:2:15-17: field access + builtinObjectRemoveKey_super_assert.jsonnet:2:10-17: assertion condition \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.filter8.jsonnet.golden @@ -0,0 +1,3 @@ +type error: expected function, got array + argument evaluation + std.filter8.jsonnet:1:1-37: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.filter_swapped_args.jsonnet.golden @@ -0,0 +1,3 @@ +type error: expected function, got array + argument evaluation + std.filter_swapped_args.jsonnet:1:1-39: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.flatmap5.jsonnet.golden @@ -0,0 +1,5 @@ +runtime error: a + std.flatmap5.jsonnet:1:21-29: error statement + std.flatmap5.jsonnet:2:10-49: function call + argument evaluation + std.flatmap5.jsonnet:2:1-50: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.join7.jsonnet.golden @@ -0,0 +1,2 @@ +runtime error: in std.join all items should be strings + std.join7.jsonnet:1:1-28: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.join8.jsonnet.golden @@ -0,0 +1,2 @@ +runtime error: in std.join all items should be arrays + std.join8.jsonnet:1:1-34: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.makeArrayNamed3.jsonnet.golden @@ -0,0 +1,2 @@ +parameter blahblah is not defined + std.makeArrayNamed3.jsonnet:1:1-55: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.makeArray_bad.jsonnet.golden @@ -0,0 +1,3 @@ +type error: expected BoundedNumber<0, 2147483647>, got string + argument evaluation + std.makeArray_bad.jsonnet:1:1-37: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.makeArray_bad2.jsonnet.golden @@ -0,0 +1,3 @@ +type error: expected function, got string + argument evaluation + std.makeArray_bad2.jsonnet:1:1-26: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.makeArray_noninteger.jsonnet.golden @@ -0,0 +1,3 @@ +runtime error: cannot convert number with fractional part to i32 + argument evaluation + std.makeArray_noninteger.jsonnet:1:1-35: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.makeArray_noninteger_big.jsonnet.golden @@ -0,0 +1,3 @@ +type error: number out of bounds: 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 not in 0..2147483647 + argument evaluation + std.makeArray_noninteger_big.jsonnet:1:1-37: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.manifestYamlDoc_error.jsonnet.golden @@ -0,0 +1,5 @@ +runtime error: foo + std.manifestYamlDoc_error.jsonnet:1:31-43: error statement + field evaluation + field manifestification + std.manifestYamlDoc_error.jsonnet:1:1-48: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.mantissa2.jsonnet.golden @@ -0,0 +1 @@ +0.6562500000000002 \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.mantissa3.jsonnet.golden @@ -0,0 +1 @@ +0.8399999999999999 \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.mantissa4.jsonnet.golden @@ -0,0 +1 @@ +0.571493695641147 \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.mantissa5.jsonnet.golden @@ -0,0 +1 @@ +0.6562499999999998 \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.mantissa6.jsonnet.golden @@ -0,0 +1 @@ +0.6562499999999998 \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.mantissa7.jsonnet.golden @@ -0,0 +1 @@ +-0.6562500000000002 \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.maxArrayOnEmpty.jsonnet.golden @@ -0,0 +1,2 @@ +runtime error: expected non-empty array + std.maxArrayOnEmpty.jsonnet:1:1-18: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.md5_6.jsonnet.golden @@ -0,0 +1,3 @@ +type error: expected string, got number + argument evaluation + std.md5_6.jsonnet:1:1-13: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.minArrayOnEmpty.jsonnet.golden @@ -0,0 +1,2 @@ +runtime error: expected non-empty array + std.minArrayOnEmpty.jsonnet:1:1-18: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.modulo2.jsonnet.golden @@ -0,0 +1,3 @@ +type error: expected number, got string + argument evaluation + std.modulo2.jsonnet:1:1-23: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.modulo3.jsonnet.golden @@ -0,0 +1,3 @@ +type error: expected number, got string + argument evaluation + std.modulo3.jsonnet:1:1-23: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.primitiveEquals10.jsonnet.golden @@ -0,0 +1,4 @@ +runtime error: x + std.primitiveEquals10.jsonnet:1:21-31: error statement + argument evaluation + std.primitiveEquals10.jsonnet:1:1-36: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.primitiveEquals13.jsonnet.golden @@ -0,0 +1,2 @@ +runtime error: primitiveEquals operates on primitive types, got array + std.primitiveEquals13.jsonnet:1:1-29: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.primitiveEquals6.jsonnet.golden @@ -0,0 +1,2 @@ +runtime error: primitiveEquals operates on primitive types, got object + std.primitiveEquals6.jsonnet:1:1-29: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.primitiveEquals7.jsonnet.golden @@ -0,0 +1,2 @@ +runtime error: cannot test equality of functions + std.primitiveEquals7.jsonnet:1:1-51: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.primitiveEquals9.jsonnet.golden @@ -0,0 +1,4 @@ +runtime error: x + std.primitiveEquals9.jsonnet:1:25-35: error statement + argument evaluation + std.primitiveEquals9.jsonnet:1:1-36: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.sort3.jsonnet.golden @@ -0,0 +1,3 @@ +runtime error: foo + std.sort3.jsonnet:1:16-28: error statement + std.sort3.jsonnet:1:1-30: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.sort4.jsonnet.golden @@ -0,0 +1,2 @@ +binary operation array < number is not implemented + std.sort4.jsonnet:1:1-30: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.thisFile.jsonnet.golden @@ -0,0 +1 @@ +"std.thisFile.jsonnet" \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.thisFile2.jsonnet.golden @@ -0,0 +1 @@ +"std.thisFile.jsonnet" \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/std.toString5.jsonnet.golden @@ -0,0 +1,4 @@ +runtime error: x + std.toString5.jsonnet:1:14-24: error statement + argument evaluation + std.toString5.jsonnet:1:1-25: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/stdlib_smoke_test.jsonnet.golden @@ -0,0 +1,279 @@ +{ + "abs": 42, + "acos": 1.0471975511965979, + "asciiLower": "blah", + "asciiUpper": "BLAH", + "asin": 0.5235987755982989, + "assertEqual": true, + "atan": 1.373400766945016, + "base64": [ + "YmxhaA==", + "YmxhaA==" + ], + "base64Decode": "blah\n", + "base64DecodeBytes": [ + 98, + 108, + 97, + 104, + 10 + ], + "ceil": 5, + "char": "A", + "codepoint": 65, + "cos": 0.28366218546322625, + "count": 1, + "decodeUTF8": "AAA", + "encodeUTF8": [ + 98, + 108, + 97, + 104 + ], + "endsWith": true, + "escapeStringBash": "'test '\"'\"'test'\"'\"'test'", + "escapeStringDollars": "test 'test'test", + "escapeStringJson": "\"test 'test'test\"", + "escapeStringPython": "\"test 'test'test\"", + "exp": 148.4131591025766, + "exponent": 3, + "filter": [ + 2, + 4 + ], + "filterMap": [ + 4, + 8 + ], + "find": [ + 2, + 4 + ], + "findSubstr": [ + 0, + 5 + ], + "flatMap": [ + 2, + 3, + 4, + 6, + 6, + 9 + ], + "flattenArrays": [ + 1, + 2, + 3, + 4, + 5, + [ + 6, + 7 + ] + ], + "floor": 5, + "foldl": [ + 0, + 1, + 2, + 3 + ], + "foldr": [ + 1, + 2, + 3, + 4 + ], + "format": "test blah 42", + "get": [ + 17, + 42, + 18, + 42 + ], + "isArray": true, + "isBoolean": true, + "isFunction": true, + "isNumber": true, + "isObject": true, + "isString": true, + "join": "a,b,c", + "length": 0, + "lines": "a\nb\nc\n", + "log": 1.6094379124341003, + "lstripChars": "bbbbcccc", + "makeArray": [ + 0, + 1, + 2, + 3, + 4 + ], + "manifestIni": "a = 1\nb = 2\n[s1]\nx = 1\ny = 2\n", + "manifestJsonEx": "{\n \"a\": {\n \"b\": \"c\"\n }\n}", + "manifestJsonMinified": "{\"a\":{\"b\":\"c\"}}", + "manifestPython": "{\"a\": {\"b\": \"c\"}}", + "manifestPythonVars": "a = {\"b\": \"c\"}\n", + "manifestTomlEx": "[a]\n b = \"c\"", + "manifestXmlJsonml": "", + "manifestYamlDoc": "\"a\":\n \"b\": \"c\"", + "manifestYamlStream": "---\n42\n---\n\"a\":\n \"b\": \"c\"\n...\n", + "mantissa": 0.6249999999999999, + "map": [ + -1, + -2, + -3 + ], + "mapWithIndex": [ + 3, + 3, + 3 + ], + "mapWithKey": { + "a": 42 + }, + "max": 3, + "md5": "1bc29b36f623ba82aaf6724fd3b16718", + "member": true, + "mergePatch": { }, + "min": 2, + "objectFields": [ ], + "objectFieldsAll": [ ], + "objectHas": false, + "objectHasAll": false, + "objectKeysValues": [ ], + "objectKeysValuesAll": [ ], + "objectValues": [ ], + "objectValuesAll": [ ], + "parseHex": 3735928559, + "parseInt": 42, + "parseJson": { + "a": "b" + }, + "parseOctal": 83, + "pow": 8, + "prune": { + "y": [ + "42" + ] + }, + "range": [ + 1, + 2, + 3, + 4, + 5 + ], + "repeat": "foofoofoo", + "reverse": [ + "a", + "b" + ], + "rstripChars": "aaabbbb", + "set": [ + [ + 1, + 2, + 3 + ], + [ + 3, + 2, + 1 + ] + ], + "setDiff": [ + [ + 1, + 2 + ], + [ + 1, + 3 + ] + ], + "setInter": [ + [ + 3 + ], + [ + 2 + ] + ], + "setMember": [ + false, + true + ], + "setUnion": [ + [ + 1, + 2, + 3, + 4, + 5 + ], + [ + 1, + 2, + 3, + 4, + 5 + ] + ], + "sign": 1, + "sin": -0.9589242746631385, + "slice": "o", + "sort": [ + [ + 1, + 2, + 3 + ], + [ + 3, + 2, + 1 + ] + ], + "split": [ + "a", + "b", + "c" + ], + "splitLimit": [ + "a", + "b,c" + ], + "splitLimitR": [ + "a,b", + "c" + ], + "sqrt": 2.23606797749979, + "startsWith": true, + "strReplace": "bba", + "stringChars": [ + "b", + "l", + "a", + "h" + ], + "stripChars": "bbbb", + "substr": "s", + "tan": -3.380515006246586, + "thisFile": "stdlib_smoke_test.jsonnet", + "toString": "42", + "type": "object", + "uniq": [ + [ + 1, + 2, + 3 + ], + [ + "a", + "B", + "a" + ] + ] +} \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/strReplace3.jsonnet.golden @@ -0,0 +1,2 @@ +runtime error: 'from' string must not be zero length + strReplace3.jsonnet:1:1-36: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/string_divided_by_number.jsonnet.golden @@ -0,0 +1 @@ +binary operation string / number is not implemented \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/string_index_negative.jsonnet.golden @@ -0,0 +1 @@ +array out of bounds: -1 is not within [0,4) \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/string_index_out_of_bounds.jsonnet.golden @@ -0,0 +1 @@ +string out of bounds: 4 is not within [0,4) \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/string_minus_number.jsonnet.golden @@ -0,0 +1 @@ +binary operation string - number is not implemented \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/string_plus_function.jsonnet.golden @@ -0,0 +1 @@ +runtime error: tried to manifest function \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/supersugar8.jsonnet.golden @@ -0,0 +1,2 @@ +assert failed: null + supersugar8.jsonnet:1:10-17: assertion failure \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/syntax_error.jsonnet.golden @@ -0,0 +1,2 @@ +syntax error: expected one of "(", "[", "{", , , , , ['"'], ['\''], got "EOF" + syntax_error.jsonnet:1:5 \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/tailstrict2.jsonnet.golden @@ -0,0 +1,3 @@ +runtime error: xxx + tailstrict2.jsonnet:1:13-21: error statement + tailstrict2.jsonnet:2:14-19: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/too_many_arguments.jsonnet.golden @@ -0,0 +1,3 @@ +too many args, function has 3 +Function has the following signature: (x, y, z) + too_many_arguments.jsonnet:1:1-36: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/type_error.jsonnet.golden @@ -0,0 +1,4 @@ +runtime error: xxx + type_error.jsonnet:1:10-22: error statement + argument evaluation + type_error.jsonnet:1:1-23: function call \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/unary_minus4.jsonnet.golden @@ -0,0 +1 @@ +operator - does not operate on type string \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/unary_object.jsonnet.golden @@ -0,0 +1 @@ +operator + does not operate on type object \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/unfinished_args.jsonnet.golden @@ -0,0 +1,2 @@ +syntax error: expected one of "(", ")", ".", "?", "[", "{", , got "EOF" + unfinished_args.jsonnet:1:18 \ No newline at end of file --- /dev/null +++ b/tests/go_testdata_golden_override/variable_not_visible.jsonnet.golden @@ -0,0 +1,3 @@ +local is not defined: nested + variable_not_visible.jsonnet:1:44-51: local access + variable_not_visible.jsonnet:1:52-55: local access \ No newline at end of file --- a/tests/tests/cpp_test_suite.rs +++ b/tests/tests/cpp_test_suite.rs @@ -183,6 +183,15 @@ "number_leading_zero.jsonnet", // Jrsonnet has this overload "number_times_string.jsonnet", + // Jrsonnet has stricter implementations, this is a dumb thing that the filter value might not be + // evaluated anyway... + "std.filter7.jsonnet", + // Golang fails with max stack frames exceeded error + "std.makeArray_recursive_evalutation_order_matters.jsonnet", + // Jrsonnet has this overload + "string_times_number.jsonnet", + // Tailstrict semantics is partially unspecified + "tailstrict3.jsonnet", ]; #[test] @@ -244,17 +253,21 @@ "expected error for golden {}:\n\n{result}\n\n\n{golden}\n", entry.path().display() ), - (Ok(result), Ok(golden)) => { + (Ok(result_v), Ok(golden)) => { // Show diff relative to golden`. - let diff = JsonDiff::diff_string(&golden, &result, false); + let diff = JsonDiff::diff_string(&golden, &result_v, false); if let Some(diff) = diff { - panic!( - "Result \n{result:#}\n\ - and golden \n{golden:#}\n\ - did not match structurally:\n{diff:#}\n\ - for golden {}", - entry.path().display() - ); + if env::var_os("UPDATE_GOLDEN").is_some() { + fs::write(golden_override, result)?; + } else { + panic!( + "Result \n{result_v:#}\n\ + and golden \n{golden:#}\n\ + did not match structurally:\n{diff:#}\n\ + for golden {}", + entry.path().display() + ); + } } } (Err(_), Err(_)) => { -- gitstuff