feat: remove unsaferunsync and integrate io in tests instead
This commit is contained in:
@@ -1,15 +1,19 @@
|
||||
package wacc
|
||||
|
||||
import org.scalatest.BeforeAndAfterAll
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.Inspectors.forEvery
|
||||
import org.scalatest.matchers.should.Matchers._
|
||||
import org.scalatest.freespec.AsyncFreeSpec
|
||||
import cats.effect.testing.scalatest.AsyncIOSpec
|
||||
import java.io.File
|
||||
import sys.process._
|
||||
import java.io.PrintStream
|
||||
import scala.io.Source
|
||||
import cats.effect.unsafe.implicits.global
|
||||
import cats.effect.IO
|
||||
import wacc.{compile as compileWacc}
|
||||
|
||||
class ParallelExamplesSpec extends AsyncFreeSpec with AsyncIOSpec with BeforeAndAfterAll {
|
||||
|
||||
class ParallelExamplesSpec extends AnyFlatSpec with BeforeAndAfterAll {
|
||||
val files =
|
||||
allWaccFiles("wacc-examples/valid").map { p =>
|
||||
(p.toString, List(0))
|
||||
@@ -24,95 +28,96 @@ class ParallelExamplesSpec extends AnyFlatSpec with BeforeAndAfterAll {
|
||||
(p.toString, List(100, 200))
|
||||
}
|
||||
|
||||
// tests go here
|
||||
forEvery(files) { (filename, expectedResult) =>
|
||||
val baseFilename = filename.stripSuffix(".wacc")
|
||||
given stdout: PrintStream = PrintStream(File(baseFilename + ".out"))
|
||||
|
||||
s"$filename" should "be compiled with correct result" in {
|
||||
val result = compile(filename).unsafeRunSync()
|
||||
assert(expectedResult.contains(result))
|
||||
}
|
||||
s"$filename" - {
|
||||
"should be compiled with correct result" in {
|
||||
compileWacc(filename).map { result =>
|
||||
expectedResult should contain(result)
|
||||
}
|
||||
}
|
||||
|
||||
if (expectedResult == List(0)) it should "run with correct result" in {
|
||||
if (fileIsDisallowedBackend(filename)) pending
|
||||
if (expectedResult == List(0)) {
|
||||
"should run with correct result" in {
|
||||
if (fileIsDisallowedBackend(filename))
|
||||
IO.pure(
|
||||
succeed
|
||||
) // TODO: remove when advanced tests removed. not sure how to "pending" this otherwise
|
||||
else {
|
||||
for {
|
||||
contents <- IO(Source.fromFile(File(filename)).getLines.toList)
|
||||
inputLine = extractInput(contents)
|
||||
expectedOutput = extractOutput(contents)
|
||||
expectedExit = extractExit(contents)
|
||||
|
||||
// Retrieve contents to get input and expected output + exit code
|
||||
val contents = scala.io.Source.fromFile(File(filename)).getLines.toList
|
||||
val inputLine =
|
||||
contents
|
||||
.find(_.matches("^# ?[Ii]nput:.*$"))
|
||||
.map(_.split(":").last.strip + "\n")
|
||||
.getOrElse("")
|
||||
val outputLineIdx = contents.indexWhere(_.matches("^# ?[Oo]utput:.*$"))
|
||||
val expectedOutput =
|
||||
if (outputLineIdx == -1) ""
|
||||
else
|
||||
contents
|
||||
.drop(outputLineIdx + 1)
|
||||
.takeWhile(_.startsWith("#"))
|
||||
.map(_.stripPrefix("#").stripLeading)
|
||||
.mkString("\n")
|
||||
asmFilename = baseFilename + ".s"
|
||||
execFilename = baseFilename
|
||||
gccResult <- IO(s"gcc -o $execFilename -z noexecstack $asmFilename".!)
|
||||
|
||||
val exitLineIdx = contents.indexWhere(_.matches("^# ?[Ee]xit:.*$"))
|
||||
val expectedExit =
|
||||
if (exitLineIdx == -1) 0
|
||||
else contents(exitLineIdx + 1).stripPrefix("#").strip.toInt
|
||||
_ = assert(gccResult == 0)
|
||||
|
||||
// Assembly and link using gcc
|
||||
val asmFilename = baseFilename + ".s"
|
||||
val execFilename = baseFilename
|
||||
val gccResult = s"gcc -o $execFilename -z noexecstack $asmFilename".!
|
||||
assert(gccResult == 0)
|
||||
stdout <- IO.pure(new StringBuilder)
|
||||
process <- IO {
|
||||
s"timeout 5s $execFilename" run ProcessIO(
|
||||
in = w => {
|
||||
w.write(inputLine.getBytes)
|
||||
w.close()
|
||||
},
|
||||
out = Source.fromInputStream(_).addString(stdout),
|
||||
err = _ => ()
|
||||
)
|
||||
}
|
||||
|
||||
// Run the executable with the provided input
|
||||
val stdout = new StringBuilder
|
||||
val process = s"timeout 5s $execFilename" run ProcessIO(
|
||||
in = w => {
|
||||
w.write(inputLine.getBytes)
|
||||
w.close()
|
||||
},
|
||||
out = Source.fromInputStream(_).addString(stdout),
|
||||
err = _ => ()
|
||||
)
|
||||
exitCode <- IO.pure(process.exitValue)
|
||||
|
||||
assert(process.exitValue == expectedExit)
|
||||
assert(
|
||||
stdout.toString
|
||||
.replaceAll("0x[0-9a-f]+", "#addrs#")
|
||||
.replaceAll("fatal error:.*", "#runtime_error#\u0000")
|
||||
.takeWhile(_ != '\u0000')
|
||||
== expectedOutput
|
||||
)
|
||||
} yield {
|
||||
exitCode shouldBe expectedExit
|
||||
normalizeOutput(stdout.toString) shouldBe expectedOutput
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def allWaccFiles(dir: String): IndexedSeq[os.Path] =
|
||||
val d = java.io.File(dir)
|
||||
os.walk(os.Path(d.getAbsolutePath)).filter { _.ext == "wacc" }
|
||||
os.walk(os.Path(d.getAbsolutePath)).filter(_.ext == "wacc")
|
||||
|
||||
// TODO: eventually remove this I think
|
||||
def fileIsDisallowedBackend(filename: String): Boolean =
|
||||
Seq(
|
||||
// format: off
|
||||
// disable formatting to avoid binPack
|
||||
"^.*wacc-examples/valid/advanced.*$",
|
||||
// "^.*wacc-examples/valid/array.*$",
|
||||
// "^.*wacc-examples/valid/basic/exit.*$",
|
||||
// "^.*wacc-examples/valid/basic/skip.*$",
|
||||
// "^.*wacc-examples/valid/expressions.*$",
|
||||
// "^.*wacc-examples/valid/function/nested_functions.*$",
|
||||
// "^.*wacc-examples/valid/function/simple_functions.*$",
|
||||
// "^.*wacc-examples/valid/if.*$",
|
||||
// "^.*wacc-examples/valid/IO/print.*$",
|
||||
// "^.*wacc-examples/valid/IO/read.*$",
|
||||
// "^.*wacc-examples/valid/IO/IOLoop.wacc.*$",
|
||||
// "^.*wacc-examples/valid/IO/IOSequence.wacc.*$",
|
||||
// "^.*wacc-examples/valid/pairs.*$",
|
||||
//"^.*wacc-examples/valid/runtimeErr.*$",
|
||||
// "^.*wacc-examples/valid/scope.*$",
|
||||
// "^.*wacc-examples/valid/sequence.*$",
|
||||
// "^.*wacc-examples/valid/variables.*$",
|
||||
// "^.*wacc-examples/valid/while.*$",
|
||||
// format: on
|
||||
).find(filename.matches).isDefined
|
||||
"^.*wacc-examples/valid/advanced.*$"
|
||||
).exists(filename.matches)
|
||||
|
||||
private def extractInput(contents: List[String]): String =
|
||||
contents
|
||||
.find(_.matches("^# ?[Ii]nput:.*$"))
|
||||
.map(_.split(":").last.strip + "\n")
|
||||
.getOrElse("")
|
||||
|
||||
private def extractOutput(contents: List[String]): String = {
|
||||
val outputLineIdx = contents.indexWhere(_.matches("^# ?[Oo]utput:.*$"))
|
||||
if (outputLineIdx == -1) ""
|
||||
else
|
||||
contents
|
||||
.drop(outputLineIdx + 1)
|
||||
.takeWhile(_.startsWith("#"))
|
||||
.map(_.stripPrefix("#").stripLeading)
|
||||
.mkString("\n")
|
||||
}
|
||||
|
||||
private def extractExit(contents: List[String]): Int = {
|
||||
val exitLineIdx = contents.indexWhere(_.matches("^# ?[Ee]xit:.*$"))
|
||||
if (exitLineIdx == -1) 0
|
||||
else contents(exitLineIdx + 1).stripPrefix("#").strip.toInt
|
||||
}
|
||||
|
||||
private def normalizeOutput(output: String): String =
|
||||
output
|
||||
.replaceAll("0x[0-9a-f]+", "#addrs#")
|
||||
.replaceAll("fatal error:.*", "#runtime_error#\u0000")
|
||||
.takeWhile(_ != '\u0000')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user