diff options
Diffstat (limited to 'lab4/src/test')
12 files changed, 275 insertions, 0 deletions
diff --git a/lab4/src/test/resources/lab4/test4001_id.ans b/lab4/src/test/resources/lab4/test4001_id.ans new file mode 100644 index 0000000..b0ea4bc --- /dev/null +++ b/lab4/src/test/resources/lab4/test4001_id.ans @@ -0,0 +1,4 @@ +## Call(Fun(None,List((x,TNumber)),None,Var(x)),List(N(4.0))) : number +## step 0: Call(Fun(None,List((x,TNumber)),None,Var(x)),List(N(4.0))) +## value: N(4.0) +4.0 diff --git a/lab4/src/test/resources/lab4/test4001_id.jsy b/lab4/src/test/resources/lab4/test4001_id.jsy new file mode 100644 index 0000000..3402469 --- /dev/null +++ b/lab4/src/test/resources/lab4/test4001_id.jsy @@ -0,0 +1 @@ +function(x: number) {return x } (4) diff --git a/lab4/src/test/resources/lab4/test4002_multiparamfun.ans b/lab4/src/test/resources/lab4/test4002_multiparamfun.ans new file mode 100644 index 0000000..302ccae --- /dev/null +++ b/lab4/src/test/resources/lab4/test4002_multiparamfun.ans @@ -0,0 +1,6 @@ +## Call(Fun(None,List((x,TNumber), (y,TBool)),None,If(Var(y),Binary(Plus,Var(x),N(1.0)),Binary(Minus,Var(x),N(1.0)))),List(N(4.0), B(true))) : number +## step 0: Call(Fun(None,List((x,TNumber), (y,TBool)),None,If(Var(y),Binary(Plus,Var(x),N(1.0)),Binary(Minus,Var(x),N(1.0)))),List(N(4.0), B(true))) +## step 1: If(B(true),Binary(Plus,N(4.0),N(1.0)),Binary(Minus,N(4.0),N(1.0))) +## step 2: Binary(Plus,N(4.0),N(1.0)) +## value: N(5.0) +5.0 diff --git a/lab4/src/test/resources/lab4/test4002_multiparamfun.jsy b/lab4/src/test/resources/lab4/test4002_multiparamfun.jsy new file mode 100644 index 0000000..9c38c07 --- /dev/null +++ b/lab4/src/test/resources/lab4/test4002_multiparamfun.jsy @@ -0,0 +1 @@ +function (x: number, y: bool) { return y ? x + 1 : x - 1 } (4, true) diff --git a/lab4/src/test/resources/lab4/test4007_objliteral.ans b/lab4/src/test/resources/lab4/test4007_objliteral.ans new file mode 100644 index 0000000..4b4cc1b --- /dev/null +++ b/lab4/src/test/resources/lab4/test4007_objliteral.ans @@ -0,0 +1,4 @@ +## Obj(TreeMap(a -> N(5.0), b -> N(2.0))) : { a: number; b: number } +## value: Obj(TreeMap(a -> N(5.0), b -> N(2.0))) +{ a: 5.0, + b: 2.0 } diff --git a/lab4/src/test/resources/lab4/test4007_objliteral.jsy b/lab4/src/test/resources/lab4/test4007_objliteral.jsy new file mode 100644 index 0000000..b98f88d --- /dev/null +++ b/lab4/src/test/resources/lab4/test4007_objliteral.jsy @@ -0,0 +1 @@ +{a: 5, b: 2}
\ No newline at end of file diff --git a/lab4/src/test/resources/lab4/test4010_deref.ans b/lab4/src/test/resources/lab4/test4010_deref.ans new file mode 100644 index 0000000..69a991f --- /dev/null +++ b/lab4/src/test/resources/lab4/test4010_deref.ans @@ -0,0 +1,4 @@ +## GetField(Obj(TreeMap(f -> N(3.0))),f) : number +## step 0: GetField(Obj(TreeMap(f -> N(3.0))),f) +## value: N(3.0) +3.0 diff --git a/lab4/src/test/resources/lab4/test4010_deref.jsy b/lab4/src/test/resources/lab4/test4010_deref.jsy new file mode 100644 index 0000000..83418ef --- /dev/null +++ b/lab4/src/test/resources/lab4/test4010_deref.jsy @@ -0,0 +1 @@ +{ f: 3 }.f diff --git a/lab4/src/test/resources/lab4/test4029_simplerec.ans b/lab4/src/test/resources/lab4/test4029_simplerec.ans new file mode 100644 index 0000000..b773df9 --- /dev/null +++ b/lab4/src/test/resources/lab4/test4029_simplerec.ans @@ -0,0 +1,11 @@ +## ConstDecl(n,N(1.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(N(1.0)))) : number +## step 0: ConstDecl(n,N(1.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(N(1.0)))) +## step 1: Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(N(1.0))) +## step 2: If(Binary(Eq,N(1.0),N(0.0)),N(0.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(Binary(Minus,N(1.0),N(1.0))))) +## step 3: If(B(false),N(0.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(Binary(Minus,N(1.0),N(1.0))))) +## step 4: Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(Binary(Minus,N(1.0),N(1.0)))) +## step 5: Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(N(0.0))) +## step 6: If(Binary(Eq,N(0.0),N(0.0)),N(0.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(Binary(Minus,N(0.0),N(1.0))))) +## step 7: If(B(true),N(0.0),Call(Fun(Some(f),List((n,TNumber)),Some(TNumber),If(Binary(Eq,Var(n),N(0.0)),N(0.0),Call(Var(f),List(Binary(Minus,Var(n),N(1.0)))))),List(Binary(Minus,N(0.0),N(1.0))))) +## value: N(0.0) +0.0 diff --git a/lab4/src/test/resources/lab4/test4029_simplerec.jsy b/lab4/src/test/resources/lab4/test4029_simplerec.jsy new file mode 100644 index 0000000..61b2787 --- /dev/null +++ b/lab4/src/test/resources/lab4/test4029_simplerec.jsy @@ -0,0 +1,2 @@ +const n = 1; +(function f(n: number): number { return n === 0 ? 0 : f(n - 1) })(1)
\ No newline at end of file diff --git a/lab4/src/test/scala/jsy/lab4/Lab4Spec.scala b/lab4/src/test/scala/jsy/lab4/Lab4Spec.scala new file mode 100644 index 0000000..0c05aab --- /dev/null +++ b/lab4/src/test/scala/jsy/lab4/Lab4Spec.scala @@ -0,0 +1,217 @@ +package jsy.lab4 + +import org.scalatest.flatspec.AnyFlatSpec +import Parser.parse +import ast._ +import Lab4._ + +class Lab4StudentSpec extends AnyFlatSpec { +} + +class Lab4Spec extends AnyFlatSpec { + + /***** hastype Tests *****/ + { + val xtype = TNumber + val tenvx = extend(Map.empty, "x", xtype) + + "TypeVar" should "perform TypeVar" in { + assertResult(xtype) { + hastype(tenvx, Var("x")) + } + } + + "hastype/call-non-fun" should "yield a static type error" in { + for (e <- List( + ("3(4)"), + ("3(true)"), + ("(10 + 4 + 7 - true * 3)(true)"), + ("((function (x: number) { return 0 })(10))(true)") + )) { + intercept[StaticTypeError] { + inferType(e) + } + } + } + + "hastype/arithmetic" should "type check JavaScripty arithmetic expressions according to the lab spec" in { + for ((e,t) <- List( + ("3 <= 4", TBool), + ("'3' < '4'", TBool), + ("3 + 4", TNumber), + ("'3' + '4'", TString), + ("3 - 4", TNumber), + ("3 * 4 + 1 - 4 / 12", TNumber), + ("undefined", TUndefined) + )) { + assertResult(t){ inferType(e) } + } + } + + "hastype/functions-objects" should "type check JavaScripty function-object expressions according to the lab spec" in { + val f1 = parse("function (x: number) { return x }") + val o1 = parse("{f: 3, g: true, h: undefined}") + for ((e,t) <- List( + (f1, TFun(List(("x", TNumber)), TNumber)), + (o1, TObj(Map("f" -> TNumber, "g" -> TBool, "h" -> TUndefined))), + (Call(f1, List(N(3))), TNumber), + (GetField(o1, "g"), TBool) + )) { + assertResult(t){ inferType(e) } + } + } + + "hastype/simple-programs" should "type check JavaScripty programs according to the lab spec" in { + assertResult(TNumber) { inferType( + """ + const w = function w(y: number): number { return y === 0 ? 0.1 : y + w(y - 1) }; + w(3) + """ + )} + assertResult(TNumber) { inferType( + """ + const x = 1; + const g = function(y: number) { return x; }; + const h = function(x: number) { return g(2); }; + h(3) + """ + )} + } + + "hastype/recursive-programs" should "type check recursive JavaScripty programs according to the lab spec" in { + assertResult(TNumber) { inferType( + """ + const factorial = function f(n: number): number { + return n === 0 ? 1 : n * f(n - 1) + } + factorial(4) + """ + )} + } + } + + + /***** substitute Tests *****/ + { + "substitute" should "substitute a value for uses of a variable" in { + for ((r,e,v,x) <- List( + ("const x = 3; x", "const x = x; x", "3", "x"), + ("function (x: number) { return x + y }", "function (x: number) { return x + y }", "3", "x"), + ("function x(y: number) { return x + y }", "function x(y: number) { return x + y }", "3", "x") + )) { + assertResult(parse(r)){ substitute(parse(v), x, parse(e)) } + } + } + } + + + /***** step Tests *****/ + { + "step" should "perform one step of evaluation according to the lab spec" in { + for ((r, s) <- List ( + ("1", "4 - 3"), + ("3 + 4", "1, 3 + 4"), + ("(3) + 3", "(1 + 2) + 3"), + ("(2) + (3 / 4)", "(1 * 2) + (3 / 4)"), + ("(2 + 4)", "true ? (2 + 4) : (1 + 1)"), + ("const x = 2; x", "const x = 1 + 1; x"), + ("2", "const x = 2; x"), + ("3 + 3 + 4 + 5", "1 + 2 + 3 + 4 + 5"), + ("3", "(function (x: number) { return x })(3)"), +// ("3 + 1", "(function (x: number) { return x })(3 + 1)") + )) { + assertResult(parse(r)){oneStep(s)} + } + } + + "step/call-non-fun" should "yield a stuck error" in { + for (e <- List( + ("3(4)"), + ("3(true)"), + ("((function (x: number) { return 0 })(10))(true)") + )) { + intercept[StuckError] { iterateStep(e) } + } + } + + "step/simple-programs" should "evaluate JavaScripty programs according to the lab spec" in { + assertResult(N(6.1)) { iterateStep( + """ + const w = function w(y: number) { return y === 0 ? 0.1 : y + w(y - 1) } + w(3) + """ + )} + assertResult(N(1)) { iterateStep( + """ + const x = 1; + const g = function(y: number) { return x; }; + const h = function(x: number) { return g(2); }; + h(3) + """ + )} + assertResult(N(1.1)) { iterateStep( + """ + const g = function(x: number) { return function(y: number) { return x - y } }; + g(1)(0) + 0.1 + """ + )} + assertResult(N(6)) { iterateStep( + """ + const plus = function(x: number, y: number) { return x + y }; + plus(1 + 2, 3) + """ + )} + assertResult(N(6)) { iterateStep( + """ + const plus = function(x: number) { return function(y: number) { return x + y } }; + plus(1 + 2)(3) + """ + )} + } + + "step/recursive-programs" should "evaluate recursive JavaScripty programs according to the lab spec" in { + assertResult(N(6)) { iterateStep( + """ + const factorial = function f(n: number) { + return n === 0 ? 1 : n * f(n - 1) + } + factorial(3) + """ + )} + assertResult(S("aaa")) { iterateStep( + """ + const repeat = function(s: string) { + return function loop(n: number) { + return n === 0 ? "" : s + loop(n - 1) + } + } + repeat("a")(3) + """ + )} + } + + "step/objects" should "evaluate JavaScripty objects according to the lab spec" in { + assertResult(N(7.0)) { iterateStep( + """ + const pair = function(x: number, y: number) { + return {x: x, y: y} + }; + const p = pair(3, 4); + p.x + p.y + """ + )} + assertResult(N(5.0)) { iterateStep( + """ + const suspension = function(f: (a: number) => number, n: number) { + return {f: f, n: n} + }; + const s = suspension((a: number) => a + 1, 4); + s.f(s.n) + """ + )} + } + } + +} + +class Lab4JsyTests extends jsy.tester.JavascriptyTester(None, "lab4", Lab4) diff --git a/lab4/src/test/scala/jsy/tester/JavascriptyTester.scala b/lab4/src/test/scala/jsy/tester/JavascriptyTester.scala new file mode 100644 index 0000000..48e789c --- /dev/null +++ b/lab4/src/test/scala/jsy/tester/JavascriptyTester.scala @@ -0,0 +1,23 @@ +package jsy.tester +import java.io.File +import jsy.util.JsyApplication +import org.scalatest._ +import flatspec._ + +/* + * A ScalaTest interface for running system tests. + */ +class JavascriptyTester(rootPrefix: Option[String], testDirectory: String, jsy: JsyApplication) extends AnyFlatSpec { + val testResources = s"src${File.separator}test${File.separator}resources" + val testPrefix = rootPrefix match { + case None => testResources + case Some(p) => s"${p}${File.separator}${testResources}" + } + val testPath = s"${testPrefix}${File.separator}${testDirectory}" + jsy.test(new File(testPath)) { case (in,ans,assertion) => + s"eval on ${in}" should s"match ${ans}" in { + val (b: Boolean, msg: String) = assertion + assert(b, msg) + } + } +} |