Skip to content

Fix various small issues found when I imported all recent error tests #410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion sjsonnet/src/sjsonnet/Evaluator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,9 @@ class Evaluator(
case (l: Val.Num, r: Val.Num) =>
val ll = l.asSafeLong(pos)
val rr = r.asSafeLong(pos)
if (rr < 0) {
Error.fail("shift by negative exponent", pos)
}
if (rr >= 1 && ll >= (1L << (63 - rr)))
Error.fail("numeric value outside safe integer range for bitwise operation", pos)
else
Expand All @@ -563,7 +566,12 @@ class Evaluator(
case Expr.BinaryOp.OP_>> =>
(l, r) match {
case (l: Val.Num, r: Val.Num) =>
Val.Num(pos, (l.asSafeLong(pos) >> r.asSafeLong(pos)).toDouble)
val ll = l.asSafeLong(pos)
val rr = r.asSafeLong(pos)
if (rr < 0) {
Error.fail("shift by negative exponent", pos)
}
Val.Num(pos, (ll >> rr).toDouble)
case _ => fail()
}

Expand Down
21 changes: 11 additions & 10 deletions sjsonnet/src/sjsonnet/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,17 @@ class Parser(
).map(s => Val.Num(s._1, s._2.toDouble))

def escape[$: P]: P[String] = P(escape0 | escape1)
def escape0[$: P]: P[String] = P("\\" ~~ !"u" ~~ AnyChar.!).map {
case "\"" => "\""
case "'" => "\'"
case "\\" => "\\"
case "/" => "/"
case "b" => "\b"
case "f" => "\f"
case "n" => "\n"
case "r" => "\r"
case "t" => "\t"
def escape0[$: P]: P[String] = P("\\" ~~ !"u" ~~ AnyChar.!).flatMapX {
case "\"" => Pass("\"")
case "'" => Pass("\'")
case "\\" => Pass("\\")
case "/" => Pass("/")
case "b" => Pass("\b")
case "f" => Pass("\f")
case "n" => Pass("\n")
case "r" => Pass("\r")
case "t" => Pass("\t")
case s => Fail.opaque(f"Unknown escape sequence in string literal: $s")
}
def escape1[$: P]: P[String] = P("\\u" ~~ CharIn("0-9a-fA-F").repX(min = 4, max = 4).!).map { s =>
Integer.parseInt(s, 16).toChar.toString
Expand Down
27 changes: 22 additions & 5 deletions sjsonnet/src/sjsonnet/Std.scala
Original file line number Diff line number Diff line change
Expand Up @@ -534,11 +534,19 @@ class Std(
}

private object DecodeUTF8 extends Val.Builtin1("decodeUTF8", "arr") {
def evalRhs(arr: Lazy, ev: EvalScope, pos: Position): Val =
new Val.Str(
def evalRhs(arr: Lazy, ev: EvalScope, pos: Position): Val = {
for ((v, idx) <- arr.force.asArr.iterator.zipWithIndex) {
if (!v.isInstanceOf[Val.Num] || !v.asDouble.isWhole || v.asInt < 0 || v.asInt > 255) {
throw Error.fail(
f"Element $idx of the provided array was not an integer in range [0,255]"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's better to prints what it is

)
}
}
Val.Str(
pos,
new String(arr.force.asArr.iterator.map(_.cast[Val.Num].value.toByte).toArray, UTF_8)
new String(arr.force.asArr.iterator.map(_.asInt.toByte).toArray, UTF_8)
)
}
}

private object Substr extends Val.Builtin3("substr", "str", "from", "len") {
Expand Down Expand Up @@ -1004,8 +1012,14 @@ class Std(
}

private object ParseJson extends Val.Builtin1("parseJson", "str") {
def evalRhs(str: Lazy, ev: EvalScope, pos: Position): Val =
ujson.StringParser.transform(str.force.asString, new ValVisitor(pos))
def evalRhs(str: Lazy, ev: EvalScope, pos: Position): Val = {
try {
ujson.StringParser.transform(str.force.asString, new ValVisitor(pos))
} catch {
case e: ujson.ParseException =>
throw Error.fail("Invalid JSON: " + e.getMessage, pos)(ev)
}
}
}

private object ParseYaml extends Val.Builtin1("parseYaml", "str") {
Expand Down Expand Up @@ -1276,6 +1290,9 @@ class Std(
Util.slice(pos, ev, indexable, index, _end, _step)
},
builtin("makeArray", "sz", "func") { (pos, ev, sz: Int, func: Val.Func) =>
if (sz < 0) {
Error.fail(f"std.makeArray requires size >= 0, got $sz")
}
Val.Arr(
pos, {
val a = new Array[Lazy](sz)
Expand Down
3 changes: 3 additions & 0 deletions sjsonnet/src/sjsonnet/Val.scala
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ object Val {
override def asString: String = value
}
final case class Num(pos: Position, value: Double) extends Literal {
if (value.isInfinite) {
Error.fail("overflow")
}
def prettyName = "number"
override def asInt: Int = value.toInt
override def asLong: Long = value.toLong
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
"\u0011"
sjsonnet.Error: Element 0 of the provided array was not an integer in range [0,255]
at [std.decodeUTF8].(sjsonnet/test/resources/test_suite/error.decodeUTF8_float.jsonnet:1:15)

Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
sjsonnet.Error: Expected number, found string
sjsonnet.Error: Element 0 of the provided array was not an integer in range [0,255]
at [std.decodeUTF8].(sjsonnet/test/resources/test_suite/error.decodeUTF8_nan.jsonnet:1:15)

Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
0
sjsonnet.Error: shift by negative exponent
at [BinaryOp >>].(error.negative_shfit.jsonnet:1:8)

Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
Infinity
sjsonnet.Error: overflow
at [BinaryOp *].(error.overflow2.jsonnet:17:7)

Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
Infinity
sjsonnet.Error: overflow
at [BinaryOp *].(error.overflow2.jsonnet:17:7)

Original file line number Diff line number Diff line change
@@ -1,35 +1,3 @@
Exception in thread "main" scala.MatchError: o (of class java.lang.String)
at sjsonnet.Parser.escape0(Parser.scala:109)
at sjsonnet.Parser.escape(Parser.scala:99)
at sjsonnet.Parser.rec$2(Parser.scala:115)
at sjsonnet.Parser.doubleString(Parser.scala:115)
at sjsonnet.Parser.expr2(Parser.scala:349)
at sjsonnet.Parser.expr1(Parser.scala:275)
at sjsonnet.Parser.expr(Parser.scala:211)
at sjsonnet.Parser.document(Parser.scala:567)
at sjsonnet.CachedResolver.$anonfun$2(Importer.scala:218)
at fastparse.SharedPackageDefs.parseInputRaw(SharedPackageDefs.scala:69)
at fastparse.SharedPackageDefs.parseInputRaw$(SharedPackageDefs.scala:6)
at fastparse.package$.parseInputRaw(package.scala:5)
at fastparse.SharedPackageDefs.parse$$anonfun$1(SharedPackageDefs.scala:35)
at fastparse.ParserInputSource$fromParserInput.parseThrough(ParserInput.scala:25)
at fastparse.SharedPackageDefs.parse(SharedPackageDefs.scala:42)
at fastparse.SharedPackageDefs.parse$(SharedPackageDefs.scala:6)
at fastparse.package$.parse(package.scala:5)
at sjsonnet.CachedResolver.parse$$anonfun$1(Importer.scala:216)
at scala.collection.mutable.HashMap.getOrElseUpdate(HashMap.scala:469)
at sjsonnet.DefaultParseCache.getOrElseUpdate(ParseCache.scala:21)
at sjsonnet.CachedResolver.parse(Importer.scala:227)
at sjsonnet.Interpreter.evaluate(Interpreter.scala:175)
at sjsonnet.Interpreter.interpret0(Interpreter.scala:158)
at sjsonnet.SjsonnetMain$.renderNormal$$anonfun$1(SjsonnetMain.scala:157)
at sjsonnet.SjsonnetMain$.writeToFile(SjsonnetMain.scala:131)
at sjsonnet.SjsonnetMain$.renderNormal(SjsonnetMain.scala:155)
at sjsonnet.SjsonnetMain$.mainConfigured(SjsonnetMain.scala:332)
at sjsonnet.SjsonnetMain$.$anonfun$30$$anonfun$1(SjsonnetMain.scala:85)
at scala.util.Either.flatMap(Either.scala:360)
at sjsonnet.SjsonnetMain$.$anonfun$30(SjsonnetMain.scala:84)
at scala.util.Either.flatMap(Either.scala:360)
at sjsonnet.SjsonnetMain$.main0(SjsonnetMain.scala:77)
at sjsonnet.SjsonnetMain$.main(SjsonnetMain.scala:44)
at sjsonnet.SjsonnetMain.main(SjsonnetMain.scala)
sjsonnet.ParseError: Expected "\"":17:2, found "\\o\"\n"
at .(error.parse.string.invalid_escape.jsonnet:17:2)

31 changes: 2 additions & 29 deletions sjsonnet/test/resources/test_suite/error.parse_json.jsonnet.golden
Original file line number Diff line number Diff line change
@@ -1,30 +1,3 @@
sjsonnet.Error: Internal Error
at [std.parseJson].(sjsonnet/test/resources/test_suite/error.parse_json.jsonnet:1:14)
Caused by: ujson.ParseException: expected json value got "b" at index 0
at ujson.ParseException$.apply(Exceptions.scala:6)
at ujson.CharParser.die(CharParser.scala:98)
at ujson.CharParser.parseTopLevel0(CharParser.scala:353)
at ujson.CharParser.parseTopLevel(CharParser.scala:323)
at ujson.CharParser.parse(CharParser.scala:72)
at ujson.StringParser$.transform(StringParser.scala:28)
at sjsonnet.Std$ParseJson$.evalRhs(Std.scala:989)
at sjsonnet.Evaluator.visitApplyBuiltin1(Evaluator.scala:270)
at sjsonnet.Evaluator.visitExpr(Evaluator.scala:40)
at sjsonnet.Interpreter.evaluate$$anonfun$2$$anonfun$1(Interpreter.scala:177)
at sjsonnet.Interpreter.sjsonnet$Interpreter$$handleException(Interpreter.scala:163)
at sjsonnet.Interpreter.evaluate$$anonfun$2(Interpreter.scala:177)
at scala.util.Either.flatMap(Either.scala:360)
at sjsonnet.Interpreter.evaluate(Interpreter.scala:175)
at sjsonnet.Interpreter.interpret0(Interpreter.scala:158)
at sjsonnet.SjsonnetMain$.renderNormal$$anonfun$1(SjsonnetMain.scala:157)
at sjsonnet.SjsonnetMain$.writeToFile(SjsonnetMain.scala:131)
at sjsonnet.SjsonnetMain$.renderNormal(SjsonnetMain.scala:155)
at sjsonnet.SjsonnetMain$.mainConfigured(SjsonnetMain.scala:332)
at sjsonnet.SjsonnetMain$.$anonfun$30$$anonfun$1(SjsonnetMain.scala:85)
at scala.util.Either.flatMap(Either.scala:360)
at sjsonnet.SjsonnetMain$.$anonfun$30(SjsonnetMain.scala:84)
at scala.util.Either.flatMap(Either.scala:360)
at sjsonnet.SjsonnetMain$.main0(SjsonnetMain.scala:77)
at sjsonnet.SjsonnetMain$.main(SjsonnetMain.scala:44)
at sjsonnet.SjsonnetMain.main(SjsonnetMain.scala)
sjsonnet.Error: Invalid JSON: expected json value got "b" at index 0
at [std.parseJson].(error.parse_json.jsonnet:1:14)

Original file line number Diff line number Diff line change
@@ -1,26 +1,3 @@
sjsonnet.Error: Internal Error
sjsonnet.Error: std.makeArray requires size >= 0, got -10
at [std.makeArray].(sjsonnet/test/resources/test_suite/error.std_makeArray_negative.jsonnet:17:14)
Caused by: java.lang.NegativeArraySizeException: -10
at sjsonnet.Std.$init$$$anonfun$13(Std.scala:1262)
at sjsonnet.Std.$init$$$anonfun$adapted$7(Std.scala:1259)
at sjsonnet.functions.FunctionBuilder$$anon$3.evalRhs(FunctionBuilder.scala:47)
at sjsonnet.Evaluator.visitApplyBuiltin2(Evaluator.scala:278)
at sjsonnet.Evaluator.visitExpr(Evaluator.scala:41)
at sjsonnet.Interpreter.evaluate$$anonfun$2$$anonfun$1(Interpreter.scala:177)
at sjsonnet.Interpreter.sjsonnet$Interpreter$$handleException(Interpreter.scala:163)
at sjsonnet.Interpreter.evaluate$$anonfun$2(Interpreter.scala:177)
at scala.util.Either.flatMap(Either.scala:360)
at sjsonnet.Interpreter.evaluate(Interpreter.scala:175)
at sjsonnet.Interpreter.interpret0(Interpreter.scala:158)
at sjsonnet.SjsonnetMain$.renderNormal$$anonfun$1(SjsonnetMain.scala:157)
at sjsonnet.SjsonnetMain$.writeToFile(SjsonnetMain.scala:131)
at sjsonnet.SjsonnetMain$.renderNormal(SjsonnetMain.scala:155)
at sjsonnet.SjsonnetMain$.mainConfigured(SjsonnetMain.scala:332)
at sjsonnet.SjsonnetMain$.$anonfun$30$$anonfun$1(SjsonnetMain.scala:85)
at scala.util.Either.flatMap(Either.scala:360)
at sjsonnet.SjsonnetMain$.$anonfun$30(SjsonnetMain.scala:84)
at scala.util.Either.flatMap(Either.scala:360)
at sjsonnet.SjsonnetMain$.main0(SjsonnetMain.scala:77)
at sjsonnet.SjsonnetMain$.main(SjsonnetMain.scala:44)
at sjsonnet.SjsonnetMain.main(SjsonnetMain.scala)

9 changes: 0 additions & 9 deletions sjsonnet/test/src-js/sjsonnet/ErrorTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@ import utest._

object ErrorTests extends BaseFileTests {
val skippedTests = Set(
"test_suite/error.decodeUTF8_float.jsonnet",
"test_suite/error.function_no_default_arg.jsonnet",
"test_suite/error.negative_shfit.jsonnet",
"test_suite/error.overflow.jsonnet",
"test_suite/error.overflow2.jsonnet",
"test_suite/error.parse.string.invalid_escape.jsonnet",
"test_suite/error.parse_json.jsonnet",
"test_suite/error.std_makeArray_negative.jsonnet",

// Stack size issues with the JS runner
"test_suite/error.array_recursive_manifest.jsonnet",
"test_suite/error.function_infinite_default.jsonnet",
Expand Down
11 changes: 8 additions & 3 deletions sjsonnet/test/src-jvm-native/sjsonnet/BaseFileTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,18 @@ abstract class BaseFileTests extends TestSuite {
var res: Either[String, Value] = Right(null)
try {
res = eval(fileName)
assert(res == Left(expected.stripLineEnd))
assert(res.isLeft)
val actual = res.left.getOrElse("")
assert(actual == expected.stripLineEnd)
} catch {
case _: java.lang.StackOverflowError =>
assert(expected.contains("StackOverflowError"))
case e: sjsonnet.Error =>
assert(expected.stripLineEnd.contains(e.getMessage))
case _: Throwable =>
assert(expected.stripLineEnd.contains(e.getMessage.stripLineEnd))
case e: AssertionError =>
throw e
case e: Throwable =>
println(s"Unexpected error: ${e}")
assert(false)
}
}
Expand Down
21 changes: 5 additions & 16 deletions sjsonnet/test/src-jvm-native/sjsonnet/ErrorTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,11 @@ object ErrorTests extends BaseFileTests {
"error.recursive_function_nonterm.jsonnet"
)

val skippedTests = Set(
"error.decodeUTF8_float.jsonnet",
"error.function_no_default_arg.jsonnet",
"error.negative_shfit.jsonnet",
"error.overflow.jsonnet",
"error.overflow2.jsonnet",
"error.parse.string.invalid_escape.jsonnet",
"error.parse_json.jsonnet",
"error.std_makeArray_negative.jsonnet"
) ++ (
if (isScalaNative) {
skippedTestInScalaNative
} else {
Set()
}
)
val skippedTests = if (isScalaNative) {
skippedTestInScalaNative
} else {
Set.empty[String]
}

val tests: Tests = Tests {
test("error") - {
Expand Down