aboutsummaryrefslogtreecommitdiff
path: root/lab3/src/test/scala
diff options
context:
space:
mode:
authorJack Sangdahl <[email protected]>2024-12-12 21:02:58 -0700
committerJack Sangdahl <[email protected]>2024-12-12 21:02:58 -0700
commit08f9cae13d0dce99d40a6d93432a84cb075bebfc (patch)
tree5714d73c616b511d8fa5ea8a0ef1d8405f13ce90 /lab3/src/test/scala
parent0d13c649bdabafde59233609be7bd88e273c7ae6 (diff)
downloadcsci3155-08f9cae13d0dce99d40a6d93432a84cb075bebfc.tar.gz
csci3155-08f9cae13d0dce99d40a6d93432a84cb075bebfc.zip
Unit 3
Signed-off-by: Jack Sangdahl <[email protected]>
Diffstat (limited to 'lab3/src/test/scala')
-rw-r--r--lab3/src/test/scala/jsy/lab3/Lab3Spec.scala150
-rw-r--r--lab3/src/test/scala/jsy/tester/JavascriptyTester.scala23
2 files changed, 173 insertions, 0 deletions
diff --git a/lab3/src/test/scala/jsy/lab3/Lab3Spec.scala b/lab3/src/test/scala/jsy/lab3/Lab3Spec.scala
new file mode 100644
index 0000000..1b40c01
--- /dev/null
+++ b/lab3/src/test/scala/jsy/lab3/Lab3Spec.scala
@@ -0,0 +1,150 @@
+package jsy.lab3
+
+import org.scalatest.flatspec.AnyFlatSpec
+import Parser.parse
+import ast._
+import Lab3._
+
+class Lab3StudentSpec extends AnyFlatSpec {
+
+ "StudentSpec" should "evaluate a higher order function" in {
+ val jsyStr: String =
+ "(function f(g) { return g(g)}) (function g(x) { return x }) (5);"
+ val answer: Either[DynamicTypeError, Expr] = Right(N(5))
+ assert(answer === iterateStep(parse(jsyStr)))
+ }
+
+ it should "evaluate a recursive function" in {
+ val jsyStr: String =
+ "(function f(x) { return x <= 1 ? 1 : x * f(x - 1)}) (3);"
+ val answer: Either[DynamicTypeError, Expr] = Right(N(6))
+ assert(answer === iterateStep(parse(jsyStr)))
+ }
+
+ it should "evaluate your test case" in {
+ val jsyStr: String = "1 + 1"
+ val answer: Either[DynamicTypeError, Expr] = Right(N(2))
+ assert(answer === iterateStep(parse(jsyStr)))
+ }
+
+}
+
+class Lab3Spec extends AnyFlatSpec {
+
+ "substitute" should "perform syntatic substitution respecting shadowing" in {
+ val xplus1 = parse("x + 1")
+ val twoplus1 = parse("2 + 1")
+ assert(substitute(N(2), "x", xplus1) === twoplus1)
+ val constx3 = parse("const x = 3; x")
+ val shadowx = Binary(Plus, constx3, Var("x"))
+ assert(substitute(N(2), "x", shadowx) === Binary(Plus, constx3, N(2)))
+ }
+
+ "iterateBasic" should "work for sumTo(100)" in {
+ def sumTo(n: Int) = {
+ iterateBasic(0) { case (acc, i) =>
+ require(n >= 0)
+ if (i > n) None
+ else Some(acc + i)
+ }
+ }
+
+ assertResult(5050) { sumTo(100) }
+ }
+
+ {
+ def sumTo(n: Int): Either[String, Int] = {
+ iterate(0) { case (acc, i) =>
+ if (n < 0) Some(Left("requirement failed"))
+ else if (i > n) None
+ else Some(Right(acc + i))
+ }
+ }
+
+ "iterate" should "work for sumTo(100)" in {
+ assertResult(Right(5050)) { sumTo(100) }
+ }
+
+ "iterate" should "work for sumTo(-1)" in {
+ assertResult(Left("requirement failed")) { sumTo(-1) }
+ }
+
+ val one = parse("1")
+
+ it should "stop if the callback body returns None" in {
+ assertResult(Right(one)) {
+ iterate(one) { (_, _) => None }
+ }
+ }
+
+ it should "increment the loop counter on each iteration and use e if the callback body returns Some(e)" in {
+ assertResult(Right(parse("--1"))) {
+ iterate(one) { (e: Expr, n: Int) =>
+ if (n == 2) None else Some(Right(Unary(Neg, e)))
+ }
+ }
+ }
+ }
+
+ "step/call" should "evaluate a function using small-step semantics" in {
+ val f = "f"
+ val x = "x"
+ val e1 = Fun(None, x, Binary(Plus, Var(x), N(1)))
+ val e2 = N(2)
+ val e3 = iterateStep(Call(e1, e2))
+ assert(e3 === Right(N(3)))
+ }
+
+ it should "handle recursive functions using small-step semantics" in {
+ val f = "f"
+ val x = "x"
+ val fbody = If(
+ Binary(Eq, Var(x), N(0)),
+ Var(x),
+ Binary(Plus, Var(x), Call(Var(f), Binary(Minus, Var(x), N(1))))
+ )
+ val e1 = Fun(Some(f), x, fbody)
+ val e2 = N(3)
+ val e3 = iterateStep(Call(e1, e2))
+ assert(e3 === Right(N(6)))
+ }
+
+ /* Some tests based on rules */
+
+ {
+ val xval = N(2)
+ val varx = Var("x")
+
+ val e1 = parse("2 - 1 - 1")
+ val e1p = parse("1 - 1")
+ val e2 = parse("3 - 1 - 1")
+ val e2p = parse("2 - 1")
+ val v1 = N(0)
+ val v2 = N(1)
+
+ val vidfunction = parse("function (x) { return x }")
+
+ "DoNeg" should "perform DoNeg" in {
+ val np = -0
+ assertResult(Right(N(np))) {
+ step(Unary(Neg, v1))
+ }
+ }
+
+ "SearchUnary" should "perform SearchUnary" in {
+ assertResult(Right(Unary(Neg, e1p))) {
+ step(Unary(Neg, e1))
+ }
+ }
+
+ val e_callerror = Call(N(1), N(2))
+
+ "TypeErrorCall" should "perform TypeErrorCall" in {
+ assertResult(Left(DynamicTypeError(e_callerror))) {
+ step(e_callerror)
+ }
+ }
+ }
+}
+
+class Lab3JsyTests extends jsy.tester.JavascriptyTester(None, "lab3", Lab3)
diff --git a/lab3/src/test/scala/jsy/tester/JavascriptyTester.scala b/lab3/src/test/scala/jsy/tester/JavascriptyTester.scala
new file mode 100644
index 0000000..48e789c
--- /dev/null
+++ b/lab3/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)
+ }
+ }
+}