Skip to content

Commit c7f787a

Browse files
Add flag re-introduce broken assertions evaluation, as a temporary measure to help with migration (#536)
Workaround for #526
1 parent be25ada commit c7f787a

7 files changed

Lines changed: 114 additions & 10 deletions

File tree

sjsonnet/src-jvm-native/sjsonnet/Config.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ final case class Config(
139139
doc = """If set, reverses the import order of specified jpaths (so that the rightmost wins)"""
140140
)
141141
reverseJpathsPriority: Flag = Flag(),
142+
@arg(
143+
name = "broken-assertion-logic",
144+
doc =
145+
"Re-enable pre-0.5.5 broken assertion logic. See https://github.com/databricks/sjsonnet/issues/526."
146+
)
147+
brokenAssertionLogic: Flag = Flag(),
142148
@arg(
143149
doc = "The jsonnet file you wish to evaluate",
144150
positional = true

sjsonnet/src/sjsonnet/Evaluator.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -880,8 +880,8 @@ class Evaluator(
880880
val k2 = y.visibleKeyNames
881881
val k1len = k1.length
882882
if (k1len != k2.length) return false
883-
x.triggerAllAsserts()
884-
y.triggerAllAsserts()
883+
x.triggerAllAsserts(settings.brokenAssertionLogic)
884+
y.triggerAllAsserts(settings.brokenAssertionLogic)
885885
var i = 0
886886
while (i < k1len) {
887887
val k = k1(i)

sjsonnet/src/sjsonnet/Materializer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ abstract class Materializer {
2222
case Val.Str(pos, s) => storePos(pos); visitor.visitString(s, -1)
2323
case obj: Val.Obj =>
2424
storePos(obj.pos)
25-
obj.triggerAllAsserts()
25+
obj.triggerAllAsserts(evaluator.settings.brokenAssertionLogic)
2626
val objVisitor = visitor.visitObject(obj.visibleKeyNames.length, jsonableKeys = true, -1)
2727
val sort = !evaluator.settings.preserveOrder
2828
var prevKey: String = null

sjsonnet/src/sjsonnet/Settings.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ class Settings(
88
val preserveOrder: Boolean = false,
99
val strict: Boolean = false,
1010
val throwErrorForInvalidSets: Boolean = false,
11-
val useNewEvaluator: Boolean = false
11+
val useNewEvaluator: Boolean = false,
12+
val brokenAssertionLogic: Boolean = false
1213
)
1314

1415
object Settings {

sjsonnet/src/sjsonnet/Val.scala

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,20 +284,24 @@ object Val {
284284
value0
285285
}
286286

287-
def triggerAllAsserts(): Unit = {
287+
def triggerAllAsserts(brokenAssertionLogic: Boolean): Unit = {
288288
// We need to avoid asserting the same object more than once to prevent
289289
// infinite recursion
290290
if (!asserting) {
291291
asserting = true
292-
triggerAllAsserts(this, `super`)
292+
triggerAllAsserts(this, `super`, brokenAssertionLogic)
293293
}
294294
}
295295

296296
// As we walk up the superclass hierarchy, the `self` binding is unchanged
297297
// but `super` climbs up the hierarchy as well.
298-
@tailrec private def triggerAllAsserts(obj: Val.Obj, sup: Val.Obj): Unit = {
298+
@tailrec private def triggerAllAsserts(
299+
obj: Val.Obj,
300+
sup: Val.Obj,
301+
brokenAssertionLogic: Boolean): Unit = {
299302
if (triggerAsserts != null) triggerAsserts(obj, sup)
300-
if (sup != null) sup.triggerAllAsserts(obj, sup.getSuper)
303+
if ((!brokenAssertionLogic || triggerAsserts == null) && sup != null)
304+
sup.triggerAllAsserts(obj, sup.getSuper, brokenAssertionLogic)
301305
}
302306

303307
def addSuper(pos: Position, lhs: Val.Obj): Val.Obj = {
@@ -439,7 +443,9 @@ object Val {
439443
case null =>
440444
if (s == null) null else s.valueRaw(k, self, pos, addTo, addKey)
441445
case m =>
442-
self.triggerAllAsserts()
446+
if (!evaluator.settings.brokenAssertionLogic || !m.isInstanceOf[Val.Obj.ConstMember]) {
447+
self.triggerAllAsserts(evaluator.settings.brokenAssertionLogic)
448+
}
443449
val vv = m.invoke(self, s, pos.fileScope, evaluator)
444450
val v = if (s != null && m.add) {
445451
s.valueRaw(k, self, pos, null, null) match {

sjsonnet/test/src/sjsonnet/EvaluatorTests.scala

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package sjsonnet
22

33
import utest._
44
import TestUtils.{eval, evalErr}
5+
56
object EvaluatorTests extends TestSuite {
67
def allTests(useNewEvaluator: Boolean): Tests = Tests {
78
test("arithmetic") {
@@ -763,6 +764,90 @@ object EvaluatorTests extends TestSuite {
763764
)
764765
}
765766
}
767+
test("assertInheritanceWithBrokenAssertions") {
768+
test - assert(
769+
evalErr(
770+
"""{ } + {assert false}""",
771+
useNewEvaluator = useNewEvaluator,
772+
brokenAssertionLogic = true
773+
).contains(
774+
"sjsonnet.Error: Assertion failed"
775+
)
776+
)
777+
test - assert(
778+
evalErr(
779+
"""{assert false} + {}""",
780+
useNewEvaluator = useNewEvaluator,
781+
brokenAssertionLogic = true
782+
).contains(
783+
"sjsonnet.Error: Assertion failed"
784+
)
785+
)
786+
test - assert(
787+
evalErr(
788+
"""{assert false} + {} + {}""",
789+
useNewEvaluator = useNewEvaluator,
790+
brokenAssertionLogic = true
791+
).contains(
792+
"sjsonnet.Error: Assertion failed"
793+
)
794+
)
795+
test - assert(
796+
evalErr(
797+
"""{} + {assert false} + {}""",
798+
useNewEvaluator = useNewEvaluator,
799+
brokenAssertionLogic = true
800+
).contains(
801+
"sjsonnet.Error: Assertion failed"
802+
)
803+
)
804+
test - assert(
805+
evalErr(
806+
"""{} + {} + {assert false}""",
807+
useNewEvaluator = useNewEvaluator,
808+
brokenAssertionLogic = true
809+
).contains(
810+
"sjsonnet.Error: Assertion failed"
811+
)
812+
)
813+
test - assert(
814+
evalErr(
815+
"({assert false} + {f(x): x}).f(1)",
816+
useNewEvaluator = useNewEvaluator,
817+
brokenAssertionLogic = true
818+
).contains(
819+
"sjsonnet.Error: Assertion failed"
820+
)
821+
)
822+
test - {
823+
val problematicStrictInheritedAssertionsSnippet =
824+
"""local template = { assert self.flag };
825+
|{ a: template { flag: true, }, b: template { flag: false, } }
826+
|""".stripMargin
827+
assert(
828+
evalErr(
829+
problematicStrictInheritedAssertionsSnippet,
830+
useNewEvaluator = useNewEvaluator,
831+
brokenAssertionLogic = true
832+
).contains("sjsonnet.Error: Assertion failed")
833+
)
834+
}
835+
836+
// Behavior is different from now on.
837+
test {
838+
eval(
839+
"{assert false} + {assert true}",
840+
useNewEvaluator = useNewEvaluator,
841+
brokenAssertionLogic = true
842+
) ==> ujson.Obj()
843+
eval(
844+
"({assert false} + {x: 2}).x",
845+
useNewEvaluator = useNewEvaluator,
846+
brokenAssertionLogic = true
847+
) ==> ujson.Num(2)
848+
}
849+
}
850+
766851
}
767852
def tests = allTests(false).prefix("Evaluator") ++ allTests(true).prefix("NewEvaluator")
768853
}

sjsonnet/test/src/sjsonnet/TestUtils.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ object TestUtils {
88
preserveOrder: Boolean = false,
99
strict: Boolean = false,
1010
useNewEvaluator: Boolean = false,
11+
brokenAssertionLogic: Boolean = false,
1112
std: Std = new Std()): Either[String, Value] = {
1213
new Interpreter(
1314
Map(),
@@ -19,7 +20,8 @@ object TestUtils {
1920
preserveOrder = preserveOrder,
2021
strict = strict,
2122
throwErrorForInvalidSets = true,
22-
useNewEvaluator = useNewEvaluator
23+
useNewEvaluator = useNewEvaluator,
24+
brokenAssertionLogic = brokenAssertionLogic
2325
),
2426
std = std.Std
2527
).interpret(s, DummyPath("(memory)"))
@@ -30,12 +32,14 @@ object TestUtils {
3032
preserveOrder: Boolean = false,
3133
strict: Boolean = false,
3234
useNewEvaluator: Boolean = false,
35+
brokenAssertionLogic: Boolean = false,
3336
std: Std = new Std()): Value = {
3437
eval0(
3538
s,
3639
preserveOrder,
3740
strict,
3841
useNewEvaluator,
42+
brokenAssertionLogic,
3943
std
4044
) match {
4145
case Right(x) => x
@@ -48,12 +52,14 @@ object TestUtils {
4852
preserveOrder: Boolean = false,
4953
strict: Boolean = false,
5054
useNewEvaluator: Boolean = false,
55+
brokenAssertionLogic: Boolean = false,
5156
std: Std = new Std()): String = {
5257
eval0(
5358
s,
5459
preserveOrder,
5560
strict,
5661
useNewEvaluator,
62+
brokenAssertionLogic,
5763
std
5864
) match {
5965
case Left(err) =>

0 commit comments

Comments
 (0)